as pronounced in this topic I have been working on a OpenGL version for Texture Splatting. Basically I just took the ShieldManager, changed it and wrote a new shader.
I also implemented a few extra things to make it possible to use normal ITerrainNodes with the manager, so that the terrain lod is usable.
I have not yet written a documentation, but the use is quite simple. Add the node you want to multitexture to the manager and add passes. Each pass needs a splatting map and 3 or less color textures. The splattingmap itself can use the values red, green and blue each representing one of the color textures. Depending on how bright the color value is the colortexture will be blended. The alpha value of the splatting map will be transparency channel for the pass, so it does not overpaint everything from the previous passes.
Enough talk, here it is:
Here you go:
http://www.file-upload.net/download-256 ... ng.7z.html
CMultiTexturingManager.h
Code: Select all
#ifndef CMULTITEXTURINGMANAGER_H_INCLUDED
#define CMULTITEXTURINGMANAGER_H_INCLUDED
#include <irrlicht.h>
using namespace irr;
class CMultiTexturingManager: public video::IShaderConstantSetCallBack
{
public:
struct STexturePass
{
video::ITexture *splat_texture;
video::ITexture *red_texture;
video::ITexture *green_texture;
video::ITexture *blue_texture;
};
private:
struct SMultiTextureNode
{
//The textured node
scene::ISceneNode *Node;
core::array<STexturePass*> array_Passes;
};
public:
CMultiTexturingManager(scene::ISceneManager* psmgr);
~CMultiTexturingManager();
void drawAll();
virtual void OnSetConstants(video::IMaterialRendererServices* services,s32 userData);
bool addNode(scene::ISceneNode *node);
bool removeNode(scene::ISceneNode *node);
STexturePass *addPass(scene::ISceneNode *node);
STexturePass *addPass(scene::ISceneNode *node, video::ITexture *splat, video::ITexture *red, video::ITexture *green, video::ITexture *blue);
STexturePass *addPass(scene::ISceneNode *node, STexturePass *pass);
bool removePass(scene::ISceneNode *node, u32 layer);
bool removePass(scene::ISceneNode *node, STexturePass *pass);
private:
scene::ISceneManager* smgr;
video::IVideoDriver* driver;
core::array<SMultiTextureNode> array_Nodes;
int shaderMaterial;
};
#endif // CMULTITEXTURINGMANAGER_H_INCLUDED
Code: Select all
#include "CMultiTexturingManager.h"
CMultiTexturingManager::CMultiTexturingManager(scene::ISceneManager* psmgr){
//Assign all parameters
smgr = psmgr;
driver=psmgr->getVideoDriver();
///GLSL Shader Code
//Vertex Shader
const c8 *vertShader = "void main()\
{\
gl_TexCoord[0] = gl_MultiTexCoord0;\
gl_TexCoord[1] = gl_MultiTexCoord1;\
gl_Position = ftransform();\
}\
";
//Fragment Shader
const c8 *fragShader = "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);\
}\
";
//Create the shader material
shaderMaterial = driver->getGPUProgrammingServices()->addHighLevelShaderMaterial(
vertShader, "main", video::EVST_VS_1_1,
fragShader, "main", video::EPST_PS_1_1,
this, video::EMT_TRANSPARENT_ALPHA_CHANNEL);
}
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 0;
}
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 0;
}
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 0;
}
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.MaterialTypeParam =pack_texureBlendFunc(video::EBF_DST_COLOR,video::EBF_ONE);
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.MaterialTypeParam =pack_texureBlendFunc(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);
}
Code: Select all
#include <irrlicht.h>
using namespace irr;
#include "CMultiTexturingManager.h"
int main(int argc, char** argv)
{
//Set up device and receiver
IrrlichtDevice *device = createDevice(video::EDT_OPENGL, core::dimension2d<u32>(640,480), 32,false,false,false);
video::IVideoDriver *driver = device->getVideoDriver();
scene::ISceneManager *smgr = device->getSceneManager();
//Create the camera
SKeyMap keyMap[8];
keyMap[0].Action = EKA_MOVE_FORWARD;
keyMap[0].KeyCode = KEY_UP;
keyMap[1].Action = EKA_MOVE_FORWARD;
keyMap[1].KeyCode = KEY_KEY_W;
keyMap[2].Action = EKA_MOVE_BACKWARD;
keyMap[2].KeyCode = KEY_DOWN;
keyMap[3].Action = EKA_MOVE_BACKWARD;
keyMap[3].KeyCode = KEY_KEY_S;
keyMap[4].Action = EKA_STRAFE_LEFT;
keyMap[4].KeyCode = KEY_LEFT;
keyMap[5].Action = EKA_STRAFE_LEFT;
keyMap[5].KeyCode = KEY_KEY_A;
keyMap[6].Action = EKA_STRAFE_RIGHT;
keyMap[6].KeyCode = KEY_RIGHT;
keyMap[7].Action = EKA_STRAFE_RIGHT;
keyMap[7].KeyCode = KEY_KEY_D;
scene::ICameraSceneNode *camera = smgr->addCameraSceneNodeFPS(0,100,0.6,-1,keyMap,8);
camera->setPosition(core::vector3df(1300,250,0));
camera->setTarget(core::vector3df(600,0,600));
camera->setNearValue(0.01);
scene::ISceneNode* skydome=smgr->addSkyDomeSceneNode(driver->getTexture("Data/textures/skydome.jpg"),16,8,0.95f,2.0f);
skydome->setRotation(core::vector3df(0,-100,0));
CMultiTexturingManager *texture_manager = new CMultiTexturingManager(smgr);
//Create a terrain like in the terrain sample
scene::ITerrainSceneNode *terrain = smgr->addTerrainSceneNode(
"Data/textures/splatting_test.png",
0, // parent node
-1, // node id
core::vector3df(0.f, 2.f, 0.f), // position
core::vector3df(0.f, 0.f, 0.f), // rotation
core::vector3df(10,3,10), // scale
video::SColor ( 255, 255, 255, 255 ), // vertexColor
5, // maxLOD
scene::ETPS_17, // patchSize
3 // smoothFactor
);
terrain->setMaterialFlag(video::EMF_LIGHTING,false);
terrain->scaleTexture(1.0f, 20.0f);
terrain->setScale(core::vector3df(5,2,5));
//Add it to the manager
texture_manager->addNode(terrain);
//Set the passes
//First Pass, with Sand, Gras and Rock
texture_manager->addPass(terrain,
driver->getTexture("Data/textures/splat_1.tga"),
driver->getTexture("Data/textures/Rock.jpg"),
driver->getTexture("Data/textures/Gras.jpg"),
driver->getTexture("Data/textures/Sand.jpg"));
//Second Pass with Snow, Mud and the Vulcano's base texture
texture_manager->addPass(terrain,
driver->getTexture("Data/textures/splat_2.tga"),
driver->getTexture("Data/textures/Snow.jpg"),
driver->getTexture("Data/textures/Mud.jpg"),
driver->getTexture("Data/textures/Ashes.jpg"));
//Third Pass. the base
texture_manager->addPass(terrain,
driver->getTexture("Data/textures/splat_3.tga"),
0,
0,
driver->getTexture("Data/textures/Pebbles.jpg"));
//Fourth Pass: the Lightmap
texture_manager->addPass(terrain,
driver->getTexture("Data/textures/lm_terrain.tga"),
driver->getTexture("Data/textures/black.jpg"),
0,
0);
//Fith Pass: Lava, drawn above the Lightmap to make it "glow"
CMultiTexturingManager::STexturePass *anim_lava_pass = texture_manager->addPass(terrain,
driver->getTexture("Data/textures/splat_4.tga"),
driver->getTexture("Data/textures/lava_1.jpg"),
0,
0);
//FPS measurement
int lastFPS = -1;
while(device->run())
{
//Draw the scene
driver->beginScene(true, true, video::SColor(50,50,50,50));
smgr->drawAll();
texture_manager->drawAll();
//Dirty Workaround to make the lava animated :P
core::stringc name = "Data/textures/lava_";
name+=1+int(floor((device->getTimer()->getRealTime()/40)%29));
name+=".jpg";
anim_lava_pass->red_texture = driver->getTexture(name.c_str());
driver->endScene();
//Display the FPS
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Texture Splatting - Move with Mouse and WASD/Arrow Keys - FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
//Cleanup
device->drop();
delete texture_manager;
return 0;
}