Opengl 着色器问题 - 奇怪的光反射伪影 [英] Opengl shader problems - weird light reflection artifacts

查看:25
本文介绍了Opengl 着色器问题 - 奇怪的光反射伪影的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经为此纠结了好几天.我想我终于将其缩小到每个顶点切线的问题,但我不确定解决它的最佳方法.

Context 是 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 双切线 = 交叉(法线,切线);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);//通常是 texture2D(u_textureSampler,v_fragmentTexCoord0);浮动距离 = 长度(v_lightVec);vec3 lightVector = normalize(v_lightVec);float nxDir = max(0.0, dot(norm, lightVector));vec4 漫反射 = u_lightColorDiffuse * nxDir;浮动镜面功率 = 0.0;如果(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 镜面反射 = u_lightColorSpecular * specularPower;gl_FragColor = (漫反射 * vec4(baseColor.rgb,1.0)) + 镜面反射;

在尝试找出着色器并查看所有在线示例和教程时,我可以找到...我很困惑为什么凹凸贴图着色器不会干扰 3d 模型提供的法线贴图.我想如果没有某种参考点,你怎么知道如何修改模型的法线?按什么方向?我想这就是 TBN 矩阵的用途.但是在我上面的测试中,法线贴图中的法线向量是 0,0,1 - 直接向上.所以它似乎根本不应该修改它.任何乘以 1 的值仍然是 1.但是在数学或 TBN 矩阵中一定有一些东西搞砸了,它与 3d 模型中的法线不一样.然后这个想法对我产生了影响......在我的顶点着色器中,我还首先将顶点法线乘以 normalMatrix 以使其进入模型空间.但话又说回来,那些调试渲染是变换之前的顶点法线.

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

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

更新 #2: 我刚刚发现了另一个问题,听起来可能是真正问题的线索.

那个问题就解决了.

I've been wrestling with this for days. I think I've finally narrowed it down to a problem with the per vertex tangents, but I'm not sure the best way to fix it.

Context is iPhone app, opengl es2 using my own engine. My shader is a bump map (normal map) variety using the supplied per vertex tangent to create a TBN matrix. The vertex shader transforms the light vectors and eye vectors to tangent space, passes them to the fragment shader and calculates the lights. But some geometry in my first two test models is showing weird artifacts in the lighting. It is easiest to see in the specular component.

In trying to debug this I've replaced the normal map with a flat normal png.. all pixels are 128,128,255. I also hard coded the color.

My first model is a button shape. It shows the artifact as a scalloped specular hit on the outside ring. Important to note is that the UV mapping method here was 'flat' to make the sides which are perpendicular to the mapping basically streak the texture across there. I would think this would make the tangents hard to calculate for that geometry since two of the points would have the exact same texture coordinate.

I tried debug renders setting gl_FragColor to different variables. When setting it to the per vertex normals we see the scalloping is gone, indicating that the normals are correct. But when setting it to the per vertex tangents you can see the scallop.

The next shape is a simple sphere. With it the very top and bottom of the model is where the artifact shows. In the wireframe you'll see that this is where several triangles are meeting at one vertex. I can't wrap my head around what that means for the tangents as each triangle has completely different UV mapping there.

I suppose I'll get a lot of flack if I don't show the shader code...

Vertex Shader:

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;

Fragment Shader:

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;

In trying to figure out the shader and looking at all the samples and tutorials online I could find... I was confused by why the bump map shaders wouldn't just perturb the normal map supplied by the 3d model. I guess without some sort of reference point how you know HOW to modify model's normal? By what orientation? I guess that's what the TBN matrix is for. But in my test above the normal vector in the normal map is 0,0,1 - straight up. So it seems like it shouldn't be modifying it at all. Anything times 1 is still 1. But there must be something screwed up enough in the math or in the TBN matrix that it's not coming up with the same normal as the one in the 3d model. Then that idea struck something with me.. that in my vertex shader I'm also first multiplying the vertex normal by the normalMatrix to get it in to model space. But then again, those debug renders are of the vertex normal before it was transformed.

Is there another method to perturb the model's normal without using a TBN matrix? Rendering with a phong shader without the normal map doesn't show the artifact.

UPDATE: I'm almost positive that the problem is the precalulated tangents created by the importing app. After trying different models with different UV Maps I'm finding similar looking problems, sometimes it's a darkness instead of a highlight. So unless I can apply a normal map without a TBM matrix or converting to tangent space, I will need to find another importer.

UPDATE #2: I just found this other question that sounds like it might be a clue to the real problem. 3d graphics, unit vectors and orthogonal matrices

It's important to note that these weird lights don't happen on vertices but only in between them. Even on the sphere we're seeing a ring which is between the top vertex and the ones right below it. I'm starting to believe that this is an interpolation problem. Take just one of those triangles up there:

Ignore the bad bitangent for a second cause I'm recalculating that. But the tangents have opposite polarity. So while being interpolated between those two states your going to get vectors that point all over the place.

The new question is how do I solve it? Fixing the tangents? Fixing the shader to deal with it?

解决方案

Sometimes the simplest answer is the right one. The tangents were bad. They were not orthogonal to the normal.

I manually recalculated all the tangents and bitangents using the methods described here:

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

And that problem went away.

这篇关于Opengl 着色器问题 - 奇怪的光反射伪影的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆