5

这几天我一直在为此苦苦挣扎。我想我终于把它缩小到每个顶点切线的问题,但我不确定修复它的最佳方法。

上下文是 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 模型中的法线相同的法线。然后这个想法让我印象深刻..在我的顶点着色器中我' m 还首先将顶点法线乘以 normalMatrix 以使其进入模型空间。但是话又说回来,那些调试渲染是顶点法线在转换之前的。

是否有另一种方法可以在不使用 TBN 矩阵的情况下扰乱模型的法线?在没有法线贴图的情况下使用 phong 着色器进行渲染不会显示伪影。

更新:我几乎可以肯定问题是导入应用程序创建的预计算切线。在尝试了具有不同 UV 贴图的不同模型后,我发现了相似的外观问题,有时它是黑暗而不是高光。因此,除非我可以在没有 TBM 矩阵的情况下应用法线贴图或转换为切线空间,否则我将需要找到另一个导入器。

更新#2: 我刚刚发现另一个问题,这听起来可能是真正问题的线索。 3d 图形、单位向量和正交矩阵

需要注意的是,这些奇怪的灯光不会出现在顶点上,而只会出现在它们之间。即使在球体上,我们也看到了一个位于顶部顶点和正下方顶点之间的环。我开始相信这是一个插值问题。只取其中一个三角形:

在此处输入图像描述

第二个原因是我正在重新计算它,忽略坏的双切线。但是切线具有相反的极性。因此,在这两个状态之间进行插值时,您将获得指向各处的向量。

新问题是我该如何解决?修复切线?修复着色器来处理它?

4

1 回答 1

1

有时最简单的答案就是正确的答案。切线很糟糕。它们与法线不正交。

我使用此处描述的方法手动重新计算了所有切线和双切线:

http://www.terathon.com/code/tangent.html

这个问题就消失了。

于 2013-03-17T06:23:20.463 回答