Heightmap texturing problem (big UV buffer)

I’m quite new in opengl and i have problem with texturing heightmap.
I’m creating heightmap using diamond square plus smoothing and I am satisfied with the result.
To create heightmap i’m using
GL_PRIMITIVE_RESTART and GL_TRIANGLE_STRIP
plus three buffers:

  • vertexs,
  • indices,
  • texture coordinates (UV).
    For texturing heightmap i’m using 5 textures and depending on the height i’m displaying different textures and this all works fine (without any other special effects).

But i have big problem with buffer for texture coordinates (UV) because this buffer is usually huge (depends on heightmap size).
To display texture for one poly i need array


0,0
0,1,
1,1,
1,0

because my heightmap have lots of polygons i repeat this array many times and my texture buffer growing up e.g
for heightmap with size 500x500 texture buffer need 250MB of memory.
I’m pretty sure that to display textures i can use only this small array


0,0
0,1,
1,1,
1,0

and do some “magic” in GLSL or do this in different way.
I’m using minimum OpenGL 3.0 and here it is my vertex and fragment shaders


#version 150 core

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

in vec3 inPosition;
smooth out vec3 thePosition;

in vec4 in_Position;
in vec2 in_TextureCoord;

out vec2 pass_TexCoord;

void main(void) {
	gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(inPosition, 1.0);
	thePosition = inPosition;
	pass_TexCoord = in_TextureCoord;	
}


#version 150 core

smooth in vec3 thePosition;

uniform sampler2D ground_grass;
uniform sampler2D ground_dirt;
uniform sampler2D ground_rock;
uniform sampler2D ground_snow;

uniform int dirt_height;
uniform int grass_height;
uniform int rock_height;

in vec2 pass_TexCoord;

void main(void) {
	vec3 tx  = vec3(0.0, 0.0, 0.0);

	if (thePosition.y < dirt_height){
		tx += texture2D(ground_dirt, pass_TexCoord).rgb;
	}
	if (thePosition.y > dirt_height && thePosition.y < grass_height){
		tx += texture2D(ground_grass, pass_TexCoord).rgb;
	}
	if (thePosition.y > grass_height && thePosition.y < rock_height){
		tx += texture2D(ground_rock, pass_TexCoord).rgb;
	}
	if (thePosition.y > rock_height){
		tx += texture2D(ground_snow, pass_TexCoord).rgb;
	}
	
	gl_FragColor = vec4(tx, 1.0);
}

So how to do this “magic” in GLSL or how to fix my problem with memory?

ps. Sorry for my poor English and I hope you can understand me.

You should easily be able the compute the UV from the vertex coordinate. Lets say you want to repeat the texture every 500 units from the origin then the UV value at a vertex is just



pass_TexCoord = mod(inPosition.xy,vec2(500.0f,500.0f)) / vec2(500,0f,500.0f);

To simulate the old generate coodinate functions you can use



uniform vec4      genTextureCoordinateParams_S;
uniform vec4      genTextureCoordinateParams_T;


vec2 st;
st.s = dot(genTextureCoordinateParams_S,vec4(in_Vertex.xyz,1.0f));
st.t = dot(genTextureCoordinateParams_T,vec4(in_Vertex.xyz,1.0f));


Unfortunately not all working or I don’t understand something.
If I change only vertex shader


pass_TexCoord = mod(inPosition.xy,vec2(500.0f,500.0f)) / vec2(500,0f,500.0f);

Textures are displaying but as one big texture
http://img17.imageshack.us/img17/4628/bigtexture.png
i have to change this code on this


pass_TexCoord = mod(inPosition.xy,vec2(500.0f,500.0f));

then the textures are displaying almost correctly (texture is repeating). But very often is not displaying correctly textures are stretching (marked in red circle).
http://img28.imageshack.us/img28/9387/texture1hx.png

I’m not quite sure about what is variable “in_Vertex” in fragment shader.
If I do something like this


#version 150 core

smooth in vec3 thePosition;

uniform sampler2D ground_grass;
uniform sampler2D ground_dirt;
uniform sampler2D ground_rock;
uniform sampler2D ground_snow;

uniform int dirt_height;
uniform int grass_height;
uniform int rock_height;

in vec2 pass_TexCoord;
in vec3 in_Vertex;

uniform vec4 genTextureCoordinateParams_S;
uniform vec4 genTextureCoordinateParams_T;
uniform sampler2D texture_diffuse;
void main(void) {
	vec3 tx  = vec3(0.0, 0.0, 0.0);

	vec2 st;
	st.s = dot(genTextureCoordinateParams_S,vec4(in_Vertex.xyz,1.0f));
	st.t = dot(genTextureCoordinateParams_T,vec4(in_Vertex.xyz,1.0f));

	if (thePosition.y < dirt_height){
		tx += texture2D(ground_dirt, st).rgb;
	}
	if (thePosition.y > dirt_height && thePosition.y < grass_height){
		tx += texture2D(ground_grass, st).rgb;
	}
	if (thePosition.y > grass_height && thePosition.y < rock_height){
		tx += texture2D(ground_rock, st).rgb;
	}
	if (thePosition.y > rock_height){
		tx += texture2D(ground_snow, st).rgb;
	}
	
	gl_FragColor = vec4(tx, 1.0);
}

Textures disappear. I’m almost sure that ‘in_Vertex’ cannot be
my buffer with vertices because when I run application, application is almost frozen.

in_Vertex is your input vertex xyz - in you case it is probably inPosition - this is a vertex shader not fragment shader.

500 was just a number picked at random. The repeat size (500) is total dependent on the mesh you wish to texture. Usually there are clues like if the texture is
a tree bark it will probably need to repeat about 4 times around your tree trunk but maybe 20 times up it.



pass_TexCoord = mod(inPosition.xy,vec2(500.0f,500.0f)) / vec2(500,0f,500.0f);

This code is actually only drapping a texture from the top (ie xz plane) - it will give stretching on the vertical axis which is noticable on steep slopes.
You cannot create a formula to replace proper uv mapping. This method is typically used for aerial photos drapped onto a DTM.

If you wish to disquise this you need to do some texture blending based on height and slope. There a few examples on the WEB if you search on “texture blending based on height and slope”

There is an alternative you could try.
Assign a 4th vertex value to each vertex to assign a lookup ID.
Each lookup ID would be treated as an integer (0,1,2,3) and would correspond to the texture coordinates:


0,0
0,1
1,1
1,0

Thus use the ID as an array index into your texture coordinate.

I didn’t notice before I just pasted your code


pass_TexCoord = mod(inPosition.xy,vec2(500.0f,500.0f)) / vec2(500,0f,500.0f);

but should be


pass_TexCoord = mod(inPosition.xz,vec2(500.0f,500.0f)) / vec2(500,0f,500.0f);

or even


pass_TextureCoord = mod(inPosition.xz, vec2(0.0f, 0.0f));

With inPosition.xz textures are displaying correctly.
Now i can blend :slight_smile:

Thanks for help!

Sorry about the code error. It’s easy to make that sort of mistake when you are giving examples and not full code:mad: (My data has z as up)