当前位置:首页 » 《关于电脑》 » 正文

Three.js--》探寻Cannon.js构建震撼的3D物理交互体验(二)

24 人参与  2024年03月28日 14:15  分类 : 《关于电脑》  评论

点击全文阅读


我们用three.js可以绘制出各种酷炫的画面,但是当我们想要一个更加真实的物理效果的话,这个时候我们就需要一个物理的库,接下来我们就讲解一下今天要学习的canon,它可以给我们提供一个更加真实的物理效果,像物体的张力、摩擦力、拉伸、反弹等等各种真实的物理效果。该库都能够有一个非常好的模拟。

PS:目前博主在一家互联网公司工作,该公司的编码风格是vue+tsx,所以接下来的项目以该编码风格进行举例,详细了解参考我之前的文章:地址 。

目录

碰撞与碰撞事件

休眠与休眠事件

物体形状组合

物体施加作用力


碰撞与碰撞事件

在上一篇文章我们讲解到了碰撞的一些基本概念:地址 ,接下来我们开始学习如何监听和获取碰撞的事件和信息,如下:

得到的结果如下所示:

我们可以点击监听信息e查看一下,有如下重要的信息:

我们点击contact进入到里面,可以找到一个函数来查看当前物体碰撞的碰撞速度:

接下来通过函数来对当前物体的碰撞速度度进行一个监听:

// 监听立方体boxBody.addEventListener("collide", (e) => {    console.log("碰撞了", e)    let impactStrength = e.contact.getImpactVelocityAlongNormal()    console.log("当前的碰撞速度:", impactStrength)})

可以看到,随着时间的流逝,碰撞的高度逐渐减小,物体相互之间的碰撞速度也在逐渐减少:

休眠与休眠事件

物体的休眠指的是当物体在物理世界中没有发生运动时,会进入休眠状态以减少计算负担。当物体处于休眠状态时,物理引擎会暂停对该物体的碰撞检测和运动模拟,从而节省计算资源。只有在物体被外力唤醒(如碰撞或施加力)时,物体才会从休眠状态中唤醒,重新参与物理模拟。休眠状态有助于提高物理引擎的性能并减少不必要的计算开销。

我们在开始的时候允许物理世界的物体可以进入休眠状态:

然后我们可以设置立方体可以进入休眠状态,以及进入休眠状态的一些条件:

如下可以看到我们已经实现了立方体休眠的效果:

当然如果想监听休眠事件的话可以通过如下的方式进行:

在最后的那一刻物体进入到了休眠的状态:

物体形状组合

接下来我们通过设置物体的位置,让物体之间相互组合在一起,如下:

// 创建由两个球加一个圆柱体组成的胶囊体const capsuleBody = new CANNON.Body({    mass: 1,    position: new CANNON.Vec3(0, 5, 0),    material: boxMaterialCon,})// 创建一个球的几何体const sphereShape = new CANNON.Sphere(0.5)// 创建一个圆柱体几何体const cylinderShape = new CANNON.Cylinder(0.5, 0.5, 1.5, 20)// 将球体和圆柱体添加到body中capsuleBody.addShape(sphereShape, new CANNON.Vec3(0, 0.75, 0))capsuleBody.addShape(cylinderShape, new CANNON.Vec3(0, 0, 0))capsuleBody.addShape(sphereShape, new CANNON.Vec3(0, -0.75, 0))// 将body添加到物理世界中world.addBody(capsuleBody)phyMeshes.push(capsuleBody)// 创建胶囊体网格const capsuleGeometry =new THREE.CylinderGeometry(0.5, 0.5, 1.5, 20);const capsuleMaterial=new THREE.MeshBasicMaterial({color: 0x00ff00 })const capsuleMesh = new THREE.Mesh(capsuleGeometry, capsuleMaterial);capsuleMesh.position.copy(capsuleBody.position);capsuleMesh.quaternion.copy(capsuleBody.quaternion);scene.add(capsuleMesh);meshes.push(capsuleMesh);//创建一个球体const sphereGeometry = new THREE.SphereGeometry(0.5, 20, 20);const sphereMaterial=new THREE.MeshBasicMaterial({ color: 0x0000ff })const sphereMesh =new THREE.Mesh(sphereGeometry, sphereMaterial);sphereMesh.position.set(0, 0.75, 0);capsuleMesh.add(sphereMesh);const sphereMesh2 = new THREE.Mesh(sphereGeometry, sphereMaterial);sphereMesh2.position.set(0, -0.75, 0);capsuleMesh.add(sphereMesh2);

得到的代码效果如下所示:

接下来我们给胶囊添加一个水平的速度,然后减少弹性系数增加摩擦系数,看看胶囊会不会倒下

得到的效果如下所示:

具体操作代码如下:

import { defineComponent } from "vue";import * as THREE from 'three'import { OrbitControls }  from 'three/examples/jsm/controls/OrbitControls.js'import * as CANNON from 'cannon-es'import './index.scss'export default defineComponent({    setup() {        // 初始化物理世界        const world = new CANNON.World()        // 初始化物理世界的重力        world.gravity.set(0, -9.82, 0)        // 设置物理世界允许休眠        world.allowSleep = true                // 初始化3D世界        const scene = new THREE.Scene()        // 初始化相机        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)        camera.position.z = 8        camera.position.y = 5        camera.position.x = 2        // 初始化渲染器        const renderer = new THREE.WebGLRenderer({ antialias: true })        renderer.setSize(window.innerWidth, window.innerHeight)        document.body.appendChild(renderer.domElement)        // 初始化控制器        const controls = new OrbitControls(camera, renderer.domElement)        controls.enableDamping = true        // 创建网格数组        let phyMeshes: any[] = [] // 物理世界        let meshes: any[] = [] // 渲染世界        // 设置立方体的材质        const boxMaterialCon = new CANNON.Material("boxMaterial")        boxMaterialCon.friction = 0.2        boxMaterialCon.restitution = 0.1 // 设置弹性        // 创建由两个球加一个圆柱体组成的胶囊体        const capsuleBody = new CANNON.Body({            mass: 1,            position: new CANNON.Vec3(0, 5, 0),            material: boxMaterialCon,        })        // 创建一个球的几何体        const sphereShape = new CANNON.Sphere(0.5)        // 创建一个圆柱体几何体        const cylinderShape = new CANNON.Cylinder(0.5, 0.5, 1.5, 20)        // 将球体和圆柱体添加到body中        capsuleBody.addShape(sphereShape, new CANNON.Vec3(0, 0.75, 0))        capsuleBody.addShape(cylinderShape, new CANNON.Vec3(0, 0, 0))        capsuleBody.addShape(sphereShape, new CANNON.Vec3(0, -0.75, 0))        // 将body添加到物理世界中        world.addBody(capsuleBody)        phyMeshes.push(capsuleBody)        // 创建胶囊体网格        const capsuleGeometry =new THREE.CylinderGeometry(0.5, 0.5, 1.5, 20);        const capsuleMaterial=new THREE.MeshBasicMaterial({color: 0x00ff00 })        const capsuleMesh = new THREE.Mesh(capsuleGeometry, capsuleMaterial);        capsuleMesh.position.copy(capsuleBody.position);        capsuleMesh.quaternion.copy(capsuleBody.quaternion);        scene.add(capsuleMesh);        meshes.push(capsuleMesh);        // 给胶囊一个水平的速度        capsuleBody.velocity.set(2, 0, 0)        //创建一个球体        const sphereGeometry = new THREE.SphereGeometry(0.5, 20, 20);        const sphereMaterial=new THREE.MeshBasicMaterial({ color: 0x0000ff })        const sphereMesh =new THREE.Mesh(sphereGeometry, sphereMaterial);        sphereMesh.position.set(0, 0.75, 0);        capsuleMesh.add(sphereMesh);        const sphereMesh2 = new THREE.Mesh(sphereGeometry, sphereMaterial);        sphereMesh2.position.set(0, -0.75, 0);        capsuleMesh.add(sphereMesh2);        // 创建一个物理世界的平面        // const planeShape = new CANNON.Plane()        const planeShape = new CANNON.Box(new CANNON.Vec3(5, 0.1, 5))        // 创建一个刚体        const planeBody = new CANNON.Body({            // mass: 0, // 设置质量为0,不受碰撞的影响            shape: planeShape,            position: new CANNON.Vec3(0, 0.1, 0),            type: CANNON.Body.STATIC, // 设置物体为静态,不受碰撞的影响            material: boxMaterialCon,        })        // 将刚体添加到物理世界当中        world.addBody(planeBody)        // 物理世界创建的东西不显示,所以我们要再通过three.js再创建一个平面        // const planeGeometry = new THREE.PlaneGeometry(10, 10) // 因为渲染的东西不是无限衍生,这里给10x10        const planeGeometry = new THREE.BoxGeometry(10, 0.2, 10)        // 创建一个平面材质        const planeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 })        // 创建一个平面网格        const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)        // 旋转平面90度让其平铺        // planeMesh.rotation.x = 0.1        // 将网格添加到3D场景当中        scene.add(planeMesh)                // 渲染        let clock = new THREE.Clock()        const animate = () => {            // 获取了两次渲染之间的时间差,通常用于控制动画和物理模拟。            let delta = clock.getDelta()            world.step(delta)            // 使用时间差来推进物理世界的模拟            for(let i = 0; i < phyMeshes.length; i++) {                meshes[i].position.copy(phyMeshes[i].position)                meshes[i].quaternion.copy(phyMeshes[i].quaternion)            }            controls.update()            renderer.render(scene, camera)            requestAnimationFrame(animate)        }        animate()        return () => {            <div></div>        }    }})

物体施加作用力

在cannon中我们也可以给物体施加一些作用力,体验网站:地址 ,这里面动态的给我们显示了给物体施加作用力的效果:

接下来我们通过代码进行一个简单的实现,创建一个物理球:

然后我们设置一个点击事件,当发生点击之后,球会沿着水平方向移动,并且会发生旋转:

// 监听点击事件window.addEventListener("click", () => {    sphereBody.applyForce(new CANNON.Vec3(10, 0, 0), new CANNON.Vec3(0, 0.5, 0),)})

效果如下,我不断的点击鼠标,小球就往前移动:

当然还有如下的操作方式,这里就不再一一赘述了,感兴趣的可以自行尝试:


点击全文阅读


本文链接:http://zhangshiyu.com/post/87158.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1