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

我们用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://www.mfbz.cn/a/434980.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python - Pycharm 配置 autopep8 并设置快捷键

什么是 PEP8 官方&#xff1a;PEP 8 – Style Guide for Python Code | peps.python.org PEP8 是 Python 官方推出的一套编码的规范&#xff0c;只要代码不符合它的规范&#xff0c;就会有相应的提示&#xff0c;还可以让代码自动的格式化 Pycharm 自带的代码格式化 ​ 但这…

【C++】String常用的函数总结

目录 一、string的构造函数方式&#xff1a; 二、常用的大小/容量相关操作&#xff1a; 三、string的常用修改操作&#xff1a; 四、string的遍历&#xff1a; 五、string的任意位置插入 / 删除&#xff1a; 六&#xff1a;补充&#xff1a; 一、string的构造函数方式&a…

JavaWeb环境配置 IDE2022版

一、新建一个javaweb文件 文件名可以自己随意改 二、给建立的项目添加框架支持 勾选Web Application,点击确定 建立成功界面&#xff0c;会生成一个新的web文件夹 三、配置tomcat 1、两种打开配置文件方式&#xff1a; 第一种 第二种 2、打开后&#xff0c;点击号&#xf…

LLM | Gemma的初体验

一起来体验一下吧~ google/gemma-7b-it Hugging Face 此型号卡对应于 Gemma 型号的 7B 指令版本。还可以选择 2B 基本模型、7B 基本模型和 2B 指导模型的模型卡。 微调 使用 QLoRA 对 UltraChat 数据集执行监督微调 &#xff08;SFT&#xff09; 的脚本在 TPU 设备上使用 FS…

鸿蒙Harmony应用开发—ArkTS声明式开发(手势处理:绑定手势方法)

为组件绑定不同类型的手势事件&#xff0c;并设置事件的响应方法。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 绑定手势识别 通过如下属性给组件绑定手势识别&#xff0c;手势识别成功后可以通过事…

LVS负载均衡集群基础概念

目录 一、集群 1、集群概述 1.1 什么是集群 1.2 集群系统扩展方式 1.2.1 Scale UP&#xff08;纵向扩展&#xff09; 1.2.2 Scale OUT&#xff08;横向扩展&#xff09; 1.2.3 区别 1.3 分布式系统 1.4 分布式与集群 1.5 集群设计原则 1.6 集群设计实现 1.6.1 基础…

手回科技:人生的“小雨伞”,能否撑起自己的增长路?

有道是一年之计在于春。新年伊始&#xff0c;多家券商发布研报表达了对2024年保险市场表现的观点。 比如&#xff0c;开源证券表示&#xff0c;政策组合拳带来beta催化&#xff0c;保险业务端和弹性占优&#xff1b;中国银行证券指出&#xff0c;2024年&#xff0c;保险行业景…

Leetcode 第 125 场双周赛题解

Leetcode 第 125 场双周赛题解 Leetcode 第 125 场双周赛题解题目1&#xff1a;3065. 超过阈值的最少操作数 I思路代码复杂度分析 题目2&#xff1a;3066. 超过阈值的最少操作数 II思路代码复杂度分析 题目3&#xff1a;3067. 在带权树网络中统计可连接服务器对数目思路代码复杂…

Marin说PCB之POC电路layout设计仿真案例---01

最近娃哈哈饮料突然爆火&#xff0c;看新闻后才知道春晚的的时候宗老已经病的很严重了&#xff0c;现在也已经离我们而去了&#xff0c;宗老是一个值得我们尊敬爱戴的伟大企业家。于是乎小编我立马去他们的直播间买了一箱娃哈哈AD钙奶支持一下我们的国货。 中午午休的时候&…

智慧城市的未来:利用数字孪生技术推动智慧城市的智能化升级

目录 一、引言 二、数字孪生技术概述 三、数字孪生技术在智慧城市中的应用 1、城市规划与建设 2、城市管理与运营 3、公共服务与民生改善 4、应急管理与灾害防控 四、数字孪生技术推动智慧城市的智能化升级的价值 1、提高城市管理的智能化水平 2、优化城市资源配置 …

python将conda环境打入docker环境中

1.假设你本地已经安装好了conda相关的 ubuntu安装python以及conda-CSDN博客 并且已经创建启动过相关的环境&#xff0c;并且install了相关的包。 我本地的conda环境叫做,gptsovits_conda3 2.下载conda打包工具 conda install conda-pack pip install conda-pack 3.打包 con…

java八股文复习-----2024/03/04----基础

相关资源 大彬八股文 2024八股文 2024秋招八股文 1.了解Java的包装类型吗&#xff1f;为什么需要包装类&#xff1f; Java 是一种面向对象语言&#xff0c;很多地方都需要使用对象而不是基本数据类型。比如&#xff0c;在集合类中&#xff0c;我们是无法将 int 、double 等类型…

lvs集群介绍

目录 一、LVS集群基本介绍 1、什么是集群 2、集群的类型 2.1 负载均衡群集&#xff08;Load Balance Cluster) 2.2 高可用群集(High Availiablity Cluster) 2.3 高性能运算群集(High Performance Computing Cluster) 3、负载均衡集群的结构 ​编辑 4、LVS集群类型中的…

苹果电脑安装Android Studio和配置SDK

大家好&#xff0c;我是你们的好朋友咕噜铁蛋&#xff01;今天&#xff0c;我们要来聊一聊关于《苹果电脑安装Android Studio和配置SDK》这个话题。对于使用苹果电脑的开发者来说&#xff0c;安装Android Studio并配置SDK可能会有些不同&#xff0c;但只要跟着我的指引&#xf…

Linux篇:基础IO

一 预备知识 1. 文件内容属性&#xff0c;内容与属性都是数据&#xff0c;都要在磁盘中保存。 2. 文件分为打开的文件和没打开的文件。 3. 进程在访问一个文件的时候&#xff0c;都是要先打开这个文件。打开文件之前&#xff0c;文件在磁盘&#xff0c;打开文件之后&#xff0…

基于OpenCV的图形分析辨认02

目录 一、前言 二、实验目的 三、实验内容 四、实验过程 一、前言 编程语言&#xff1a;Python&#xff0c;编程软件&#xff1a;vscode或pycharm&#xff0c;必备的第三方库&#xff1a;OpenCV&#xff0c;numpy&#xff0c;matplotlib&#xff0c;os等等。 关于OpenCV&…

【python 1】----Pytest基础知识

定义 用于编写和执行Python测试全功能测试框架&#xff08;工具&#xff09;&#xff0c;是一个第三方库 安装 pip insatll pytest 安装pytest --version 校验 pytest的组成构成 不写调用语句也可以执行函数内容 在用例运行语句里面&#xff1a; -s:指的是开启与终端的…

【CSP试题回顾】201512-2-消除类游戏

CSP-201512-2-消除类游戏 解题思路 输入棋盘大小和颜色: 首先&#xff0c;程序从标准输入读取两个整数n和m&#xff0c;分别代表棋盘的行数和列数。然后&#xff0c;程序读取接下来的n行输入&#xff0c;每行包含m个整数&#xff0c;代表棋盘上每个方格中的棋子颜色。 初始化…

电子台账:通过标签颜色快速区分某月账页是否为空、是否锁定

目录 1 数据为空的账页&#xff0c;标签顶部没有标记色条 2 包含有效数据的账页且未进行锁定&#xff0c;标签顶部为深绿色标记色条 3 包含有效数据的账页且被锁定&#xff0c;标签顶部为橙色标记色条 通过设置账页标签的颜色&#xff0c;快速区分哪些月份的账页数据为空&am…

【书生·浦语大模型实战营】第6节 OpenCompass 大模型评测 课后作业

OpenCompass 大模型评测 0. 课程链接1. 课后作业1.1 基础作业1.2 进阶作业 2. 结业总结 0. 课程链接 链接&#xff1a;https://github.com/InternLM/tutorial/blob/main/opencompass/opencompass_tutorial.md 1. 课后作业 1.1 基础作业 使用 OpenCompass 评测 InternLM2-Cha…
最新文章