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