# GLSL Parallax Mapping

This topic is 4227 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Parallax mapping seems somewhat simple. I understand the equations and have shaders set up to perform it. Thing is I need another more keen eye in the ways of GLSL to take a look at this code. I can't figure out what's wrong with it. I am currently supplying correct variables please take a look.
// vertex shader
varying vec3 normal, lightVector, halfVector, viewVector, texCoord;

void main()
{
vec4 worldPos;

normal = normalize(gl_NormalMatrix * gl_Normal);
vec3 tangent = gl_MultiTexCoord1.xyz;;
vec3 binormal = cross(tangent, normal);

mat3 TBNMatrix;
TBNMatrix[0] =  gl_NormalMatrix * tangent;
TBNMatrix[1] =  gl_NormalMatrix * binormal;
TBNMatrix[2] =  normal;

worldPos = gl_ModelViewMatrix * gl_Vertex;
lightVec = normalize(vec3(gl_LightSource[0].position - worldPos));

viewVector = vec3(-worldPos) * TBNMatrix ;

halfVector = normalize(gl_LightSource[0].halfVector.xyz);

gl_TexCoord[0] = gl_MultiTexCoord0;
texCoord = glMultiTexCoord0;
gl_Position = ftransform();

}

varying vec3 normal, lightVector, halfVector, viewVector, texCoord;
uniform sampler2D decalMap, heightMap, normalMap;

void main()
{
vec4 diffuseLight, specularLight;
float shine = 64.0;
float scale = 0.5;
float bias = 0.25;

normal = normalize(normal);
lightVector = normalize(lightVector);
viewVector = normalize(viewVector);

// Get the height value and calculate the new texture coord.
float height = scale * texture2D(heightMap, texCoord).r - bias;
vec2 newTexCoord = height * viewVector + texCoord;

// Get the bump map normal.
vec3 normalTex = texture2D(normalMap, newTexCoord).xyz;

// Convert from 0 to 1 range to -1 to 1.
normalTex = normalize(2.0 * normalTex + 1.0);

// Calculate the bump value as n dot l.
float dp = saturate(dot(normalMap, lightVector));

// Get the decal texture color with the new tex coords.
vec4 decalCol = texture2D(decalMap, newTexCoord);

float lightIntensity = max(dot(normal, lightVector), 0.0);

diffuseLight = lightIntensity * gl_LightSource[0].diffuse;
diffuseLight = diffuseLight * dp;
specularLight = pow(max(dot(n, normalize(halfVector)), 0.0), shine) * gl_LightSource[0].specular;

vec4 lightColor = diffuseLight + specularLight + gl_LightSource[0].ambient;

vec4 texColor = texture2D(decalMap,newTexCoord);

vec4 color = texColor * lightColor;
gl_FragColor = color;
}


Please have a look and please ask any questions and I'll respond. My current results are a black square, that's it, no lighting, no textures... :(

##### Share on other sites
Have you checked the shader log? A black square might be a result of the fragment program not being bound. Two things I could spot are:

Quote:
 lightVec = normalize(vec3(gl_LightSource[0].position - worldPos));
I can't find lightVec declared anywhere, maybe oyu meant lightVector (since there is an active varying by that name whose value you haven't set)?

Quote:
 vec3 tangent = gl_MultiTexCoord1.xyz;;
Two semicolons after that line. The compiler may ignore an empty statement, or it may issue an error (I don't know).

##### Share on other sites
How does one check said shader log?

##### Share on other sites
Quote:
 Original post by EnalisHow does one check said shader log?

You can get the compiler output by using glGetInfoLogARB. This usually contains something like "Shader will run in hardware/software" or will give you an error message.

A black square can also mean not having a sampler bound correctly but it looks like you have an error in the shader.

Hope that helps

##### Share on other sites
That function seems to crash the program, I even got the correct length to feed it.

##### Share on other sites
Got it working and you were right. There is one error in each file. If I fix those and still doesn't work I'll reply, thanks for your help!

##### Share on other sites
Ok, here's what I'm down to.
In the fragment shader only here are the errors

(18) : error C1020 : invalid operands to "add"
(18) : error C1056 : invalid initialization
(27) : warning C7506 : Opengl does not define the global function saturate

varying vec3 normal, lightVector, halfVector, viewVector, texCoord;uniform sampler2D decalMap, heightMap, normalMap;void main(){	vec4 diffuseLight, specularLight;		float shine = 64.0;	float scale = 0.5;	float bias = 0.25;	normal = normalize(normal);	lightVector = normalize(lightVector);	viewVector = normalize(viewVector);	// Get the height value and calculate the new texture coord.	float height = scale * texture2D(heightMap, gl_TexCoord[0]).r - bias;	vec2 newTexCoord = height * viewVector + gl_TexCoord[0];	// Get the bump map normal.	vec3 normalTex = texture2D(normalMap, newTexCoord).xyz;		// Convert from 0 to 1 range to -1 to 1.	normalTex = normalize(2.0 * normalTex + 1.0);	// Calculate the bump value as n dot l.	float dp = saturate(dot(normalMap, lightVector));		// Get the decal texture color with the new tex coords.	vec4 decalCol = texture2D(decalMap, newTexCoord);	float lightIntensity = max(dot(normal, lightVector), 0.0);	diffuseLight = lightIntensity * gl_LightSource[0].diffuse;	diffuseLight = diffuseLight * dp;	specularLight = pow(max(dot(n, normalize(halfVector)), 0.0), shine) * gl_LightSource[0].specular;		vec4 lightColor = diffuseLight + specularLight + gl_LightSource[0].ambient;	vec4 texColor = texture2D(decalMap,newTexCoord);	vec4 color = texColor * lightColor;//	vec4 color = texture2D(decalMap, texCoord) * 1.0;	gl_FragColor = color;}

##### Share on other sites
I had to count to find the right lines - but anyway here's what you should do:

Quote:
 Original post by Enalis(18) : error C1020 : invalid operands to "add"(18) : error C1056 : invalid initialization

You are doing a vec2 = vec3 + vec4. If you want to ignore that latter components, what you want is something like:
vec2 newTexCoord = height * viewVector.xy + gl_TexCoord[0].st;

Quote:
 (27) : warning C7506 : Opengl does not define the global function saturate

As it says, GLSL doesn't have a function called saturate(). I think HLSL's saturate() clamps the value to a [0, 1] range (not sure) and if that's the case you need:
float dp = clamp(dot(normalMap, lightVector), 0.0, 1.0);

##### Share on other sites
Quote:
 Original post by Enalis(27) : warning C7506 : Opengl does not define the global function saturate

#27 is a warning. If you remove the two previous errors, it should run ok, if you are using NVidia. If you're on an ATI, then you need to use clamp.

##### Share on other sites
Ok, thank you all for your help so far. But now here's the new problem, shit is what the shader looks like and it's not good.

##### Share on other sites
Try the following for the height map sampling.
// use a scale of 0.05, try bias of 0 for nowfloat height = texture2D(heightMap, gl_TexCoord[0]).r - bias;float offset = scale * (2.0 * height - 1.0);vec2 newTexCoord = gl_TexCoord[0].st + viewVector.xy * height;

My shader does something to that affect.

Hope that helps

##### Share on other sites
Ok, so here's the change that I made:

// Get the height value and calculate the new texture coord.
float height = texture2D(heightMap, texCoord).r - bias;
float offset = scale * (2.0 * height - 1.0);
vec2 newTexCoord = texCoord.st + viewVector.xy * offset;

And what I did was as I lowered the size of scale it looked more like a normal texture. When I put it at 0.0001 it nearly looked like the original texture which makes sense because there's less offset. So here's my question, would it be possible that I have the wrong viewVector or something like that?

##### Share on other sites
A few swift calculation changes and I'm almost there
float scale = 0.05float bias = 0.025float height = texture2D(heightMap, texCoord).r;//float offset = scale * (2.0 * height - 1.0);float offset = (height * scale) - bias;vec2 newTexCoord = texCoord.st + (viewVectorNew.xy * offset);

Here are the results

##### Share on other sites
maybe you should take a look at the rendermonkey and shaderdesigner examples and look how they did it :)

##### Share on other sites
I have made some parallax stuff too, but it looks kind of what the second screenshot shows, kind of messy and stretched. I used the code from the Shader Designer example. Though, I read someplace that I should use a heightmap that is bigger in size than the normal texture (i.e. texture = 256x256, heightmap = 512x512 instead of the other way around). Can this really be true?

##### Share on other sites
i had the same problems with the shader designer sample as well, but i thought that it was simply my fault. their examples seem to be coded for a static camera only.. the intensity of the light was influenced by my camera movement, etc Oo

##### Share on other sites
Ah yes, that is correct... Shader Designer uses a static camera.. hmm, so how did you solve it? Should only be a small revamp of some portion of the code I guess :)

##### Share on other sites
Are u sure that the camera an light uses right coordinates when you send to the shader? With my TBN matrix I need to negate the tangent vector.

ains

##### Share on other sites
I am not even sure I am calculating the tangents and binormals correctly :)

##### Share on other sites
http://www.terathon.com/code/tangent.php

works fine, using it in my engine, too.