Three.js中使用MarkPass(掩碼)的高級(jí)效果組合器

1、MarkPass的作用:

可以對(duì)指定的scene運(yùn)行后期效果。

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、過(guò)程概述:

(1)創(chuàng)建一個(gè)作為背景圖片的場(chǎng)景。
(2)創(chuàng)建一個(gè)場(chǎng)景,里面包含一個(gè)看起來(lái)像地球的球體。
(3)創(chuàng)建一個(gè)場(chǎng)景,里面包含一個(gè)看起來(lái)像火星的球體。
(4)創(chuàng)建EffectComposer對(duì)象,用于將這三個(gè)場(chǎng)景渲染到一個(gè)圖片中。
(5)在渲染為火星的球體上應(yīng)用彩色效果。
(6)在渲染為地球的球體上應(yīng)用褐色效果。

3.3、注意事項(xiàng):

1、 我們直接使用場(chǎng)景的背景屬性來(lái)添加星光背景圖片。還有一種可選方式也可以同于添加背景圖片,那就是利用THREE.OrthoGraphicCamera(正交攝像機(jī))。因?yàn)門(mén)HREE.OrthoGraphicCamera不會(huì)根據(jù)物體距離攝像機(jī)的距離來(lái)縮放物體,所以可以添加一個(gè)正對(duì)攝像機(jī)的THREE.PlaneGeometry幾何體,然后在上面添加圖片。
2、場(chǎng)景渲染時(shí)候需要將渲染器改為組合器的渲染器,并且需要將WebGLRenderer中autoClear設(shè)置為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();
        // 創(chuàng)建三個(gè)場(chǎng)景
        this.sceneEarth = new Scene();
        this.sceneMars = new Scene();
        this.sceneBG = new Scene();

        // 相機(jī)設(shè)置
        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;

        // 渲染器設(shè)置
        this.webGLRenderer = new WebGLRenderer({ antialias: true });
        this.webGLRenderer.setClearColor(0x000000, 1.0); //設(shè)置背景顏色
        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);

        // 環(huán)境光
        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 // 不啟動(dòng)深度測(cè)試即設(shè)置成false就擁有類(lèi)似透視的效果

        });
        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根據(jù)scene和camera渲染出一個(gè)場(chǎng)景,和普通的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,效果就應(yīng)用到整個(gè)場(chǎng)景,添加了就只應(yīng)用到場(chǎng)景中的物體,用完記得需要清除。
        //掩碼的作用:可以對(duì)指定的scene運(yùn)行后期效果
        const marsMark = new MaskPass(this.sceneMars, this.camera);

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

        const effectColorify = new ShaderPass(ColorifyShader);//整個(gè)顏色覆蓋屏幕
        effectColorify.uniforms['color'].value.setRGB(0.5, 0.5, 1);

        // 組合通道
        this.composer = new EffectComposer(this.webGLRenderer);
        //需要注意的是需要將使用掩碼前,要將composer.renderTarget.stencilBuffer設(shè)置為true,用于限制渲染區(qū)域。
        //另外,使用完掩碼后,需要使用ClearMaskPass()去掉掩碼區(qū)域
        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);
        //掩碼的作用:可以對(duì)指定的scene運(yùn)行后期效果
        this.composer.addPass(marsMark);//添加掩碼,后續(xù)通道只會(huì)影響掩碼區(qū)域,取消掩碼需要加入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;//一定要設(shè)置
        window.requestAnimationFrame(() => this.render());
        this.earthSphere.rotation.y+=0.02;
        this.marsSphere.rotation.y+=0.02;
        this.composer.render(this.clock.getDelta());//參數(shù)設(shè)置成兩幀間隔時(shí)間
    }
    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;
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Threejs 為什么? webGL太難用,太復(fù)雜! 但是現(xiàn)代瀏覽器都支持 WebGL 這樣我們就不必使用 Fla...
    強(qiáng)某某閱讀 6,481評(píng)論 1 21
  • 準(zhǔn)備工作: 1、three.js https://threejs.org/build/three.js 2、搭建項(xiàng)...
    月_關(guān)閱讀 5,849評(píng)論 0 1
  • 1、簡(jiǎn)介 WebGL 是在瀏覽器中實(shí)現(xiàn)三維效果的一套規(guī)范,而 Three.js 可以看成是瀏覽器對(duì) WebGL 規(guī)...
    風(fēng)之化身呀閱讀 3,637評(píng)論 0 4
  • 本文主要是講解 Three.js 的相關(guān)概念,幫助大家對(duì) Three.js 以及相關(guān)知識(shí)形成比較完整的理解。今年來(lái)...
    Simon王小白閱讀 8,670評(píng)論 2 9
  • 久違的晴天,家長(zhǎng)會(huì)。 家長(zhǎng)大會(huì)開(kāi)好到教室時(shí),離放學(xué)已經(jīng)沒(méi)多少時(shí)間了。班主任說(shuō)已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,822評(píng)論 16 22

友情鏈接更多精彩內(nèi)容