Ogre::Terrain and material:

Problems building or running the engine, queries about how to use features etc.
Post Reply
Evorlde
Gnoblar
Posts: 8
Joined: Tue Mar 25, 2014 9:18 pm
x 1

Ogre::Terrain and material:

Post by Evorlde »

Hi,

I need to use .material on Ogre::Terrain to make a fog of war.
My problem is to change .material after terrain loading.

1) First I saw this post on TerrainMaterialGenerator:
http://www.ogre3d.org/tikiwiki/tiki-ind ... +Generator
I don't know how use this sub-classe to apply .material on my Terrain.
I tried like this:
A) I set my defaultMaterialGenerator BEFORE having defined and loaded Terrain:

Code: Select all

Ogre::TerrainGlobalOptions::getSingleton().setDefaultMaterialGenerator(Ogre::TerrainMaterialGeneratorPtr(new TerrainMaterialGenerator))
B) I try to apply my .material on my terrain AFTER having defined and loaded Terrain

Code: Select all

Ogre::MaterialPtr	mat = Ogre::MaterialManager::getSingleton().getByName("PlainTexture");
Ogre::TerrainGlobalOptions::getSingleton().getDefaultMaterialGenerator()->updateParams(mat, _terrainGroup->getTerrain(0, 0));
Ogre::TerrainGlobalOptions::getSingleton().getDefaultMaterialGenerator()->generate(_terrainGroup->getTerrain(0, 0));
Ogre::TerrainGlobalOptions::getSingleton().getDefaultMaterialGenerator()->_markChanged();
_terrainGroup->getTerrain(0, 0)->update();
But without success. My terrain is displayed but without my texture set in .material.

2) I saw this post:
http://www.ogre3d.org/forums/viewtopic.php?f=5&t=72455
A) I set my defaultMaterialGenerator BEFORE having defineed and loaded Terrain

Code: Select all

Ogre::TerrainMaterialGeneratorPtr terrainMaterialGenerator;
TerrainMaterial *terrainMaterial = OGRE_NEW TerrainMaterial("TextureModColor", true, false);
terrainMaterialGenerator.bind(terrainMaterial);
_terrainGlobals->setDefaultMaterialGenerator(terrainMaterialGenerator);
My Terrain is display with my texture set in .material, so all is OK.

B) BUT when i try to change .material AFTER having defined and loaded terrain, like this:

Code: Select all

terrainMaterial->setMaterialByName("TextureModSimple");
The texture is changed but for all my terrains. And i just want change one terrain

Code: Select all

_terrainGroup->getTerrain(0, 0);

My Question:

How can i apply .material on JUST 1 Terrain after having loaded my terrains?

Thank,
Evorlde
Gnoblar
Posts: 8
Joined: Tue Mar 25, 2014 9:18 pm
x 1

Re: Ogre::Terrain and material:

Post by Evorlde »

Nobody know how set .material on Ogre::Terrain?
Arth
Gnoblar
Posts: 12
Joined: Sun Dec 22, 2013 9:42 am
x 2

Re: Ogre::Terrain and material:

Post by Arth »

To change the textures for only one Ogre::Terrain you can do the following (no need for a TerrainMaterialGenerator):
Ogre::Terrain* terrain = mTerrainGroup->getTerrain(x, y);
terrain->setLayerTextureName(0,0,"textureName1_diffusespecular.dds");
terrain->setLayerTextureName(0,1,"textureName1_normalheight.dds");
terrain->setLayerTextureName(1,0,"textureName2_diffusespecular.dds");
terrain->setLayerTextureName(1,1,"textureName2_normalheight.dds");
terrain->setLayerTextureName(2,0,"textureName3_diffusespecular.dds");
terrain->setLayerTextureName(2,1,"textureName3_normalheight.dds");
mTerrainGroup->unloadTerrain(x,y);
mTerrainGroup->loadTerrain(x,y, true);
Evorlde
Gnoblar
Posts: 8
Joined: Tue Mar 25, 2014 9:18 pm
x 1

Re: Ogre::Terrain and material:

Post by Evorlde »

Arth wrote:To change the textures for only one Ogre::Terrain you can do the following (no need for a TerrainMaterialGenerator):
Ogre::Terrain* terrain = mTerrainGroup->getTerrain(x, y);
terrain->setLayerTextureName(0,0,"textureName1_diffusespecular.dds");
terrain->setLayerTextureName(0,1,"textureName1_normalheight.dds");
terrain->setLayerTextureName(1,0,"textureName2_diffusespecular.dds");
terrain->setLayerTextureName(1,1,"textureName2_normalheight.dds");
terrain->setLayerTextureName(2,0,"textureName3_diffusespecular.dds");
terrain->setLayerTextureName(2,1,"textureName3_normalheight.dds");
mTerrainGroup->unloadTerrain(x,y);
mTerrainGroup->loadTerrain(x,y, true);
Thank for your answer.
I can't use this technique because Unload and Load Terrain take too much time. I can't unload and load my Terrain each time an unit move on it.

Actually i do this:

Code: Select all

Ogre::MaterialPtr	mat = _terrainGroup->getTerrain(0, 0)->getMaterial();
mat->getTechnique(1)->createPass();
mat->getTechnique(1)->getPass(1)->createTextureUnitState("iconPop.png", 0);
The result:
Image

We can see that my texture is displayed on my terrain (at the position 0, 0, 0) but not at the good size. It's the brown/black image just above my cursor.
I want my texture takes all the Terrain size.

How can i change this size?

Thank,
Attachments
texture-on-terrain-bad-size.png
Arth
Gnoblar
Posts: 12
Joined: Sun Dec 22, 2013 9:42 am
x 2

Re: Ogre::Terrain and material:

Post by Arth »

Don't create new TextureUnitStates or passes, that does not modify the original textures.

Try this:

Code: Select all

Ogre::MaterialPtr	mat = _terrainGroup->getTerrain(0, 0)->getMaterial();
mat->getTechnique(0)->getPass(0)->getTextureUnitState("MyTextureForChange0")->setTextureName("NewTextureName0.dds");
mat->getTechnique(0)->getPass(0)->getTextureUnitState("MyTextureForChange1")->setTextureName("NewTextureName1.dds");
mat->getTechnique(0)->getPass(0)->getTextureUnitState("MyTextureForChange2")->setTextureName("NewTextureName2.dds");
//And in the materialGenerator at function "void TerrainMaterialGeneratorA::SM2Profile::addTechnique(
const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt)" find the following section and Change it that way (this is to mark the correct TextureUnits, so that you can find it in the material using "getTextureUnitState"):

Code: Select all

// layer textures
for (uint i = 0; i < numLayers; ++i)
{
// diffuse / specular
[color=#FF0000]Ogre::TextureUnitState* tu = [/color]pass->createTextureUnitState(terrain->getLayerTextureName(i, 0));
[color=#FF0000]tu->setName("MyTextureForChange" + Ogre::StringConverter::ToString(i));[/color]

// normal / height
pass->createTextureUnitState(terrain->getLayerTextureName(i, 1));
}
Please note, that when unloading/loading the changes done that way are lost and must be applied new (or you additionally use terrain->setLayerTextureName)
Evorlde
Gnoblar
Posts: 8
Joined: Tue Mar 25, 2014 9:18 pm
x 1

Re: Ogre::Terrain and material:

Post by Evorlde »

1) I saw the setTextureName function but this replace texture.
I just want add an other texture above the first. This is why i try to do a createTextureUnitState.
Add another texture above the first allow me to always have the Terrain Texture below and it makes better effect (for example if my texture added is a little transparent the player will see Terrain Texture below, instead seeing black texture...)

2) Actually i have stopped to use MaterialGenerator, because i can do a getMaterial an my Terrain without this class.
Should i use MaterialGenerator? I don't know what is the role of MaterialGenerator.

Do you know how can i use createTextureUnitState?

Thank, I feel like I'm close to solving my problem with your help.
Arth
Gnoblar
Posts: 12
Joined: Sun Dec 22, 2013 9:42 am
x 2

Re: Ogre::Terrain and material:

Post by Arth »

The "MaterialGenerator" Class is used, when you need to apply your own material and/or shader for Terrain Rendering.

If you need to blend in your (fog)texture and you can affort to use on texture-layer, you can simply use the last texture-layer and set it's blend values as needed. You can do that at runtime.

Code: Select all

Ogre::Real value = 0.8f;
Ogre::TerrainLayerBlendMap* layer = terrain->getLayerBlendMap(layerId); //layerId is the Layerindex for the fog texture
Ogre::uint16 size = terrain->getLayerBlendMapSize();
for(pointX=0; pointX<size; ++pointX)
{
for(pointY=0; pointY<size; ++pointY)
{
layer->setBlendValue(pointX, pointY, value);
}
}
Evorlde
Gnoblar
Posts: 8
Joined: Tue Mar 25, 2014 9:18 pm
x 1

Re: Ogre::Terrain and material:

Post by Evorlde »

Arth wrote:
If you need to blend in your (fog)texture and you can affort to use on texture-layer, you can simply use the last texture-layer and set it's blend values as needed. You can do that at runtime.

Code: Select all

Ogre::Real value = 0.8f;
Ogre::TerrainLayerBlendMap* layer = terrain->getLayerBlendMap(layerId); //layerId is the Layerindex for the fog texture
Ogre::uint16 size = terrain->getLayerBlendMapSize();
for(pointX=0; pointX<size; ++pointX)
{
for(pointY=0; pointY<size; ++pointY)
{
layer->setBlendValue(pointX, pointY, value);
}
}
Before, i used this technique but this takes too much time to apply the texture.
This is why i would like material/shader.
But it's seem like if there are no way to just add a texture to a Ogre::Terrain material since Ogre V1.8.
Evorlde
Gnoblar
Posts: 8
Joined: Tue Mar 25, 2014 9:18 pm
x 1

Re: Ogre::Terrain and material:

Post by Evorlde »

I found that this is not a TextureUnitState size problem, but a Pass configuration problem.
Because if i do a removeAllTextureUnitState in my pass and i do a createTextureUnitState on my Pass after, the Texture have a good size (it takes all the Terrain size).

Code: Select all

Ogre::MaterialPtr	mat = _terrainGroup->getTerrain(0, 0)->getMaterial();
mat->getTechnique(1)->getPass(0)->removeAllTextureUnitState();
mat->getTechnique(1)->getPass(0)->createTextureUnitState("iconPop.png", 0);
But if i do a createPass and i try to do a createTextureUnitState on this new Pass, the Texture have a bad size (like on my screenshot, posted in a previous answer).

Code: Select all

Ogre::MaterialPtr	mat = _terrainGroup->getTerrain(0, 0)->getMaterial();
mat->getTechnique(1)->createPass();
mat->getTechnique(1)->getPass(1)->createTextureUnitState("iconPop.png", 0);
I tried to debug with visual studio debuger, and both Pass (Pass created by Ogre::Terrain and Pass created by me) are totally equals except that my Pass don't have fragmentProgram and VertexProgram...

I'm sur at 90% that i need to create a fragmentProgram and vertexProgram to my Pass. But i don't have ideas how doing this.

Someone can help me on this please?

Thank,
Arth
Gnoblar
Posts: 12
Joined: Sun Dec 22, 2013 9:42 am
x 2

Re: Ogre::Terrain and material:

Post by Arth »

Before, i used this technique but this takes too much time to apply the texture.
This is why i would like material/shader.
But it's seem like if there are no way to just add a texture to a Ogre::Terrain material since Ogre V1.8.
If you lower the resolution of the BlendMapSize it will be faster.
Maybe it would be good if you descibe a litte more what you are using the terrain for and how many you create (since you state one "Unit" is on the entirey Ogre::Terrain).
But if i do a createPass and i try to do a createTextureUnitState on this new Pass, the Texture have a bad size (like on my screenshot, posted in a previous answer).
Not sure whats the problem here is, but an addtional pass will impact performance (since the terrain is rendered twice). You can try to disable "vertexCompression" (Ogre::TerrainGlobalOptions::getSingleton().setUseVertexCompressionWhenAvailable(false);). However i'm afraid that without proper shaders you will run into more problems here.

But to answer you question:
To correctly add an texture blended over the terrain, where you can set the blendstrenght per Terrain you need to add that feature to the TerrainSystem:
- add duing creation of the Material in the TerrainMaterialGenerator an additional Textureunitstate for your additional texture.
- adjust "uint8 TerrainMaterialGeneratorA::SM2Profile::getMaxLayers(const Terrain* terrain) const" to also account for your additional texture (simply an additional "--freeTextureUnits;")
- send blendstrenght var to the fragmentshader of the specific terrrain:

Code: Select all

Ogre::MaterialPtr   mat = _terrainGroup->getTerrain(0, 0)->getMaterial();
Ogre::Pass* pass = mat->getTechnique(0)->getPass(0);
Ogre::GpuProgramParametersSharedPtr params = pass->getFragmentProgramParameters();
params->setNamedConstant("MyBlendStrenght", 0.8f);
- modify the Terrain shader in the TerrainMaterialGenerator to blend in your Texture according to the value of "MyBlendStrenght" (here you should have practice in Shaders).
Evorlde
Gnoblar
Posts: 8
Joined: Tue Mar 25, 2014 9:18 pm
x 1

Re: Ogre::Terrain and material:

Post by Evorlde »

Hi,

I come back after a few days working on my FogOfWar.
I finally followed your advice and use BlendMap to do my FogOfWar.
As you said, with good parameters there is no lag.

Here it's the result:
Image

Currently my FogOfWar have a square form, but i can easily add an option to make it circle form instead.
On this picture you can see:
__ The black zone: it's a zone never explored by player.
__ The green zone: it's the zone currently visible by player.
__ The grey zone: it's the zone which has already been explored by player but which is no longer visible.
Don't mind about ninja, he don't move so it's why he remained in the departure area (grey zone on the picture). I just simulated the fog move and no unity move (it's just a landmark for me).

Thank you very much, ;)

Evorlde
Attachments
FogOfWarCut.png
FogOfWarCut.png (3.41 KiB) Viewed 529 times
Post Reply