【问题标题】:How can I eliminate normal map seams on cube-mapped Three.js BoxBufferGeometry?如何消除立方体贴图 Three.js BoxBufferGeometry 上的法线贴图接缝?
【发布时间】:2018-04-04 05:31:24
【问题描述】:

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 边界处都有明显的接缝:

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

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

【问题讨论】:

  • 我猜问题是对应的uv坐标不连续。您可以使用以下小提琴轻松看到这一点:jsfiddle.net/f2Lommf5/4269。这是因为纹理投影在盒子的每一侧。真实球体的 uv 坐标看起来不同。
  • @Mugen87 用球体进行相同的实验确实消除了接缝,但包括两极的变形。我想这很明确地表明这是由于法线贴图的切线空间问题。大概有一种方法可以通过调整接缝/极点附近的法线贴图来纠正这些问题?
  • 我认为 three.js 通常无法做你想做的事,因为它使用导数动态创建切线框架。在 three.js 中渲染烘焙的法线贴图是不可能的,我相信已经有很多版本了。您可以在平面上渲染砖块纹理之类的东西,应该可以。
  • 是的,我在这里挖掘了一下:github.com/mrdoob/three.js/blob/… 并担心可能是这种情况。我认为可以通过预先计算切线来解决,但我想在这种情况下它将使用自定义着色器。希望在three.js的上下文中有一个解决方案。

标签: 3d three.js


【解决方案1】:

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

你要么需要从头开始编写你的着色器(或组装它),要么尝试使用onBeforeCompile (我建议不要这样做,这很诱人,但可能会导致比它值得更头痛的问题。) em>

如果您决定完全更改几何图形(如 cmets 中所建议的那样),您将遇到纹理分布不佳的情况。

编辑

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

问题在于three.js 生成切线的方式(即时,使用dFdxdFdy)。

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

【讨论】:

  • 看来,不幸的是,你是对的。我可能会为此编写一个自定义着色器,与此同时,我正在使用一个球体(它确实会引入一些拉伸)。
  • 幸运的是,你不正确。如果 OP 使用正确的法线贴图,则没有可见的接缝。
  • 我认为该声明具有误导性,您可能想说的(我正在考虑编辑答案)是:in this particular case of a cubemapped sphere, if the resolution of the sphere is high enough, the divergence of the tangents will be so small resulting in no seam。不幸的是,一旦您将其从高分辨率球体(32 x 4 = 128 段)更改为普通/低分辨率球体,接缝就会变得可见。
  • 我已经编辑了答案并添加了截图@WestLangley
【解决方案2】:

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

当您“球化”顶点和法线时,空间中的这些点仍然保持它们的 2 和 3 顶点/法线对:

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

【讨论】:

  • 为什么会出现这个问题?使用三角形汤时,您到处都有重复的顶点。这与法线映射无关,问题在于使用导数计算 TBN 框架所产生的不连续性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多