首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >是否有可能让雾与材料的不透明度相互作用?

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

Stack Overflow用户
提问于 2018-09-20 12:49:52
回答 3查看 1.2K关注 0票数 2

我正在做一个展示建筑物的项目。的要求是根据相机与建筑物之间的距离让建筑物逐渐淡出(透明),也必须跟随摄像机的运动。

我考虑使用THREE.Fog(),但雾似乎只能改变材质的颜色。

上面是一张有白色雾的建筑物的照片。

  • 这些建筑物是用瓷砖建造的,每个瓷砖都是一个几何形状(我用var bigGeometry = new THREE.Geometry(); bigGeometry.merge(smallGeometry);将所有的建筑物合并成一个)。
  • 紫色/蓝色的东西是地面,和ground.material.fog = false;。所以地面不会与雾相互作用。

我的问题是:

  • 是否有可能让雾与建筑物材料的不透明度相互作用,而不是颜色?(更白的翻译为更透明)
  • 或者,我应该使用阴影控制材料的不透明度,根据距离的相机?但我不知道该怎么做。
  • 我还考虑了添加alphaMap。如果是这样的话,每个建筑瓷砖必须映射一个alphaMap和所有这些alphaMap必须与相机的运动互动。这将是一项艰巨的工作。

有什么建议吗?

向你问好,亚瑟

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-09-25 20:32:57

我就是行动。花了一些时间阅读如何使用Three.js的着色材料。我得到了一些按需要工作的代码。

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

其基本思想是:

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

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

代码语言:javascript
运行
复制
// 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;

票数 1
EN

Stack Overflow用户

发布于 2018-09-21 01:51:22

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

下面是如何根据一个物体的距离来改变它的不透明度。这实际上不需要THREE.Fog,我不知道您将如何直接使用fog数据。相反,我将使用THREE.NodeMaterial,它(就three.js r96而言)是相当实验性的。另一种选择是用THREE.ShaderMaterial编写一个自定义着色器,这也很好。

代码语言:javascript
运行
复制
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/

截图:

票数 2
EN

Stack Overflow用户

发布于 2022-06-14 20:09:55

几年后,我也遇到了同样的问题,我用.onBeforeCompile函数解决了这个问题,这个函数可能更方便使用。有一个很好的教程这里

代码本身是简单的,可以很容易地更改为其他材料。它只使用fogFactor作为材料中的α值。

这里的物质功能:

代码语言:javascript
运行
复制
alphaFog() {
const material = new THREE.MeshPhysicalMaterial();
material.onBeforeCompile = function (shader) {

  const alphaFog =
      `
      #ifdef USE_FOG
        #ifdef FOG_EXP2
          float fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );
        #else
          float fogFactor = smoothstep( fogNear, fogFar, vFogDepth );
        #endif
        gl_FragColor.a = saturate(1.0 - fogFactor);
      #endif
  `

  shader.fragmentShader = shader.fragmentShader.replace(
      '#include <fog_fragment>', alphaFog
  );

  material.userData.shader = shader;
};


material.transparent = true
return material;
}

然后你就可以像

代码语言:javascript
运行
复制
    const cube = new THREE.Mesh(geometry, this.alphaFog());
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52425575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档