【发布时间】:2014-02-03 04:00:57
【问题描述】:
短版:我在顶点着色器中操作顶点的位置,但是当我根据顶点position计算法线时,法线是根据原始顶点位置计算的.顶点着色器不应该知道新顶点在哪里吗?
长版:我正在基于three.js normalmap 着色器在three.js R.58 中编写自定义着色器。我将平面纹理(0.5、0.5、1.0 lavender)作为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。然而,当我将一个平面变形为一个球体时,着色无法按预期工作——片段着色器似乎认为球体仍然是一个平面——或者其他什么。
这是一个带有点光源的球体,显示了扭曲的高光:
演示: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
【问题讨论】:
-
在顶点着色器中没有自动完成;这实际上是重点。之后有些事情会自动发生(例如透视分割),但输出变化的规范化不是其中之一。在固定功能管道中,有一个自动重新规范化的功能,但这不适用于 WebGL。
-
也就是说,通常在顶点中,您解决此问题的方法是使用 Tangent、Bitangent 和 Normal 向量将光照向量转换为切线空间。然后所有的光照计算都在片段着色器中在与法线采样相同的坐标空间(切线空间)中完成。还有一些替代方法,例如在片段着色器中将法线转换为世界/视图空间,但这种方法更昂贵,主要用于延迟着色。 不幸的是,如果不包括与此问题相关的着色器,我无法写出实际答案。
-
嗯,好的。我将修改我的问题以使其更有意义。
-
这与您之前的问题stackoverflow.com/questions/17528878/… 有何不同?另外,我建议您更新到当前版本的three.js。
-
没有。在这种情况下,数据是单向的——从 CPU 到 GPU。
标签: opengl-es three.js glsl webgl shader