使用环境参考
Node.js v16.19.1
正文
模型网格合并
接下来要实现一些后处理效果,比如外轮廓发光效果。我想让整体模型进行外发光,打开 blender 软件观察了一下模型的结构,由四个子块组成,这时可以通过软件进行合并,或者去 three 里面去合并。
如下在 blender 里的层级显示,从灵活度考虑,不推荐在模型里合并,Pass。
在 three 中加载完 glf 模型,观察其 children,就是四个子部分,利用代码合并它们。
import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils'
// 、、、
async addModel() {
const model = await loadGLTF('gltf/SheenChair.glb')
const geometryArray = []
const materialArray = []
model.traverse(obj => {
// traverse 会遍历所有,一些模型含有光源,空节点,做下过滤
if (obj instanceof THREE.Mesh) {
geometryArray.push(obj.geometry)
materialArray.push(obj.material)
}
})
const mergeGeo = mergeBufferGeometries(geometryArray, true)
const group = new THREE.Mesh(mergeGeo, materialArray)
this.scene.add(group)
}
描边后处理
把 scene 的背景颜色搞暗一些,加入外发光后处理效果:
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass'
import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils'
import { initCamera, initScene, initWebGLRenderer } from './init'
import { loadGLTF } from './load'
import { AnimationManager } from './animation'
class Game {
scene: THREE.Scene
camera: THREE.PerspectiveCamera
renderer: THREE.WebGLRenderer
orbitControls: OrbitControls
raycaster = new THREE.Raycaster()
mouse = new THREE.Vector2()
animationManager = new AnimationManager()
// 后处理
composer: EffectComposer
outlinePass: OutlinePass
constructor() {
this.scene = initScene()
this.camera = initCamera()
this.scene.add(this.camera)
this.renderer = initWebGLRenderer()
this.orbitControls = this.addOrbitControls(this.camera, this.renderer)
this.addModel()
this.addResizeEventListener()
this.addClickEvent()
this.composer = new EffectComposer(this.renderer)
const renderPass = new RenderPass(this.scene, this.camera)
this.composer.addPass(renderPass)
const outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), this.scene, this.camera)
// 描边 pass 的各种参数
outlinePass.edgeStrength = 4
outlinePass.edgeGlow = 1
outlinePass.edgeThickness = 1
outlinePass.visibleEdgeColor.set('#ffffff')
outlinePass.hiddenEdgeColor.set('#190a05')
this.composer.addPass(outlinePass)
this.outlinePass = outlinePass
}
addClickEvent() {
this.renderer.domElement.addEventListener('pointermove', (ev) => {
this.mouse.x = (ev.clientX / window.innerWidth) * 2 - 1
this.mouse.y = -(ev.clientY / window.innerHeight) * 2 + 1
this.raycaster.setFromCamera(this.mouse, this.camera)
const intersects = this.raycaster.intersectObject(this.scene, true)
if (intersects.length) {
// 想多个模型发光就声明一个数组,往里 push 即可
this.outlinePass.selectedObjects = [intersects[0].object]
} else {
this.outlinePass.selectedObjects = []
}
})
}
addOrbitControls(camera: THREE.Camera, renderer: THREE.WebGLRenderer) {
const controls = new OrbitControls(camera, renderer.domElement)
controls.autoRotate = true
controls.enableDamping = true
controls.update()
return controls
}
async addModel() {
const model = await loadGLTF('gltf/SheenChair.glb')
const geometryArray = []
const materialArray = []
model.traverse(obj => {
if (obj instanceof THREE.Mesh) {
geometryArray.push(obj.geometry)
materialArray.push(obj.material)
}
})
const mergeGeo = mergeBufferGeometries(geometryArray, true)
const group = new THREE.Mesh(mergeGeo, materialArray)
this.scene.add(group)
}
addResizeEventListener() {
window.addEventListener('resize', () => {
this.camera.aspect = window.innerWidth / window.innerHeight
this.camera.updateProjectionMatrix()
this.renderer.setSize(window.innerWidth, window.innerHeight)
})
}
startMainLoop() {
// 等待一帧用于初始化
Promise.resolve().then(() => {
this.step()
})
}
step() {
requestAnimationFrame(this.step.bind(this))
this.orbitControls && this.orbitControls.update()
this.animationManager.step()
// 注意上面 this.composer 已经 addPass 了普通渲染流程,这里注释掉
// this.renderer.render(this.scene, this.camera)
this.composer.render()
}
}
const game = new Game()
game.startMainLoop()
更多文章与分享
Three 学习项目链接:https://github.com/KuoKuo666/threejs-study
个人网站:www.kuokuo666.com
2023!Day Day Up!