项目的场景中需要点击建筑物产生描边的效果,看着很是不错,本期就来给大家讲解一下怎么来实现。本次使用的是threejs138版本,在vue3+vite+ant的项目中使用。
下面来看看实现的效果。房子建筑有了明显的描边效果。
实现步骤
- 增加composer.js
注意的点:
1. FXAAShader主要解决composer.render后锯齿的问题。
2. outlinePass 可以写成多个,也可以写成变量传递。
3. outlinePass.hiddenEdgeColor默认是白色,可以不写。
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass';
import { GammaCorrectionShader } from 'three/examples/jsm/shaders/GammaCorrectionShader.js'
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader';
import scene from '../scene';
import camera from '../camera';
import renderer from '../renderer';
import * as THREE from 'three';
const effectComposer = new EffectComposer(renderer.renderer)
const renderPass = new RenderPass(scene, camera)
effectComposer.addPass(renderPass)
const composer = new EffectComposer(renderer.renderer)
composer.renderToScreen = false
composer.addPass(new RenderPass(scene, camera))
// 着色器
let shaderPass = new ShaderPass(new THREE.ShaderMaterial({
uniforms: {
baseTexture: { value: null },
bloomTexture: { value: composer.renderTarget2.texture },
tDiffuse: {
value: null
}
},
vertexShader:'\t\t\tvarying vec2 vUv;\n' +
'\n' +
'\t\t\tvoid main() {\n' +
'\n' +
'\t\t\t\tvUv = uv;\n' +
'\n' +
'\t\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n' +
'\n' +
'\t\t\t}',
fragmentShader:'\t\t\tuniform sampler2D baseTexture;\n' +
'\t\t\tuniform sampler2D bloomTexture;\n' +
'\n' +
'\t\t\tvarying vec2 vUv;\n' +
'\n' +
'\t\t\tvoid main() {\n' +
'\n' +
'\t\t\t\tgl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );\n' +
'\n' +
'\t\t\t}',
defines: {}
}), 'baseTexture')
shaderPass.renderToScreen = false
shaderPass.needsSwap = true
//将创建的通道添加到EffectComposer(效果组合器)对象中
effectComposer.addPass(shaderPass)
// 创建阴影效果
const effectFXAA = new ShaderPass(FXAAShader);
effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight);
effectComposer.addPass(effectFXAA);
const effectColorSpaceConversion = new ShaderPass(GammaCorrectionShader)
// effectColorSpaceConversion.renderToScreen = true;
effectComposer.addPass(effectColorSpaceConversion)
// 创建高亮边框
const outlineParams = {
edgeStrength: 2.0,
edgeGlow: 1.0,
edgeThickness: 1,
pulsePeriod: 0,
rotate: false,
usePatternTexture: {
wrapS: THREE.RepeatWrapping,
wrapT: THREE.RepeatWrapping,
},
};
const outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera);
outlinePass.edgeStrength = Number(outlineParams.edgeStrength);
outlinePass.edgeGlow = Number(outlineParams.edgeGlow);
outlinePass.edgeThickness = Number(outlineParams.edgeThickness);
outlinePass.pulsePeriod = Number(outlineParams.pulsePeriod);
outlinePass.renderToScreen = false;
outlinePass.usePatternTexture = false;
outlinePass.visibleEdgeColor.set('#3875ff');
outlinePass.hiddenEdgeColor.set('white');
//创建效果组合器对象,可以在该对象上添加后期处理通道,通过配置该对象,使它可以渲染我们的场景,并应用额外的后期处理步骤,在render循环中,使用EffectComposer渲染场景、应用通道,并输出结果。
effectComposer.addPass(outlinePass)
effectComposer.render()
export default {composer,effectComposer,outlinePass};
- 在animate里面重复调用,以下着重注意的点有三点。
- Composer.composer的引入位置必须是在renderer.render()之后。否则不能出来效果。
- Composer.effectComposer的位置必须是在最后,否则合成器不能展示成功。
- glowMaterialList 里面的值是需要发光的物体名称,可以通过mitt或者vuex或者watch监听等方法来同步监听。
import camera from './camera';
import renderer from './renderer';
import controls from './controls';
import scene from './scene';
import { TWEEN } from 'three/examples/jsm/libs/tween.module.min';
import composer from './modify/composer';
import * as THREE from 'three';
var materials ={
scene:null,
}
var glowMaterialList=['Cylinder022']
function animate() {
controls.update();
TWEEN.update();
// 使用渲染器渲染相机看这个场景的内容渲染出来
renderer.renderer.render(scene, camera);
// 将不需要处理辉光的材质进行存储备份
scene.traverse((v) => {
// 备份一份场景背景然后清空
if (v instanceof THREE.Scene) {
materials.scene = v.background
v.background = null
}
if (!glowMaterialList.includes(v.name) && v.isMesh) {
// 备份当前材质内容
materials[v.uuid] = v.material
// 将不需要辉光的材质设置为黑色
v.material = new THREE.MeshBasicMaterial({ color: 'black' })
}
})
if (composer.composer) { composer.composer.render() }
scene.traverse((v) => {
if (materials[v.uuid]) {
v.material = materials[v.uuid]
delete materials[v.uuid]
}
if (v instanceof THREE.Scene) {
v.background = materials.scene
delete materials.scene
}
})
if (composer.effectComposer) { composer.effectComposer.render() }
requestAnimationFrame(animate);
}
export default animate;
- resize的时候增加适应屏幕
import camera from "./camera";
import rendererModule from "./renderer";
import composer from './modify/composer';
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix();
// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
// console.log("resize");
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix();
// 更新渲染器
rendererModule.renderer.setSize(window.innerWidth, window.innerHeight);
// 设置渲染器的像素比例··
rendererModule.renderer.setPixelRatio(window.devicePixelRatio);
// 更新渲染器
composer.composer.setSize(window.innerWidth, window.innerHeight);
});
四、在点击时候调用composer.outlinPass方法
注意的点有:
- selectedObjects是一个数组mesh,里面可以包含多个物体。
- 如果只想选一个,那么一定要记得清空。
- 所有的相同材质的物体都会描边。
import composer from '../modify/composer';
// 事件的监听
window.addEventListener("click", (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -((event.clientY / window.innerHeight) * 2 - 1);
camera.updateMatrixWorld(true)
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(scene);
if (intersects.length > 0) {
// console.log(intersects)
//点击房屋
let target = intersects[0].object;
if (selectedObject !== target) {
composer.outlinePass.selectedObjects = [target]
}
} else if (selectedObject) {
selectedObject = null;
}
});
以上就是实现物体描边的步骤,只需要调节composer.js里面outlineParams的参数就可以调节到你需要的描边的颜色、粗细等参数,还有是否闪烁,闪烁的交替颜色等,如果还有不懂的可以联系我哦。