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

news/2024/4/16 16:09:58/文章来源:https://blog.csdn.net/qq_53123067/article/details/136502446

我们用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 = 8camera.position.y = 5camera.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.2boxMaterialCon.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) // 因为渲染的东西不是无限衍生,这里给10x10const 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.luyixian.cn/news_show_996299.aspx

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

相关文章

Django学习记录08——图表及文件上传案例

1.图表Echarts的应用 Apache ECharts 1.1 使用方法 引用echarts.js即可到官方文档中查询使用 1.2 常用图标的使用 图表展示页面的部署&#xff08;主要展示折线图、柱状图、饼图&#xff09; {% block content %}<div class"container"><div class&qu…

Java单测Mock升级实践

Java单测Mock升级实践 一、背景 众所周知&#xff0c;单元测试是改善代码质量&#xff0c;提升研发交付品质的手段之一&#xff0c;能否写出好的单元测试用例&#xff0c;也是衡量我们研发专业性的标准之一。所以&#xff0c;想要成为一名合格的研发&#xff0c;就应该要有编…

Android Studio中debug功能详解

本文为大家分享了Android Studio debug功能的具体使用方法&#xff0c;供大家参考&#xff0c;具体内容如下 运行debug模式 \1. 进入debug – 点击图中红色圆圈圈起的左边绿色按钮&#xff0c;运行app的debug模式&#xff0c;快捷键ShiftF9 – 点击图中红色圆圈圈起的右边按…

【异常处理】Vue报错 Component template should contain exactly one root element.

问题描述 启动VUE项目后控制台报错&#xff1a; Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.翻译为&#xff1a;组件模板应该只包含一个根元素 查看vue代码&#xff0…

恢复IDEA误删除的git提交,提交被删除,尝试恢复提交

​​​​​​ dgqDESKTOP-JRQ5NMD MINGW64 /f/IdeaProjects/workspace/spzx-parent ((8bb112e...)) $ git reflog 8bb112e (HEAD, origin/master, master) HEAD{0}: checkout: moving from master to 8bb112e5ac18dfe4bbd64adfd06363e46b609f21 8bb112e (HEAD, origin/master, …

Objective-C blocks 概要

1.block的使用 1.1什么是block&#xff1f; Blocks是C语言的扩充功能&#xff1a;带有自动变量&#xff08;局部变量&#xff09;的匿名函数。 “带有自动变量”在Blocks中表现为“截取自动变量" “匿名函数”就是“不带名称的函数” 块&#xff0c;封装了函数调用及调用…

【LeetCode:98. 验证二叉搜索树 + 递归】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

【树上倍增】【割点】 【换根法】3067. 在带权树网络中统计可连接服务器对数目

作者推荐 视频算法专题 本文涉及知识点 树上倍增 树 图论 并集查找 换根法 深度优先 割点 LeetCode3067. 在带权树网络中统计可连接服务器对数目 给你一棵无根带权树&#xff0c;树中总共有 n 个节点&#xff0c;分别表示 n 个服务器&#xff0c;服务器从 0 到 n - 1 编号…

剑指offer 二维数组中的查找 C++

目录 前言 一、题目 二、解题思路 1.直接查找 2.二分法 三、输出结果 前言 最近在牛客网刷题&#xff0c;刷到二维数组的查找&#xff0c;在这里记录一下做题过程 一、题目 描述 在一个二维数组中&#xff08;每个一维数组的长度相同&#xff09;&#xff0c;每一行都按照…

Rust入门:Rust如何调用C静态库的函数

关于Rust调用C&#xff0c;因为接口比较复杂&#xff0c;貌似Rust不打算支持。而对于C函数&#xff0c;则相对支持较好。 如果要研究C/Rust相互关系的话&#xff0c;可以参考&#xff1a; https://docs.rs/cxx/latest/cxx/ Rust ❤️ C 这里只对调用C静态库做一个最简短的介…

Linux第71步_将linux中的多个文件编译成一个驱动模块

学习目的&#xff1a;采用旧字符设备测试linux系统点灯&#xff0c;进一步熟悉其设计原理。采用多文件参与编译&#xff0c;深度学习编写Makefile&#xff0c;有利于实现驱动模块化设计。 1、创建MyOldLED目录 输入“cd /home/zgq/linux/Linux_Drivers/回车” 切换到“/home…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:PinchGesture)

用于触发捏合手势&#xff0c;触发捏合手势的最少手指为2指&#xff0c;最大为5指&#xff0c;最小识别距离为5vp。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 接口 PinchGesture(value?: { finge…

01_Maven

文章目录 Maven安装MavenMaven的工作流程配置MavenMaven的使用module和project的关系如何用Maven导包 如何用Maven进行项目构建指令介绍clean指令compile指令package指令install指令 Maven的依赖管理如何导包scope作用域依赖传递依赖冲突 使用Maven开发项目Junit如何使用Junit …

灵神笔记(1)----动态规划篇

文章目录 介绍动态规划入门&#xff1a;从记忆化搜索到递推打家劫舍递归记忆化递归递推滚动变量 背包0-1 背包递归写法记忆化递归 目标和记忆化搜索递推两个数组一个数组 完全背包记忆化递归搜索 零钱兑换记忆化递归递推 背包问题变形[至多|恰好|至少] 最长公共子序列记忆化搜索…

在CentOS中安装Docker

安装Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道。…

el-table 插入单选并进行校验

<template><div><el-form :model"list" ref"ruleForm"><el-table :data"list.tableData" style"width: 100%"><el-table-column prop"time" label"日期" width"180"><…

Linux——线程(2)

在上一篇博客中我介绍了Linux中的线程是什么样的&#xff0c;就如同进程可以通过 fork创建&#xff0c;可以被终止&#xff0c;可以退出一样&#xff0c;线程也可以被我们用户控制&#xff0c;这 篇博客我会介绍线程的控制&#xff0c;并且基于线程的控制所产生的一些问题进行 …

python+django+vue电影票订购系统dyvv4

电影院订票信息管理系统综合网络空间开发设计要求。目的是将电影院订票通过网络平台将传统管理方式转换为在网上操作&#xff0c;方便快捷、安全性高、交易规范做了保障&#xff0c;目标明确。电影院订票信息管理系统可以将功能划分为用户和管理员功能[10]。 语言&#xff1a;…

【学习心得】响应数据加密的原理与逆向思路

一、什么是响应数据加密&#xff1f; 响应数据加密是常见的反爬手段的一种&#xff0c;它是指服务器返回的不是明文数据&#xff0c;而是加密后的数据。这种密文数据可以被JS解密进而渲染在浏览器中让人们看到。 它的原理和过程图如下&#xff1a; 二、响应数据加密的逆向思路 …

【web安全】实战 批量横扫springboot命令执行漏洞

天命&#xff1a;这次目标批量横扫&#xff0c;但是没完全成功&#xff0c;也没完全失败 步骤1&#xff1a;磨刀准备 这次先针对漏洞来寻找目标&#xff0c;所以寻找这种 springboot 的目标 利用CVE漏洞&#xff0c;进行命令执行攻击 先找靶场训练一波&#xff0c;叠加反弹sh…