# In GLSL is it possible to offset vertices based on height map colour?

I am attempting to generate some terrain based upon a heightmap. I have generated a 32 x 32 grid and a corresponding height map ->

In my vertex shader I am trying to offset the position of the Y axis based upon the colour of the heightmap, white vertices being higher than black ones.

//Vertex Shader Code
#version 330

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform sampler2D heightmap;

layout (location=0) in vec4 vertexPos;
layout (location=1) in vec4 vertexColour;
layout (location=3) in vec2 vertexTextureCoord;
layout (location=4) in float offset;

out vec4 fragCol;
out vec4 fragPos;
out vec2 fragTex;

void main()
{
// Retreive the current pixel's colour
vec4 hmColour = texture(heightmap,vertexTextureCoord);

// Offset the y position by the value of current texel's colour value ?
vec4 offset = vec4(vertexPos.x , vertexPos.y + hmColour.r, vertexPos.z , 1.0);

// Final Position
gl_Position = projectionMatrix * viewMatrix * modelMatrix * offset;

// Data sent to Fragment Shader.
fragCol = vertexColour;
fragPos = vertexPos;
fragTex = vertexTextureCoord;
}


However the code I have produced only creates a grid with none of the y vertices higher than any others.

This is the C++ code that generates the grid and texture co-orientates which I believe to be correct as the texture is mapped to the grid, hence the white blob in the middle.

The grid-lines are generated in the fragment shader, sorry for any confusion.

I have tried multiplying the r value of hmColour by 1000 unfortunately that had no effect.

The only other problem it could be is that the texture coordinate data is incorrect ?

for (int z = 0; z < MAP_Z  ; z++)
{
for(int x = 0; x < MAP_X  ; x++)
{
//Generate Vertex Buffer

vertexData[iVertex++] = float (x) * MAP_X;
vertexData[iVertex++] = 0;
vertexData[iVertex++] =  -(float) (z) * MAP_Z;

//Colour Buffer  NOT NEEDED
colourData[iColour++] = 255.0f; // R
colourData[iColour++] = 1.0f; // G
colourData[iColour++] = 0.0f; // B

//Texture Buffer

textureData[iTexture++] = (float ) x * (1.0f / MAP_X);
textureData[iTexture++] = (float ) z * (1.0f / MAP_Z);

}
}


The heightmap texture I am trying to use appears like so (without grid-lines).

This is the corresponding fragment shader

// Fragment Shader Code
#version 330

uniform sampler2D hmTexture;

layout (location=0) out vec4 fragColour;

in vec2 fragTex;

in vec4 pos;

void main(void) {

vec2 line = fragTex * 32;
// Without Gridlines
fragColour = texture(hmTexture,fragTex);

// With grid lines
// + mix(vec4(0.0, 0.0, 1.0, 0.0), vec4(1.0, 1.0, 1.0, 1.0),
//  smoothstep(0.05,fract(line.y), 0.99) * smoothstep(0.05,fract(line.x),0.99));

}

• your images didn't show up – concept3d Nov 4 '13 at 0:01
• Additional images, and better info on any of the inputs into the shader would make this a much easier question to answer. – Arelius Nov 4 '13 at 6:02
• Thanks for adding the additional code, this helps. After seeing the additional code, I'm even more certain it's a problem of the scale of hmColour as outlined in my answer. – Arelius Nov 6 '13 at 0:31

So, what you're doing looks generally ok. There are a few possible sources of error.

As Matthew said, you could be passing in uv coordinates wrong, and looking up the same thing everywhere.

My best guess however, is something related to the coordinate space.

vec4 offset = vec4(vertexPos.x , vertexPos.y + hmColour.r, vertexPos.z , 1.0);


So, for starters, this all happens in model space. Which seems appropriate to me but let's keep that in mind as we evaluate the following.

This implies that the grid varies in the X and Z axes, It is possible that the model is in the XY plane and one of the matrices puts it into the XZ plane. However, if everything else is working correctly, I'd expect this to be noticeable.

The other big possibility is that everything is in fact working... sort of except everything is very small. In all likely-hood, hmColour is in the range of 0.0 and 1.0 (unless you are using 32 bit per channel textures) And it's quite likely that vertexPos is in a much larger range than that. Considering that the terrain seems to poke through the grid in a few spots in the only image you posted I suspect this is the case. The easy test for this is to multiply hmColour.r by something large.

vec4 offset = vec4(vertexPos.x , vertexPos.y + hmColour.r * 1000.0, vertexPos.z , 1.0);


Or something similar.

It seems like you did not set the uv coordinates at each vertex, so it's most likely just sampling at the same point every time, resulting in a mesh with the same y offset. Try setting the UV coords at each vertex to the distance from the bottom left corner on each axis divided by the grid length.

You may also want to multiply the color value by some constant because in shader, the color value is always between 0 and 1.