• EffectComposer + ShaderPass 实现分区特效


    一、实现步骤

    EffectComposer + Layers 实现分区特效中,EffectComposer更像是渲染出一张有辉光特效的“背景图”,renderer在这张“背景图”上渲染正常方块,以至于无论相机在哪个角度,都看到正常方块绘制在发光方块之上。针对这个问题,参考threejs提供的案例,使用ShaderPass实现分区辉光效果。步骤如下:

    1、创建两个效果组合器bloomComposer和finalComposer,其中bloomComposer用来生成辉光效果,并将其渲染的结果作为着色器材质的输入,传递给finalComposer。finalComposer则用来渲染整个场景,在材质通道ShaderPass中将辉光效果整合到scene内。

    const initComposer = () => {
        bloomComposer = new EffectComposer(renderer);
        bloomComposer.renderToScreen = false;
    
        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.addPass(renderScene);
        bloomComposer.addPass(bloomPass);
    
        finalComposer = new EffectComposer(renderer);
        const finalShader = new THREE.ShaderMaterial({
            uniforms: {
                baseTexture: { value: null },
                bloomTexture: { value: bloomComposer.renderTarget2.texture }
            },
            vertexShader: `
                varying vec2 vUv;
                void main() {
                    vUv = uv;
                    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
                }
            `,
            fragmentShader: `
                uniform sampler2D baseTexture;
                uniform sampler2D bloomTexture;
                varying vec2 vUv;
                void main() {
                    gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );
                }
            `,
            defines: {}
        });
        const finalPass = new ShaderPass(finalShader, "baseTexture");
        finalPass.needsSwap = true;
        finalComposer.addPass(renderScene);
        finalComposer.addPass(finalPass);
    };
    

    2、创建正常方块和发光方块,并为它们设置不同的渲染图层,在渲染的过程钟将相机设置到对应图层进行渲染。

    也可以像threejs案例中那样,在渲染发光物体时将非发光物体设置为黑色,这种方式对辉光效果有作用,因为黑色的物体不会产生辉光效果。对其他后处理效果就不一定适用了。

    3、先用bloomComposer渲染出辉光效果,再使用finalComposer渲染场景。

    const render = () => {
        renderer.autoClear = false;
        renderer.clear();
    
        camera.layers.set(1);
        bloomComposer.render();
    
        renderer.clearDepth(); // 清除深度缓存
    
        camera.layers.set(0);
        finalComposer.render(scene, camera);
        
        requestAnimationFrame(render);
    };
    

    二、效果

    三、完整代码

    index.html

    <!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 src="./src/index.js"></script>
      </body>
    </html>

    index.js

    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";
    
    let scene, camera, renderer, bloomComposer, finalComposer;
    
    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 = () => {
        bloomComposer = new EffectComposer(renderer);
        bloomComposer.renderToScreen = false;
    
        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.addPass(renderScene);
        bloomComposer.addPass(bloomPass);
    
        finalComposer = new EffectComposer(renderer);
        const finalShader = new THREE.ShaderMaterial({
            uniforms: {
                baseTexture: { value: null },
                bloomTexture: { value: bloomComposer.renderTarget2.texture }
            },
            vertexShader: `
                varying vec2 vUv;
                void main() {
                    vUv = uv;
                    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
                }
            `,
            fragmentShader: `
                uniform sampler2D baseTexture;
                uniform sampler2D bloomTexture;
                varying vec2 vUv;
                void main() {
                    gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );
                }
            `,
            defines: {}
        });
        const finalPass = new ShaderPass(finalShader, "baseTexture");
        finalPass.needsSwap = true;
        finalComposer.addPass(renderScene);
        finalComposer.addPass(finalPass);
    };
    
    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);
        bloomComposer.render();
    
        renderer.clearDepth(); // 清除深度缓存
    
        camera.layers.set(0);
        finalComposer.render(scene, camera);
        
        requestAnimationFrame(render);
    };
    init();
    initComposer();
    main();
    render();
    
  • 相关阅读:
    hdu2588-GCD-(欧拉函数+分解因子)
    欧拉定理及其扩展定理公式
    hdu2973-YAPTCHA-(欧拉筛+威尔逊定理+前缀和)
    hdu5391-Zball in Tina Town-威尔逊定理(假证明)
    deleted
    deleted
    deleted
    deleted
    deleted
    deleted
  • 原文地址:https://www.cnblogs.com/zerotoinfinity/p/15910759.html
Copyright © 2020-2023  润新知