一、效果展示

辉光效果

在这里插入图片描述

二、如何实现

  • 1.基于EffectComposer后期渲染器。
  • 2.借助UnrealBloomPass渲染通道,实现辉光效果。
  • 3.了解three.js中 layers 分层的概念,实现分层渲染。
  • 4.单帧两次渲染,分别渲染两个不同的场景,组合成为需要的场景。

三、代码实现

<!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="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";

      let scene, camera, renderer, composer;

      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);
        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 = () => {
        composer = new EffectComposer(renderer);

        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;
        composer.addPass(renderScene);
        composer.addPass(bloomPass);
      };

      const main = () => {
        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.set(1);
        scene.add(bloomBox);
      };

      const render = () => {
        renderer.autoClear = false;
        renderer.clear();
        camera.layers.set(1);
        composer.render();

        renderer.clearDepth(); // 清除深度缓存

        camera.layers.set(0);
        renderer.render(scene, camera);
        requestAnimationFrame(render);
      };
      init();
      initComposer();
      main();
      render();
    </script>
  </body>
</html>


四、注意点

  1. UnrealBloomPass将会影响渲染器的alpha通道,需要修改源码解决。源码地址
  2. 使用layers分层渲染,只有当渲染目标与camera处与同一层时才会渲染
  3. 在使用分层渲染时,需要注意光源问题,所有场景默认都是在mask(1)层的,失去光源可能丢失渲染效果
  4. 分层渲染时需要关闭autoClear(定义渲染器是否在渲染每一帧之前自动清除其输出)属性,避免渲染效果被清除。
  5. 此方案会有深度信息丢失问题(单帧渲染两次,清除了Depth信息,同时使用了不同的渲染器),解决方案参考 ShaderPass方案
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐