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!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KUOKUO众享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值