Tile based texturing using shaders (CG)

Anything and everything that's related to OGRE or the wider graphics field that doesn't fit into the other forums.
Post Reply
whisp
Gnoblar
Posts: 14
Joined: Fri May 27, 2011 2:48 pm

Tile based texturing using shaders (CG)

Post by whisp »

Hi!

I'm trying to texture a heightmap-terrain using different kinds of small tiles repetitive. The tile-textures itself are saved in a texture atlas.

My idea was, that the vertex program would create the texture coordinates from the atlas for the corresponding tile that should be used, while a second texture would be used to decide which tile to be used. E.g. a vertex at xz-position (10, 20) would lookup the second texture at position (10, 20), find for example the color (255,0,0), and decide, when (255,0,0), then set the coordinates to that dirt tile in the top right corner of the texture atlas.

Yet accessing textures seems to be not that common in vertex programms and only available past certain profiles. One way i found was vertex texture fetch. But this way is not supported on many ATI DirectX 9 cards. For ATI cards there shall be another way instead, render to vertex buffer, which i didn't read more about yet.

Since i'm new to Shader-Programs i'm not sure if there aren't easier, faster, more elegant ways to accomplish the tiling. Any hints?

Thanks

whisp
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: Tile based texturing using shaders (CG)

Post by bstone »

Move the tile logic to the fragment program. Allocate one sampler for the tile map and another for the atlas. Pass the world xz coords from the vertex program to the fragment program and use them to access the respective tile and then the atlas. This involves a dependent texture fetch but will work on all hardware.
whisp
Gnoblar
Posts: 14
Joined: Fri May 27, 2011 2:48 pm

Re: Tile based texturing using shaders (CG)

Post by whisp »

Thank you, bstone.

I tried to produce the output as proposed by you, but for some unknown reasons the tiling doesn't work, the texturing results are strange, hard to describe.

In the following i will post the shader code i'm using, the lines are commented with what i think they do. Info about the geometry: The terrain page that should be textured with tiles consists of 65 * 65 vertices (64 * 64 grid squares). The vertices defining the terrain page are 1 coordinate from each other, there is only 1 vertex per "grid-corner" and no texture coordinates provided. Each grid-square should display 1 texture-tile. The tile map texture i'm using holds the tile data for the page and has a size of 64 * 64 pixels.

Code: Select all

struct VP_Output
{
  float4 position : POSITION;
  float2 texCoord : TEXCOORD0;
  float2 pageVertXZ;
};

// Vertex program
VP_Output TerrainVP(
		float4 position : POSITION,
		uniform float4 page0, //page 0 are the world xz-coordinates of the page's top left corner
		uniform float4x4 worldViewProj)
{
  VP_Output OUT;
 
  OUT.position =  mul(worldViewProj, position);
  
  // Vertex pos relative to page pos
  float2 vposr;
  vposr.xy = position.xz - page0.xz;
  
  // Forwarding to fragment shader, used for tile map lookup
  OUT.pageVertXZ = vposr;
  
  // Texture Coordinates, 1/8 of the tileset (8 * 8 tiles texture atlas)
  float2 tex;
  tex.x = vposr.x * 0.125;
  tex.y = vposr.y * 0.125;
  
  OUT.texCoord = tex;

  return OUT;
}


struct FP_Output
{
  float4 color : COLOR;
};

FP_Output TerrainFP(float2 texCoord : TEXCOORD0,
					float2 pageVertXZ,
					uniform sampler2D lookupTex : TEXUNIT1,
                    uniform sampler2D decal : TEXUNIT0)
{
  FP_Output OUT;
  
  // The texture atlas is 256 * 256 pixels, each tile is 32 * 32
  // set texCoord relative to texture atlas 0,0
  texCoord = texCoord - (pageVertXZ * 32.0f);
  
  // lookup the tile map to get the  tile type (color)
  float4 tiletype = tex2D(lookupTex, pageVertXZ);

  // if the tiletype is "red", use the second tile in the atlas, instead of the first.
  if (tiletype.y == 1.0) 
  {
	texCoord.x += 32;
  }
  
  OUT.color = tex2D(decal, texCoord);
  return OUT;
}
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: Tile based texturing using shaders (CG)

Post by bstone »

Make sure filtering is disabled for your tilemap sampler. Otherwise you will most likely get weird results.
whisp
Gnoblar
Posts: 14
Joined: Fri May 27, 2011 2:48 pm

Re: Tile based texturing using shaders (CG)

Post by whisp »

I changed that, but the problem is somewhere else.

The tile map isn't applied tilewise over the whole page, instead it's applied pixelwise over each single grid-square. Yet not with the pixel colors of the tile map texture, but, correctly, with the colors from the atlas: The lookup coordinates seem not to change per vertex, but vary per pixel instead. So every pixel, it looks for the next tile type, picks a single pixel from that tile in the atlas and puts that single pixel in the output. As if pageVertXZ would increase for every pixel, instead every vertex.
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: Tile based texturing using shaders (CG)

Post by bstone »

Fix the shaders then until it works :)
whisp
Gnoblar
Posts: 14
Joined: Fri May 27, 2011 2:48 pm

Re: Tile based texturing using shaders (CG)

Post by whisp »

Several of my approachs were wrong in this shader, but in the meanwhile i found a possible solution:

The data passed from a vertex program to a fragment program always gets interpolated. It's not possible to pass custom values that don't get interpolated, thus the interpolation needs to be removed in the fragment shader.

In this case i need the non-interpolated model-space-coordinates of the vertices in order to look up the tile-map texture.

In the vertex shader i calculated the texture coordinates:

Code: Select all

// Texture Coordinates, 1/8 of the tileset
OUT.texCoord = OUT.pageVertXZ.xy * 0.125;
With this coordinates the vertex position can be calculated in the fragment shader:

Code: Select all

// set texCoord relative to 0,0
float2 pageVertXZ = floor(indata.texCoord * 8);
The interpolation-value just gets cropped, what's left is the vertex coordinate in model space.

Other mistakes:
  • The vertex program receives vertex positions in model space, thus, in my case, there's no need to calculate coordinates relative to the page top-left corner, it's already there
  • Texture coordinates are always between 0 and 1, be it in the vertex program or in the fragment program
And finally the simple and working shaders:

Code: Select all

// Vertex program output structure
struct VP_Output
{
  float4 wvpos : POSITION;
  float2 texCoord : TEXCOORD0;
};

// Vertex program
VP_Output TerrainVP(
		float4 position : POSITION,
		uniform float4x4 worldViewProj)
{
  VP_Output OUT;
 
  // Translated position
  OUT.wvpos =  mul(worldViewProj, position);
  
  // Texture Coordinates, 1/8 of the tileset 
  OUT.texCoord  = position.xz * 0.125;
  
  return OUT;
}

// Fragment program output structure
struct FP_Output
{
  float4 color : COLOR;
};

// Fragment program
FP_Output TerrainFP(VP_Output indata,
					uniform sampler2D lookupTex : TEXUNIT1,
                    uniform sampler2D decal : TEXUNIT0)
{
	FP_Output OUT;

	// calculate model space vertex xz-coordinates
	float2 pageVertXZ = floor(indata.texCoord * 8);

    // texture coordinates for the top-left tile in tile atlas
	float2 tc2 = indata.texCoord - pageVertXZ * 0.125;

	// tile-map lookup coordinates in a 0-1 range
	float2 lookupXZ = pageVertXZ * 0.015625; // (/64)
	
	// tiletype
	float4 tiletype = tex2D(lookupTex, lookupXZ);

	// for the respective tiletype use the second tile from the atlas
	// instead the top-left tile
	if (tiletype.g == 0.0) tc2.x += 0.125;

	// Pick the proper pixel from the atlas
	OUT.color = tex2D(decal, tc2);
	return OUT;
}
bstone
OGRE Expert User
OGRE Expert User
Posts: 1920
Joined: Sun Feb 19, 2012 9:24 pm
Location: Russia
x 201

Re: Tile based texturing using shaders (CG)

Post by bstone »

Here you go. Good job.
swuth
Bronze Sponsor
Bronze Sponsor
Posts: 53
Joined: Wed Mar 25, 2015 10:01 pm

Re: Tile based texturing using shaders (CG)

Post by swuth »

Hi need to do something similar to this. I have a .map file which is a 2d Array of TextureID's which I use to lookup UV's in a Texture Atlas. I am pretty new to Ogre, could you explain how I could use your shader for something like that?

Thanks

CH
Post Reply