three.js+vue3+vite教学(七、更改几何体属性)

更改几何体属性

我们可以通过gui来动态更改我们几何体的大小以及位置等等

我们先把想更改的属性定义出来,再加一个折叠面板方便我们观看

大小

在这里插入图片描述
在这里插入图片描述

通过watch来侦听属性的变化

在这里插入图片描述
在这里插入图片描述

xyz都侦听

在这里插入图片描述
在这里插入图片描述

位置

位置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

移动

增加translate(跳跃,并不是更改坐标)

在这里插入图片描述
在这里插入图片描述

代码

<template>
    <div ref="statsRef"></div>
    <div className="contain" ref="containerRef">
    </div>
</template>

<script setup lang='ts'>
import {
    AxesHelper,
    BoxGeometry,
    Color,
    Fog,
    Mesh,
    MeshBasicMaterial,
    MeshLambertMaterial,
    PerspectiveCamera,
    PlaneGeometry,
    Scene,
    SphereGeometry,
    SpotLight,
    WebGLRenderer
} from 'three';
import { ref, reactive, onMounted, watch } from 'vue'
import Stats from 'stats.js'
import * as dat from 'dat.gui'

const containerRef = ref<HTMLDivElement>()
const statsRef = ref<HTMLDivElement>()
const stats = new Stats()
stats.dom.style.top = "50px"
stats.showPanel(0)
// 创建场景
const scene = new Scene()
// 创建照相机
const camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
// 设置摄像机位置
camera.position.set(-30, 40, 30)
// 设置摄像机朝向(看哪)
camera.lookAt(scene.position)
// webgl渲染器
const renderer = new WebGLRenderer()
renderer.setClearColor(new Color(0xeeeeee))
renderer.setSize(window.innerWidth, window.innerHeight)
// 可以渲染阴影
renderer.shadowMap.enabled = true

// 光源
const spotLight = new SpotLight(0xffffff)
spotLight.castShadow = true
spotLight.position.set(-40, 60, -10)
scene.add(spotLight)

// 添加平面几何体
const planeGeometry = new PlaneGeometry(60, 20)
// 添加材质
const meshBasicMaterial = new MeshLambertMaterial({ color: 0xcccccc })
const plane = new Mesh(planeGeometry, meshBasicMaterial)
// 接受阴影
plane.receiveShadow = true
// 调整位置
plane.rotation.x = -0.5 * Math.PI //放平
plane.position.x = 15
plane.position.y = 0
plane.position.z = 0
scene.add(plane)

// 添加几何体
const cubeGeometry = new BoxGeometry(4, 4, 4)
const cubeMaterial = new MeshLambertMaterial({ color: 0xff0000, wireframe: false })
const cube = new Mesh(cubeGeometry, cubeMaterial)
cube.castShadow = true
cube.position.set(2, 2, 2)
scene.add(cube)

// 球体
const sphereGeometry = new SphereGeometry(4)
const sphereMaterial = new MeshLambertMaterial({ color: 0x7777ff, wireframe: false })
const sphere = new Mesh(sphereGeometry, sphereMaterial)
sphere.castShadow = true
sphere.position.x = 20
sphere.position.y = 4
sphere.position.z = 2
scene.add(sphere)
// 添加坐标系
const axes = new AxesHelper(20)
scene.add(axes)

const controlRef = ref({
    rotationSpeed: 0.02,//旋转速度
    bouncingSpeed: 0.03,//弹跳速度
    numberOfObjects: 0,//统计
    addCube: function () {
        const cubeGeometry = new BoxGeometry(4, 4, 4)
        // const cubeMaterial = new MeshLambertMaterial({ color: Math.random() * 255, wireframe: false })
        const cube = new Mesh(cubeGeometry, cubeMaterial)
        cube.name = "cube-" + scene.children.length
        cube.castShadow = true
        cube.position.x = -30 + Math.round((Math.random() * 60))
        cube.position.y = Math.round((Math.random() * 5))
        cube.position.z = -20 + Math.round((Math.random() * 40))
        scene.add(cube)
        // console.log(scene.children);
        this.numberOfObjects = scene.children.length
    },
    // 删除
    remove: function () {
        // 拿到所有子物体
        const allChildren = scene.children
        // 拿到最后一个
        const lastObject = allChildren[allChildren.length - 1]
        if (lastObject instanceof Mesh && lastObject.name.startsWith('cube')) {
            scene.remove(lastObject)
        }
        this.numberOfObjects = scene.children.length
    },
    // 雾化
    addFog: function () {
        const fog = new Fog(0xffffff, 0.015, 100)
        fog.name = 'fog'
        scene.fog = fog
        this.numberOfObjects = scene.children.length
    },
    // 移除雾化 
    removeFog: function () {
        scene.fog = null
    },
    // 改变材质
    toggleMaterial: function () {
        if (!scene.overrideMaterial) {
            scene.overrideMaterial = new MeshLambertMaterial({
                color: 0xffffff
            })
        } else {
            scene.overrideMaterial = null
        }
    },
    scaleX: 1,
    scaleY: 1,
    scaleZ: 1,
    positionX: 1,
    positionY: 1,
    positionZ: 1,
    translateX: 0,
    translateY: 0,
    translateZ: 0,
    obj: {
        x: 0,
        y: 0,
        z: 0,
    },
    translate: function () {
        this.obj.x = this.translateX
        this.obj.y = this.translateY
        this.obj.z = this.translateZ
    }
})
// const gui = new dat.GUI()
// gui.add(controlRef.value,"rotationSpeed",0,0.5)
// gui.add(controlRef.value,"bouncingSpeed",0,0.5)
// 判斷
if (document.querySelectorAll(".dg.ac>.dg.main.a").length === 0) {
    const gui = new dat.GUI()
    gui.add(controlRef.value, "numberOfObjects").listen()
    gui.add(controlRef.value, "addCube")
    gui.add(controlRef.value, "remove")
    gui.add(controlRef.value, "addFog")
    gui.add(controlRef.value, "removeFog")
    gui.add(controlRef.value, "toggleMaterial")
    gui.add(controlRef.value, "rotationSpeed", 0, 0.5)
    gui.add(controlRef.value, "bouncingSpeed", 0, 0.5)

    // 折叠面板
    const scaleFolder = gui.addFolder('scale')
    scaleFolder.add(controlRef.value, "scaleX", 0, 5)
    scaleFolder.add(controlRef.value, "scaleY", 0, 5)
    scaleFolder.add(controlRef.value, "scaleZ", 0, 5)

    const positionFolder = gui.addFolder('position')
    positionFolder.add(controlRef.value, "positionX", -5, 5)
    positionFolder.add(controlRef.value, "positionY", -5, 5)
    positionFolder.add(controlRef.value, "positionZ", -5, 5)

    const translateFolder = gui.addFolder('translate')
    translateFolder.add(controlRef.value, "translateX", -5, 5)
    translateFolder.add(controlRef.value, "translateY", -5, 5)
    translateFolder.add(controlRef.value, "translateZ", -5, 5)
    translateFolder.add(controlRef.value, "translate")
}

watch(() =>
    controlRef.value.scaleX, (n) => {
        cube.scale.setX(n)
    }
)
watch(() =>
    controlRef.value.scaleY, (n) => {
        cube.scale.setY(n)
    }
)
watch(() =>
    controlRef.value.scaleZ, (n) => {
        cube.scale.setZ(n)
    }
)
watch(() =>
    controlRef.value.positionX, (n) => {
        cube.position.setX(n)
    }
)
watch(() =>
    controlRef.value.positionY, (n) => {
        cube.position.setY(n)
    }
)
watch(() =>
    controlRef.value.positionZ, (n) => {
        cube.position.setZ(n)
    }
)
watch(() => controlRef.value.obj, (n) => {
    cube.translateX(n.x)
    cube.translateX(n.y)
    cube.translateX(n.z)
}, { deep: true })


let step = 0

function renderScene() {
    stats.update()
    scene.traverse((e) => {
        // if (e instanceof Mesh && e != plane) {
        //     e.rotation.x += controlRef.value.rotationSpeed
        //     e.rotation.y += controlRef.value.rotationSpeed
        //     e.rotation.z += controlRef.value.rotationSpeed
        // }
        if (e.name.startsWith('cube')) {
            e.rotation.x += controlRef.value.rotationSpeed
            e.rotation.y += controlRef.value.rotationSpeed
            e.rotation.z += controlRef.value.rotationSpeed
        }
    })
    cube.rotation.x += controlRef.value.rotationSpeed
    cube.rotation.y += controlRef.value.rotationSpeed
    cube.rotation.z += controlRef.value.rotationSpeed

    step += controlRef.value.bouncingSpeed
    sphere.position.x = 20 + 10 * Math.cos(step)
    sphere.position.y = 2 * 10 * Math.abs(Math.sin(step))

    requestAnimationFrame(renderScene)
    renderer.render(scene, camera)
}

renderScene()
onMounted(() => {
    statsRef.value?.append(stats.dom)
    containerRef.value?.appendChild(renderer.domElement)
    renderer.render(scene, camera)
})

// 监听窗口变化
window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight
    // 更新相机投影矩阵
    camera.updateProjectionMatrix()
    renderer.setSize(window.innerWidth, window.innerHeight)
}, false)
</script>

<style scoped>

</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

林多多@

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

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

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

打赏作者

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

抵扣说明:

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

余额充值