Open GLES Normal Map Shader Lighting Incorrect
I dont know whats wrong with the above code.
But I wrote a new one, which seems to work.
Maybe this is gonna help someone who wants a simple Open GLES Normal Map Shader:
VP
uniform mat4 worldViewProjMatrix;
uniform vec4 lightDirObjSpace;
attribute vec4 vertex;
attribute vec3 normal;
attribute vec3 tangent;
attribute vec3 binormal;
attribute vec4 uv0;
varying vec2 vTexCoord;
varying vec3 vLightVector;
void main( void )
{
vTexCoord = uv0.st;
vLightVector.x = dot( lightDirObjSpace.xyz, tangent );
vLightVector.y = dot( lightDirObjSpace.xyz, binormal );
vLightVector.z = dot( lightDirObjSpace.xyz, normal );
gl_Position = worldViewProjMatrix * vec4(vertex.xyz, 1.0);
}
FP
uniform vec3 surfaceDiffuseColour;
uniform vec3 surfaceAmbientColour;
uniform sampler2D tex0;
varying vec2 vTexCoord;
varying vec3 vLightVector;
void main(void)
{
vec3 normal = normalize(((texture2D( tex0, vTexCoord ).xyz) * 2.0) - 1.0);
float diffuse = max(0.0, dot(normalize(normal), normalize(vLightVector)));
gl_FragColor = vec4(surfaceDiffuseColour * diffuse + surfaceAmbientColour, 1.0);
}
Normal Mapping Issues
I can spot 1 obvious mistake in your code. TBN
is generated by the bitangent
, tangent
and normal
. While the bitangent
and tangent
are transformed from model space to view space, the normal
is not transformed. That does not make any sense. All the 3 vetors have to be related to the same coordinate system:
vec4 bitan = V * M * vec4(bitangent, 0.0);
vec4 tang = V * M * vec4(tangent, 0.0);
vec4 norm = V * M * vec4(normal, 0.0);
mat3 TBN = transpose(mat3(tang.xyz, bitan.xyz, norm.xyz));
Implementing Normal Mapping using OpenGL/GLSL
That normal map is in tangent-space, but you are treating it as object-space.
You need a bitangent and/or tangent vector per-vertex in addition to your normal in order to form the basis to perform transformation into and out of tangent-space. This matrix is often referred to as simply TBN
.
You have two options here:
Transform all of your lighting direction vectors into tangent-space
- Useful for forward-shading, can be done in a vertex shader
Transform your normal map from tangent-space back to view-space
- Required by deferred-shading, must be done in fragment shader
Both options require the construction of a TBN matrix, and if your tangent-space basis is orthogonal (modeling software like Assimp can be configured to do this for you) you can transpose the TBN matrix to do either one.
You are implementing forward-shading, so solution #1 is the approach you should take.
Below is a rough overview of the necessary steps for solution #1. Ordinarily you would do the calculation of the lighting direction vector in the vertex shader for better performance.
Vertex Shader to Transform of Lighting Vectors into Tangent-space:
attribute vec3 tangent;
attribute vec3 bitangent;
varying vec3 N;
varying vec3 V;
varying vec3 E;
varying vec3 T;
varying vec3 B;
void main()
{
N = normalize(gl_NormalMatrix*gl_Normal);
V = vec3(gl_ModelViewMatrix*gl_Vertex);
E = normalize(-V);
T = normalize(gl_NormalMatrix*tangent);
B = normalize(gl_NormalMatrix*bitangent);
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;
}
Fragment Shader to Transform Lighting Vectors into Tangent-space:
varying vec3 N;
varying vec3 V;
varying vec3 E;
varying vec3 B;
varying vec3 T;
uniform sampler2D textureUnit;
uniform sampler2D normalTextureUnit;
uniform vec4 TexColor;
#define MAX_LIGHTS 1
void main()
{
// Construct Tangent Space Basis
mat3 TBN = mat3 (T, B, N);
vec3 normal = normalize (texture2D(normalTextureUnit,gl_TexCoord[0].st).xyz*2.0 - 1.0);
vec4 color = vec4(0,0,0,0);
for(int i = 0; i < MAX_LIGHTS; i++)
{
vec4 lightPos = gl_LightSource[i].position;
vec3 L = lightPos.w > 0 ? lightPos.xyz - V : lightPos;
L *= TBN; // Transform into tangent-space
float dist = length(L);
L = normalize(L);
float NdotL = max(dot(L,N),0.0);
if(NdotL > 0)
{
float att = 1.0;
if(lightPos.w > 0)
{
att = 1.0/ (gl_LightSource[i].constantAttenuation +
gl_LightSource[i].linearAttenuation * dist +
gl_LightSource[i].quadraticAttenuation * dist * dist);
}
vec4 diffuse = clamp(att*NdotL*gl_FrontLightProduct[i].diffuse,0,1);
color += att*gl_FrontLightProduct[i].ambient + diffuse;
}
}
vec4 textureColor = texture2D(textureUnit, vec2(gl_TexCoord[0]));
gl_FragColor = TexColor*textureColor + gl_FrontLightModelProduct.sceneColor + color;
}
There is a tutorial here that should fill in the gaps and explain how to compute tangent and bitangent.
Problem with Parallax Normal Mapping in Opengl , GLSL
Wild guess following
I'd bet either on a tangent basis (vectors) problem, or on view vector being transformed/considered in the wrong coordinate space.
Without more information, it's difficult for me to say more...
Some source code, or animation of the problem would be helpful.
Related Topics
Using Opencv and Svm With Images
How to Sort a Vector of Pairs Based on the Second Element of the Pair
How to Get Rid of 'Deprecated Conversion from String Constant to 'Char*'' Warnings in Gcc
Where Exactly Does C++ Standard Say Dereferencing an Uninitialized Pointer Is Undefined Behavior
Replace Substring With Another Substring C++
How to Find the Index of Current Object in Range-Based For Loop
How Is a Variable At the Same Address Producing 2 Different Values
How to Check Whether Operator== Exists
Static Member Initialization in a Class Template
"Invalid Use of Incomplete Type" Error With Partial Template Specialization
Is There a Replacement For Unistd.H For Windows (Visual C)
How to Make Cmake Output into a 'Bin' Dir
Examples of When a Bitwise Swap() Is a Bad Idea
The Procedure Entry Point _Gxx_Personality_V0 Could Not Be Located