ThreeJs实现小球自由落体效果

简介: 这篇文章详细介绍了如何在Three.js中利用物理引擎Cannon.js实现小球自由落体效果,包括物理世界的创建、物体的添加及同步物理状态到三维场景中的具体实现。

之前有做过关于Threejs基础功能的一些演示,包括绘制简单的模型,以及给这个模型添加一些动画,但是这些都还是停留在绘制的阶段,动画也是匀速移动,而非模仿自然界中的重力加速度以及阻力等效果实现的。

今天讲一个可以模拟自然界中一些物理属性的组件,这里引入一个新的组件Cannon,这是一个开源3D物理引擎,可以用来开发和模拟真实世界的物理效果,包括碰撞,重力,约束等,

Cannon.js的特点如下:

轻量级和高性能:Cannon.js被设计为一个快速而轻便的物理引擎,代码简洁且易于理解。 真实的物理模拟:Cannon.js提供了一套完整的3D物理模拟功能,包括刚体碰撞、力学模拟和约束等。这使得开发者可以模拟真实世界中的物理效果。 灵活的约束系统:Cannon.js的约束系统非常灵活,并且支持各种类型的约束,如距离约束、弹簧约束、旋转约束等。开发者可以根据需要创建各种类型的约束。 基于WebGL:Cannon.js与WebGL技术结合使用,可以轻松实现在浏览器中展示3D物理效果,并且与其他WebGL应用程序进行集成。 跨平台兼容性:Cannon.js可以在多种浏览器上运行,并且支持移动设备和桌面设备。这使得开发者可以轻松地在各种平台上开发和运行物理模拟应用程序。 下面来制作一个通过cannon来制作的一个自由落体的效果,因为传统threejs,即使做成动画效果一般也只是匀速移动,很难做出下落时有重力加速度的效果,首先还是需要用threejs绘制一个场景,在场景中去添加cannon的一些属性和方法,主要流程如下,先创建一个物理世界,在物理世界中添加一个球体和一个底面,让球落到底面,但是因为cannon中不提供具体的模型显示,所以我们需要根据物理模型来构建实体模型,并同步物理模型中的球体位置到实体模型中的物体位置。

按照threejs的步骤搭建一个3D场景,下面在物理场景中添加一个地面以及一个球体:

// 实体模型的网格小球,这里是用来对应显示物理模型下的球体位置
      const geometry = new THREE.SphereGeometry(3);
      const material = new THREE.MeshLambertMaterial({
        color: 0x00ffff,
      });
      this.boxmesh = new THREE.Mesh(geometry, material);
      this.scene.add(this.boxmesh)

      //实体地面的网格模型,这里用来显示对应物理对应的地面
      const planeGeometry = new THREE.PlaneGeometry(200, 200);
      const planeMaterial = new THREE.MeshLambertMaterial({
        color:0x777777,
      });
      const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
      planeMesh.rotateX(-Math.PI / 2);
      this.scene.add(planeMesh)

效果如下

ThreeJs实现小球自由落体效果_实体模型

下面要给这个小球添加物理属性,比如重力加速度以及落地后根据材质的不同设置回弹的系数,物理属性实际上是配置另一套物理模型,新建物理世界,在物理世界中创建小球模型和地面模型,然后将threejs中我们绘制的模型与物理世界的模型绑定起来,当物理世界的球体位置发生变化的时候,threejs场景中球体位置也随着发生变化,那么就等于是吧物理引擎的一套规则投射到threejs场景中了,下面就需要创建一套物理世界的规则:

//新建一个物理模型世界
      this.world = new CANNON.World();
      // 设置物理世界重力加速度,此处设置为y轴的反方向,也就是往y轴反方向存在重力
      this.world.gravity.set(0, -9.8, 0);

      // 新建一个物理小球:对应threejs的网格小球
      const sphereMaterial = new CANNON.Material()
      this.box = new CANNON.Body({
        mass: 1,//碰撞体质量
        material: sphereMaterial,//设置小球的材质
        shape:new CANNON.Sphere(3),//设置小球的半径大小
      });
      this.box.position.y = 100;//设置小球的位置
      this.world.addBody(this.box);//将小球添加到物理世界中

      // 新建物理地面
      const groundMaterial = new CANNON.Material()
      const groundBody = new CANNON.Body({
        mass: 0, // 质量为0,始终保持静止,不会受到力碰撞或加速度影响
        shape:new CANNON.Plane(),//新建物理模型的底面
        material: groundMaterial,//地面材质
      });
      // 改变平面默认的方向,法线默认沿着z轴,旋转到平面向上朝着y方向
      groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0);
      this.world.addBody(groundBody);

创建完成后为了动态效果还需要再渲染中刷新页面:

initAnimate() {
      requestAnimationFrame(this.initAnimate);
      this.world.step(1/60);
      // 渲染循环中,同步物理球body与网格球mesh的位置
      this.boxmesh.position.copy(this.box.position);
      this.renderer.render(this.scene, this.camera);
    },

最终的完整代码如下:

initCarton(){
      //新建一个物理模型世界
      this.world = new CANNON.World();
      // 设置物理世界重力加速度,此处设置为y轴的反方向,也就是往y轴反方向存在重力
      this.world.gravity.set(0, -9.8, 0);

      // 新建一个物理小球:对应threejs的网格小球
      const sphereMaterial = new CANNON.Material()
      this.box = new CANNON.Body({
        mass: 1,//碰撞体质量
        material: sphereMaterial,//设置小球的材质
        shape:new CANNON.Sphere(3),//设置小球的半径大小
      });
      this.box.position.y = 100;//设置小球的位置
      this.world.addBody(this.box);//将小球添加到物理世界中

      // 新建物理地面
      const groundMaterial = new CANNON.Material()
      const groundBody = new CANNON.Body({
        mass: 0, // 质量为0,始终保持静止,不会受到力碰撞或加速度影响
        shape:new CANNON.Plane(),//新建物理模型的底面
        material: groundMaterial,//地面材质
      });
      // 改变平面默认的方向,法线默认沿着z轴,旋转到平面向上朝着y方向
      groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0);
      this.world.addBody(groundBody);

      // 设置地面材质和小球材质之间的碰撞反弹恢复系数,也就是底面和小球的材质之间存在的反弹系数,
      const contactMaterial = new CANNON.ContactMaterial(groundMaterial, sphereMaterial, {
        restitution: 0.5 //反弹恢复系数
      })
      // 把关联的材质添加到物理世界中
      this.world.addContactMaterial(contactMaterial)

      // 实体模型的网格小球,这里是用来对应显示物理模型下的球体位置
      const geometry = new THREE.SphereGeometry(3);
      const material = new THREE.MeshLambertMaterial({
        color: 0x00ffff,
      });
      this.boxmesh = new THREE.Mesh(geometry, material);
      this.scene.add(this.boxmesh)

      //实体地面的网格模型,这里用来显示对应物理对应的地面
      const planeGeometry = new THREE.PlaneGeometry(200, 200);
      const planeMaterial = new THREE.MeshLambertMaterial({
        color:0x777777,
      });
      const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
      planeMesh.rotateX(-Math.PI / 2);
      this.scene.add(planeMesh)
    },

    initAnimate() {
      requestAnimationFrame(this.initAnimate);
      this.world.step(1/60);
      // 渲染循环中,同步物理球body与网格球mesh的位置
      this.boxmesh.position.copy(this.box.position);
      this.renderer.render(this.scene, this.camera);
    },

实现效果如下:

这里不支持上传视频,我就只能上传个图片了,如果想看动态效果可以私我,我发给你视频,或者需要源码也可以给我私信:

ThreeJs实现小球自由落体效果_实体模型_02

相关文章
|
Java
clone()方法使用时遇到的问题解决方法(JAVA)
我们平时在自定义类型中使用这个方法时会遇到的 4 个问题。
303 1
|
8月前
|
人工智能 计算机视觉 Python
CodeBuddy 实现图片转素描手绘工具
总的来说,这次使用 CodeBuddy 实现图片转素描手绘工具的体验非常棒。它不仅帮我实现了一直想尝试的功能,还让我在开发过程中学习到了很多新知识和技巧。如果你也和我一样,对编程实现有趣的功能感兴趣,又担心自己搞不定复杂的代码,不妨试试 CodeBuddy,相信它会给你带来惊喜!
222 1
|
开发框架 JavaScript 前端开发
使用 Node.js 和 Express 构建 Web 应用
【10月更文挑战第2天】使用 Node.js 和 Express 构建 Web 应用
tp5时间戳字段报错Invalid datetime format: 1292 Incorrect datetime value
tp5时间戳字段报错Invalid datetime format: 1292 Incorrect datetime value
660 0
|
搜索推荐 前端开发 UED
惊!这些前端技巧竟然能让你的网站在搜索引擎中获得更高排名!
【10月更文挑战第30天】在数字化时代,网站的搜索引擎排名直接影响流量和品牌知名度。本文通过四个真实案例,揭秘前端技巧如何提升搜索引擎排名:1. 关键词优化与布局;2. 高质量内容与多媒体优化;3. 网站结构优化与URL优化;4. 提升页面加载速度。这些技巧不仅提高排名,还能增强用户体验,助力业务发展。
263 3
|
安全 Ubuntu Linux
Linux系统无法启动或启动过程中卡住
【10月更文挑战第5天】
2267 3
|
JavaScript 前端开发
js怎样获取浏览器窗口尺寸
js怎样获取浏览器窗口尺寸
|
缓存 算法 网络协议
盘点腾讯后台开发各级工程师(T1-T9)需要具备哪些能力
盘点腾讯后台开发各级工程师(T1-T9)需要具备哪些能力
盘点腾讯后台开发各级工程师(T1-T9)需要具备哪些能力
element中el-radio无法切换点击和input框无法输入的问题(整理)
element中el-radio无法切换点击和input框无法输入的问题(整理)
|
NoSQL Linux
centos 7 源代码安装新版本gdb
centos 7 源代码安装新版本gdb
583 0

热门文章

最新文章