辉光
辉光就是让一个模型进行发光,可以实现灯泡,车灯的效果。
全局辉光
threejs官网案例:threejs.org/examples/?q...
- 引入实现辉光所需要的扩展库
js
//引入后处理扩展库
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
//引入渲染器通道RenderPass
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
// 引入UnrealBloomPass辉光通道
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
- EffectComposer
想要在用threejs输出一张图像,除了必不可少的场景、相机外还需要WebGLRenderer把图像渲染到页面上,如果你需要对一个webgl渲染器的渲染结果进行后期处理,就把它作为EffectComposer
的参数。
kotlin
this.composer = new EffectComposer(this.renderer)
- RenderPass
通过EffectComposer指定需要后期处理的渲染器后。再通过渲染器通道RenderPass
指定后处理对应的相机camera
和场景scene
。
//
const renderPass = new RenderPass(this.scene, this.camera);
- 发光通道UnrealBloomPass
参数1是一个二维向量Vector2
,二维向量尺x、y分量要和Canvas画布的宽、高度尺寸保持一致。参数2是发光强度,参数3是发光阈值,参数4是发光半径。
javascript
this.bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight),1,0.5,0.5)
- 给
EffectComposer
添加渲染器通道RenderPass
和发光通道。
kotlin
// 设置renderPass通道
this.composer.addPass(renderPass); this.composer.addPass(this.bloomPass)
- 循环执行
kotlin
this.composer.render()
效果图:前后对比
部分辉光
threejs官网案例threejs.org/examples/q=...
-
有时候我们只希望部分物体发光,但是辉光会对场景中所有模型产生效果,那么就会导致其他不希望有辉光效果的物体出现了辉光。
-
想要实现部分模型有辉光的效果就不得不提到图层。
- 图层简介:图层对象为Object3D对象分配了1-32个图层,编号为0-31。 默认所有 Object3D 对象都存储在第 0 个图层上。图层对象可以用于控制对象的显示,和相机处于同一个图层的物体才可以被显示出来。每个继承自 Object3D 的对象都有一个 Object3D.layers 对象。Mesh、Camera、Group等都继承自基类 Object3D,所以它们都有一个 layers 属性。
-
具体实现方式如下;
- 思路:准备两个后处理器 EffectComposer,一个用于产生辉光效果(bloomComposer ),另一个用来正常渲染整个场景(finalComposer)。在创建一个集合对象,用来存储要辉光的模型,主要是用于区分辉光和不辉光的模型
-
准备基础数据和方法后面要用
javascript
BLOOM_SCENE: 1,
bloomLayer: new THREE.Layers(),
materials: {},
darkMaterial: new THREE.MeshBasicMaterial({ color: 'black' })
init() {
this.bloomLayer.set(this.BLOOM_SCENE);
},
//要启用图层1,才会展示辉光效果
initCamera() {
......
this.camera.layers.enable(1)
},
//非辉光图层的模型颜色全部变为黑色
darkenNonBloomed(obj) {
if (obj.isMesh && this.bloomLayer.test(obj.layers) === false) {
this.materials[obj.uuid] = obj.material;
obj.material = this.darkMaterial;
}
},
//恢复非辉光图层的模型颜色
restoreMaterial(obj) {
if (this.materials[obj.uuid]) {
obj.material = this.materials[obj.uuid];
delete this.materials[obj.uuid];
}
},
initModelGlow(url) {
const loader = new GLTFLoader()
loader.load(url, (gltf) => {
const model = gltf.scene;
gltf.scene.traverse((obj) => {
if (obj.isMesh) {
//注意:设置导入的模型图层与辉光涂层一样才会显示辉光
obj.layers.set(this.BLOOM_SCENE)
}
})
model.translateX(5)
this.scene.add(model);
});
},
- 创建辉光图层,将辉光物体添加在该图层上,用于区分辉光物体和非辉光物体
kotlin
this.bloomLayer.set(this.BLOOM_LAYER);
- 利用 UnrealBloomPass实现辉光
kotlin
let renderScene = new RenderPass(this.scene, this.camera)
this.bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight))
this.bloomPass.strength = this.params.bloomStrength
this.bloomPass.threshold = this.params.bloomThreshold
this.bloomPass.radius = this.params.bloomRadius
- 准备第一个后处理器 EffectComposer,产生辉光效果
kotlin
this.bloomComposer = new EffectComposer(this.renderer)
this.bloomComposer.renderToScreen = false; //不渲染到屏幕
this.bloomComposer.addPass(renderScene)
this.bloomComposer.addPass(this.bloomPass)
- 这块不是很懂,貌似是利用ShaderPass着色器合成最终通道(不包含辉光特效)
php
const mixPass = new ShaderPass(
new THREE.ShaderMaterial({
uniforms: {
baseTexture: { value: null },
bloomTexture: { value: this.bloomComposer.renderTarget2.texture }
},
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'
);
mixPass.needsSwap = true;
- 利用 finalComposer 渲染,finalComposer 将加入两个通道,一个是 bloomComposer 的渲染结果,另一个则是正常的渲染结果。
kotlin
this.finalComposer = new EffectComposer(this.renderer);
this.finalComposer.addPass(renderScene);
this.finalComposer.addPass(mixPass);
-
循环渲染
先将不辉光的模型材质设置为黑色,模型设置为黑色后,辉光也没有效果。然后执行辉光合成器的render进行渲染,此时场景渲染辉光,而不需要辉光的模型因为设置了黑色,所以也看不出来。到此,场景中需要辉光的模型就实现了辉光,而不需要辉光的模型目前是看不见的,所以接下来,我们要将材质设置为黑色的模型还原成原本的材质颜色,再执行最终合成器的render进行渲染,因为finalComposer合成器中不包含辉光特效,所以第二次redner后,只渲染了正常不辉光的模型,而第一次渲染辉光的模型也被混合在一起了,所以场景最终就实现了一部分模型辉光,一部分不辉光。
kotlin
render() {
this.scene.traverse(this.darkenNonBloomed)
// 渲染辉光合成器\
this.bloomComposer.render()
// 还原不会光的材质
this.scene.traverse(this.restoreMaterial)
// 渲染最终合成器
this.finalComposer.render()
// this.renderer.render(this.scene, this.camera)
},
效果图
以下案例源码在此处: gitee.com/ldglys/thre... 如果对您有所帮助请给个star。如果有不懂的可留言,看到会回复。