Multitexturing of Terrain

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
JFT90
Posts: 22
Joined: Sun Jan 03, 2016 6:53 pm

Multitexturing of Terrain

Post by JFT90 »

Hi!

I am trying to use the old Multitexturingmanager( from freetimcoder) (http://irrlicht.sourceforge.net/forum/v ... re#p225314)
I also tried to change certain parts of the manager as suggested in answers on page 3. But it doesn't change anything.
Currently the output looks like this:
Image
I am not really sure what is going on.
Tried CodeXL to see if there is a bug in the shader. The only thing I found is that a lot of OpenGL commands used are deprecated.

Is there a better Way to do multitexturing of the Terrain than using the shader approach?

Thanks for your help in advance!

Code:
Multitexturingmanager.h:

Code: Select all

#ifndef CMULTITEXTURINGMANAGER_H_INCLUDED
#define CMULTITEXTURINGMANAGER_H_INCLUDED
 
#include <irrlicht/irrlicht.h>
#include <irrlicht/SMaterial.h>
 
 
class CMultiTexturingManager: public irr::video::IShaderConstantSetCallBack
{
public:
    struct STexturePass
    {
        irr::video::ITexture *splat_texture;
        irr::video::ITexture *red_texture;
        irr::video::ITexture *green_texture;
        irr::video::ITexture *blue_texture;
    };
 
private:
    struct SMultiTextureNode
    {
        //The textured node
        irr::scene::ISceneNode *Node;
        irr::core::array<STexturePass*> array_Passes;
    };
 
public:
    CMultiTexturingManager(irr::scene::ISceneManager* psmgr);
 
    ~CMultiTexturingManager();
 
    void drawAll();
 
    virtual void OnSetConstants(irr::video::IMaterialRendererServices* services,irr::s32 userData);
 
    bool addNode(irr::scene::ISceneNode *node);
 
    bool removeNode(irr::scene::ISceneNode *node);
 
    STexturePass *addPass(irr::scene::ISceneNode *node);
    STexturePass *addPass(irr::scene::ISceneNode *node, irr::video::ITexture *splat, irr::video::ITexture *red, irr::video::ITexture *green, irr::video::ITexture *blue);
    STexturePass *addPass(irr::scene::ISceneNode *node, STexturePass *pass);
 
    bool removePass(irr::scene::ISceneNode *node, irr::u32 layer);
    bool removePass(irr::scene::ISceneNode *node, STexturePass *pass);
 
private:
        irr::scene::ISceneManager* smgr;
 
        irr::video::IVideoDriver* driver;
 
        irr::core::array<SMultiTextureNode> array_Nodes;
 
        int shaderMaterial;
 
};
 
#endif // CMULTITEXTURINGMANAGER_H_INCLUDED
 
Multitexturingmanager.cpp:

Code: Select all

#include "cmultitexturingmanager.h"
 
using namespace irr;
 
CMultiTexturingManager::CMultiTexturingManager(irr::scene::ISceneManager* psmgr):
smgr(psmgr),driver(psmgr->getVideoDriver()),array_Nodes(irr::core::array<SMultiTextureNode>()),shaderMaterial(0)
{
    //Create the shader material
    shaderMaterial = driver->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles(
                         "media/shader/mapvert.glsl", "main", video::EVST_VS_1_1,
                         "media/shader/mapfrag.glsl", "main", video::EPST_PS_1_1,
                         this, video::EMT_ONETEXTURE_BLEND);
}
 
CMultiTexturingManager::~CMultiTexturingManager()
{
    //Erase everything
    for(u32 i=0; i<array_Nodes.size(); i++)
    {
        while(!array_Nodes[i].array_Passes.empty())
        {
            array_Nodes[i].array_Passes.erase(0);
        }
    }
    while(!array_Nodes.empty())
    {
        array_Nodes.erase(0);
    }
}
 
bool CMultiTexturingManager::addNode(scene::ISceneNode *node)
{
    for(u32 i=0; i<array_Nodes.size(); i++)
    {
        if(array_Nodes[i].Node == node)
        {
            return false;
        }
    }
    SMultiTextureNode tmpNode;
    tmpNode.Node = node;
    array_Nodes.push_back(tmpNode);
    return true;
}
 
bool CMultiTexturingManager::removeNode(scene::ISceneNode *node)
{
    for(u32 i=0; i<array_Nodes.size(); i++)
    {
        if(array_Nodes[i].Node == node)
        {
            array_Nodes.erase(i);
            return true;
        }
    }
    return false;
}
 
CMultiTexturingManager::STexturePass *CMultiTexturingManager::addPass(scene::ISceneNode *node)
{
    for(u32 i=0; i<array_Nodes.size(); i++)
    {
        if(array_Nodes[i].Node == node)
        {
            STexturePass *pass = new STexturePass();
            pass->red_texture = node->getMaterial(0).getTexture(0);
            pass->green_texture = node->getMaterial(0).getTexture(1);
            pass->blue_texture = node->getMaterial(0).getTexture(2);
            pass->splat_texture = node->getMaterial(0).getTexture(3);
 
            array_Nodes[i].array_Passes.push_back(pass);
            return pass;
        }
    }
    return nullptr;
}
 
CMultiTexturingManager::STexturePass *CMultiTexturingManager::addPass(scene::ISceneNode *node, video::ITexture *splat, video::ITexture *red, video::ITexture *green, video::ITexture *blue)
{
    for(u32 i=0; i<array_Nodes.size(); i++)
    {
        if(array_Nodes[i].Node == node)
        {
            STexturePass *pass = new STexturePass();
            pass->red_texture = red;
            pass->green_texture = green;
            pass->blue_texture = blue;
            pass->splat_texture = splat;
 
            array_Nodes[i].array_Passes.push_back(pass);
            return pass;
        }
    }
    return nullptr;
}
 
CMultiTexturingManager::STexturePass *CMultiTexturingManager::addPass(scene::ISceneNode *node, STexturePass *pass)
{
    for(u32 i=0; i<array_Nodes.size(); i++)
    {
        if(array_Nodes[i].Node == node)
        {
            //STexturePass *Pass = pass;
 
            array_Nodes[i].array_Passes.push_back(pass);
            return pass;
        }
    }
    return nullptr;
}
 
bool CMultiTexturingManager::removePass(scene::ISceneNode *node, u32 layer)
{
    for(u32 i=0; i<array_Nodes.size(); i++)
    {
        if(array_Nodes[i].Node == node)
        {
            for(u32 j = 0; j<array_Nodes[i].array_Passes.size(); j++)
            {
                if(j==layer)
                    array_Nodes[i].array_Passes.erase(j);
                return true;
            }
        }
    }
    return false;
}
 
bool CMultiTexturingManager::removePass(scene::ISceneNode *node, STexturePass *pass)
{
    for(u32 i=0; i<array_Nodes.size(); i++)
    {
        if(array_Nodes[i].Node == node)
        {
            for(u32 j = 0; j<array_Nodes[i].array_Passes.size(); j++)
            {
                if(array_Nodes[i].array_Passes[j]==pass)
                    array_Nodes[i].array_Passes.erase(j);
                return true;
            }
        }
    }
    return false;
}
 
 
void CMultiTexturingManager::drawAll()
{
 
    for(u32 i=0; i<array_Nodes.size(); i++)
    {
        //I learned this meshbuffer trick from Viz_Fuerte's "Simple but useful projects"
        if(!smgr->isCulled(array_Nodes[i].Node))
        {
            array_Nodes[i].Node->setVisible(true);
            array_Nodes[i].Node->OnRegisterSceneNode();
            array_Nodes[i].Node->updateAbsolutePosition();
            array_Nodes[i].Node->setVisible(false);
            //Reset the transformation
 
            if(array_Nodes[i].Node->getType()==scene::ESNT_TERRAIN)
                driver->setTransform(video::ETS_WORLD,core::IdentityMatrix);
            else
                driver->setTransform(video::ETS_WORLD,array_Nodes[i].Node->getAbsoluteTransformation());
 
            for(u32 j=0; j<array_Nodes[i].array_Passes.size(); j++)
            {
                array_Nodes[i].Node->setMaterialTexture(0,array_Nodes[i].array_Passes[j]->splat_texture);
                array_Nodes[i].Node->setMaterialTexture(1,array_Nodes[i].array_Passes[j]->red_texture);
                array_Nodes[i].Node->setMaterialTexture(2,array_Nodes[i].array_Passes[j]->green_texture);
                array_Nodes[i].Node->setMaterialTexture(3,array_Nodes[i].array_Passes[j]->blue_texture);
 
                if(array_Nodes[i].Node->getType()==scene::ESNT_TERRAIN)
                {
                    video::SMaterial material = array_Nodes[i].Node->getMaterial(0);
                    material.MaterialType = (video::E_MATERIAL_TYPE)shaderMaterial;
                    material.BlendOperation = video::EBO_ADD;
                    material.MaterialTypeParam = pack_textureBlendFunc(video::EBF_SRC_ALPHA ,video::EBF_ONE_MINUS_SRC_ALPHA);
 
                    driver->setMaterial(material);
                    driver->drawMeshBuffer(((scene::ITerrainSceneNode*)array_Nodes[i].Node)->getRenderBuffer());
 
                }
                else
                {
                    for(u32 k=0; k<array_Nodes[i].Node->getMaterialCount(); ++k)
                    {
                        video::SMaterial material = array_Nodes[i].Node->getMaterial(k);
                        material.MaterialType = (video::E_MATERIAL_TYPE)shaderMaterial;
                        material.BlendOperation = video::EBO_ADD;
                        material.MaterialTypeParam = pack_textureBlendFunc(video::EBF_DST_COLOR,video::EBF_ONE);
 
                        driver->setMaterial(material);
                        switch(array_Nodes[i].Node->getType())
                        {
                        case scene::ESNT_ANIMATED_MESH:
                            driver->drawMeshBuffer(((scene::IAnimatedMeshSceneNode*)array_Nodes[i].Node)->getMesh()->getMeshBuffer(k));
                            break;
                        default:
                            driver->drawMeshBuffer(((scene::IMeshSceneNode*)array_Nodes[i].Node)->getMesh()->getMeshBuffer(k));
                            break;
                        };
                    }
                }
            }
        }
    }
}
 
void CMultiTexturingManager::OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
    int layer0 = 0;
    int layer1 = 1;
    int layer2 = 2;
    int layer3 = 3;
    services->setPixelShaderConstant("splatMap",(float*)&layer0,1);
    services->setPixelShaderConstant("layer_red",(float*)&layer1,1);
    services->setPixelShaderConstant("layer_green",(float*)&layer2,1);
    services->setPixelShaderConstant("layer_blue",(float*)&layer3,1);
}
 
Shader:
Vertexshader:

Code: Select all

attribute vec4 AttrMultiTexCoord0;
attribute vec4 AttrMultiTexCoord1;
varying vec4 VaryingTexCoord0;
varying vec4 VaryingTexCoord1;
 
void main()
{
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    VaryingTexCoord0 = gl_MultiTexCoord0;
    VaryingTexCoord1 = gl_MultiTexCoord1;
}
 
Fragmentshader:

Code: Select all

varying vec4 VaryingTexCoord0;
varying vec4 VaryingTexCoord1;
uniform sampler2D splatMap;
uniform sampler2D layer_red;
uniform sampler2D layer_green;
uniform sampler2D layer_blue;
 
void main()
{
    vec4 SplatCol=texture2D(splatMap,VaryingTexCoord0.xy);
    vec4 RedCol=texture2D(layer_red,VaryingTexCoord1.xy);
    vec4 GreenCol=texture2D(layer_green,VaryingTexCoord1.xy);
    vec4 BlueCol=texture2D(layer_blue,VaryingTexCoord1.xy);
    gl_FragColor=(vec4(SplatCol.r*RedCol+SplatCol.g*GreenCol+SplatCol.b*BlueCol))*vec4(1,1,1,SplatCol.a);
}
 
Irrlicht with bgfx-Driver https://gitlab.com/JFT/Irrlicht_extended (forked from Irrlicht trunk)
JFT90
Posts: 22
Joined: Sun Jan 03, 2016 6:53 pm

Re: Multitexturing of Terrain

Post by JFT90 »

I fixed the Problem by changing the Code in the function OnSetConstants to:

Code: Select all

 
void CMultiTexturingManager::OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
    int layer0 = 0;
    int layer1 = 1;
    int layer2 = 2;
    int layer3 = 3;
    services->setPixelShaderConstant("splatMap", &layer0, 1);
    services->setPixelShaderConstant("layer_red", &layer1, 1);
    services->setPixelShaderConstant("layer_green", &layer2, 1);
    services->setPixelShaderConstant("layer_blue", &layer3, 1);
}
 
so just removing (float*) in the setPixelShaderConstant(..) calls did the trick.
I also noticed I forgot to change:

Code: Select all

 
material.MaterialTypeParam = pack_textureBlendFunc(video::EBF_DST_COLOR,video::EBF_ONE);
 
to

Code: Select all

 
material.MaterialTypeParam = pack_textureBlendFunc(video::EBF_SRC_ALPHA, video::EBF_ONE_MINUS_SRC_ALPHA);
 
for other nodes than terrainnodes.
There are still two other problems remaining:
Artifacts - small blue , red and green lines appering randomly -it's like a tiny part pf the splattmap shines through. Doesn't show up on all Systems though -> graphics card dependent?
The artifacts can also be seen in the screenshot
Image
Right now there is no texture tilling and the non splatmap textures just get streched all over the terrain - I am trying to fix that at the moment.
Irrlicht with bgfx-Driver https://gitlab.com/JFT/Irrlicht_extended (forked from Irrlicht trunk)
Post Reply