如何在立方体映射的Three.js BoxBufferGeometry上消除法线贴图?

时间:2018-04-02 13:17:28

标签: 3d three.js

BoxBufferGeometry转换为球体后,并按如下方式正确设置法线:

let geometry = new THREE.BoxBufferGeometry(1, 1, 1, 64, 64, 64);
const vertices = geometry.attributes.position;
const normals = geometry.attributes.normal;

for (let i = 0; i < vertices.count; i++) {
  const v = new THREE.Vector3().fromArray(vertices.array, i * 3);
  v.normalize();
  normals.setXYZ(i, v.x, v.y, v.z);
  v.setLength(radius);
  vertices.setXYZ(i, v.x, v.y, v.z);
}

vertices.needsUpdate = true;
normals.needsUpdate = true;

为了测试,我在每个面上渲染具有完全平坦的法线贴图(即所有像素都是rgb(128, 128, 255))的球体。我的假设是,对于没有法线贴图的渲染,我看起来没有区别,但不幸的是,我在每个面的边缘/ uv边界处得到了明显的接缝:

Significant normal map seams on sphere

这是一个显示问题的小提琴:https://jsfiddle.net/Lcf1wgvo/5/

如何消除这些接缝?我知道任何球体上都会出现切线空间不连续性,但至少不应该是一个完全平坦的切线空间法线贴图显示没有接缝吗?

2 个答案:

答案 0 :(得分:1)

你不能使用threejs切线框架来实现这一点。您必须使用顶点数据生成切线,以使它们在该接缝处对齐。

您需要从头开始编写着色器(或组装它),或者尝试使用onBeforeCompile (我建议不要这样做,这很诱人,但可能会引起更多的麻烦而不是它的价值。)

如果您决定完全更改几何体(如评论中所述),您将会遇到纹理分布不佳。

修改

在这种特殊情况下,可以通过使球体的分辨率非常高来避免接缝。来自OP示例的那个创建了一个128x64的分段球体,它具有相当高的分辨率。不幸的是,随着面部之间的角度增加,这开始破裂。您可以看到立方体接缝,也可以看到三角形接缝(转到左下角)。

问题是three.js生成切线的方式(动态,使用dFdxdFdy)。

enter image description here

在向法线贴图添加实际细节时,它也会很快失败: https://jsfiddle.net/65xabvx4/12/

答案 1 :(得分:-1)

问题是ThreeJS(和WebGL)每个顶点只能支持一个法线。因此,当它创建BoxBufferGeometry时,为了制作锐边,它会复制边缘顶点并为每个边缘顶点分配不同的法线。当您向小提琴添加VertexNormalsHelper时,可以很容易地看到这一点。 enter image description here 看看边顶点有2个法线,角有3个法线?这意味着它们在每个点上也有2个和3个顶点,每个面都有一个顶点。

当你&#34; spherize&#34;在顶点和法线中,这些空间中的点仍保持其2和3个顶点/正常对:

enter image description here

红色圆圈(角点顶点)在该点处有3个重叠法线,蓝色圆圈(边缘顶点)有2个法线。渲染时,片段着色器在连接顶点之间输出平滑渐变,但在占据相同空间的两个顶点之间进行混合时会出现打嗝。