认识three.js物理引擎

物理引擎有很多,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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果不使用物理引擎,可以通过手动计算重力和位置,来实现自由落体的效果。下面是一个示例代码: ```javascript // 创建场景和摄像机 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.z = 5; // 创建渲染器 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 创建球体和材质 const geometry = new THREE.SphereGeometry(1, 32, 32); const material = new THREE.MeshBasicMaterial({color: 0xff0000}); const sphere = new THREE.Mesh(geometry, material); scene.add(sphere); // 计算重力和速度 const g = -9.8; // 重力加速度 let t = 0; // 时间 const v0 = 0; // 初始速度 const dt = 0.01; // 时间间隔 let v = v0; // 当前速度 let y = 10; // 初始高度 const minY = 1; // 最低高度 // 动画循环 function animate() { requestAnimationFrame(animate); // 计算球体位置 if (y > minY) { v += g * dt; y += v * dt; } sphere.position.y = y; renderer.render(scene, camera); } animate(); ``` 上述代码中,我们手动计算了重力和速度,并在每一帧中更新球体的位置。在计算过程中,我们使用了时间间隔 `dt`,和时间 `t`,来模拟重力和速度的变化。需要注意的是,当球体的高度低于最低高度 `minY` 时,停止计算,否则球体会一直下落。 需要根据具体场景的需求,调整重力加速度、初始速度、时间间隔等参数,来达到最佳效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值