three.js中如何实现模型材质局部辉光(发光)效果

1,495 阅读3分钟

前言

今天给大家分享一下在three.js中如何实现一个模型材质的局部辉光(发光)效果

相关API的使用:

  1. EffectComposer(渲染后处理的通用框架,用于将多个渲染通道(pass)组合在一起创建特定的视觉效果)
  2. RenderPass(是用于渲染场景的通道。它将场景和相机作为输入,使用Three.js默认的渲染器(renderer)来进行场景渲染,并将结果输出给下一个渲染通道)
  3. UnrealBloomPass(是 three.js 中用于实现泛光效果的后期处理效果,通过高斯模糊和屏幕混合技术,将亮度较高的区域扩散开来,从而实现逼真的泛光效果。)
  4. ShaderPass(是一个自定义着色器的通道。它允许你指定自定义的着色器代码,并将其应用于场景的渲染结果。这样你可以创建各种各样的图形效果,如高斯模糊、后处理效果等)

在上一篇 Three.js加载外部glb,fbx,gltf,obj 模型文件 的文章基础上

首先引入相关的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'

新增以下函数方法

  1. 效果合成器方法:createEffectComposer
  2. 获取需要辉光效果材质的方法:getFlowMeaterList

创建效果合成器方法(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) {
			    modelMaterialList.push(v)	
			}
		})
		this.glowMaterialList = modelMaterialList.map(v=>v.name)
   }

处理不需要辉光的材质

渲染场景方法(sceneAnimation):处理不需要辉光的材质。

注意:1.辉光效果会影响整个场景中的内容如:背景,灯光辅助线,控制器辅助线等 这里需要通过对不需要辉光(发光)的内容进行单独判断处理

2.辉光效果的强度大小,取决于材质本身的发光强度,如果材质的发光效果不够明显可以手动修改材质类型,或者更换其它模型

原理:在每次辉光渲染器执行之前先将不需要发光的材质进行存储备份,然后改变材质类型颜色(黑色),在辉光渲染器执行之后再将原材质内容给恢复

   sceneAnimation() {
	           this.renderAnimation = requestAnimationFrame(() => this.sceneAnimation())
              this.scene.traverse((v) => {
			if (v instanceof THREE.GridHelper) {
				this.materials.gridHelper = v.material
				v.material = new THREE.MeshStandardMaterial({ color: '#000' })
			}

			if (v instanceof THREE.Scene) {
				this.materials.scene = v.background
				this.materials.environment = v.environment
				v.background = null
				v.environment = null
			}

			if (!this.glowMaterialList.includes(v.name) && v.isMesh) {
				this.materials[v.uuid] = v.material
				v.material = new THREE.MeshStandardMaterial({ color: '#000' })
			}
		})

		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.GridHelper) {
				v.material = this.materials.gridHelper
				delete this.materials.gridHelper
			}

			if (v instanceof THREE.Scene) {
				v.background = this.materials.scene
				v.environment = this.materials.environment
				delete this.materials.scene
				delete this.materials.environment
			}
		})
		this.effectComposer.render()
		this.controls.update()
	}

完整的代码可参考:gitee.com/ZHANG_6666/…

界面效果对比

1.辉光开启前

image.png 1.辉光开启后

image.png