Three.js+TypeScript+Webpack学习记录(四)

使用环境参考

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!

Three.js+TypeScript+Webpack学习记录(四)

https://www.kuokuo666.com/home/kk057.html

作者

KUOKUO众享

发布于

2023-04-24

更新于

2024-03-05

许可协议

评论