位移贴图的UV映射?

4

摘要

我正在尝试将位移贴图(高度贴图)应用于一个相当简单的对象(六边形平面),但是我遇到了一些意外的结果。我使用灰度,因此我认为我的高度图只应该影响网格的 Z 值。然而,我创建的位移贴图会在 X 和 Y 平面上拉伸网格。此外,它似乎没有使用我创建的 UV 映射,而所有其他纹理都成功应用了。

模型和 UV 映射

这里是 Blender 中我的六边形网格及其对应的 UV 映射的参考图像。

六边形模型和 UV 映射

漫反射贴图和位移贴图

这些是我通过 Three.JS 应用于网格的漫反射贴图和位移贴图。

六边形漫反射和位移贴图

渲染结果

当我没有应用位移贴图渲染平面时,您可以看到六边形平面保持在线条内。然而,当我添加位移贴图时,它明显影响了顶点的 X 和 Y 位置,而不仅仅是影响 Z 值,将平面扩展到远离线条之外。

六边形平面渲染结果 -- 有和没有位移贴图

代码

这是相关的 Three.js 代码:

    // Textures
    var diffuseTexture = THREE.ImageUtils.loadTexture('diffuse.png', null, loaded);
    var displacementTexture = THREE.ImageUtils.loadTexture('displacement.png', null, loaded);
    
    // Terrain Uniform
    var terrainShader = THREE.ShaderTerrain["terrain"];
    var uniformsTerrain = THREE.UniformsUtils.clone(terrainShader.uniforms);
    
  //uniformsTerrain["tNormal"].value = null;
  //uniformsTerrain["uNormalScale"].value = 1;
    
    uniformsTerrain["tDisplacement"].value = displacementTexture;
    uniformsTerrain["uDisplacementScale"].value = 1;
    
    uniformsTerrain[ "tDiffuse1" ].value = diffuseTexture;
  //uniformsTerrain[ "tDetail" ].value = null;
    uniformsTerrain[ "enableDiffuse1" ].value = true;
  //uniformsTerrain[ "enableDiffuse2" ].value = true;
  //uniformsTerrain[ "enableSpecular" ].value = true;

  //uniformsTerrain[ "uDiffuseColor" ].value.setHex(0xcccccc);
  //uniformsTerrain[ "uSpecularColor" ].value.setHex(0xff0000);
  //uniformsTerrain[ "uAmbientColor" ].value.setHex(0x0000cc);

  //uniformsTerrain[ "uShininess" ].value = 3;
  //uniformsTerrain[ "uRepeatOverlay" ].value.set(6, 6);
    
    // Terrain Material
    var material = new THREE.ShaderMaterial({
        uniforms:uniformsTerrain,
        vertexShader:terrainShader.vertexShader,
        fragmentShader:terrainShader.fragmentShader,
        lights:true,
        fog:true
    });
    
    // Load Tile
    var loader = new THREE.JSONLoader();
    loader.load('models/hextile.js', function(g) {
      //g.computeFaceNormals();
      //g.computeVertexNormals();
        g.computeTangents();
        g.materials[0] = material;
        
        tile = new THREE.Mesh(g, new THREE.MeshFaceMaterial());
        scene.add(tile);
    });

假设

目前我有三个可能会导致出现问题的原因:

  1. UV贴图未应用到位于我的置换图上。
  2. 我的置换图制作错误。
  3. 在该过程中我可能错过了一个关键步骤,这个步骤将锁定置换到仅Z轴。

当然,还有第四个秘密选项,即没有上述任何一个原因,我只是真的不知道自己在做什么。或者以上原因的混合。

实时示例

您可以查看实时示例 在此

如果有更多相关知识的人能够指导我,我将非常感激!

编辑1:根据建议,我已经注释掉了 computeFaceNormals()computeVertexNormals()。虽然它确实有所改善,但网格仍然被扭曲。

2个回答

4
在您的地形材料中,设置wireframe = true,您就可以看到发生了什么。
您的代码和纹理基本上没问题。问题出现在加载程序回调函数中计算顶点法线时。
外环几何体的计算出的顶点法线有些向外。这很可能是因为在computeVertexNormals()中它们是通过平均每个相邻面的面法线来计算出来的,并且“侧面”的面法线(黑色部分)被平均到组成“盖子”外环的那些顶点的顶点法线计算中。
结果,“盖子”的外环在位移贴图下向外扩张。
编辑:果然,从您的模型中来看,外环的顶点法线向外。内环的顶点法线全部平行。也许Blender使用的是与computeVertexNormals()相同的逻辑来生成顶点法线。 vertex normals

1
这是对你最初问题的相当详细的回答。现在你已经改变了代码和问题...你的模型已经有法线了,所以很可能正在使用它们,因为你已经注释掉了法线计算。只需学习如何设置顶点法线即可按照自己的意愿进行设置。在我看来,你的其余代码看起来很好。 :-) - WestLangley
这是一个相当详细的答案,我很感激。我所做的唯一更改就是你建议的那些,而我做出这些更改是为了表明它们实际上并没有解决问题。在Blender中,我有一个完全平坦的平面,如果法线被错误地生成,我不知道如何或为什么会出现这种情况。如果您可以通过更新您的答案以包括有关顶点法线正确生成的资源来帮助我达到解决方案(位移按预期显示),我将非常感激,并且可以考虑这是一个完整的答案。 - rrowland
2
rrowland 只需在您的模型中搜索 zindex 为 0.538017 的每个顶点,并将它们的顶点法线设置为 0,0,1。 - Gero3
1
@rrowland,你问了很好的问题——这就是我为什么要花时间为你调查的原因。但是,恕我直言,在事实已经发生后添加新问题是不正确的。如果你需要更多帮助,请发布一个新帖子。(我没有使用过Blender,所以无法帮助你解决这个问题。) - WestLangley
感谢您进一步解答我的问题。我查看了一些Blender教程,并找到了正常显示选项,它展示了与您美丽的可视化相同的错误法线。我通过使用细分创建了一个极薄的层,将其排除在UV映射之外,从而使法线变得平直,解决了这个问题。感谢您的帮助,希望我没有冒犯您!如果没有您详细的回答,我将无法解决这个问题。 - rrowland
显示剩余2条评论

1
问题在于您的对象是如何构建的,因为位移沿着法向量发生。

代码在这里。

https://github.com/mrdoob/three.js/blob/master/examples/js/ShaderTerrain.js#L348-350

"vec3 dv = texture2D( tDisplacement, uvBase ).xyz;",

这个函数接受位移纹理的 RGB 向量。

"float df = uDisplacementScale * dv.x + uDisplacementBias;",

这只获取向量的红色值,因为uDisplacementScale通常为1.0,而uDisplacementBias为0.0。

"vec3 displacedPosition = normal * df + position;",

这会沿着法向量改变位置。

因此,要解决问题,您可以更新法线或着色器。


如果可能的话,我想坚持使用标准并使用提供的着色器,而不是自定义我的着色器。您能否推荐一种方法来提供自己的法线或修复生成的法线? - rrowland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接