OpenGL - 为什么normalize()不是幂等的?

4
我正在使用OpenGL ES 2.0在Java中开发Android游戏。目前,我正在编写自己的顶点和片段着色器。我在我的片段着色器中遇到了一个奇怪的问题:normalize(u_LightPos - v_Position)normalize(normalize(u_LightPos - v_Position))不同,其中u_LightPos是一个uniform变量,v_Position是一个varying变量。
为什么normalize()不具有幂等性?为什么我必须调用两次才能得到一个真正的法线(长度为1的向量)?这非常令人困惑。
编辑:这是顶点着色器:
uniform mat4 u_MVPMatrix;
uniform mat4 u_MVMatrix;
attribute vec4 a_Position;
attribute vec3 a_Normal;
varying vec3 v_Position;
varying vec3 v_Normal;
void main() {
    v_Position = vec3(u_MVMatrix * a_Position);
    v_Normal = vec3(u_MVMatrix * vec4(a_Normal, 0.0));
    gl_Position = u_MVPMatrix * a_Position;
}

这里是片段着色器:

precision mediump float;
uniform vec3 u_LightPos;
uniform vec4 u_Color;
varying vec3 v_Position;
varying vec3 v_Normal;
void main() {
    float distance = length(u_LightPos - v_Position);
    vec3 lightVector = normalize(normalize(u_LightPos - v_Position));
    float diffuse = max(dot(v_Normal, lightVector), 0.0);
    gl_FragColor = u_Color * diffuse;
}

如果我不对 lightVector 进行双重规范化,那么点积将会大于1.1,我已经测试过了。而且,对 v_Normal 进行规范化并不能改变这个事实。


2
第一个版本的长度与1相差多少?如果这个差距非常小,我猜测这是一个数值问题。你在着色器中设置了浮点精度吗? - BDL
不,这是一个相当大的数量。有时甚至比0.1多得多,甚至达到10或更多。 精度为“precision mediump float”。 - Kenji
1
u_LightPos的值是多少,v_Position的大致范围是多少?如果这些值非常大,是否仍可能存在精度问题?如果将精度设置为highp,是否会有任何变化? - Reto Koradi
你说得对。这是一个精度问题。向量没有被正确归一化,因为向量之间的差异太大了。谢谢。 - Kenji
1个回答

6

这是一个精度问题。将精度设置为highp可以解决这个问题。u_LightPos和v_Position之间的差异太大,导致了一个值过大以至于无法正确归一化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接