【Three.js基础学习】16.Physice

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

课程回顾

        物理库

            3D

            Ammo.js

            Cannon.js

            Oimo.js

            2D

            Matter.js

            P2.js

            Planck.js

            Box2D.js

        补充:一些看似3D的效果实际使用2D库来实现的

        物理 和 three.js的结合 概念补充

        假象在当前物体或场景外, 有一个看不见的物理量世界 ,那么遵循物理世界规则,若有一个小球在

        半空中掉落,碰触到地面,然后在滚落到旁边。这个时候 three.js 展示的每一帧都要获取这个物理量

        世界的位置信息,然后更新到three.js中,实现展示,因此需要资料库

        这里采用cannon.js

        1.下载,引入

        npm install --save cannon

        import CANNON from 'cannon'

        2.创建一个物理世界

        const world = new CANNON.world()

        world.gravity(0,-9.82,0) 添加重力  9.82 重力常量

        vec3 文档 https://schteppe.github.io/cannon.js/docs/classes/Vec3.html

        vec3 和 vector 区别

        vec3 是cannon.js中局部位置

        vector是three.js

        和three.js一样 想要创建网格 ,但是网格必须有个几何体

        同样cannon.js 想要创建身体 ,首先创建一个形状

        3.如何通过物理方式动起来

        在物理世界有了一个和three.js 一样的物理,但是要更新在tick中

        首先应该确保在跟新步长时候,保证精度(准确性)

        保证上一个更新帧率 和这次跟新帧率没有问题

        然后将物理世界的球的位置 设置到 three.js中

       

        4.球会一直往下,再来个地板

        此时会发现,地板是正对着摄像头,因为在three.js中我们旋转地板,那么在物理世界同样

        cannon.js中的旋转是使用四元数(上方文档)

        5.球应该弹起来

            需要材料,创建两种材料对应 球和地板

            例如:混泥土材料  (当然由于球和地板设置相同材质 ,所以 简化代码)

                塑料材料

            同时创建接触材料,就是混泥土遇到塑料材料情况

            new CANNON.ContactMaterial()

            放到world中,同时在物理世界中的物体也要应用上 这和three.js相似

            也不用一个一个设置,统一设置应用

            world.defaultContactMaterial = defaultContactMaterial

       

        6. 对物体施力的方法

            applyforce-从空间的指定点施加一个力(不一定是物体表面)比如风,在多米诺骨牌上轻轻一推,或者在愤怒的小鸟上施加一个很大的力

            applylmpulse类似applyforce,但不是增加力,而是增加速度

            applyLocalForce-与applyForce相同,但坐标是主体的局部(e,e,e将是主体的中心

            applyLocallmpulse-与applylmpulse相同,但坐标是主体的局部

        7. 将球写成一个函数,这样方便调用

       

        球体之间的碰撞 显示不出,但是不同物体 应当要旋转  quaternion

        8.GPU要测试每一个物体 之间是否碰撞 ,性能消耗 ,帧率下降

        Gannon.js 有范宽阶段

        例子:当一个球体向某一方向形式,反方向有一堆物体, 它不会去尽心测试是否该物体会碰撞反方向的物体,减少消耗

        NaiveBroadphase-tests every Bodies against every other Bodies

        GridBroadphase -quadrilles the world and only tests Bodies against other  // 网格范宽

        Bodies in the same grid box or the neighbors' grid boxes

        SAPBroadphase ((Sweep And Prune)-tests Bodies on arb!trary axes duringmultiples steps // 清除与清扫 效果更好

        world.allowSleep = true

        加入睡眠属性 :效果:让一些静止不动的物体,让它保持,当运动物体再次碰撞 ,在动起来

        同样可以优化性能问题:解决帧率下降的问题

        同时可以更改睡眠限时

        比如物体静止,过一秒,好的这个物体在睡觉

        9.添加声音

        10.如何移出物体

        11.限制条件

        HingeConstraint -acts like a door hinge.  (铰链约束:像门一样)

        DistanceConstraint -forces the bodies to keep a distance between each other (距离约束)

        LockConstraint -merges the bodies like if they were one piece (锁定约束)

        PointToPointConstraint -glues the bodies to a specific point (对点约束)


 

        12.cannonES  

        由于cannonJS ,不更新 ;因此在它的基础上cannonEs更新,替换掉

        npm uninstall --save cannon

        npm install --save cannon-es@0.15.1

        13. Amon.js

一、代码

import './style.css'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import * as dat from 'dat.gui'
import CANNON from 'cannon'/*** Debug*/
const gui = new dat.GUI()
const debugObject = {}
debugObject.createSphere = () =>{createSphere(Math.random() * 0.5,{x: (Math.random() - 0.5) * 3,y:3,z:(Math.random() - 0.5) * 3})
}
debugObject.createBox = () =>{createBox(Math.random(),Math.random(),Math.random(),{x: (Math.random() - 0.5) * 3,y:3,z:(Math.random() - 0.5) * 3})
}
debugObject.reset = () => {for(const object of objectsToUpdate){// removeobject.body.removeEventListener('collide',playHitSound)world.removeBody(object.body)// Remove scenescene.remove(object.mesh)}objectsToUpdate.splice(0,objectsToUpdate.length)
}gui.add(debugObject,'createSphere')
gui.add(debugObject,'createBox')
gui.add(debugObject,'reset')/*** Base*/
// Canvas
const canvas = document.querySelector('canvas.webgl')// Scene
const scene = new THREE.Scene()/* 
* sounds
*/
const hitSound = new Audio('/sounds/hit.mp3')
const playHitSound = (collisition) => {// 加入变量 ,判断碰撞产生的 冲击强度 ,小于一定程度不让播放// console.log(collisition.contact.getImpactVelocityAlongNormal())let impactStrength =  collisition.contact.getImpactVelocityAlongNormal()if(impactStrength > 1.5){hitSound.volume = Math.random() // 让声音产生不同大小hitSound.currentTime = 0 // 将播放时间重置0,不至于碰撞-》播放结束;碰撞-》播放结束hitSound.play()}}/*** Textures*/
const textureLoader = new THREE.TextureLoader()
const cubeTextureLoader = new THREE.CubeTextureLoader()const environmentMapTexture = cubeTextureLoader.load(['/textures/environmentMaps/0/px.png','/textures/environmentMaps/0/nx.png','/textures/environmentMaps/0/py.png','/textures/environmentMaps/0/ny.png','/textures/environmentMaps/0/pz.png','/textures/environmentMaps/0/nz.png'
])/* Physice
*/// World
const world = new CANNON.World()
world.broadphase = new CANNON.SAPBroadphase(world) // 优化,帧率下降;通过范宽阶段,减少GPU为计算每个物体碰撞的计算量
world.allowSleep = true
world.gravity.set(0,-9.82,0)// materials
const defaultMaterial = new CANNON.Material('default')  // 中间的参数其实只是命名 , 球和地板都用这个材质
const defaultContactMaterial = new CANNON.ContactMaterial( // 接触材质defaultMaterial,defaultMaterial,{friction:0.1,  // 摩擦系数restitution:0.7 //}
)
world.addContactMaterial(defaultContactMaterial) // 将材质添加物理世界
world.defaultContactMaterial = defaultContactMaterial // 统一 设置材质(当然也可以在body中单独设置)/* Floor
*/
const floorShape = new CANNON.Plane()
const floorBody = new CANNON.Body()
floorBody.mass = 0
floorBody.addShape(floorShape);
// 设置四元数 旋转
floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(-1,0,0),Math.PI * 0.5
)
world.add(floorBody);/*** Floor*/
const floor = new THREE.Mesh(new THREE.PlaneBufferGeometry(10, 10),new THREE.MeshStandardMaterial({color: '#777777',metalness: 0.3,roughness: 0.4,envMap: environmentMapTexture})
)
floor.receiveShadow = true
floor.rotation.x = - Math.PI * 0.5
scene.add(floor)/*** Lights*/
const ambientLight = new THREE.AmbientLight(0xffffff, 0.7)
scene.add(ambientLight)const directionalLight = new THREE.DirectionalLight(0xffffff, 0.2)
directionalLight.castShadow = true
directionalLight.shadow.mapSize.set(1024, 1024)
directionalLight.shadow.camera.far = 15
directionalLight.shadow.camera.left = - 7
directionalLight.shadow.camera.top = 7
directionalLight.shadow.camera.right = 7
directionalLight.shadow.camera.bottom = - 7
directionalLight.position.set(5, 5, 5)
scene.add(directionalLight)/*** Sizes*/
const sizes = {width: window.innerWidth,height: window.innerHeight
}window.addEventListener('resize', () =>
{// Update sizessizes.width = window.innerWidthsizes.height = window.innerHeight// Update cameracamera.aspect = sizes.width / sizes.heightcamera.updateProjectionMatrix()// Update rendererrenderer.setSize(sizes.width, sizes.height)renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})/*** Camera*/
// Base camera
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
camera.position.set(- 3, 3, 3)
scene.add(camera)// Controls
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true/*** Renderer*/
const renderer = new THREE.WebGLRenderer({canvas: canvas
})
renderer.shadowMap.enabled = true
renderer.shadowMap.type = THREE.PCFSoftShadowMap
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))/* Unites
*/
const objectsToUpdate = [];// sphere
// 将几何体,材质放到外部,避免性能消耗,防止重复创建时,都要创建一次几何体和材质
const sphereGeometry = new THREE.SphereBufferGeometry(1,20,20)
const sphereMaterial = new THREE.MeshStandardMaterial({metalness:0.3,roughness:0.4,envMap:environmentMapTexture
})const createSphere = (radius,position) =>{// Three.js meshconst mesh = new THREE.Mesh(sphereGeometry,sphereMaterial)mesh.scale.set(radius,radius,radius)mesh.castShadow  = true ; // 投射阴影mesh.position.copy(position)scene.add(mesh)// CANNON.js bodyconst shape = new CANNON.Sphere(radius)const body = new CANNON.Body({mass:1,position:new CANNON.Vec3(0,3,0),shape, // 这里注意大小写material:defaultMaterial})body.position.copy(position)body.addEventListener('collide',playHitSound) // 监听碰撞 collideworld.addBody(body)// save in objects to updateobjectsToUpdate.push({mesh,body})
}
createSphere(0.5,{x:0,y:3,z:0})//box
const boxGeometry = new THREE.BoxBufferGeometry(1,1,1) // 宽度,深度,高度
const boxMaterial = new THREE.MeshStandardMaterial({metalness:0.3,roughness:0.4,envMap:environmentMapTexture
})const createBox = (width,height,depth,position) =>{// Three.js meshconst mesh = new THREE.Mesh(boxGeometry,boxMaterial)mesh.scale.set(width,height,depth)mesh.castShadow  = true ; // 投射阴影mesh.position.copy(position)scene.add(mesh)// CANNON.js bodyconst shape = new CANNON.Box(new CANNON.Vec3(width * 0.5,height * 0.5,depth * 0.5))const body = new CANNON.Body({mass:1,position:new CANNON.Vec3(0,3,0),shape, // 这里注意大小写material:defaultMaterial})body.position.copy(position)body.addEventListener('collide',playHitSound) // 监听碰撞 collideworld.addBody(body)// save in objects to updateobjectsToUpdate.push({mesh,body})
}/*** Animate*/
const clock = new THREE.Clock()
let oldElapsedTime = 0 // 创建变量 标识上一刻度时间const tick = () =>
{const elapsedTime = clock.getElapsedTime()const deltaTime = elapsedTime - oldElapsedTimeoldElapsedTime = elapsedTime// Update physics worldworld.step(1/60,deltaTime,3) // 每秒60帧率 , 上一刻度用来多少时间 , for(const objects of objectsToUpdate){objects.mesh.position.copy(objects.body.position)objects.mesh.quaternion.copy(objects.body.quaternion)}// Update controlscontrols.update()// Renderrenderer.render(scene, camera)// Call tick again on the next framewindow.requestAnimationFrame(tick)
}tick()

二、知识点 

1.图形

2.three.js 和cannon.js

  1.下载,引入

npm install --save cannon

 import CANNON from 'cannon'

     由于cannonJS ,不更新 ;因此在它的基础上cannonEs更新,替换掉

        npm uninstall --save cannon

        npm install --save cannon-es@0.15.1

效果:

Physice


总结

学习,学呗!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/376609.html

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

相关文章

雷达视频采集卡 HPx-410

产品简介 雷达视频采集卡 HPx-410,应用于接入导航雷达数据,导航雷达视频,适用于JRC雷达、古野furuon雷达、Sperry雷达等多种型号的雷达。 HPx-410 可以接入导航雷达数据,引入导航雷达原始回波,然后将雷达视频采集到计…

html5——列表、表格

目录 列表 无序列表 有序列表 自定义列表 表格 基本结构 示例 表格的跨列 表格的跨行 列表 无序列表 <ul>【声明无序列表】 <li>河间驴肉火烧</li>【声明列表项】 <li>唐山棋子烧饼</li> <li>邯郸豆沫</li> <l…

python爬虫加入进度条

安装tqdm和requests库 pip install tqdm -i https://pypi.tuna.tsinghua.edu.cn/simplepip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple带进度条下载 import time # 引入time模块&#xff0c;用于处理时间相关的功能 from tqdm import * # 从tqdm包中…

基于SpringBoot+Hadoop+python的物品租赁系统(带1w+文档)

基于SpringBootHadooppython的物品租赁系统(带1w文档) 基于SpringBootHadooppython的物品租赁系统(带1w文档) 物品租赁系统是电子、信息技术相结合&#xff0c;是一种必然的发展趋势。以互联网为基础&#xff0c;以服务于广大用户为目的&#xff0c;发展整体优势&#xff0c;扩…

Vue3 pdf.js将二进制文件流转成pdf预览

好久没写东西&#xff0c;19年之前写过一篇Vue2将pdf二进制文件流转换成pdf文件&#xff0c;如果Vue2换成Vue3了&#xff0c;顺带来一篇文章&#xff0c;pdf.js这个东西用来解决内网pdf预览&#xff0c;是个不错的选择。 首先去pdfjs官网&#xff0c;下载需要的文件 然后将下载…

数据仓库哈哈

数据仓库 基本概念数据库&#xff08;database&#xff09;和数据仓库&#xff08;Data Warehouse&#xff09;的异同 整体架构分层架构方法论ER模型&#xff08;建模理论&#xff09;维度模型 何为分层第一层&#xff1a;数据源&#xff08;ODS ER模型&#xff09;设计要点日志…

python中的os模块和shutil模块

目录 os 1. 获取当前脚本绝对路径 2.获得工作路径&#xff1b; 3.该路径文件和目录 4.walk&#xff0c;查看目录下所有的文件&#xff08;含子孙文件&#xff09; 5.创建文件夹 6.os.makedirs(path) 7.路径拼接 8. 获取当前文件的上级目录 9.判断路径是否存在 10.是…

一 GD32 MCU 开发环境搭建

GD32 系列为通用型 MCU &#xff0c;所以开发环境也可以使用通用型的 IDE &#xff0c;目前使用较多的是 KEIL、 IAR 、 GCC 和 Embedded Builder &#xff0c;客户可以根据个人喜好来选择相应的开发环境。 目录 1、使用 Keil 开发 GD32 目前市面通用的MDK for ARM版本有Kei…

WPF学习(2) -- 样式基础

一、代码 <Window x:Class"学习.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend/2008&…

Contact Form联系表单自动发送邮件(超级简单)

前几天发现了aoksend推出的这个联系表单的组件&#xff0c;非常好用&#xff0c;只有一个php文件&#xff0c;把php文件放到网站主目录里面。然后去aoksend注册和配置好域名和发信邮箱&#xff0c;可以得到发送密钥&#xff1a;app_key&#xff0c;然后配置好邮件模板&#xff…

Linux常见配置

linux 常见配置 一、配置固定IP Centos配置固定IP 使用vim编辑/etc/sysconfig/network-scripts/ifcfg-ens33文件&#xff0c;填入如下 二、配置环境变量 1、将要配置的环境变量写入相应文件 ~/.bashrc # 用户环境变量配置文件 /etc/profile # 全局环境变量配置文件2、执行…

安防视频监控/云存储/视频汇聚EasyCVR平台播放设备录像不稳定,是什么原因?

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;EasyCVR基于云边端一体化架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;可提供7*24小时实时高清视频监控、云端录像、云存储、录像检索与回看、智能告警…

无障碍全免费上手智能体:Autogen Studio结合Deepseek Coder打造一款AI旅游规划师

本文的唯一目的是通过打造一款AI旅游规划师&#xff0c;通俗易懂、深入浅出的讲清楚AI应用的大方向-智能体-的原理。 无需科学上网&#xff0c;无需付费API&#xff0c;无需编程能力&#xff0c;一小时即可部署、搭建一款复杂的、多代理交互的AI智能体-旅游规划师&#xff0c;…

【Linux】:文件fd

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家带来关于文件fd的相关知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据…

FastAPI 学习之路(四十一)定制返回Response

接口中返回xml格式内容 from fastapi import FastAPI, Responseapp FastAPI()# ① xml app.get("/legacy") def get_legacy_data():data """<?xml version"1.0"?><shampoo><Header>Apply shampoo here.</Header&…

[笔记] SEW的振动分析工具DUV40A

1.便携式振动分析仪 DUV40A 文档编号&#xff1a;26871998/EN SEW是一家国际化的大型的机械设备供应商。产品线涵盖电机&#xff0c;减速机&#xff0c;变频器等全系列动力设备。DUV40A是他自己设计的一款振动分析工具。 我们先看一下它的软硬件参数&#xff1a; 内置两路传…

国内外大模型 SuperCLUE 基准测试

本心、输入输出、结果 文章目录 国内外大模型 SuperCLUE 基准测试前言国内外大模型 SuperCLUE 基准测试榜单什么是中文大模型基准 SuperCLUE国内外大模型 SuperCLUE 基准测试 编辑 | 简简单单 Online zuozuo 地址 | https://blog.csdn.net/qq_15071263 如果觉得本文对你有帮助,…

大数据开发中的数据驱动决策:关键问题与实践指南

目录 决策前的准备工作1. 我已经掌握了哪些信息&#xff1f;2. 我们已经做出决定了吗&#xff1f;3. 我们需要哪些额外信息以及何时需要&#xff1f; 决策过程中的关键问题1. 我们需要做这个决定吗&#xff1f;2. 错误地做出这个决定的代价是什么&#xff1f; 决策后的反思1. 我…

Excel第28享:如何新建一个Excel表格

一、背景需求 小姑电话说&#xff1a;要新建一个表格&#xff0c;并实现将几个单元格进行合并的需求。 二、解决方案 1、在电脑桌面上空白地方&#xff0c;点击鼠标右键&#xff0c;在下拉的功能框中选择“XLS工作表”或“XLSX工作表”都可以&#xff0c;如下图所示。 之后&…

数据库-三范式

第一范式 1 数据库所有字段都只有单一属性。 2 单一属性由基本数据类型构成。 3 数据库的表都是二维的行与列。 例如上面的例子就不满足第一范式&#xff0c;因为是可以继续拆分的&#xff0c;拆分为更多的属性。 第二范式 1 符合第一范式 2 表必须有个主建 3 其它字段可以…