短版本:我正在操纵顶点着色器中顶点的位置,但是当我根据顶点position
计算法线时,法线会根据原始值计算顶点位置。顶点着色器不应该知道新顶点的位置吗?
长版本:我正在基于three.js normalmap
着色器在three.js R.58中编写自定义着色器。我将平面纹理(0.5,0.5,1.0淡紫色)作为tNormal
传递到着色器,然后在顶点着色器中设置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 );
此代码适用于默认的sphereGeometry和planeGeometry。然而,当我将一个平面变形为一个球体时,阴影不能按预期工作 - 片段着色器似乎认为球体仍然是一个平面 - 或者其他东西。
这是带有pointLight的球体,显示了扭曲的镜面高光:
演示:http://meetar.github.io/planebending/plane_bending.html
只有当原始平面面向点光源时才显示 - 在其他旋转时,无论相机在哪里,球体都是黑色的,这表明平面法线仍然以某种方式计算,就像顶点未被计算一样重新定位。
我设置了geometry.dynamic = true
以及geometry.normalsNeedUpdate
和geometry.tangentsNeedUpdate
,我正在调用geometry.computeTangents()
,但似乎没有任何效果。
我认为在GLSL中,用于计算法线的场景组件(例如normalMatrix
和tangent
)会考虑顶点着色器的任何顶点操作。我错过了什么?这是针对three.js的特定内容吗?
修改
检查控制台,我看到变形平面中的每个面仍然具有(0,0,1)的世界空间法线,就像它处于未变形状态时一样,而不是像sphereGeometry实例那样,其法线的变化取决于他们的方向。
这是另一个演示:这两个对象具有相同的材料。左边是SphereGeometry,右边是变形的PlaneGeometry。当平面变形时,法线似乎不会更新以反映面部的新方向,并且镜面反射不会正确显示。
演示:http://meetar.github.io/planebending/plane_bending_06.html
答案 0 :(得分:5)
简短版本:你不能!
长版本:即使顶点着色器正在移动顶点,它只知道当前顶点的更新位置 - 来计算新的面法线,它会有知道所有邻居顶点的更新位置,到目前为止,WebGL不允许这样做。
尽管顶点着色器确实计算法线,但它们都基于原始法线,它们与原始顶点位置一起传递到顶点着色器。这些计算大多只是片段着色器所需的标准正常相关事物,例如光的位置,变换等,并且它们都假设顶点将在对象空间中相对于彼此保持静止。
使用CPU更新法线并将它们传递给顶点着色器相对容易,但如果必须在顶点着色器中执行,则有一些偷偷摸摸的方法可以伪造它,例如使用bump maps;如果根据任何类型的参数计算移动顶点,你可以generate some neighbors on the fly and check the normal between them,这肯定是作弊。
来源: