Three.js中使用MarkPass(掩码)的高级效果组合器

1、MarkPass的作用:

可以对指定的scene运行后期效果。

2、效果图:
3、使用步骤:
3.1、引入文件
import { RenderPass } from '../../node_modules/three/examples/jsm/postprocessing/RenderPass';
import { ShaderPass } from '../../node_modules/three/examples/jsm/postprocessing/ShaderPass';
import { ClearMaskPass, MaskPass } from 'three/examples/jsm/postprocessing/MaskPass';
import { CopyShader } from 'three/examples/jsm/shaders/CopyShader';
3.2、过程概述:

(1)创建一个作为背景图片的场景。
(2)创建一个场景,里面包含一个看起来像地球的球体。
(3)创建一个场景,里面包含一个看起来像火星的球体。
(4)创建EffectComposer对象,用于将这三个场景渲染到一个图片中。
(5)在渲染为火星的球体上应用彩色效果。
(6)在渲染为地球的球体上应用褐色效果。

3.3、注意事项:

1、 我们直接使用场景的背景属性来添加星光背景图片。还有一种可选方式也可以同于添加背景图片,那就是利用THREE.OrthoGraphicCamera(正交摄像机)。因为THREE.OrthoGraphicCamera不会根据物体距离摄像机的距离来缩放物体,所以可以添加一个正对摄像机的THREE.PlaneGeometry几何体,然后在上面添加图片。
2、场景渲染时候需要将渲染器改为组合器的渲染器,并且需要将WebGLRenderer中autoClear设置为false

4、完整源代码:
import { OrthographicCamera, Vector3, Scene, WebGLRenderer, Color, SphereGeometry, MeshPhongMaterial, TextureLoader, Mesh, Clock, AmbientLight, DirectionalLight, PlaneGeometry, MeshBasicMaterial, PerspectiveCamera } from 'three';
import { RenderPass } from '../../node_modules/three/examples/jsm/postprocessing/RenderPass';
import { ShaderPass } from '../../node_modules/three/examples/jsm/postprocessing/ShaderPass';
import { ClearMaskPass, MaskPass } from 'three/examples/jsm/postprocessing/MaskPass';
import { CopyShader } from 'three/examples/jsm/shaders/CopyShader';
import { OrbitControls } from '../../node_modules/three/examples/jsm/controls/OrbitControls';
import { SepiaShader } from '../../node_modules/three/examples/jsm/shaders/SepiaShader';
import { ColorifyShader } from '../../node_modules/three/examples/jsm/shaders/ColorifyShader';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
export class Effect {
    private sceneEarth!: Scene;
    private sceneMars!: Scene;
    private sceneBG!: Scene;
    private cameraBG!: OrthographicCamera;
    private camera!: PerspectiveCamera;
    private webGLRenderer!: WebGLRenderer;
    private earthSphere!: Mesh;
    private marsSphere!: Mesh;
    private earthMaterial!: MeshPhongMaterial;
    private marsMaterial!: MeshPhongMaterial;
    private clock !: Clock;
    private ambEarth!: AmbientLight;
    private ambMars!: AmbientLight;
    private dirEarth!: DirectionalLight;
    private dirMars!: DirectionalLight;
    private bgPass!: RenderPass;
    private earthPass!: RenderPass;
    private marsPass!: RenderPass;
    private composer!:EffectComposer;
    constructor() {
        this.clock = new Clock();
        // 创建三个场景
        this.sceneEarth = new Scene();
        this.sceneMars = new Scene();
        this.sceneBG = new Scene();

        // 相机设置
        this.camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
        this.camera.position.x = -10;
        this.camera.position.y = 15;
        this.camera.position.z = 25;
        this.camera.lookAt(new Vector3(0, 0, 0));

        this.cameraBG = new OrthographicCamera(-window.innerWidth, window.innerWidth, window.innerHeight, -window.innerHeight, -10000, 10000);
        this.cameraBG.position.z = 50;

        // 渲染器设置
        this.webGLRenderer = new WebGLRenderer({ antialias: true });
        this.webGLRenderer.setClearColor(0x000000, 1.0); //设置背景颜色
        this.webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        this.webGLRenderer.setPixelRatio(window.devicePixelRatio);
        this.webGLRenderer.shadowMap.enabled = true;
        document.body.appendChild(this.webGLRenderer.domElement);

        // 地球
        this.earthSphere = this.createEarthMesh(new SphereGeometry(10, 40, 40));
        this.earthSphere.position.x = -10;
        this.sceneEarth.add(this.earthSphere);
        // 火星
        this.marsSphere = this.createMarshMesh(new SphereGeometry(5, 40, 40));
        this.earthSphere.position.x = 20;
        this.sceneMars.add(this.marsSphere);

        // 环境光
        this.ambEarth = new AmbientLight(0x181818);
        this.sceneEarth.add(this.ambEarth);
        this.ambMars = new AmbientLight(0x181818);
        this.sceneMars.add(this.ambMars);

        // 方向光
        this.dirEarth = new DirectionalLight(0xffffff, 0.6);
        this.dirEarth.position.set(550, 100, 550);
        this.sceneEarth.add(this.dirEarth);

        this.dirMars = new DirectionalLight(0xffffff, 0.6);
        this.dirMars.position.set(550, 100, 550);
        this.sceneMars.add(this.dirMars);

        // 背景平面
        const bgPlane = new PlaneGeometry(1, 1);
        const bgPlaneMaterial = new MeshBasicMaterial({
            map: new TextureLoader().load('../assets/starry-deep-outer-space-galaxy.jpg'),
            depthTest: false // 不启动深度测试即设置成false就拥有类似透视的效果

        });
        const bgMesh = new Mesh(bgPlane, bgPlaneMaterial);
        bgMesh.position.z = -100;
        bgMesh.scale.set(window.innerWidth * 2, window.innerHeight * 2, 1);
        this.sceneBG.add(bgMesh);

        // 后期处理
        //RenderPass根据scene和camera渲染出一个场景,和普通的webGLRenderer一样
        this.bgPass = new RenderPass(this.sceneBG, this.cameraBG);
        // this.bgPass.clear = false;
        this.earthPass = new RenderPass(this.sceneEarth, this.camera);
        this.earthPass.clear = false;//if set to true, the pass clears its buffer before rendering
        this.marsPass = new RenderPass(this.sceneMars, this.camera);
        this.marsPass.clear = false;
        
        const effectCopy = new ShaderPass(CopyShader);
        effectCopy.renderToScreen = true;

        const clearMark = new ClearMaskPass();
        // earth mark
        const earthMark = new MaskPass(this.sceneEarth, this.camera);
        // earthMark.inverse = true;

        //mars mark
        //sceneMask和clearMask可以理解成ps图层的透明部分。不添加mask,效果就应用到整个场景,添加了就只应用到场景中的物体,用完记得需要清除。
        //掩码的作用:可以对指定的scene运行后期效果
        const marsMark = new MaskPass(this.sceneMars, this.camera);

        const effectSepia = new ShaderPass(SepiaShader);//乌贼墨效果
        effectSepia.uniforms['amount'].value = 0.8;

        const effectColorify = new ShaderPass(ColorifyShader);//整个颜色覆盖屏幕
        effectColorify.uniforms['color'].value.setRGB(0.5, 0.5, 1);

        // 组合通道
        this.composer = new EffectComposer(this.webGLRenderer);
        //需要注意的是需要将使用掩码前,要将composer.renderTarget.stencilBuffer设置为true,用于限制渲染区域。
        //另外,使用完掩码后,需要使用ClearMaskPass()去掉掩码区域
        this.composer.renderTarget1.stencilBuffer = true;
        this.composer.renderTarget2.stencilBuffer = true;

        this.composer.addPass(this.bgPass);
        this.composer.addPass(this.earthPass);
        this.composer.addPass(this.marsPass);
        //掩码的作用:可以对指定的scene运行后期效果
        this.composer.addPass(marsMark);//添加掩码,后续通道只会影响掩码区域,取消掩码需要加入THREE.ClearMaskPass通道
        this.composer.addPass(effectColorify);
        this.composer.addPass(clearMark);
        this.composer.addPass(earthMark);
        this.composer.addPass(effectSepia);
        this.composer.addPass(clearMark);
        this.composer.addPass(effectCopy);


        const orbitControls= new OrbitControls(this.camera, this.webGLRenderer.domElement);
        orbitControls.autoRotate =false;

        window.addEventListener('resize', ()=>this.onWindowResize());
        this.render();
    }
    private onWindowResize() {
        this.webGLRenderer.setSize(window.innerWidth, window.innerHeight);
        this.camera.aspect = window.innerWidth/window.innerHeight;
        this.camera.updateProjectionMatrix();

        this.cameraBG.left = -window.innerWidth;
        this.cameraBG.right = window.innerWidth;
        this.cameraBG.top = window.innerHeight;
        this.cameraBG.bottom = -window.innerHeight;
        this.cameraBG.updateProjectionMatrix();
    }
    private render() {
        this.webGLRenderer.autoClear = false;//一定要设置
        window.requestAnimationFrame(() => this.render());
        this.earthSphere.rotation.y+=0.02;
        this.marsSphere.rotation.y+=0.02;
        this.composer.render(this.clock.getDelta());//参数设置成两帧间隔时间
    }
    private createMarshMesh(geom) {

        this.marsMaterial = new MeshPhongMaterial({
            map: new TextureLoader().load('../assets/Mars_2k-050104.png'),
            normalMap: new TextureLoader().load('../assets/Mars-normalmap_2k.png')
        });
        const mesh = new Mesh(geom, this.marsMaterial);
        return mesh;
    }

    private createEarthMesh(geom) {
        this.earthMaterial = new MeshPhongMaterial({
            map: new TextureLoader().load('../assets/Earth.png'),
            specularMap: new TextureLoader().load('../assets/EarthSpec.png'),
            normalMap: new TextureLoader().load('../assets/EarthNormal.png'),
            specular: new Color(0x4444aa)
        });
        const mesh = new Mesh(geom, this.earthMaterial);
        return mesh;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Threejs 为什么? webGL太难用,太复杂! 但是现代浏览器都支持 WebGL 这样我们就不必使用 Fla...
    强某某阅读 6,163评论 1 21
  • 准备工作: 1、three.js https://threejs.org/build/three.js 2、搭建项...
    月_关阅读 5,656评论 0 1
  • 1、简介 WebGL 是在浏览器中实现三维效果的一套规范,而 Three.js 可以看成是浏览器对 WebGL 规...
    风之化身呀阅读 3,541评论 0 4
  • 本文主要是讲解 Three.js 的相关概念,帮助大家对 Three.js 以及相关知识形成比较完整的理解。今年来...
    Simon王小白阅读 8,500评论 2 9
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,565评论 16 22