【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.mzph.cn/bicheng/46066.shtml

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

相关文章

Java核心篇之JVM探秘:对象创建与内存分配机制

系列文章目录 第一章 Java核心篇之JVM探秘:内存模型与管理初探 第二章 Java核心篇之JVM探秘:对象创建与内存分配机制 第三章 Java核心篇之JVM探秘:垃圾回收算法与垃圾收集器 第四章 Java核心篇之JVM调优实战:Arthas工具使用及…

《Windows API每日一练》9.25 系统菜单

/*------------------------------------------------------------------------ 060 WIN32 API 每日一练 第60个例子POORMENU.C:使用系统菜单 GetSystemMenu函数 AppendMenu函数 (c) www.bcdaren.com 编程达人 -------------------------------------------…

亿康源用科技引领发展,开启大健康产业新篇章

(本台记者报)近日,杭州有一家公司凭借深厚的科技研发实力与卓越的创新能力在大健康领域屡受好评,其研发的新品一经推出便成为行业热议。为了探寻该公司的经营秘诀,我们找到了这家公司——亿康源,并有幸与亿…

防火墙组网与安全策略实验

实验要求: 实现: 防火墙接口配置: 所有接口均配置为三层接口 由于G1/0/3口下为vlan环境,所以防火墙需要配置子接口 : 交换机划分vlan分开生产区和办公区、配置trunk干道 : 安全策略: 生产区访…

深度学习概览

引言 深度学习的定义与背景 深度学习是机器学习的一个子领域,涉及使用多层神经网络分析和学习复杂的数据模式。深度学习的基础可以追溯到20世纪80年代,但真正的发展和广泛应用是在21世纪初。计算能力的提升和大数据的可用性使得深度学习在许多领域取得…

[C++] 由浅入深理解面向对象思想的组成模块

文章目录 (一) 类的默认成员函数(二) 构造函数构造函数的特征构造函数示例无参构造带参构造 冲突:全缺省参数的构造函数与无参构造函数 (三)析构函数特性析构函数的析构过程解析 (四)拷贝构造函数什么是拷贝构造?特性为…

初始c语言(2)运算符与表达式

一 c语言提供的运算符类型 以上会后续介绍 二 现阶段我们掌握如下的基本操作符 注意!计算机的除法只会保留整数部分(若被除数未负则不同的软件取整的结果不唯一) 三 自加()自减(--)符号 若为…

GESP CCF C++ 四级认证真题 2024年6月

第 1 题 下列代码中,输出结果是( ) A. 12 24 24 12 B. 24 12 12 24 C. 12 12 24 24 D. 24 24 12 12 第 2 题 下面函数不能正常执行的是() A. B. C. D. 第 3 题 下面程序…

AI Native时代:重塑人机交互与创作流程

随着2024年上海世界人工智能大会的圆满落幕,业界领袖们纷纷就AI应用的新机遇展开深入讨论。结合a16z播客中的观点,本文将探讨AI原生(AI Native)应用的几个关键特征,这些特征正在重新定义我们的工作方式和创作过程。 一…

0708,LINUX目录相关操作 + LINUX全导图

主要是冷气太足感冒了,加上少吃药抗药性差,全天昏迷,学傻了学傻了 01:简介 02: VIM编辑器 04:目录 05:文件 03:常用命令 06:进程 07:进程间的通信 cat t_c…

微信小程序毕业设计-青少年科普教学系统项目开发实战(附源码+论文)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:微信小程序毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计…

ftp pool 功能分析及 golang 实现

本文探究一种轻量级的 pool 实现 ftp 连接。 一、背景 简要介绍:业务中一般使用较多的是各种开源组件,设计有点重,因此本文探究一种轻量级的 pool 池的思想实现。 期望:设置连接池最大连接数为 N 时,批量执行 M 个 F…

vs2017/2019串口Qt Serial Port/modbus使用报错

vs2017/2019 Qt Serial Port/modbus配置 /* * 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 LNK2019 无法解析的外部符号 "__declspec(dllimport) public: __cdecl QModbusTcpClient::QModbusTcpClient(class QObject *)" (__imp_??…

基于javaScript的冒泡排序

目录 一.前言 二.设计思路和原理 三.源代码展示 四. 案例运行结果 一.前言 冒泡排序简而言之,就是一种算法,能够把一系列的数据按照一定的顺序进行排列显示(从小到大或从大到小)。例如能够将数组[5,4,3,2,1]中的元素按照从小到…

了解Maven

一.环境搭建 如果使用的是社区版 版本要求为:2021.1-2022.1.4 如果使用的是idea专业版就无需版本要求,专业版下载私信我,免费教你下载 二,Maven 什么是Maven,也就是一个项目管理工具,用来基于pom的概念&#xff0c…

Ghidra comment add script

init # -*- coding: utf-8 -*- import re from ghidra.program.model.listing import CodeUnit# 获取当前程序和指令迭代器 program getCurrentProgram() listing program.getListing() instructionIterator listing.getInstructions(True)# 用于存储唯一的指令类型和操作数…

PostgreSQL修改最大连接数

在使用PostgreSQL 的时候,经常会遇到这样的错误提示, sorry, too many clients already,这是因为默认PostgreSQL最大连接数是 100, 一般情况下,个人使用时足够的,但是在生产环境,这个连接数是远远不够的&am…

python机器学习5 数据容器

Python中有几个数据容器如下: List,数组,如同Array数组。 Dictionarie,字典,可以通过文字来访问数据。 Sets,序列集,做数学交集、并集等计算时使用。 Tuple,序列&#xff0c…

回归求助 教程分享

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 今日 217/10000 抱个拳,送个礼 更多内容,见微*公号往期文章:通透!!十大回…

NFT如何解决音乐版权的问题

音乐版权问题一直困扰着音乐产业。传统的音乐版权管理模式存在以下问题。需要注意的是,NFT在音乐版权领域仍处于早期发展阶段,存在一些需要解决的问题,例如技术标准不统一、应用场景有限、法律法规不明朗等。但随着技术的进步和市场的完善&am…