我已经在苦苦挣扎了好几天。 我认为问题最终可以归结为每个顶点切线的问题,但我不确定该如何修复。
背景是iPhone应用,使用自己的引擎opengl es2。我的着色器是一种凹凸贴图(法线贴图),使用提供的每个顶点切线创建TBN矩阵。顶点着色器将光线向量和眼睛向量转换为切线空间,将它们传递到片段着色器并计算灯光。但是我的前两个测试模型中的一些几何体现出奇怪的照明伪影。在高光部分最容易看到这一点。
在尝试调试时,我用一个平面法线PNG替换了法线贴图。所有像素都是128,128,255。我还硬编码颜色。
我的第一个模型是一个按钮形状。它显示为外环上有齿状的镜面反射。值得注意的是,这里的UV映射方法是'flat',以使垂直于映射的侧面基本上沿纹理横跨。我认为这将使得难以计算该几何体的切线,因为其中两个点将具有完全相同的纹理坐标。
我尝试了调试渲染,将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模型中的法线相同的法线。然后我想到了一个想法...在我的顶点着色器中,我还首先将顶点法线乘以normalMatrix,以将其放入模型空间中。但是,那些调试渲染是在变换之前的顶点法线。
是否有其他方法可以扭曲模型的法线而不使用TBN矩阵?使用Phong着色器进行渲染而不使用法线贴图不会显示出这种现象。
更新:我几乎可以确定问题是导入应用程序创建的预计算切线。尝试使用具有不同UV映射的不同模型时,我发现类似的问题,有时是暗淡而不是亮点。因此,除非我可以应用没有TBM矩阵或转换为切线空间的法线贴图,否则我将需要找到另一个导入器。
更新#2:我刚刚发现了这个听起来可能是真正问题线索的其他问题。3D图形、单位向量和正交矩阵
重要的是要注意,这些奇怪的光线只在顶点之间而不是在顶点上发生。即使在我们看到的球体上也有一个环,它位于顶部顶点和直接下面的顶点之间。我开始相信这是一个插值问题。只取上面的其中一个三角形:
先忽略错误的副切线,因为我正在重新计算它。但是切线具有相反的极性。因此,在两种状态之间进行插值时,您将得到指向各处的向量。
新问题是如何解决它?修复切线?修复着色器来处理它?