光栅化法线贴图代码转光线追踪closest hit着色器结果不一致排查
代码问题排查点
- TBN矩阵转置错误
原光栅化代码中构造的mat3(T, B, N)本身就是「切线空间→世界空间」的变换矩阵,无需额外转置。你当前代码加了transpose后,矩阵变为「世界空间→切线空间」,和需求完全相反,这是最核心的错误。 - 副切线符号不匹配
原光栅化代码中副切线B的计算为-normalize(cross(N, T)),你需要确认顶点数据中存储的BiTangant是否和这个符号一致:如果顶点烘焙的副切线是cross(N, T)得到的,就会和原逻辑符号相反,导致法线沿切线平面翻转。 - 法线变换未使用逆转置矩阵
如果你的模型存在非均匀缩放,直接用模型变换矩阵的mat3部分变换法线/切线/副切线会导致向量方向偏移,正确的法线变换矩阵应该是模型变换矩阵的逆矩阵的转置。 - 辅助校验点
可以先去掉法线贴图逻辑,直接返回插值的顶点法线,确认光照基础逻辑正确后再调试法线贴图部分;同时确认法线贴图的存储格式是否符合约定,比如是否需要翻转G通道适配当前坐标系。
修正后参考代码
vec3 getNormalFromMap(MaterialInfo material, Vertex vertex) { // 法线变换矩阵(逆转置)可移到CPU侧预计算传入,减少着色器运行开销 mat3 normalMatrix = transpose(inverse(mat3( meshProperties[gl_InstanceCustomIndexEXT].ModelTransform * MeshTransform[gl_InstanceCustomIndexEXT].Transform ))); vec3 T = normalize(normalMatrix * vertex.tangent); vec3 N = normalize(normalMatrix * vertex.normal); // 正交化切线保证T和N垂直,避免网格变形带来的误差 T = normalize(T - dot(T, N) * N); // 按原光栅化逻辑计算副切线,和原代码符号对齐,也可以用顶点存储的B校验符号一致性 vec3 B = -normalize(cross(N, T)); // 移除多余的transpose,直接构造切线空间转世界空间的矩阵 mat3 TBN = mat3(T, B, N); vec3 tangentNormal = texture(TextureMap[material.NormalMapID], vertex.uv).xyz; tangentNormal = normalize(tangentNormal * 2.0 - 1.0); return normalize(TBN * tangentNormal); }
内容的提问来源于stack exchange,提问作者klj
相关产品推荐
相关产品推荐

