先来个效果图
之前写的那个稍微有点问题,帧率只有30,参照官方代码修改后,帧率可以达到50了,在不全屏的状态下,帧率60
// 用于模型边缘高亮
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js"
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js"
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js"
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js"
import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js"
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass.js"
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass.js"
然后需要注意,我这里使用的是vue的框架,但是对于变量的定义我用的是全局的定义。
// 模型边缘高光
let composer;
let outlinePass;
let renderPass;
let effectFXAA;
add_composer() {
// 创建一个EffectComposer(效果组合器)对象,然后在该对象上添加后期处理通道。
composer = new EffectComposer(renderer)
// 新建一个场景通道 为了覆盖到原来的场景上
renderPass = new RenderPass(scene, camera)
composer.addPass(renderPass);
// 物体边缘发光通道
outlinePass = new OutlinePass(mouse, scene, camera)
outlinePass.visibleEdgeColor.set(parseInt(0x00ff00)) // 呼吸显示的颜色
outlinePass.hiddenEdgeColor = new THREE.Color(0, 0, 0) // 呼吸消失的颜色
composer.addPass(outlinePass)
// 解决高亮后环境变暗的问题
const outputPass = new OutputPass();
composer.addPass( outputPass );
// 自定义的着色器通道 作为参数
effectFXAA = new ShaderPass(FXAAShader)
effectFXAA.uniforms[ 'resolution' ].value.set( 1 / window.innerWidth, 1 / window.innerHeight );
composer.addPass(effectFXAA)
},
把上面这个函数,在mounted的时候调用一下,初始化一次,后面想让哪个模型高亮,就传哪个模型进去
现在就需要在点击模型的事件中去调用这个函数
// 点击模型事件
pick(event) {
const found = self.cast(event)[0];
if (found) {
// [transformer]是给变压器加,[transformer,car]是给变压器和房子加,子模型要.object
outlinePass.selectedObjects = [found.object];
}
},
我的self就是this。
我想要实现的是子模型的高亮,所以我要取子模型的object,其次需要注意的就是传入的参数是个数组,你传入哪些模型,点击的时候,那些模型就会一起高亮,我这里传入的是一个,是选中的子模型。
如果你不想让这个模型边缘高亮了,那么outlinePass.selectedObjects = []; 这个数组里放哪个模型哪个模型边缘高亮,通过修改 outlinePass.selectedObjects 实现。
当不想要高亮的时候,把composer赋值为空就可以了。
doubel_pick(event) {
outlinePass.selectedObjects = [];
},
当窗口大小改变时,需要对应着改变渲染的大小
// 随着窗体的变化修改场景
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
composer.setSize(window.innerWidth, window.innerHeight);
effectFXAA.uniforms[ 'resolution' ].value.set( 1 / window.innerWidth, 1 / window.innerHeight );
}
// 监听窗体调整大小事件
window.addEventListener('resize', onResize, false);
const animate = () => {
stats.update();
controls.update();
//renderer.render(scene, camera); 不在需要renderer.render了
composer.render(scene, camera)
self.render_animation = requestAnimationFrame(animate);
};
animate()
这里需要注意的就是不要再添加renderer.render了,因为前面new EffectComposer的时候已经把renderer添加进去了,后面就是组合效果,只需要循环render后面这个composer就可以了,这是我的理解。
当然这也是造成之前帧率低的主要原因,循环渲染了,所以,删掉他,直接composer.render(scene, camera),帧率50,在不全屏的情况下,帧率60,基本满足需求。
附官方案例
案例:https://threejs.org/examples/?q=outlin#webgl_postprocessing_outline
源码:https://github.com/mrdoob/three.js/blob/master/examples/webgl_postprocessing_outline.html
前面被其他博客误导了。