Thanks for answer hybrid. Can you give me a hint on how to use texture coords?
Besides, i think the problem seems not to be lying in the shader, but in the use of setTextureMaterial on a terrain mesh. The screenshot shows the perfectly splatted texture, but simply repeated 16 times. If i do this without any use of shaders i get the exactly same result:
Code: Select all
video::ITexture* pTexture = m_pDriver->getTexture("./graphics/textures/terrain/terrain.png");
scene::IMesh* terrainMesh = m_pSceneMgr->addTerrainMesh(name.c_str(), heightMap, heightMap, core::dimension2d<f32>(1, 1), 10);
if (terrainMesh) {
m_pTerrain = m_pSceneMgr->addMeshSceneNode(terrainMesh);
}
m_pTerrain->setMaterialTexture(0, pTexture);
Here are the shaders:
Vertex Shader:
Code: Select all
void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;
gl_Position = ftransform();
}
Pixel Shader:
Code: Select all
uniform sampler2D splatMap;
uniform sampler2D layer_red;
uniform sampler2D layer_green;
uniform sampler2D layer_blue;
void main() {
vec4 SplatCol = texture2D(splatMap, gl_TexCoord[0].xy);
vec4 RedCol = texture2D(layer_red, gl_TexCoord[1].xy);
vec4 GreenCol = texture2D(layer_green, gl_TexCoord[1].xy);
vec4 BlueCol = texture2D(layer_blue, gl_TexCoord[1].xy);
gl_FragColor = vec4(SplatCol.r * RedCol + SplatCol.g * GreenCol + SplatCol.b * BlueCol) * vec4(1, 1, 1, SplatCol.a);
}
The shader Callback (TerrainTexturing.cpp):
Code: Select all
#include "TerrainTexturing.h"
TerrainTexturing::TerrainTexturing(IrrlichtDevice *pDevice, scene::ISceneManager* pSceneMgr)
{
//Assign all parameters
m_pSceneMgr = pSceneMgr;
m_pDriver = pSceneMgr->getVideoDriver();
io::path vertShader;
io::path fragShader;
io::path vsFile = "terrain.vsh";
io::path psFile = "terrain.psh";
// log action
core::stringc msg = core::stringc("compiling material terrainsplat");
pDevice->getLogger()->log(msg.c_str(), ELL_INFORMATION);
// create destination path for (driver specific) shader files
if (m_pDriver->getDriverType() == video::EDT_OPENGL) {
vertShader = core::stringc("./graphics/shaders/glsl/") + vsFile;
fragShader = core::stringc("./graphics/shaders/glsl/") + psFile;
}
//Create the shader material
m_nShaderMaterial = m_pDriver->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles(vertShader, "main", video::EVST_VS_1_1,
fragShader, "main", video::EPST_PS_1_1,
this, video::EMT_TRANSPARENT_ALPHA_CHANNEL);
m_pTextureSplat = new STextureSplat();
m_pMultitextureNode = new SMultiTextureNode;
}
TerrainTexturing::~TerrainTexturing()
{
if (m_pMultitextureNode != NULL) {
delete m_pMultitextureNode;
m_pMultitextureNode = NULL;
}
if (m_pTextureSplat != NULL) {
delete m_pTextureSplat;
m_pTextureSplat = NULL;
}
}
bool TerrainTexturing::addNode(scene::ISceneNode *pNode)
{
if (m_pMultitextureNode->pNode == pNode) {
return false;
} else {
m_pMultitextureNode->pNode = pNode;
}
return true;
}
TerrainTexturing::STextureSplat *TerrainTexturing::addTextures(scene::ISceneNode *pNode, video::ITexture *pSplat, video::ITexture *pRed, video::ITexture *pGreen, video::ITexture *pBlue)
{
if (m_pMultitextureNode->pNode == pNode) {
m_pTextureSplat->pRedTexture = pRed;
m_pTextureSplat->pGreenTexture = pGreen;
m_pTextureSplat->pBlueTexture = pBlue;
m_pTextureSplat->pSplatTexture = pSplat;
return m_pTextureSplat;
}
return NULL;
}
void TerrainTexturing::drawAll()
{
//meshbuffer trick, only draw non culled nodes
if (!m_pSceneMgr->isCulled(m_pMultitextureNode->pNode)) {
m_pMultitextureNode->pNode->OnRegisterSceneNode();
m_pMultitextureNode->pNode->updateAbsolutePosition();
scene::IMesh* pMesh = ((scene::IMeshSceneNode*)m_pMultitextureNode->pNode)->getMesh();
//Reset the transformation
if (m_pMultitextureNode->pNode->getType() == scene::ESNT_MESH) {
m_pDriver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
} else {
m_pDriver->setTransform(video::ETS_WORLD, m_pMultitextureNode->pNode->getAbsoluteTransformation());
}
//set the splatting textures
m_pMultitextureNode->pNode->setMaterialTexture(0, m_pTextureSplat->pSplatTexture);
m_pMultitextureNode->pNode->setMaterialTexture(1, m_pTextureSplat->pRedTexture);
m_pMultitextureNode->pNode->setMaterialTexture(2, m_pTextureSplat->pGreenTexture);
m_pMultitextureNode->pNode->setMaterialTexture(3, m_pTextureSplat->pBlueTexture);
//pass the shader material to the terrain node
if (m_pMultitextureNode->pNode->getType() == scene::ESNT_MESH) {
m_pMultitextureNode->pNode->setMaterialType((video::E_MATERIAL_TYPE)m_nShaderMaterial);
}
}
}
void TerrainTexturing::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);
}
The shader Callback (TerrainTexturing.h):
Code: Select all
#ifndef TERRAINTEXTURING_H
#define TERRAINTEXTURING_H
#include <irrlicht.h>
#include <SMaterial.h>
using namespace irr;
class TerrainTexturing: public video::IShaderConstantSetCallBack
{
public:
struct STextureSplat {
video::ITexture *pRedTexture;
video::ITexture *pGreenTexture;
video::ITexture *pBlueTexture;
video::ITexture *pSplatTexture;
};
private:
struct SMultiTextureNode {
scene::ISceneNode *pNode;
STextureSplat* pTextureSplat;
};
public:
TerrainTexturing(IrrlichtDevice *pDevice, scene::ISceneManager* pSceneMgr);
~TerrainTexturing();
void drawAll();
virtual void OnSetConstants(video::IMaterialRendererServices* pServices,s32 userData);
bool addNode(scene::ISceneNode *pNode);
STextureSplat *addTextures(scene::ISceneNode *pNode, video::ITexture *pSplat, video::ITexture *pRed, video::ITexture *pGreen, video::ITexture *pBlue);
private:
scene::ISceneManager *m_pSceneMgr;
video::IVideoDriver *m_pDriver;
scene::ISceneNode *m_pNode;
SMultiTextureNode *m_pMultitextureNode;
STextureSplat *m_pTextureSplat;
int m_nShaderMaterial;
};
#endif
And here is how i use it in my main:
Code: Select all
video::IImage* heightMap = m_pDriver->createImageFromFile("./graphics/textures/terrain/terrain-heightmap.png");
video::ITexture* pTexture = m_pDriver->getTexture("./graphics/textures/terrain/terrain-firstpass.png");
scene::IMesh* terrainMesh = m_pSceneMgr->addTerrainMesh(name.c_str(), heightMap, heightMap, core::dimension2d<f32>(1, 1), 10);
if (terrainMesh) {
m_pTerrain = m_pSceneMgr->addMeshSceneNode(terrainMesh);
}
m_pTextureMgr->addNode((ISceneNode*)m_pTerrain);
m_pTextureMgr->addTextures((ISceneNode*)m_pTerrain,
m_pDriver->getTexture("./graphics/textures/terrain/terrain-secondpass.png"),
m_pDriver->getTexture("./graphics/textures/terrain/rock.jpg"),
m_pDriver->getTexture("./graphics/textures/terrain/grass.jpg"),
m_pDriver->getTexture("./graphics/textures/terrain/sand.jpg"));
int lastFPS = -1;
while (device->run()) {
//Draw the scene
m_pDriver->beginScene(true, true, video::SColor(50, 50, 50, 50));
m_pSceneMgr->drawAll();
m_pTextureMgr->drawAll();
m_pDriver->endScene();
int fps = m_pDriver->getFPS();
if (lastFPS != fps) {
core::stringw str = L"Texture Splatting with water - Move with Mouse and WASD/Arrow Keys - FPS:";
str += fps;
m_pDevice->setWindowCaption(str.c_str());
lastFPS = fps;
}
}