Terrain Help
Terrain Help
Can anyone tell me exactly how to read in a blend map to create multi-textured terrain using irrlicht? I created some terrain using the scenemanager->addTerrainSceneNode() method which is nice cause it reads in a heightmap on its own, but it seems like when you make terrain this way you can only stretch one texture over the whole mesh. I want to be able to have dirt textures, grass textures, stone textures, etc. on my terrain. Can anyone show me how to do this with Irrlicht?
You can create a shader specifically for this or use the EMT_ONETEXTURE_BLEND with the EBF_SRC_ALPHA blend factor and store the blendmap in the first textures alpha channel.
The first method is faster and should be able to run on fixed function hardware but you can only lerp between 2 textures. (Eg. Grass and rock.).
Another method is one proposed by arras to skew the texcoords of each terrain vertex to create a lookup from a big texture containing multiple textures inside it, but if you want a smooth transition you would have to create "boundary textures" for the edges and the corners and this can get pretty messy quickly.
I recommend reading up on shaders then storing the desired strength of each texture in each component of the vertex color, then using the vertex color (which will be interpolated smoothly accross all fragments) to decide how to mix between the different textures in the pixel shader.
I might decide to release something thats similar to this (but better) soon, but no promises.
The first method is faster and should be able to run on fixed function hardware but you can only lerp between 2 textures. (Eg. Grass and rock.).
Another method is one proposed by arras to skew the texcoords of each terrain vertex to create a lookup from a big texture containing multiple textures inside it, but if you want a smooth transition you would have to create "boundary textures" for the edges and the corners and this can get pretty messy quickly.
I recommend reading up on shaders then storing the desired strength of each texture in each component of the vertex color, then using the vertex color (which will be interpolated smoothly accross all fragments) to decide how to mix between the different textures in the pixel shader.
I might decide to release something thats similar to this (but better) soon, but no promises.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
Thanks for the help! That would be pretty amazing and very helpful if you could release something like that. I've been reading up on Pixel shaders and I understand how to write them but what I'm confused about is how you interface the compiled pixel shader with the Irrlicht application. That is, how you get the information from the shader to the functions that actually render the mesh. Any help in that area would be greatly appreciated.
Thanks
Thanks
Okay, so I've written a pixel shader and it seems to work to some degree, but there is still a problem. It does use the blend map to determine where the textures are to be placed on the terrain, however the textures lose all of their details. For example, instead of having a dirt road that has cracks, twigs, and other detail like it does in the .jpg texture file, it just comes up as a brown color on the terrain with no detail at all. This gives my terrain a very smooth look with no realism at all. I was wondering if anyone could tell me, why I'm losing the detail in my textures.
I add a terrain Scene Node and set the material textures and the material type with the following code:
My pixel Shader looks like this:
Any help with this would be greatly appreciated!
Thanks!
I add a terrain Scene Node and set the material textures and the material type with the following code:
Code: Select all
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"media/terrain-heightmap.bmp",
0, // parent node
-1, // node id
core::vector3df(0.f, 0.f, 0.f), // position
core::vector3df(0.f, 0.f, 0.f), // rotation
core::vector3df(40.0f, 4.4f, 40.0f), // scale
video::SColor ( 255, 255, 255, 255 ), // vertexColor,
5, // maxLOD
scene::ETPS_17, // patchSize
5 // smoothFactor
);
terrain->setMaterialTexture(0,driver->getTexture("media/blend_hm17.jpg")); terrain->setMaterialTexture(1,driver->getTexture("media/grass.jpg"));
terrain->setMaterialTexture(2,driver->getTexture("media/dirt.jpg"));
terrain->setMaterialTexture(3,driver->getTexture("media/stone.jpg"));
s32 newMaterialType = driver->getGPUProgrammingServices()->addHighLevelShaderMaterialFromFiles( 0,0,video::EVST_VS_2_0,"TerrainPS.psh","ps_main",video::EPST_PS_2_0,0video::EMT_SOLID);
terrain->setMaterialType((video::E_MATERIAL_TYPE)newMaterialType);
Code: Select all
float4x4 matViewProjection : ViewProjection;
float texScale = 10.0;
sampler AlphaMap = sampler_state
{
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
ADDRESSU = WRAP;
ADDRESSV = WRAP;
ADDRESSW = WRAP;
};
sampler TextureOne = sampler_state
{
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
ADDRESSU = WRAP;
ADDRESSV = WRAP;
ADDRESSW = WRAP;
};
sampler TextureTwo = sampler_state
{
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
ADDRESSU = WRAP;
ADDRESSV = WRAP;
ADDRESSW = WRAP;
};
sampler TextureThree = sampler_state
{
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
ADDRESSU = WRAP;
ADDRESSV = WRAP;
ADDRESSW = WRAP;
};
struct PS_OUTPUT
{
float4 diffuse : COLOR0;
};
PS_OUTPUT ps_main(float shade : TEXCOORD0,
float2 tiledTexC : TEXCOORD1,
float2 nonTiledTexC : TEXCOORD0) : COLOR
{
PS_OUTPUT output = (PS_OUTPUT)0;
// Layer maps are tiled
float3 c0 = tex2D(TextureOne, mul(tiledTexC,texScale));
float3 c1 = tex2D(TextureTwo, mul(tiledTexC,texScale));
float3 c2 = tex2D(TextureThree, mul(tiledTexC,texScale));
// Blendmap is not tiled.
float3 B = tex2D(AlphaMap, nonTiledTexC);
// Find the inverse of all the blend weights so that we can
// scale the total color to the range [0, 1].
float totalInverse = 1.0f / (B.r + B.g + B.b);
c0 *= B.r * totalInverse;
c1 *= B.g * totalInverse;
c2 *= B.b * totalInverse;
float3 final = (c0 + c1 + c2);//* shade;
output.diffuse = float4(final,1.0f);
return output;
}
technique Default_DirectX_Effect
{
pass Pass_0
{
PixelShader = compile ps_2_0 ps_main();
}
}
Thanks!