-
Parallax mapping woes.
I've been spending the last couple of nights trying to get a nice parallax mapping shader working.
I've had some sucesss - in most cases, it works and looks pretty good.
I'm using a cube as a test object. On some sides of the cube, the offset may not be quite in the right direction, and on others, at certain angles the parallax offset effect because far greater than normal, and at a different angle much less than normal.
The screenshot I'm posting is just one case. If you need more to illustrate the problem I'm trying to describe, just ask.
I think it might be the way I'm calculating the
tangent space view vector, but I don't know for sure.
I also have a similar problem with the lighting (inconsistancy accross the faces/angles/directions).
Vertex Program (GLSL):
Code:
attribute vec3 tangent;
uniform vec4 viewPos; //object space
uniform vec4 lightPos; //object space - not used
varying vec3 normal;
varying vec3 lightVec;
varying vec3 eyeVec;
varying vec2 texCoords;
void main(void)
{
vec3 vertex = (gl_ModelViewMatrix*gl_Vertex).xyz;
vec3 vertexInv = (gl_ModelViewMatrixInverse*gl_Vertex).xyz;
normal = normalize(gl_NormalMatrix*gl_Normal);
vec3 bitangent = cross(normal, tangent);
mat3 tbn = mat3(tangent, bitangent, normal);
vec3 L = normalize(gl_LightSource[0].position.xyz-vertex);
lightVec = L*tbn;
vec3 E = viewPos.xyz-gl_Vertex.xyz;
eyeVec = E*tbn;
eyeVec *= vec3(1,-1,1);
texCoords = gl_MultiTexCoord0.xy;
gl_Position = ftransform();
}
Fragment Shader (GLSL - parallax shifting code highlighted)
Code:
uniform sampler2D baseMap;
uniform sampler2D bumpMap; //requires 32-bit texture - parallax map in alpha channel
varying vec3 normal;
varying vec3 lightVec;
varying vec3 eyeVec;
varying vec2 texCoords;
const float scale = 0.05;
const float bias = -scale/2.0;
vec3 unpackVec(vec4 v)
{
return v.xyz * 2.0 - 1.0;
}
void main(void)
{
vec3 L = normalize(lightVec);
vec3 E = normalize(eyeVec);
float height = texture2D(bumpMap, texCoords).a*scale+bias;
vec2 parallax = texCoords + height * E.xy;
vec3 bump = texture2D(bumpMap, parallax).xyz*2.0 - 1.0;
bump = normalize(bump);
vec3 reflVec = (2.0*dot(bump, L))*bump - L;
vec4 ambient = gl_LightSource[0].ambient*gl_FrontMaterial.ambient;
vec4 diffuse = (texture2D(baseMap, parallax)*gl_LightSource[0].diffuse*gl_FrontMaterial.diffuse)*max(dot(bump, L), 0.0);
vec4 specular = gl_LightSource[0].specular*gl_FrontMaterial.specular*pow(max(dot(reflVec, E), 0.0), gl_FrontMaterial.shininess);
gl_FragColor = ambient+diffuse+specular;
}
-
The top portion of the cube does not have the illusion of depth because of the angle of the surface in respect to the camera.
Notice the right side and left sides of the cube. The right side looks nearly perfect and flawless and the left side looks very good but obviously something is wrong with the tangent vectors. The brick depth should be facing in towards the right, not out towards the left. The top surface problem is probably because parallax mapping cannot account for the angle.
All this is probably due to the angle of the surface with respect to the camera. Part of the problem to is that you go to great extents to make the sides look perfect and mess the illusion up by using the incorrect texture for the top. The brick at the top should have a top to it, yet it does not. It has good looking sides but when you get to the top the texture does not line up and looks very odd. No matter what pains you go through to create the illusion of depth, it will always be lost with the top texture.
Looks very good though. Excellent work. My guess is your tangent vectors are somehow incorrect at some point.
On a side note how are you texturing everything in the scene? Are you unwrapping U'V's or using something simpler?
-
For the cube I just used (sloppy) planar mapping for each side. The scene in the background is a map made with GTKRadiant, so I didn't do any UV mapping there really.
I don't think the tangent vectors themselves are being caculated wrong - I'm using OGRE as my rendering sub-system now, so I'm assuming if there was a problem there, it would've been caught before now.
But since the tangents are caculated based on UVs, could it just be the texture mapping as you mentioned throwing everything off? That would account for the problem varying by model and face.
-
Well, I tried as an experiment flipping the texture horizontally on the floor of a BSP mesh. It fixed my "backwards lighting" issue, but It's not doing much for the parallax.
For example, on one wall, the lighting vertically is backwards - if the light is over top of one of the bricks, the bottom of that brick will be lit. But the parallax mapping on that wall works fine, so fipping the texture to fix the lighting will kill the parallax mapping.
On another wall, the lighting is fine, but the parallax is backwards.
The floor seems fine as far as the vertical shift goes, but looking accross the floor horizontal to the texture doesn't seem to work - it just shifts the vertical coord more.
The ceiling shifts opposite of the floor.
On another wall, I can look straight at it, and the parallax will be shifted to the left.
There's also a weird issue in some cases where the lighting on the bumps will "flip" depending on the view direction.
Is there some way I can correct this stuff based on the normal or something?