是否可以让雾与材料的不透明度相互作用?

时间:2018-09-20 12:49:53

标签: three.js webgl shader

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

我考虑使用THREE.Fog(),但雾似乎只能改变材质的颜色。 Buildings with White Fog enabled 上面是白雾蒙蒙的建筑物的照片。

  • 建筑物位于图块中,每个图块是一个单一的几何图形(我将所有建筑物合并为一个) var bigGeometry = new THREE.Geometry(); bigGeometry.merge(smallGeometry);
  • 紫色/蓝色是地面,ground.material.fog = false;是地面。因此地面不会与雾相互作用。

我的问题是:

  • 是否可以使雾与建筑物的材料的不透明性(而不是颜色)相互作用? (更多的白色表示透明)
  • 还是应该使用Shader根据距相机的距离控制材质的不透明度?但是我不知道该怎么做。
  • 我还考虑过添加alphaMap。如果是这样,则每个建筑图块都必须映射一个alphaMap,并且所有这些alphaMap必须与相机的运动进行交互。这将需要大量的工作。

有什么建议吗?

最好的问候, 亚瑟

2 个答案:

答案 0 :(得分:1)

  

注意:我怀疑可能比不透明更容易/更漂亮的方法来解决此问题。特别要注意的是,部分不透明的建筑物将在其后面显示其他建筑物。要解决此问题,请考虑使用渐变或其他场景背景,并选择雾色来匹配该颜色,而不要使用不透明度。但是为了尝试...

以下是根据对象的距离更改对象的不透明度的方法。这实际上并不需要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/

截屏: screenshot of solution

答案 1 :(得分:0)

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

代码如下: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;

enter image description here