opengl - Normal Rotation in GLSL -
i have written basic programme loads model , renders screen. i'm using glsl transform model appropriately, normals seem wrong after rotating them every combination of model matrix, view matrix, inverse, transpose, etc think of. model matrix rotation around y-axis using glm:
angle += deltatime; modelmat = glm::rotate(glm::mat4(), angle, glm::vec3(0.f, 1.f, 0.f)); my current vertex shader code (i've modified normal line many many times):
#version 150 core uniform mat4 projmat; uniform mat4 viewmat; uniform mat4 modelmat; in vec3 inposition; in vec3 innormal; out vec3 passcolor; void main() { gl_position = projmat * viewmat * modelmat * vec4(inposition, 1.0); vec3 normal = normalize(mat3(inverse(modelmat)) * innormal); passcolor = normal; } and fragment shader:
#version 150 core in vec3 passcolor; out vec4 outcolor; void main() { outcolor = vec4(passcolor, 1.0); } i know sure uniform variables beingness passed shader properly, model gets transformed properly, , initial normals right if calculations such directional lighting.
i've created gif of rotating model, sorry low quality: http://i.imgur.com/lglkhcb.gif?1
what confuses me how normals appear rotate on multiple axis, don't think should happen when multiplied simple rotation matrix on 1 axis.
edit:
i've added more of client code below.
this buffers bound model, in mesh class (vao gluint, defined in class):
gluint vbo[3]; glgenvertexarrays(1, &vao); glbindvertexarray(vao); glgenbuffers(normals? (uvcoords? 3 : 2) : (uvcoords? 2 : 1), vbo); glbindbuffer(gl_array_buffer, vbo[0]); glbufferdata(gl_array_buffer, vcount * 3 * sizeof(glfloat), vertices, gl_static_draw); glvertexattribpointer(0, 3, gl_float, gl_false, 0, 0); glenablevertexattribarray(0); if(normals) { glbindbuffer(gl_array_buffer, vbo[1]); glbufferdata(gl_array_buffer, vcount * 3 * sizeof(glfloat), normals, gl_static_draw); glvertexattribpointer(1, 3, gl_float, gl_true, 0, 0); glenablevertexattribarray(1); } if(uvcoords) { glbindbuffer(gl_array_buffer, vbo[2]); glbufferdata(gl_array_buffer, vcount * 2 * sizeof(glfloat), uvcoords, gl_static_draw); glvertexattribpointer(2, 2, gl_float, gl_false, 0, 0); glenablevertexattribarray(2); } glbindvertexarray(0); glgenbuffers(1, &ib); glbindbuffer(gl_element_array_buffer, ib); glbufferdata(gl_element_array_buffer, icount * sizeof(glushort), indices, gl_static_draw); this shaders compiled after beingness loaded memory simple readf(), in material class:
u32 vertexshader = glcreateshader(gl_vertex_shader); u32 fragmentshader = glcreateshader(gl_fragment_shader); glshadersource(vertexshader, 1, (const glchar**)&vscontent, 0); glcompileshader(vertexshader); if(!validateshader(vertexshader)) homecoming false; glshadersource(fragmentshader, 1, (const glchar**)&fscontent, 0); glcompileshader(fragmentshader); if(!validateshader(fragmentshader)) homecoming false; programhandle = glcreateprogram(); glattachshader(programhandle, vertexshader); glattachshader(programhandle, fragmentshader); glbindattriblocation(programhandle, 0, "inposition"); glbindattriblocation(programhandle, 1, "innormal"); //glbindattriblocation(programhandle, 2, "inuvcoords"); gllinkprogram(programhandle); if(!validateprogram()) homecoming false; and validateshader(gluint) , validateprogram() functions:
bool material::validateshader(gluint shaderhandle) { char buffer[2048]; memset(buffer, 0, 2048); glsizei len = 0; glgetshaderinfolog(shaderhandle, 2048, &len, buffer); if(len > 0) { logger::log("ve::material::validateshader: failed compile shader - %s", buffer); homecoming false; } homecoming true; } bool material::validateprogram() { char buffer[2048]; memset(buffer, 0, 2048); glsizei len = 0; glgetprograminfolog(programhandle, 2048, &len, buffer); if(len > 0) { logger::log("ve::material::validateprogram: failed link programme - %s", buffer); homecoming false; } glvalidateprogram(programhandle); glint status; glgetprogramiv(programhandle, gl_validate_status, &status); if(status == gl_false) { logger::log("ve::material::validateprogram: failed validate program"); homecoming false; } homecoming true; } each material instance has std::map of meshs, , rendered so:
void material::render() { if(loaded) { gluseprogram(programhandle); for(auto = mmd->uniforms.begin(); != mmd->uniforms.end(); ++it) { glint loc = glgetuniformlocation(programhandle, (const glchar*)it->first); switch(it->second.type) { case e_ut_float3: gluniform3fv(loc, 1, it->second.f32ptr); break; case e_ut_mat4: gluniformmatrix4fv(loc, 1, gl_false, it->second.f32ptr); break; default: break; } } for(mesh* m : mmd->objects) { glint loc = glgetuniformlocation(programhandle, "modelmat"); gluniformmatrix4fv(loc, 1, gl_false, &m->gettransform()->gettransformmatrix()[0][0]); m->render(); } } } it->second.f32ptr float pointer &some_vec3[0] or &some_mat4[0][0]. manually upload model's transformation matrix before rendering, (which rotation matrix, transform class (returned mesh::gettransform()) glm::rotation() since trying figure out problem).
lastly, mesh render code:
if(loaded) { glbindvertexarray(vao); glbindbuffer(gl_element_array_buffer, ib); gldrawelements(gl_triangles, indexcount, gl_unsigned_short, 0); } i think necessary code, can post more if needed.
your nomal matrix calculation wrong. right normal matrix transpose of inverse of upper-left 3x3 submatrix of model or modelview matrix (depending on space want lighting calculations).
what inverting total 4x4 matrix , taking upper-left 3x3 submatrix of that, totally wrong.
you should calculate transpose(inverse(mat3(modelmat))), shouldn't in shader, calulate toghether model matrix on cpu avoid letting gpu calculate quite expensive matrix inversion per vertex.
opengl matrix rotation glsl normals
No comments:
Post a Comment