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;
}
}