irrlicht代码法线贴图相关问题
irrlicht的代码关于法线贴图的范例即 PerPixelLighting。
程序准备资源部分,
先是一个砖墙普遍纹理,设到 text0
然后是一个法线纹理贴图,设到text1(中间经过处理,将对比度,转换成相应的法线数据)
然后是在COpenGLDriver::drawVertexPrimitiveList函数中,会走到case EVT_TANGENTS:这个分支.
接下来的代码 要结合渲染脚本(一段嵌入的伪汇编,irrlicht 1.7 估计还没有引入glsl)
case EVT_TANGENTS:
if (vertices)
{
glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Normal);
glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].TCoords);
glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Pos);
}
else
{
glNormalPointer(GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(12));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(S3DVertexTangents), buffer_offset(24));
glTexCoordPointer(2, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(28));
glVertexPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(0));
}
if (MultiTextureExtension)
{
extGlClientActiveTexture(GL_TEXTURE1_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (vertices)
glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Tangent);
else
glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36));
extGlClientActiveTexture(GL_TEXTURE2_ARB);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if (vertices)
glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast<const S3DVertexTangents*>(vertices))[0].Binormal);
else
glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(48));
}
break;
因为程序并没有设置 text2,所以这段代码令人费解
同样,在text1处,传入的纹理映射数组,也令人不解
所以,它们不是纹理映射,是顶点法线的切空间中的两个轴(相关切空间可以参考 相关文章)
因为多边形的位置在空间中不断变化,根据法线纹理来计算光照,需要将光线变换到切空间中去。
这样才能直接计算出光照值。
text1 text2关于传入的是tangent 和bitangent,
以便在顶点渲染与像素渲染脚本中使用,将光线变换到顶点的切空间,并最终计算出每个顶点的像素值。
相应的渲染脚本存在 COpenGLParallaxMapRenderer.cpp中的数组变量中:
OPENGL_PARALLAX_MAP_VSH OPENGL_PARALLAX_MAP_PSH
注意脚本中的这一段代码:
"#input\n"\
"# 0-3: transposed world matrix;\n"\
"#;12: Light01 position \n"\
"#;13: x,y,z: Light01 color; .w: 1/LightRadius^2 \n"\
"#;14: Light02 position \n"\
"#;15: x,y,z: Light02 color; .w: 1/LightRadius^2 \n"\
"#;16: Eye position \n"\
"\n"\
"ATTRIB InPos = vertex.position;\n"\
"ATTRIB InColor = vertex.color;\n"\
"ATTRIB InNormal = vertex.normal;\n"\
"ATTRIB InTexCoord = vertex.texcoord[0];\n"\
"ATTRIB InTangent = vertex.texcoord[1];\n"\
"ATTRIB InBinormal = vertex.texcoord[2];\n"\
所以 text1 text2传进去的纹理映射参数,在计算时是作为顶点切空间tangent和binormal(也就是bitangent)。
text2没指定纹理,也没关系,因为实际计算的时候并没有涉及到text2纹理相关的内存。
弄清参数传递机制后,接下来,生成tangent binormal以及相应的光线变换到切空间算法参考
Mathematics for 3D Game Programming and Computer Graphics 这本说的6.8章节(最新版本的好像在7.8章节)
这段代码有点怪异,究其原因也是因为tangent 和 binormal没有现成的机制传给渲染脚本导致的。