Three.js带Depth实现分区辉光

一、效果

在这里插入图片描述

二、如何实现

  • 1.基于EffectComposer后期渲染器。
  • 2.借助UnrealBloomPass渲染通道,实现辉光效果。
  • 3.接住ShaderPass,保此原有material。
  • 4.单帧两次渲染,分别渲染辉光部分,还原正常部分。
  • 5.相比直接分层两次渲染,修复了深度信息丢失导致的层级问题。

三、代码实现

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <script type="x-shader/x-vertex" id="vertexshader">

      varying vec2 vUv;

      void main() {

          vUv = uv;

          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

      }
    </script>

    <script type="x-shader/x-fragment" id="fragmentshader">

      uniform sampler2D baseTexture;
      uniform sampler2D bloomTexture;

      varying vec2 vUv;

      void main() {

          gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );

      }
    </script>
    <script type="module">
      import * as THREE from "./node_modules/three/build/three.module.js";
      import { OrbitControls } from "./node_modules/three/examples/jsm/controls/OrbitControls.js";
      import { EffectComposer } from "./node_modules/three/examples/jsm/postprocessing/EffectComposer.js";
      import { UnrealBloomPass } from "./node_modules/three/examples/jsm/postprocessing/UnrealBloomPass.js";
      import { RenderPass } from "./node_modules/three/examples/jsm/postprocessing/RenderPass.js";
      import { ShaderPass } from "./node_modules/three/examples/jsm/postprocessing/ShaderPass.js";
      import { FXAAShader } from "./node_modules/three/examples/jsm/shaders/FXAAShader.js";

      let scene, camera, renderer, bloomComposer, finalComposer;

      const ENTIRE_SCENE = 0,
        BLOOM_SCENE = 1;

      const bloomLayer = new THREE.Layers();
      bloomLayer.set(BLOOM_SCENE);
      const darkMaterial = new THREE.MeshBasicMaterial({ color: "black" });
      const materials = {};
      const params = {
        exposure: 0,
        bloomStrength: 1.5,
        bloomThreshold: 0,
        bloomRadius: 0,
      };

      const init = () => {
        // 场景
        scene = new THREE.Scene();
        // 相机
        camera = new THREE.PerspectiveCamera(
          70,
          window.innerWidth / window.innerHeight,
          1,
          100000
        );
        camera.position.set(50, 50, 50);
        camera.position.y = 50;
        // 渲染器
        renderer = new THREE.WebGLRenderer({
          antialias: true,
        });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.toneMapping = THREE.ReinhardToneMapping;
        document.body.appendChild(renderer.domElement);
        // 环境光
        const light = new THREE.AmbientLight(0xffffff, 0.6);
        light.layers.enable(0);
        light.layers.enable(1);
        scene.add(light);
        // 控制器
        const controls = new OrbitControls(camera, renderer.domElement);
        scene.add(new THREE.AxesHelper(100));
        window.onresize = () => {
          renderer.setSize(window.innerWidth, window.innerHeight);
          camera.aspect = window.innerWidth / window.innerHeight;
          camera.updateProjectionMatrix();
        };
      };

      const initComposer = () => {
        const effectFXAA = new ShaderPass(FXAAShader);
        effectFXAA.uniforms["resolution"].value.set(
          0.6 / window.innerWidth,
          0.6 / window.innerHeight
        );
        effectFXAA.renderToScreen = true;
        const renderScene = new RenderPass(scene, camera);
        const bloomPass = new UnrealBloomPass(
          new THREE.Vector2(window.innerWidth, window.innerHeight),
          1.5,
          0.4,
          0.85
        );
        bloomPass.threshold = params.bloomThreshold;
        bloomPass.strength = params.bloomStrength;
        bloomPass.radius = params.bloomRadius;

        bloomComposer = new EffectComposer(renderer);
        bloomComposer.renderToScreen = false;
        bloomComposer.addPass(renderScene);
        bloomComposer.addPass(bloomPass);
        bloomComposer.addPass(effectFXAA);

        const finalPass = new ShaderPass(
          new THREE.ShaderMaterial({
            uniforms: {
              baseTexture: { value: null },
              bloomTexture: { value: bloomComposer.renderTarget2.texture },
            },
            vertexShader: document.getElementById("vertexshader").textContent,
            fragmentShader: document.getElementById("fragmentshader")
              .textContent,
            defines: {},
          }),
          "baseTexture"
        );
        finalPass.needsSwap = true;

        finalComposer = new EffectComposer(renderer);
        finalComposer.addPass(renderScene);
        finalComposer.addPass(finalPass);
        finalComposer.addPass(effectFXAA);
      };

      const render = () => {
        scene.traverse((obj) => {
          if (obj.isMesh && bloomLayer.test(obj.layers) === false) {
            materials[obj.uuid] = obj.material;
            obj.material = darkMaterial;
          }
        });
        bloomComposer.render();
        scene.traverse((obj) => {
          if (materials[obj.uuid]) {
            obj.material = materials[obj.uuid];
            delete materials[obj.uuid];
          }
        });
        finalComposer.render();
        requestAnimationFrame(render);
      };

      const main = () => {
        init();
        initComposer();

        const geometry = new THREE.BoxGeometry(20, 20, 10);
        // 正常方块
        const normalMtl = new THREE.MeshLambertMaterial({ color: 0x00ffff });
        const normalBox = new THREE.Mesh(geometry, normalMtl);
        normalBox.position.z = -5;
        normalBox.layers.set(0);
        scene.add(normalBox);

        // 发光方块
        const bloomMtl = new THREE.MeshLambertMaterial({ color: 0xff5500 });
        const bloomBox = new THREE.Mesh(geometry, bloomMtl);
        bloomBox.position.z = 5;
        bloomBox.layers.enable(1);
        scene.add(bloomBox);
      };
      main();
      render();
    </script>
  </body>
</html>

四、注意点

  1. UnrealBloomPass将会影响渲染器的alpha通道,需要修改源码解决。 源码地址
  2. 分层渲染时,由于清除了深度信息,会导致模型层级问题。
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要在 three.js实现局部辉光,你可以使用 ShaderMaterial 和自定义的着色器来实现。以下是一个简单的示例代码,展示了如何在 three.js实现局部辉光效果: ```javascript // 创建一个具有局部辉光效果的材质 const glowMaterial = new THREE.ShaderMaterial({ uniforms: { glowColor: { value: new THREE.Color(0x00ff00) }, // 辉光颜色 coeficient: { value: 1.0 }, // 辉光强度系数 power: { value: 1.0 } // 辉光强度 }, vertexShader: ` varying vec3 vNormal; void main() { vNormal = normalize(normalMatrix * normal); gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: ` uniform vec3 glowColor; uniform float coeficient; uniform float power; varying vec3 vNormal; void main() { float intensity = pow(coeficient - dot(vNormal, vec3(0.0, 0.0, 1.0)), power); gl_FragColor = vec4(glowColor, intensity); } `, side: THREE.FrontSide, blending: THREE.AdditiveBlending, transparent: true }); // 创建一个需要应用局部辉光的物体 const geometry = new THREE.BoxGeometry(1, 1, 1); const mesh = new THREE.Mesh(geometry, glowMaterial); // 将物体添加到场景中 scene.add(mesh); ``` 在上述代码中,我们创建了一个自定义的 ShaderMaterial,其中包含了顶点着色器和片段着色器。顶点着色器用于计算每个顶点的法线向量,片段着色器根据法线向量和辉光参数计算每个片段的颜色和强度。 你可以根据自己的需求调整着色器中的参数和逻辑来实现不同的局部辉光效果。希望这个示例能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值