I've been trying to figure this out for a few days now, but I just can't get it right. I've read multiple tutorials and possible explanations, I even watched a java tutorial without finding the solution. This is what I do:
First I build the tangent values to pass as attributes:
//this parsing has not been updated, unlike the shaders, correct parsing in the answer below float f; vec3 edge1, edge2, tangentbuf; vec2 deltaUV1, deltaUV2; //for each face, x=vert,y=uv, z=normal for (size_t i = 0; i < totalrefs.size(); i += 9) { edge1 = verticeref[totalrefs[i + 3] - 1] - verticeref[totalrefs[i] - 1]; edge2 = verticeref[totalrefs[i + 6] - 1] - verticeref[totalrefs[i] - 1]; deltaUV1 = texkoordref[totalrefs[i + 4] - 1] - texkoordref[totalrefs[i + 1] - 1]; deltaUV2 = texkoordref[totalrefs[i + 7] - 1] - texkoordref[totalrefs[i + 1] - 1]; f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y); tangentbuf = f*vec3( (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x), (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y), (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z)); normalize(tangentref[tangentcount++]); tangentref[totalrefs[i] - 1] += vec4(normalize(tangentbuf), 1); tangentref[totalrefs[i + 3] - 1] += vec4(normalize(tangentbuf), 1); tangentref[totalrefs[i + 6] - 1] += vec4(normalize(tangentbuf), 1); } //for (auto &x : tangentref)x = normalize(x / x.w); //find average for (auto &x : tangentref)x = normalize(x); //just normalize is enough? Normalizing or dividing seems to give the same result, and I think this is correct this far. With these shaders:
vert
#version 400 layout ( location = 0 ) in vec3 vertex_position; layout ( location = 1 ) in vec2 tex_cord; layout ( location = 2 ) in vec3 vertex_normal; layout ( location = 3 ) in vec3 vertex_tangent; uniform mat4 model; //model matrix, aka model 2 world uniform mat4 modelviewmatrix; //view*model matrix uniform mat3 normalmatrix; // transpose/invert(view*model) uniform mat4 priv_mat; //projection-view-model pre multiplied uniform vec4 LightPosition; //after view*lightpos, ie viewspace out vec3 lightdir; out vec3 viewdir; out vec2 fUV; out vec3 position; void main() { gl_Position=priv_mat*vec4(vertex_position,1.0); fUV=tex_cord; position=(model*vec4(vertex_position,1.0)).xyz; len=length(vertex_position); // Transform normal and tangent to eye space vec3 n = normalize(normalmatrix * vertex_normal); vec3 t = normalize(normalmatrix * vec3(vertex_tangent)); t = normalize(t-dot(t,n)*n); //Gramm-Schmidt process vec3 bitangent = normalize( cross( n, t ) ); mat3 tbn = transpose(mat3(t,bitangent,n)); //why transpose?? vec3 pos=vec3(modelviewmatrix*vec4(vertex_position,1.0)); // Transform light dir. and view dir. to tangent space lightdir = normalize( tbn * (LightPosition.xyz - pos) ); viewdir = tbn * normalize(-pos); } And frag
#version 400 in float len; in vec3 lightdir; //tang light in vec3 viewdir; //tang view in vec2 fUV; in vec3 position; uniform sampler2D png_tex; uniform sampler2D bump_map; uniform vec4 LightPosition; uniform vec3 LightIntensity; uniform vec3 Kd; // Diffuse reflectivity uniform vec3 Ka; // Ambient reflectivity uniform vec3 Ks; // Specular reflectivity uniform float Shininess; // Specular shininess factor out vec4 Color; vec3 phongModel( vec3 norm, vec3 diffr ); void main() { vec4 b_normal = (255.0/128.0) * texture( bump_map, fUV )-1.0; // Lookup the normal from the normal map vec4 texColor = texture( png_tex, fUV ); // The color texture is used as the diffuse reflectivity Color = vec4( phongModel(b_normal.xyz, texColor.rgb), 1.0 ); } vec3 phongModel( vec3 norm, vec3 diffr ) { vec3 r = reflect( -lightdir, norm ); vec3 ambient = LightIntensity * Ka; float sDotN = max( dot(lightdir, norm), 0.0 ); vec3 diffuse = Kd*LightIntensity * diffr * sDotN; vec3 spec = vec3(0.0); if( sDotN > 0.0 ) spec = LightIntensity * Ks * pow( max( dot(r,viewdir), 0.0 ), Shininess ); return ambient + diffuse + spec; } I only got this result: the shaders are updated as I went along, so the ones posted above work (for me anyway)
Which has 2 obvious errors: When I rotate the object, the shading doesn't follow the lightsource and goes from dark to full bright, and, it seems to have dents at seams where the cube-sphere wraps. The normalmapping seems to work though, but again I struggle with the shading. Is there an obvious error here?


