Appearance
所谓threejs后期处理,就像ps一样,对threejs的渲染结果进行后期处理,比如添加发光效果。
OutlinePass.js:高亮发光描边
OutlinePass.js扩展库提供的类OutlinePass就可以给一个模型添加一个高亮发光描边
引入EffectComposer.js
js
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';大家都知道three.js WebGL渲染器执行渲染方法.render()会得到一张图像,如果你需要对一个webgl渲染器的渲染结果进行后期处理,就把它作为EffectComposer的参数。
js
// 创建后处理对象EffectComposer,WebGL渲染器作为参数
const composer = new EffectComposer(renderer);渲染器通道RenderPass
js
// 引入渲染器通道RenderPass
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';通过EffectComposer(renderer)指定了需要后处理的渲染器WebGLRenderer,渲染器通道RenderPass的作用是指定后处理对应的相机camera和场景scene。
js
// 创建一个渲染器通道,场景和相机作为参数
const renderPass = new RenderPass(scene, camera);给EffectComposer添加一个渲染器通道RenderPass。
js
// 设置renderPass通道
composer.addPass(renderPass);OutlinePass通道
OutlinePass可以给指定的某个模型对象添加一个高亮发光描边效果。
js
// 引入OutlinePass通道
import { OutlinePass } from 'three/addons/postprocessing/OutlinePass.js';创建OutlinePass通道
js
// OutlinePass第一个参数v2的尺寸和canvas画布保持一致
const v2 = new THREE.Vector2(window.innerWidth, window.innerHeight);
// const v2 = new THREE.Vector2(800, 600);
const outlinePass = new OutlinePass(v2, scene, camera);OutlinePass属性.selectedObjects
three.js场景中有多个模型的话,你希望给哪个模型对象设置发光描边效果,就可以通过OutlinePass的选择对象属性.selectedObjects设置。
js
// 一个模型对象
outlinePass.selectedObjects = [mesh];
// 多个模型对象
outlinePass.selectedObjects = [mesh1,mesh2,group];设置OutlinePass通道
最后把创建好的OutlinePass通道添加到后处理composer中。
js
// 设置OutlinePass通道
composer.addPass(outlinePass);渲染循环执行EffectComposer.render()
渲染循环中后处理EffectComposer执行.render(),会调用webgl渲染器执行.render(),也就是说renderer.render(scene, camera)不用再执行。
js
// 渲染循环
function render() {
composer.render();
// renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();此时看到这里描边的效果就已经实现了
再介绍几个描边的属性,用来控制描边的效果
描边颜色.visibleEdgeColor
js
//模型边缘高亮边框颜色,默认白色
outlinePass.visibleEdgeColor.set(0xffff00);描边厚度.edgeThickness
outlinePass.edgeThickness表示高亮发光描边的厚度,默认值1
js
// 轮廓边缘描边厚度设置
outlinePass.edgeThickness = 4.0;
console.log('描边厚度',outlinePass.edgeThickness);描边亮度.edgeStrength
outlinePass.edgeThickness表示高亮描边的发光强度,默认值3
js
outlinePass.edgeStrength = 6;描边闪烁.pulsePeriod
outlinePass.pulsePeriod的功能是控制描边的闪烁频率,默认0不闪烁。
js
outlinePass.pulsePeriod = 2;完整代码
html
<template>
<div id="canvas"></div>
</template>
<script setup>
import * as THREE from 'three';
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
// 引入渲染器通道RenderPass
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { OutlinePass } from 'three/addons/postprocessing/OutlinePass.js';
import { DotScreenPass } from 'three/examples/jsm/postprocessing/DotScreenPass.js';
import { SMAAPass } from 'three/examples/jsm/postprocessing/SMAAPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
import { GlitchPass } from 'three/addons/postprocessing/GlitchPass.js';
const route = useRoute();
onMounted(() => {
// 创建场景
const scene = new THREE.Scene();
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(50, 50, 50);
//材质对象Material
const material = new THREE.MeshLambertMaterial({
color: 0x00ffff //设置材质颜色
});
// 创建网格模型
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0, 10, 0);
scene.add(mesh); //网格模型添加到场景中
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
// tip: 环境光
// 环境光AmbientLight:没有特定的光源位置,整体改变场景的光照明暗度
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(100, 60, 50);
// 方向光指向对象网格模型mesh,可以不设置,默认的位置是0,0,0
// directionalLight.target = mesh;
scene.add(directionalLight);
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5, 0xff0000);
scene.add(dirLightHelper);
/**
* 光源设置
*/
//点光源
// const pointLight = new THREE.PointLight(0xffffff, 1.0);
// pointLight.decay = 0.0; //光源光照强度不随距离改变衰减
// //点光源位置
// // pointLight.position.set(400, 0, 0);//点光源放在x轴上
// pointLight.position.set(400, 200, 300); //偏移光源位置,观察渲染效果变化
// scene.add(pointLight); //点光源添加到场景中
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = window.innerWidth; //宽度
const height = window.innerHeight; //高度
/**
* 透视投影相机设置
*/
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185); //相机在Three.js三维坐标系中的位置
camera.lookAt(0, 0, 0); //相机观察目标指向Three.js坐标系原点
// OutlinePass第一个参数v2的尺寸和canvas画布保持一致
const v2 = new THREE.Vector2(window.innerWidth, window.innerHeight);
// const v2 = new THREE.Vector2(800, 600);
const outlinePass = new OutlinePass(v2, scene, camera);
outlinePass.selectedObjects = [mesh];
//模型描边颜色,默认白色
outlinePass.visibleEdgeColor.set(0xffff00);
//高亮发光描边厚度
outlinePass.edgeThickness = 4;
//高亮描边发光强度
outlinePass.edgeStrength = 6;
//模型闪烁频率控制,默认0不闪烁
outlinePass.pulsePeriod = 2;
const renderPass = new RenderPass(scene, camera);
/**
* 创建渲染器对象
*/
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
renderer.render(scene, camera); //执行渲染操作
// 创建后处理对象EffectComposer,WebGL渲染器作为参数
const composer = new EffectComposer(renderer);
// 开启后处理 像素处理
const dotScreenPass = new DotScreenPass();
const smaaPass = new SMAAPass();
// 开启后处理 发光处理
const unrealBloomPass = new UnrealBloomPass();
// 开启后处理 闪烁处理
const glitchPass = new GlitchPass();
// 强度
// unrealBloomPass.strength = 0;
// 曝光强度
// renderer.toneMapping = THREE.ACESFilmicToneMapping; //老旧的电影的感觉
// renderer.toneMappingExposure = 2;
composer.addPass(renderPass);
composer.addPass(outlinePass);
// 关闭
dotScreenPass.enabled = false;
composer.addPass(dotScreenPass);
// 加上这个就没有锯齿感了
composer.addPass(smaaPass);
composer.addPass(glitchPass);
// 开启发光
composer.addPass(unrealBloomPass);
document.getElementById('canvas').appendChild(renderer.domElement);
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
function render() {
// renderer.render(scene, camera); //执行渲染操作
composer.render();
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
}
render();
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
// controls.addEventListener('change', function () {
// renderer.render(scene, camera); //执行渲染操作
// // 浏览器控制台查看相机位置变化
// console.log('camera.position', camera.position);
// }); //监听鼠标、键盘事件
window.onresize = () => {
if (route.query.type === '1') {
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
return;
} else if (route.query.type === '2') {
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix();
}
};
});
</script>