1.Three.js 实现模型材质局部辉光(发光,光晕)效果
2.解决辉光效果影响场景背景图显示的问题
相关API的使用:
1. EffectComposer(渲染后处理的通用框架,用于将多个渲染通道(pass)组合在一起创建特定的视觉效果)
2. RenderPass(是用于渲染场景的通道。它将场景和相机作为输入,使用Three.js默认的渲染器(renderer)来进行场景渲染,并将结果输出给下一个渲染通道)
3. UnrealBloomPass(是 three.js 中用于实现泛光效果的后期处理效果,通过高斯模糊和屏幕混合技术,将亮度较高的区域扩散开来,从而实现逼真的泛光效果。)
4. ShaderPass(是一个自定义着色器的通道。它允许你指定自定义的着色器代码,并将其应用于场景的渲染结果。这样你可以创建各种各样的图形效果,如高斯模糊、后处理效果等)
在上一篇 Three.js加载外部glb,fbx,gltf,obj 模型文件 的文章基础上新增一个 createEffectComposer(效果合成器方法)和sceneAnimation( 效果器渲染方法)以及getFlowMeaterList(获取需要辉光效果材质的方法)
首先引入相关的api
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js'
import { UnrealBloomPass} from 'three/examples/jsm/postprocessing/OutlinePass.js'
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js'
创建效果合成器方法(createEffectComposer):需要创建两个合成器 effectComposer 用于正常渲染场景,glowComposer用于渲染辉光效果
createEffectComposer() {
const { clientHeight, clientWidth } = this.container
// 场景渲染器
this.effectComposer = new EffectComposer(this.renderer)
const renderPass = new RenderPass(this.scene, this.camera)
this.effectComposer.addPass(renderPass)
//创建辉光效果
this.unrealBloomPass = new UnrealBloomPass(new THREE.Vector2(clientWidth, clientHeight), 0, 0, 0)
this.unrealBloomPass.threshold = 1 // 辉光强度
this.unrealBloomPass.strength = 0 // 辉光阈值
this.unrealBloomPass.radius = 1 //辉光半径
this.unrealBloomPass.renderToScreen = false //
// 辉光合成器
this.glowComposer = new EffectComposer(this.renderer)
this.glowComposer.renderToScreen = false
this.glowComposer.addPass(new RenderPass(this.scene, this.camera))
this.glowComposer.addPass(this.unrealBloomPass)
// 着色器
let shaderPass = new ShaderPass(new THREE.ShaderMaterial({
uniforms: {
baseTexture: { value: null },
bloomTexture: { value: this.glowComposer.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 = true
shaderPass.needsSwap = true
this.effectComposer.addPass(shaderPass)
}
获取需要辉光渲染的材质:
getFlowMeaterList(){
const modelMaterialList= []
this.model.traverse((v) => {
if (v.isMesh && v.material) {
const { name, color,map } = v.material
// 统一将模型材质 设置为 MeshLambertMaterial 类型
v.material = new THREE.MeshLambertMaterial({
map,
transparent: true,
color,
name,
})
modelMaterialList.push(v)
}
})
this.glowMaterialList = modelMaterialList.map(v=>v.name)
}
渲染场景方法(sceneAnimation):处理不需要辉光的材质。注意:辉光效果会影响场景背景图的正常显示需要单独处理(这里通过 instanceof THREE.Scene 判断是否是场景材质然后进行单独处理)
sceneAnimation() {
this.renderAnimation = requestAnimationFrame(() => this.sceneAnimation())
this.controls.update()
// 将不需要处理辉光的材质进行存储备份
this.scene.traverse((v) => {
// 备份一份场景背景然后清空
if (v instanceof THREE.Scene) {
this.materials.scene = v.background
v.background = null
}
if (!this.glowMaterialList.includes(v.name) && v.isMesh) {
// 备份当前材质内容
this.materials[v.uuid] = v.material
// 将不需要辉光的材质设置为黑色
v.material = new THREE.MeshBasicMaterial({ color: 'black' })
}
})
// 执行辉光效果器渲染
this.glowComposer.render()
// 在辉光渲染器执行完之后在恢复材质原效果
this.scene.traverse((v) => {
if (this.materials[v.uuid]) {
v.material = this.materials[v.uuid]
delete this.materials[v.uuid]
}
if (v instanceof THREE.Scene) {
v.background = this.materials.scene
delete this.materials.scene
}
})
// 执行场景效果器渲染
this.effectComposer.render()
}
完整的代码可参考:https://gitee.com/ZHANG_6666/Three.js3D/blob/master/src/views/renderModel.js
界面效果对比