Opengl es 在顶点着色器中定位顶点后,如何更新法线?

Opengl es 在顶点着色器中定位顶点后,如何更新法线?,opengl-es,three.js,glsl,webgl,shader,Opengl Es,Three.js,Glsl,Webgl,Shader,简短版本:我正在顶点着色器中操纵顶点的位置,但是当我基于顶点位置计算法线时,法线是基于原始顶点位置计算的。顶点着色器不应该知道新顶点在哪里吗 Long version:我正在基于three.jsnormalmap着色器在three.js R.58中编写一个自定义着色器。我将平面纹理(0.5、0.5、1.0淡紫色)作为t法线传递给着色器,然后设置planeGeometry的顶点在顶点着色器中的位置以将其弯曲成球体 下面是顶点着色器中计算法线的位置: vec3 newPosition = mix(

简短版本:我正在顶点着色器中操纵顶点的位置,但是当我基于顶点
位置计算法线时,法线是基于原始顶点位置计算的。顶点着色器不应该知道新顶点在哪里吗

Long version:我正在基于three.js
normalmap
着色器在three.js R.58中编写一个自定义着色器。我将平面纹理(0.5、0.5、1.0淡紫色)作为
t法线
传递给着色器,然后设置
planeGeometry
的顶点在顶点着色器中的位置以将其弯曲成球体

下面是顶点着色器中计算法线的位置:

vec3 newPosition = mix( position, goalPosition, mixAmount );

vec4 mvPosition = modelViewMatrix * vec4( newPosition, 1.0 );
vViewPosition = -mvPosition.xyz;

vNormal = normalize( normalMatrix * normal );

//tangent and binormal vectors
vTangent = normalize( normalMatrix * tangent.xyz );

vBinormal = cross( vNormal, vTangent ) * tangent.w;
vBinormal = normalize( vBinormal );
此代码适用于默认的球体测量和平面几何。但是,当我将一个平面变形为一个球体时,着色并不像预期的那样工作–碎片着色器似乎认为球体仍然是一个平面–或者其他东西

这是带有点光源的球体,显示扭曲镜面反射高光:

演示:

这仅在原始平面面对点光源时才会显示-在其他旋转时,球体是黑色的,无论摄影机在哪里,这表明平面法线仍在以某种方式计算,就好像顶点没有被重新定位一样

我已经设置了
geometry.dynamic=true
以及
geometry.normalsNeedUpdate
geometry.Tangentseedupdate
,我正在调用
geometry.computeTangents()
,但似乎什么都不起作用

我的印象是,在GLSL中,用于计算法线的场景组件(如
法线矩阵
切线
)考虑了顶点着色器的任何顶点操作。我错过了什么?这是three.js特有的吗

编辑:

在控制台中检查时,我看到变形平面中的每个面仍具有(0,0,1)的世界空间法线,就像它在未变形状态下一样,这与球体测量实例相反,球体测量实例的法线根据其方向而变化

这是另一个演示:这两个对象具有相同的材质。左边是球面测量,右边是变形的平面几何。当平面变形时,法线似乎不会更新以反映面的新方向,并且镜面反射也不会正确显示


演示:

短版:你不能

长版本:即使顶点着色器正在移动顶点,它也只知道当前顶点的更新位置–要计算新的面法线,它必须知道所有相邻顶点的更新位置,到目前为止,WebGL不允许这样做

尽管顶点着色器确实计算法线,但它们都基于原始法线,原始法线与原始顶点位置一起传递给顶点着色器。这些计算大多只是片段着色器所需的标准法线相关内容,例如说明灯光位置、变换等,它们都假设顶点在对象空间中相对于彼此保持静止

使用CPU更新法线并将其传递给顶点着色器相对容易,但如果必须在顶点着色器中执行此操作,则有一些鬼鬼祟祟的方法来伪造它,例如使用;如果顶点是基于任何类型的参数计算移动的,你可以,这绝对是欺骗

资料来源:


顶点着色器中不会自动执行任何操作;这才是重点。有些事情会在之后自动发生(例如透视分割),但输出变量的规范化不是这些事情之一。在固定功能管道中,有一个功能可以自动重新规格化,但在WebGL中不适用。也就是说,通常在顶点中,处理此问题的方法是使用切线、双切线和法向量将照明向量转换为切线空间。然后,在片段着色器中,在与法线采样相同的坐标空间(切线空间)中完成所有照明计算。还有其他方法,例如在片段着色器中将法线转换为世界/视图空间,但这种方法成本更高,主要用于延迟着色。不幸的是,如果不包括与这个问题相关的着色器,我就无法写出一个实际的答案。嗯,好的。我将修改我的问题以使其更有意义。这与您先前的问题有何不同?另外,我建议您更新到three.js.No的当前版本。在这种情况下,数据是单向的——从CPU到GPU。GLSL实际上允许您在几何体着色器中描述的内容。为此,有一种称为邻接的原语。但既然我们在讨论WebGL,你应该忘记我甚至提到了GS。关于使用函数计算顶点着色器中的法线,我不确定这是否是“欺骗”。这不是解决这个问题的通用方法。不过还是有一些有用的链接。