我已经为此奋斗了好几天。我想我终于将问题范围缩小到了每个顶点切线的问题,但我不确定解决它的最佳方法。
上下文是 iPhone 应用程序,opengl es2 使用我自己的引擎。我的着色器是凹凸贴图(法线贴图)类型,使用提供的每个顶点切线来创建 TBN 矩阵。顶点着色器将光矢量和眼睛矢量变换到切线空间,将它们传递给片段着色器并计算灯光。但我的前两个测试模型中的一些几何形状在照明中显示出奇怪的伪影。在镜面反射分量中最容易看到。
在尝试调试此问题时,我用平面法线 png 替换了法线贴图。所有像素均为 128,128,255。我还对颜色进行了硬编码。
我的第一个模型是按钮形状。它将工件显示为外环上的扇形镜面反射。需要注意的是,这里的 UV 贴图方法是“平坦的”,以使垂直于贴图的侧面基本上在该处形成纹理条纹。我认为这会使该几何体的切线难以计算,因为其中两个点将具有完全相同的纹理坐标。
我尝试调试渲染将 gl_FragColor 设置为不同的变量。当将其设置为每个顶点法线时,我们看到扇贝消失了,表明法线是正确的。但是当将其设置为每个顶点切线时,您可以看到扇贝。
下一个形状是一个简单的球体。有了它,模型的最顶部和底部就是工件显示的地方。在线框中,您会看到这是多个三角形在一个顶点相交的地方。我无法理解这对切线意味着什么,因为每个三角形都有完全不同的 UV 映射。
我想如果我不显示着色器代码我会受到很多批评......
顶点着色器:
v_fragmentTexCoord0 = a_vertexTexCoord0;
gl_Position = u_modelViewProjectionMatrix * vec4(a_vertexPosition,1.0);
vec3 normal = normalize(u_normalMatrix * a_vertexNormal);
vec3 tangent = normalize(u_normalMatrix * a_vertexTangent);
vec3 bitangent = cross(normal, tangent);
mat3 TBNMatrix = mat3(tangent, bitangent, normal);
v_eyeVec = -a_vertexPosition.xyz;
v_eyeVec *= TBNMatrix;
v_lightVec = u_lightPosition - a_vertexPosition.xyz;
v_lightVec *= TBNMatrix;
v_normal = a_vertexTangent;
片段着色器:
vec3 norm = texture2D(u_normalSampler, v_fragmentTexCoord0).rgb * 2.0 - 1.0;
vec4 baseColor = vec4(0.6015625,0.0,0.0,1.0); // is normally texture2D(u_textureSampler,v_fragmentTexCoord0);
float dist = length(v_lightVec);
vec3 lightVector = normalize(v_lightVec);
float nxDir = max(0.0, dot(norm, lightVector));
vec4 diffuse = u_lightColorDiffuse * nxDir;
float specularPower = 0.0;
if(nxDir != 0.0)
{
vec3 cameraVector = v_eyeVec;
vec3 halfVector = normalize(v_lightVec + cameraVector);
float nxHalf = max(0.0,dot(norm, halfVector));
specularPower = pow(nxHalf, u_shininess);
}
vec4 specular = u_lightColorSpecular * specularPower;
gl_FragColor = (diffuse * vec4(baseColor.rgb,1.0)) + specular;
在尝试找出着色器并查看所有在线示例和教程时,我发现...我很困惑为什么凹凸贴图着色器不仅仅会扰乱 3D 模型提供的法线贴图。我想如果没有某种参考点你怎么知道如何修改模型的法线?以什么方向?我想这就是 TBN 矩阵的用途。但在我上面的测试中,法线贴图中的法线向量是 0,0,1 - 直线向上。所以看起来根本不应该修改它。任何乘以 1 的值仍然是 1。但是数学或 TBN 矩阵中一定有一些问题,导致它无法得出与 3D 模型中相同的法线。然后这个想法引起了我的注意……在我的顶点着色器中,我首先将顶点法线乘以法线矩阵,以将其放入模型空间。但话又说回来,这些调试渲染是在转换之前的顶点法线。
是否有另一种方法可以在不使用 TBN 矩阵的情况下扰乱模型的法线?使用不带法线贴图的 phong 着色器进行渲染不会显示伪影。
UPDATE:我几乎可以肯定问题是由导入应用程序创建的预先计算的切线。在尝试使用不同 UV 贴图的不同模型后,我发现了类似的问题,有时是黑暗而不是高光。因此,除非我可以在没有 TBM 矩阵的情况下应用法线贴图或转换为切线空间,否则我需要找到另一个导入器。
更新#2:我刚刚发现另一个问题听起来可能是真正问题的线索。3D 图形、单位向量和正交矩阵 https://stackoverflow.com/questions/4553503/3d-graphics-unit-vectors-and-orthogonal-matrices
需要注意的是,这些奇怪的灯光不会发生在顶点上,而只会发生在顶点之间。即使在球体上,我们也看到顶部顶点和其正下方顶点之间有一个环。我开始相信这是一个插值问题。只取其中一个三角形:
忽略坏的双切线是第二个原因,我正在重新计算它。但切线具有相反的极性。因此,在这两个状态之间进行插值时,您将获得指向各处的向量。
新的问题是我该如何解决?修复切线?修复着色器来处理它?