是否可以让 Fog 与 material 的不透明度交互?

Is it possible to let Fog interact with the material's opacity?

我正在做一个显示建筑物的项目。 要求是让建筑物根据摄像机和建筑物之间的距离逐渐淡出(透明)。另外,这个效果必须跟随摄像机的移动。

我考虑使用THREE.Fog(),但雾似乎只能改变material的颜色。 上图是白雾缭绕的建筑图

我的问题是:

有什么建议吗?

此致, 亚瑟

NOTE: I suspect there are probably easier/prettier ways to solve this than opacity. In particular, note that partially-opaque buildings will show other buildings behind them. To address that, consider using a gradient or some other scene background, and choosing a fog color to match that, rather than using opacity. But for the sake of trying it...

以下是如何根据对象的距离改变对象的不透明度。这实际上并不需要 THREE.Fog,我不确定您将如何直接使用雾数据。相反,我将使用 THREE.NodeMaterial,它(从 three.js r96 开始)是相当实验性的。另一种方法是使用 THREE.ShaderMaterial 编写自定义着色器,这也很好。

const material = new THREE.StandardNodeMaterial();
material.transparent = true;
material.color = new THREE.ColorNode( 0xeeeeee );

// Calculate alpha of each fragment roughly as:
// alpha = 1.0 - saturate( distance / cutoff )
//
// Technically this is distance from the origin, for the demo, but
// distance from a custom THREE.Vector3Node would work just as well.
const distance = new THREE.Math2Node(
  new THREE.PositionNode( THREE.PositionNode.WORLD ),
  new THREE.PositionNode( THREE.PositionNode.WORLD ),
  THREE.Math2Node.DOT
);
const normalizedDistance = new THREE.Math1Node(
  new THREE.OperatorNode(
    distance,
    new THREE.FloatNode( 50 * 50 ),
    THREE.OperatorNode.DIV
  ),
  THREE.Math1Node.SAT
);
material.alpha = new THREE.OperatorNode(
  new THREE.FloatNode( 1.0 ),
  normalizedDistance,
  THREE.OperatorNode.SUB
);

演示:https://jsfiddle.net/donmccurdy/1L4s9e0c/

截图:

我是OP。在花了一些时间阅读如何使用 Three.js 的着色器后 material。我得到了一些可以正常工作的代码。

代码如下:https://jsfiddle.net/yingcai/4dxnysvq/

基本思路是:

  1. 创建包含 controls.target(Vector3 位置)的制服。
  2. 将顶点位置属性传递给顶点着色器中的变化。所以 片段着色器可以访问它。
  3. 获取每个顶点位置与controls.target之间的距离。根据距离计算 alpha 值。
  4. 为顶点颜色分配 alpha 值。

另一个重要的事情是:因为淡出遮罩应该跟随相机移动,所以不要忘记每帧更新制服中的控件。

// Create uniforms that contains control position value.
uniforms = {
    texture: {
      value: new THREE.TextureLoader().load("https://threejs.org/examples/textures/water.jpg")
    },
    control: {
      value: controls.target
    }
  };

// In the render() method.
// Update the uniforms value every frame.
uniforms.control.value = controls.target;