glsl - Tangent calculation on a Sphere leaves missing faces at the South Pole -
howdy wonderful folks!
i doing planetary simulation of earth space , stuck @ normal mapping stage. went through bunch of tutorials on internet , wrote logic calculate tangents, pass them vertex shader , calculate normal in tbn space , use normal calculate lighting using phong model. seems work correctly @ south pole of planet, missing triangles , hence black spots:
code calculating geometry of sphere goes along lines of:
void sphere::generatemesh(){ float deltaphi = (float)pi/stacks; float deltatheta = (2 * (float)pi)/slices; for(float phi = 0; phi < pi ; phi += deltaphi){ for(float theta = 0; theta < 2*pi - 0.001; theta += deltatheta){ float x1 = -sinf(phi) * sinf(theta) * radius; float y1 = -cosf(phi) * radius; float z1 = -sinf(phi) * cosf(theta) * radius; float u1 = float( atan2(x1, z1) / (2 * pi) + 0.5 ); float v1 = float( -asin(y1) / (float)pi + 0.5 ); float x2 = -sinf(theta + deltatheta) * sinf(phi) * radius; float y2 = -cosf(phi) * radius; float z2 = -sinf(phi) * cosf(theta + deltatheta) * radius; float u2 = float( atan2(x2, z2) / (2 * pi) + 0.5 ); float v2 = float( -asin(y2) / ((float)pi) + 0.5 ); float x3 = -sinf(theta + deltatheta) * sinf(phi + deltaphi) * radius; float y3 = -cosf(phi + deltaphi) * radius; float z3 = -sinf(phi + deltaphi) * cosf(theta + deltatheta) * radius; float u3 = float( atan2(x3, z3) / (2 * (float)pi) + 0.5 ); float v3 = float( -asin(y3) / (float)pi + 0.5 ); float x4 = -sinf(theta) * sinf(phi + deltaphi) * radius; float y4 = -cosf(phi + deltaphi) * radius; float z4 = -sinf(phi + deltaphi) * cosf(theta) * radius; float u4 = float( atan2(x4, z4) / (2 * (float)pi) + 0.5 ); float v4 = float( -asin(y4) / (float)pi + 0.5 ); vec3f p1(x1, y1, z1); vec3f uv1(u1, v1, 0); vec3f p2(x2, y2, z2); vec3f uv2(u2, v2, 0); vec3f p3(x3, y3, z3); vec3f uv3(u3, v3, 0); vec3f p4(x4, y4, z4); vec3f uv4(u4, v4, 0); //addtriangle(x1, y1, z1, u1, v1, // x2, y2, z2, u2, v2, // x3, y3, z3, u3, v3); //addtriangle(x1, y1, z1, u1, v1, // x3, y3, z3, u3, v3, // x4, y4, z4, u4, v4); addtriangle(p1, uv1, p2, uv2, p3, uv3); addtriangle(p1, uv1, p3, uv3, p4, uv4); } } }
the addtriangle method adds triangles data structures in turn used passing vertices, normals, tangents , texture coordinates in vertex buffer objects shaders. method looks this:
void object::addtriangle(vec3f v1, vec3f u1, vec3f v2, vec3f u2, vec3f v3, vec3f u3){ //add triangle addtriangle(v1, v2, v3); //todo integrate uv coordinates in face //add texture coordinates uv vector uv.push_back(u1); uv.push_back(u2); uv.push_back(u3); vec3f e1 = v2 - v1; vec3f e2 = v3 - v1; float deltau1 = u2.x - u1.x; float deltav1 = u2.y - u1.y; float deltau2 = u3.x - u1.x; float deltav2 = u3.y - u1.y; float f = 1.f / (deltau1 * deltav2 - deltau2 * deltav1); vec3f tangent; tangent = f * (deltav2 * e1 - deltav1 * e2); auto tangentiter = find(tangents.begin(), tangents.end(), tangent); // if tangent not in vector, add , set iter // vector's tail. if (tangentiter == tangents.end()){ tangents.push_back(tangent); tangentiter = tangents.end() - 1; } gluint tangentindex = tangentiter - tangents.begin(); face* face = faces.back(); face->t = tangentindex; vector<vec3f> trianglevertices; trianglevertices.push_back(v1); trianglevertices.push_back(v2); trianglevertices.push_back(v3); (unsigned = 0; < trianglevertices.size(); i++){ vec3f v = trianglevertices.at(i); if (sharedtangents.find(v) == sharedtangents.end()){ sharedtangents.insert(pair<vec3f, vec3f>(v, tangent)); } else{ vec3f& vt = sharedtangents.at(v); vt += tangent; } } }
while initializing buffers, call method calculate tangents each vertex:
void object::calculatevertextangents(){ vector<vec3f> vertextangentlist; //find mean of tangents shared vertex, //and normalize , add them vertex tangent vector (unsigned = 0; < points.size(); i++){ vec3f vt = sharedtangents.at(points.at(i)); vt.normalize(); vertextangentlist.push_back(vt); } outvertextangents = new float[faces.size() * 3 * 3]; vec3f vt; int index = 0; (unsigned = 0; < faces.size(); i++){ (unsigned j = 0; j < 3; j++){ vt = vertextangentlist.at((*faces.at(i))[j]); outvertextangents[index] = vt.x; outvertextangents[index + 1] = vt.y; outvertextangents[index + 2] = vt.z; index += 3; } } }
and vertex , fragments shader code lies here: vertex shader:
#version 400 core in vec3 vposition; in vec2 vtexcoord; in vec3 vnormal; in vec3 vtangent; uniform mat4 projection; uniform mat4 view; uniform mat4 model; uniform vec4 lightposition; out vec2 texcoord; out vec3 lightvec; out vec3 eyevec; out vec3 halfvec; out vec3 vpos; void main(){ mat4 modelview = view * model; mat4 normalmatrix = transpose(inverse(modelview)); vec3 n = normalize ( ( normalmatrix * vec4( vnormal, 0.0 ) ).xyz ); vec3 t = normalize ( ( normalmatrix * vec4( vtangent, 0.0 ) ).xyz ); vec3 b = cross (n, t); vec4 vertexineye = modelview * vec4(vposition, 1.0); vpos = vertexineye.xyz; vec3 lightdir = normalize( lightposition.xyz - vertexineye.xyz ); vec3 temp; temp.x = dot (lightdir, t); temp.y = dot (lightdir, b); temp.z = dot (lightdir, n); lightvec = normalize(temp); temp.x = dot (vertexineye.xyz, t); temp.y = dot (vertexineye.xyz, b); temp.z = dot (vertexineye.xyz, n); eyevec = normalize(temp); vertexineye = normalize(vertexineye); vec3 halfvector = normalize(vertexineye.xyz + lightdir); temp.x = dot (halfvector, t); temp.y = dot (halfvector, b); temp.z = dot (halfvector, n); halfvec = temp ; texcoord = vtexcoord; gl_position = projection * modelview * vec4(vposition, 1.0); }
fragment shader:
#version 400 core uniform vec4 lightcolor; uniform vec4 diffusecolor; uniform sampler2d mysampler; uniform sampler2d night; uniform sampler2d clouds; uniform sampler2d specmap; uniform sampler2d bumpmap; in vec3 vpos; in vec3 lightvec; in vec3 eyevec; in vec3 halfvec; in vec2 texcoord; out vec4 frag_color; void main(){ vec3 normal = 2.0 * texture(bumpmap, texcoord).rgb - 1.0; //normal.z = 1 - normal.x * normal.x - normal.y * normal.y; normal = normalize ( normal ); vec4 spec = vec4(1.0, 0.941, 0.898, 1.0); vec4 specmapcolor = texture2d(specmap, texcoord); vec3 l = lightvec; vec3 n = normal; vec3 emissive = normalize(-vpos); vec3 r = reflect(-l, n); float dotprod = max(dot(r, emissive), 0.0); vec4 speccolor = spec * pow(dotprod,6.0) * 0.6; float diffuse = max(dot(n, l), 0.0); vec2 cloud_color = texture2d( clouds, texcoord).rg; vec3 day_color = (texture2d( mysampler, texcoord ).rgb * diffuse + speccolor.rgb * specmapcolor.g) * (1 - cloud_color.r) + cloud_color.r * diffuse; vec3 night_color = texture2d( night, texcoord ).rgb * (1 - cloud_color.r) * 0.5; vec3 color = day_color; if(dot(n, l) < 0.1) color = mix(night_color, day_color, (diffuse + 0.1) * 5.0); frag_color = vec4(color, 1.0); }
i appreciate if able point out i'm doing wrong in calculation of tangents? if information helps, when render sphere vertex normals , phong shading, perfect looking planet.
edit: here's screenshot when i'm using texture shading , not using tangent space normal mapping:
Comments
Post a Comment