[Partly Solved] Terrain seam with orthophoto

Problems building or running the engine, queries about how to use features etc.
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

[Partly Solved] Terrain seam with orthophoto

Post by Etty »

Hello,

I'm using terrain paging with an orthophoto as a diffuse texture for the terrain.

Code: Select all

//-------------------------------------------------------------------------------------
void City_Paged::defineTerrain(long x, long y)
{
	String filename = mTerrainGroup->generateFilename(x, y);
	if(ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(), filename))
	{
		mTerrainGroup->defineTerrain(x, y);
	}
	else
	{
		Image img ;
		loadHeightmap(x, -y, img);

		TerrainMaterialGeneratorA::SM2Profile* matProfile = 0;
		matProfile = (TerrainMaterialGeneratorA::SM2Profile*) mTerrainGlobals->getDefaultMaterialGenerator()->getActiveProfile();
		if (matProfile)
		{
			matProfile->setLayerParallaxMappingEnabled(false);
		}

		Terrain::ImportData* importData = OGRE_NEW Terrain::ImportData();
		
		importData->terrainSize = TERRAIN_SIZE;
		importData->worldSize = TERRAIN_WORLD_SIZE;

		importData->inputScale = 200;

		importData->minBatchSize = 33;
		importData->maxBatchSize = 65;

		importData->layerList.resize(1);

		importData->layerList[0].worldSize = TERRAIN_WORLD_SIZE;
		loadDiffuseTexture(x, -y, *importData);

		mTerrainGroup->defineTerrain(x, y, &img, &importData->layerList);
		mTerrainsImported = true;		
	}
}

//-------------------------------------------------------------------------------------
void City_Paged::loadHeightmap(int x, int y, Image& img)
{
	char heightmap[255];
	_snprintf(heightmap, 255, "terrain/City_06/hm/City_heightmap_%d_%d.png", x, y);
	img.load(heightmap, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
}

//-------------------------------------------------------------------------------------
void City_Paged::loadDiffuseTexture(int x, int y, Terrain::ImportData& importData)
{
	char diffusemap[255];
	_snprintf(diffusemap, 255, "terrain/City_06/or/City_texture_%d_%d.DDS", x, y);
	importData.layerList[0].textureNames.push_back(diffusemap);
}
I have a little problem between my chunk, a seam is visible. As illustrated here : Screenshot 01
When I move farther, it seems to disappear : Screenshot 02

I've checked a lot of post about terrain seam etc. but I couldn't find something to fix this problem. I've already disabled parallax to reduce the effect.
I thought it was the terrain skirt but after setting it to 0 nothing changed.

If I set the compositeMapDistance to 0 the seam is reduced but there is still something visible and the global image quality is reduced : Screenshot 03

Note that with a seamless texture it doesn't occur : Screenshot 04
But well I can't use a seamless texture in my case.. Also I'm sure my picture is correctly split.

Can anyone help me making my chunks fit perfectly together ?
Last edited by Etty on Thu Apr 25, 2013 12:33 pm, edited 2 times in total.
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: Terrain seam with orthophoto

Post by Etty »

*Update*

I obtained interesting result by changing the filtering method ( look at the "cut" in the road ):

Bilinear
Trilinear
Anisotropic
None

But I'd like to have a better option than setting the filtering at none.
Still searching for a better option :?
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: Terrain seam with orthophoto

Post by bstone »

Try clamping the textures with "tex_address_mode clamp".
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: Terrain seam with orthophoto

Post by Etty »

Thanks for your answer,

I checked in OgreTerrainMaterialGeneratorA and the textureAddressingMode is already set at clamp.
Or Should I specify tex_address_mode_clamp somewhere else ?

By the way, I modified the clamp mode to a border one and set a texture border colour as red here are the results :

Screenshot 1
Screenshot 2
Screenshot 3

As I move, it is noticeable that something change. Could it be something with LOD and shaders ?
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: Terrain seam with orthophoto

Post by bstone »

It's hard to say then. Are you sure your photos are matching perfectly otherwise?
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: Terrain seam with orthophoto

Post by Etty »

Yep they are will split, when I put them back together in an editor they are fine.
User avatar
alberts
Gremlin
Posts: 177
Joined: Fri Mar 31, 2006 8:43 am
Location: Granada-Cádiz-Jaén, Spain
x 20

Re: Terrain seam with orthophoto

Post by alberts »

I had a similar problem before (http://www.ogre3d.org/forums/viewtopic. ... 40#p453642). I think you have to use seamless textures with the terrain material generator.
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: Terrain seam with orthophoto

Post by Etty »

Thanks alberts but absolutely have to use an orthophoto to texture my terrain so I can't use a seamless texture.
User avatar
alberts
Gremlin
Posts: 177
Joined: Fri Mar 31, 2006 8:43 am
Location: Granada-Cádiz-Jaén, Spain
x 20

Re: Terrain seam with orthophoto

Post by alberts »

I mean you will probably have to write your custom material generator. :(

Please let me know if you found any other solution.
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: Terrain seam with orthophoto

Post by Etty »

Sure I will if I find something ! Thanks for your concern :)
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: Terrain seam with orthophoto

Post by Etty »

I read the code behind MaterialGeneratorA ( the one used by terrains ) and I don't think it's the source of the problem but the filtering.

By looking closely to the seam on this screen you notice that the last pixel of the right terrain has red. Check this screen to see where that red comes from. ( In none filtering mode there is no red check this screen).

So I believe it's the way the bilinear / trilinear and anisotropic filtering work. To make the texture smoother it extrapolate the color of the pixels with it's neighbor. In the case of a terrain chunk, for pixels on the border, it'll still extrapolate with it's neighbor but one side has no other pixel and then it checks on the other side of the texture.

So since I can't ask filtering to calculate values of a pixel with adjacent objects' textures, a possible resolution of the problem would be to have a 1 border pixel in every image that would repeat the one before last pixel of the adjacent texture. Illustration This is the basic idea. I just don't know what to put in corner nor even if it will be used.

So this is handled when I split my original texture into multiples ones, well I think that's where it should be handled. Then I have to tell the material to not use 100% of the uv but 1 less pixel on all sides. Then filtering will calculate with that extra pixel which correspond to the first shown pixel of the next terrain.

Would it work ? Or would it only use the uv used ?
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: Terrain seam with orthophoto

Post by bstone »

If that were the source of the problem then clamping would have fixed it.
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: Terrain seam with orthophoto

Post by Etty »

Here are the only reference to any addressing mode in MaterialGeneratorA, I put them in bold and italic. As you see all of them are set as TAM_CLAMP except shadows. I believe that the filtering is handled somewhere else in ogre, haven't seen where yet, and that it doesn't take care about this.

Code: Select all

	//---------------------------------------------------------------------
	void TerrainMaterialGeneratorA::SM2Profile::addTechnique(
		const MaterialPtr& mat, const Terrain* terrain, TechniqueType tt)
	{

		Technique* tech = mat->createTechnique();

		// Only supporting one pass
		Pass* pass = tech->createPass();

		GpuProgramManager& gmgr = GpuProgramManager::getSingleton();
		HighLevelGpuProgramManager& hmgr = HighLevelGpuProgramManager::getSingleton();
		if (!mShaderGen)
		{
			bool check2x = mLayerNormalMappingEnabled || mLayerParallaxMappingEnabled;
			if (hmgr.isLanguageSupported("cg"))
				mShaderGen = OGRE_NEW ShaderHelperCg();
			else if (hmgr.isLanguageSupported("hlsl") &&
				((check2x && gmgr.isSyntaxSupported("ps_4_0")) ||
				(check2x && gmgr.isSyntaxSupported("ps_2_x")) ||
				(!check2x && gmgr.isSyntaxSupported("ps_2_0"))))
				mShaderGen = OGRE_NEW ShaderHelperHLSL();
			else if (hmgr.isLanguageSupported("glsl"))
				mShaderGen = OGRE_NEW ShaderHelperGLSL();
			else if (hmgr.isLanguageSupported("glsles"))
				mShaderGen = OGRE_NEW ShaderHelperGLSLES();
			else
			{
				// todo
			}

			// check SM3 features
			mSM3Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_3_0");
			mSM4Available = GpuProgramManager::getSingleton().isSyntaxSupported("ps_4_0");

		}
		HighLevelGpuProgramPtr vprog = mShaderGen->generateVertexProgram(this, terrain, tt);
		HighLevelGpuProgramPtr fprog = mShaderGen->generateFragmentProgram(this, terrain, tt);

		pass->setVertexProgram(vprog->getName());
		pass->setFragmentProgram(fprog->getName());

		if (tt == HIGH_LOD || tt == RENDER_COMPOSITE_MAP)
		{
			// global normal map
			TextureUnitState* tu = pass->createTextureUnitState();
			tu->setTextureName(terrain->getTerrainNormalMap()->getName());
			[b][i]tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);[/i][/b]

			// global colour map
			if (terrain->getGlobalColourMapEnabled() && isGlobalColourMapEnabled())
			{
				tu = pass->createTextureUnitState(terrain->getGlobalColourMap()->getName());
				[b][i]tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);[/i][/b]
			}

			// light map
			if (isLightmapEnabled())
			{
				tu = pass->createTextureUnitState(terrain->getLightmap()->getName());
				[b][i]tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);[/i][/b]
			}

			// blend maps
			uint maxLayers = getMaxLayers(terrain);
			uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
			uint numLayers = std::min(maxLayers, static_cast<uint>(terrain->getLayerCount()));
			for (uint i = 0; i < numBlendTextures; ++i)
			{
				tu = pass->createTextureUnitState(terrain->getBlendTextureName(i));
				[b][i]tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);[/i][/b]
			}

			// layer textures
			for (uint i = 0; i < numLayers; ++i)
			{
				// diffuse / specular
				pass->createTextureUnitState(terrain->getLayerTextureName(i, 0));
				// normal / height
				pass->createTextureUnitState(terrain->getLayerTextureName(i, 1));
			}

		}
		else
		{
			// LOW_LOD textures
			// composite map
			TextureUnitState* tu = pass->createTextureUnitState();
			tu->setTextureName(terrain->getCompositeMap()->getName());
			[b][i]tu->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);[/i][/b]

			// That's it!

		}

		// Add shadow textures (always at the end)
		if (isShadowingEnabled(tt, terrain))
		{
			uint numTextures = 1;
			if (getReceiveDynamicShadowsPSSM())
			{
				numTextures = getReceiveDynamicShadowsPSSM()->getSplitCount();
			}
			for (uint i = 0; i < numTextures; ++i)
			{
				TextureUnitState* tu = pass->createTextureUnitState();
				tu->setContentType(TextureUnitState::CONTENT_SHADOW);
				[b][i]tu->setTextureAddressingMode(TextureUnitState::TAM_BORDER);[/i][/b]
				tu->setTextureBorderColour(ColourValue::White);
			}
		}

	}
I did a quick try. Let's say I have the two tiles [A] .
I edited my textures to replace the first pixel column of A by the first pixel column of B. And replaced the last pixel column of B by the last pixel column of A. So now they look like this :
[First Pixel of B|AAA...AAA] [BBB...BBB|Last Pixel of A]

And the result is that the two terrain don't have a seam anymore : screenshot
The wireframe so you see where one terrain ends and the other begins : wireframe view

If that is confusing have a look at this screenshot. I did the same textures edit except that I replaced more than 1 pixel wide column for visibility purpose.

Of course with more than 2 tiles it wouldn't work [B|AAA...AAA][C|BBB...BBB|A][CCC...CCC|B].
This is why I have to edit the material to only use the uv -1 pixel on each side and hope the filtering doesn't take care of the uv I'm using.
scrawl
OGRE Expert User
OGRE Expert User
Posts: 1119
Joined: Sat Jan 01, 2011 7:57 pm
x 216

Re: Terrain seam with orthophoto

Post by scrawl »

The addressing mode that interests you is for the layer textures. It is not set, and will default to TAM_WRAP.

Code: Select all

         // layer textures
         for (uint i = 0; i < numLayers; ++i)
         {
            // diffuse / specular
            pass->createTextureUnitState(terrain->getLayerTextureName(i, 0))->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
            // normal / height
            pass->createTextureUnitState(terrain->getLayerTextureName(i, 1))->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
         }
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: [SOLVED] Terrain seam with orthophoto

Post by Etty »

Thank you scrawl I can't believe it was just under my eyes, I feel a bit blind.

Thank you bstone for being right till the beginning and alberts for your support.
User avatar
alberts
Gremlin
Posts: 177
Joined: Fri Mar 31, 2006 8:43 am
Location: Granada-Cádiz-Jaén, Spain
x 20

Re: [SOLVED] Terrain seam with orthophoto

Post by alberts »

I have set the texture addressing mode to CLAMP (both diffuse/specular and normal/height) but I cannot get things work as well as you. The seams look better now but they are still visible.
To test it, I have used the following image as the diffuse texture for the page.

Image

And here are the (expected) artifacts near the page borders in Ogitor (it uses the default terrain material generator).

Image

And following is the same map loaded in my application (texture addressing mode set to CLAMP).

Image

Here is the result when not using the testing image.

Image

At least the opposite border are not shown in the page limits. Dou you know what the problem could be? Have you modified anything else in the terrain material generator?
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: [SOLVED] Terrain seam with orthophoto

Post by bstone »

alberts wrote:At least the opposite border are not shown in the page limits. Dou you know what the problem could be? Have you modified anything else in the terrain material generator?
The UVs are clearly off on those images, going beyond the 0..1 range.
User avatar
alberts
Gremlin
Posts: 177
Joined: Fri Mar 31, 2006 8:43 am
Location: Granada-Cádiz-Jaén, Spain
x 20

Re: [SOLVED] Terrain seam with orthophoto

Post by alberts »

Thanks bstone. Where are UVs set for a terrain page? I tried to modify the page world size but the artifax are still visible.

This are the parameters used for the terrain (Ogitor scene file):

Code: Select all

<OBJECT object_id="375133504" name="Terrain Group" typename="Terrain Group Object" parentnode="SceneManager">
    <PROPERTY id="blendmap::texturesize" type="2" value="1024"></PROPERTY>
    <PROPERTY id="colourmap::enabled" type="12" value="false"></PROPERTY>
    <PROPERTY id="colourmap::texturesize" type="2" value="128"></PROPERTY>
    <PROPERTY id="layer" type="2" value="0"></PROPERTY>
    <PROPERTY id="lightmap::texturesize" type="2" value="1024"></PROPERTY>
    <PROPERTY id="locked" type="12" value="false"></PROPERTY>
    <PROPERTY id="pagemapsize" type="2" value="513"></PROPERTY>
    <PROPERTY id="pagenameprefix" type="7" value="Page"></PROPERTY>
    <PROPERTY id="pageworldsize" type="6" value="2560"></PROPERTY>
    <PROPERTY id="pg::densitymapsize" type="2" value="1024"></PROPERTY>
    <PROPERTY id="pg::detaildistance" type="2" value="240"></PROPERTY>
    <PROPERTY id="pg::pagesize" type="2" value="40"></PROPERTY>
    <PROPERTY id="tuning::compositemapdistance" type="2" value="10000"></PROPERTY>
    <PROPERTY id="tuning::compositemaptexturesize" type="2" value="1024"></PROPERTY>
    <PROPERTY id="tuning::maxbatchsize" type="2" value="65"></PROPERTY>
    <PROPERTY id="tuning::maxpixelerror" type="2" value="3"></PROPERTY>
    <PROPERTY id="tuning::minbatchsize" type="2" value="33"></PROPERTY>
    <PROPERTY id="updatescript" type="7" value=""></PROPERTY>
    <CUSTOMPROPERTIES>
    </CUSTOMPROPERTIES>
  </OBJECT>
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: [SOLVED] Terrain seam with orthophoto

Post by Etty »

Well my result isn't 100% perfect either but I didn't want to bother with that for the moment.
Note that I've also disabled parallax ( /viewtopic.php?f=1&t=75800 )

Screenshot 01 and if we look closer screenshot 2

There is still a little seam visible but it's really better than what I had before. Again another picture with no filtering : screenshot
I guess the filtering is now calculating the pixels with only their direct neighbors from the same texture. The pixels on the right border are then calculated with only to top, left and bottom ones.

I'm actually working a bit on it, making my textures repeating 1 pixel of their neighbors and trying to modify the MaterialGeneratorA to not use the border of the image to texture the terrain. But I don't know a lot about shader and material so I kinda try to swim but sink :lol:

I spotted this line (~n°643) :

Code: Select all

Real baseUVScale = 1.0f / (terrain->getSize() - 1);
And this (~n°870):

Code: Select all

"   float2 uv = float2(posIndex.x * baseUVScale, 1.0 - (posIndex.y * baseUVScale));\n"; 
Modifying them change my texture position and scale on the terrain but I couldn't get a perfect result and I'm not sure if it's because I didn't modify it correctly or if it's just change nothing to the seam.

My original textures are 4096x4096 and if I repeat the borders they become 4098x4098. Is there a better way to make the material use the pixels from (2,2) to (4097, 4097) ?

Well I'll turn the [Solved] to [Partly Solved] since alberts still has an issue with that and well me too, even if I'm somewhat happy for now.
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: [Partly Solved] Terrain seam with orthophoto

Post by Etty »

Sorry for double.

Your problem look like your texture is too small to fill the complete terrain. I also do that :

Code: Select all

importData.layerList[0].worldSize = TERRAIN_WORLD_SIZE;
Since it's clamping now, if it reach the end of the texture it'll just stretch it. For example if I change the value to TERRAIN_WORLD_SIZE/2 that will be the result :
Image

The last pixel is stretched like in your screen.
scrawl
OGRE Expert User
OGRE Expert User
Posts: 1119
Joined: Sat Jan 01, 2011 7:57 pm
x 216

Re: [Partly Solved] Terrain seam with orthophoto

Post by scrawl »

Have you tried to use

Code: Select all

importData.layerList[0].worldSize = TERRAIN_WORLD_SIZE+1;
Alternatively change this line

Code: Select all

Real baseUVScale = 1.0f / (terrain->getSize() - 1);
to

Code: Select all

Real baseUVScale = 1.0f / (terrain->getSize());

?
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: [Partly Solved] Terrain seam with orthophoto

Post by Etty »

That didn't do the trick unfortunately.

Here is a sample if you have some times to download and test :

0_0.png
1_0.png

Original picture without the repeated border :

no_repeat_0_0
no_repeat_1_0
User avatar
alberts
Gremlin
Posts: 177
Joined: Fri Mar 31, 2006 8:43 am
Location: Granada-Cádiz-Jaén, Spain
x 20

Re: [Partly Solved] Terrain seam with orthophoto

Post by alberts »

What exactly didn’t do the trick? Set worlSize value to TERRAIN_WORLD_SIZE+1 when importing data or modify the baseUVScale variable in the material generator? I’m creating my own material generator. If it is the latter alternative you will save me a lot of work :) . I have to create my own material generator (as suggeted by scrawl) because I import the terrain directly from Ogitor. I’m not setting up importing params.
Etty
Kobold
Posts: 36
Joined: Fri Mar 15, 2013 11:09 am
Location: Belgium
x 3

Re: [Partly Solved] Terrain seam with orthophoto

Post by Etty »

Sorry, I meant :
Tried both but none worked.
User avatar
alberts
Gremlin
Posts: 177
Joined: Fri Mar 31, 2006 8:43 am
Location: Granada-Cádiz-Jaén, Spain
x 20

Re: [Partly Solved] Terrain seam with orthophoto

Post by alberts »

Thanks etty.

I’m still trying to figure out how to solve the uv texture size issue. I forgot to mention that I’m still using 1.7 branch and the default material generator doesn’t have the line Scrawl suggested to change. Could someone please tell me where the material generator (in 1.7 branch) is suppose to set the uv texture size?
Post Reply