物理引擎有很多,ammo.js、oimophysics、canno-es,这里我使用的是canno-es
1、安装
import install cannon-es
2、小球物理运动
import * as THREE from "three"
import gsap from 'gsap'
import * as CANNON from "cannon-es"
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 1、创建场景
const scene = new THREE.Scene()
// 2、创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
300
)
// 设置相机位置 x y z坐标 场景中添加相机
camera.position.set(0, 0, 18)
scene.add(camera)
// 创建球和平面
const sphereG = new THREE.SphereGeometry(1, 20, 20)
const sphereM = new THREE.MeshStandardMaterial()
const sphere = new THREE.Mesh(sphereG,sphereM)
sphere.castShadow = true
scene.add(sphere)
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(20, 20),
new THREE.MeshStandardMaterial()
)
floor.position.set(0, -5, 0)
floor.rotation.x = -Math.PI / 2
floor.receiveShadow = true
scene.add(floor)
// 创建物理世界
// const world = new CANNON.World({ gravity: 9.8 })
const world = new CANNON.World()
world.gravity.set(0, -9.8, 0) // 方向和重力 y是上所以取反
// 创建物理小球 半径1
const sphereShape = new CANNON.Sphere(1)
const sphereWorldMaterial = new CANNON.Material()
const sphereBody = new CANNON.Body({
shape: sphereShape,
position: new CANNON.Vec3(0, 0, 0),
// 小球质量是1
mass: 1,
// 物体材质
material: sphereWorldMaterial
})
// 将物体添加到物理世界
world.addBody(sphereBody)
// 创建物理地面
const floorShape = new CANNON.Plane()
const floorBody = new CANNON.Body()
// 质量为0使物体保持不动
floorBody.mass = 0
floorBody.addShape(floorShape)
// 地面位置
floorBody.position.set(0, -5, 0)
// 旋转地面位置
floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0), -Math.PI / 2)
world.addBody(floorBody)
// 添加环境和平行光
// const ambLight = new THREE.AmbientLight(0xffffff, 0.5)
// scene.add(ambLight)
const dirLight = new THREE.DirectionalLight(0xffffff, 0.5)
dirLight.castShadow = true
scene.add(dirLight)
// 环境光
const light = new THREE.AmbientLight( 0xffffff, 0.5 ); // soft white light
scene.add( light )
// 初始化渲染器
const renderer = new THREE.WebGL1Renderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 开启场景中的阴影
renderer.shadowMap.enabled = true
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)
// 使用渲染器,通过相机将场景渲染进来
// renderer.render(scene, camera)
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 添加坐标轴辅助器
const axesHelp = new THREE.AxesHelper(5)
scene.add(axesHelp)
const clock = new THREE.Clock()
function render () {
let deltTime = clock.getDelta()
// 更新物理引擎世界的物体
world.step(1/120, deltTime)
sphere.position.copy(sphereBody.position)
controls.update()
renderer.render(scene, camera)
// 渲染下一zhen就会调用render函数
requestAnimationFrame(render)
}
render()
3、小球物理运动+音效 +设置两种材质(摩擦、弹性)
import * as THREE from "three"
import gsap from 'gsap'
import * as CANNON from "cannon-es"
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 1、创建场景
const scene = new THREE.Scene()
// 2、创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
300
)
// 设置相机位置 x y z坐标 场景中添加相机
camera.position.set(0, 0, 18)
scene.add(camera)
// 创建球和平面
const sphereG = new THREE.SphereGeometry(1, 20, 20)
const sphereM = new THREE.MeshStandardMaterial()
const sphere = new THREE.Mesh(sphereG,sphereM)
sphere.castShadow = true
scene.add(sphere)
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(20, 20),
new THREE.MeshStandardMaterial()
)
floor.position.set(0, -5, 0)
floor.rotation.x = -Math.PI / 2
floor.receiveShadow = true
scene.add(floor)
// 创建物理世界
// const world = new CANNON.World({ gravity: 9.8 })
const world = new CANNON.World()
world.gravity.set(0, -9.8, 0) // 方向和重力 y是上所以取反
// 创建物理小球 半径1
const sphereShape = new CANNON.Sphere(1)
// 设置物体材质
const sphereWorldMaterial = new CANNON.Material("sphere")
const sphereBody = new CANNON.Body({
shape: sphereShape,
position: new CANNON.Vec3(0, 0, 0),
// 小球质量是1
mass: 1,
// 物体材质
material: sphereWorldMaterial
})
// 将物体添加到物理世界
world.addBody(sphereBody)
// 创建击打声音 下载的音频:https://sc.chinaz.com/yinxiao/211202141640.htm
const hideSound = new Audio('./media/jida.mp3')
// 添加碰撞事件
function hitEvent (e) {
// console.log(e)
// 获取碰撞的强度
const impactStrenght = e.contact.getImpactVelocityAlongNormal()
console.log(impactStrenght)
if (impactStrenght > 2) {
// 从0开始播放
hideSound.currentTime = 0
hideSound.play()
}
}
sphereBody.addEventListener('collide', hitEvent)
// 创建物理地面
const floorShape = new CANNON.Plane()
const floorBody = new CANNON.Body()
const floorMaterial = new CANNON.Material("floor")
floorBody.material= floorMaterial
// 质量为0使物体保持不动
floorBody.mass = 0
floorBody.addShape(floorShape)
// 地面位置
floorBody.position.set(0, -5, 0)
// 旋转地面位置
floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0), -Math.PI / 2)
world.addBody(floorBody)
// 设置2种材质碰撞的参数
const defaultContactMeaterial = new CANNON.ContactMaterial(sphereWorldMaterial, floorMaterial, {
friction: 0.1, // 摩擦力
restitution: 0.7 // 弹性
})
// 将材料的关联设置添加到物理世界
world.addContactMaterial(defaultContactMeaterial)
// 添加环境和平行光
// const ambLight = new THREE.AmbientLight(0xffffff, 0.5)
// scene.add(ambLight)
const dirLight = new THREE.DirectionalLight(0xffffff, 0.5)
dirLight.castShadow = true
scene.add(dirLight)
// 环境光
const light = new THREE.AmbientLight( 0xffffff, 0.5 ); // soft white light
scene.add( light )
// 初始化渲染器
const renderer = new THREE.WebGL1Renderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 开启场景中的阴影
renderer.shadowMap.enabled = true
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)
// 使用渲染器,通过相机将场景渲染进来
// renderer.render(scene, camera)
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 添加坐标轴辅助器
const axesHelp = new THREE.AxesHelper(5)
scene.add(axesHelp)
const clock = new THREE.Clock()
function render () {
let deltTime = clock.getDelta()
// 更新物理引擎世界的物体
world.step(1/120, deltTime)
sphere.position.copy(sphereBody.position)
controls.update()
renderer.render(scene, camera)
// 渲染下一zhen就会调用render函数
requestAnimationFrame(render)
}
render()
4、立方体碰撞后旋转+点击创建立方体+音效变化 + 施加力
import * as THREE from "three"
import gsap from 'gsap'
import * as CANNON from "cannon-es"
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
// 1、创建场景
const scene = new THREE.Scene()
// 2、创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
300
)
// 设置相机位置 x y z坐标 场景中添加相机
camera.position.set(0, 0, 18)
scene.add(camera)
// 创建物理世界
// const world = new CANNON.World({ gravity: 9.8 })
const world = new CANNON.World()
world.gravity.set(0, -9.8, 0) // 方向和重力 y是上所以取反
// 设置物体材质
const cubeWorldMaterial = new CANNON.Material("cube")
let cubeArr = []
// 创建立方体和平面
function createCube () {
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1)
const cubeMaterial = new THREE.MeshStandardMaterial()
const cube = new THREE.Mesh(cubeGeometry,cubeMaterial)
cube.castShadow = true
scene.add(cube)
// 创建物理小球 半径 1/2
const cubeShape = new CANNON.Box(new CANNON.Vec3(0.5, 0.5, 0.5))
const cubeBody = new CANNON.Body({
shape: cubeShape,
position: new CANNON.Vec3(0, 0, 0),
// 小球质量是1
mass: 1,
// 物体材质
material: cubeWorldMaterial
})
cubeBody.applyForce(
new CANNON.Vec3(1, 0, 0), // 添加的力大小和方向
new CANNON.Vec3(0, 0, 0) // 施加的力的位置
)
// 将物体添加到物理世界
world.addBody(cubeBody)
// 创建击打声音 下载的音频:https://sc.chinaz.com/yinxiao/211202141640.htm
const hideSound = new Audio('./media/jida.mp3')
// 添加碰撞事件
function hitEvent (e) {
// console.log(e)
// 获取碰撞的强度
const impactStrenght = e.contact.getImpactVelocityAlongNormal()
// console.log(impactStrenght)
if (impactStrenght > 2) {
// 从0开始播放
hideSound.currentTime = 0
hideSound.volume = impactStrenght / 20
hideSound.play()
}
}
cubeBody.addEventListener('collide', hitEvent)
cubeArr.push({
mesh: cube, // 渲染
body: cubeBody // 物理
})
}
window.addEventListener('click', () => {
createCube()
})
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(20, 20),
new THREE.MeshStandardMaterial()
)
floor.position.set(0, -5, 0)
floor.rotation.x = -Math.PI / 2
floor.receiveShadow = true
scene.add(floor)
// 创建物理地面
const floorShape = new CANNON.Plane()
const floorBody = new CANNON.Body()
const floorMaterial = new CANNON.Material("floor")
floorBody.material= floorMaterial
// 质量为0使物体保持不动
floorBody.mass = 0
floorBody.addShape(floorShape)
// 地面位置
floorBody.position.set(0, -5, 0)
// 旋转地面位置
floorBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0), -Math.PI / 2)
world.addBody(floorBody)
// 设置2种材质碰撞的参数
const defaultContactMeaterial = new CANNON.ContactMaterial(cubeWorldMaterial, floorMaterial, {
friction: 0.1, // 摩擦力
restitution: 0.7 // 弹性
})
// 将材料的关联设置添加到物理世界
world.addContactMaterial(defaultContactMeaterial)
// 设置世界碰撞的默认材料
world.defaultContactMaterial = defaultContactMeaterial
// 添加环境和平行光
// const ambLight = new THREE.AmbientLight(0xffffff, 0.5)
// scene.add(ambLight)
const dirLight = new THREE.DirectionalLight(0xffffff, 0.5)
dirLight.castShadow = true
scene.add(dirLight)
// 环境光
const light = new THREE.AmbientLight( 0xffffff, 0.5 ); // soft white light
scene.add( light )
// 初始化渲染器
const renderer = new THREE.WebGL1Renderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 开启场景中的阴影
renderer.shadowMap.enabled = true
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)
// 使用渲染器,通过相机将场景渲染进来
// renderer.render(scene, camera)
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 添加坐标轴辅助器
const axesHelp = new THREE.AxesHelper(5)
scene.add(axesHelp)
const clock = new THREE.Clock()
function render () {
let deltTime = clock.getDelta()
// 更新物理引擎世界的物体
world.step(1/120, deltTime)
// cube.position.copy(cubeBody.position)
cubeArr.forEach(item => {
item.mesh.position.copy(item.body.position)
// 设置渲染的物体跟随物理的物体旋转
item.mesh.quaternion.copy(item.body.quaternion)
})
controls.update()
renderer.render(scene, camera)
// 渲染下一帧就会调用render函数
requestAnimationFrame(render)
}
render()