3.js - 自由落体,落到地面后会弹一下

在这里插入图片描述

import * as THREE from 'three'
import gsap from 'gsap' // 导入动画库
import * as dat from 'dat.gui' // 导入dat.gui

`导入 cannon-es 引擎`
import * as CANNON from 'cannon-es'

// --------------------------------------------------------------------------------

const scene = new THREE.Scene()

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 300)
camera.position.set(0, 0, 18)
scene.add(camera)

// 渲染器透明
const renderer = new THREE.WebGLRenderer({ alpha: true })
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true
// @ts-ignore
renderer.physicallyCorrectLights = true
document.body.appendChild(renderer.domElement)

// -------------------------------------------------------------------------------

// 创建球
const sphereGeometry = new THREE.SphereGeometry(1, 20, 20)
const sphereMaterial = new THREE.MeshPhysicalMaterial()
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
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()
world.gravity.set(0, -9.8, 0)

// 创建物理小球形状
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),
	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 ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
scene.add(ambientLight)

// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5)
directionalLight.castShadow = true
directionalLight.position.set(0, 8, 0) // 平行光的位置
scene.add(directionalLight)
// 平行光辅助器
const directionalLightHelp = new THREE.DirectionalLightHelper(directionalLight)
scene.add(directionalLightHelp)

// -------------------------------------------------------------------------------

const axesHelper = new THREE.AxesHelper(8)
scene.add(axesHelper)

const clock = new THREE.Clock()

const render = () => {
	`getDelta():返回,距离上次调用,getDelta(),以来经过的秒数`
	let deltaTime = clock.getDelta()
	
	`
	  world.step():更新物理引擎里的世界物体
	    参数一:指定了,物理引擎内部模拟的时间步长(以秒为单位),
	           在这里,设置为,大约每1/120秒更新一次物理世界,
	    参数而:实际的时间差,它允许物理引擎根据实际的帧率调整其模拟,
	           以保持物理行为的稳定性、一致性,`
	world.step(1/120, deltaTime)
	
	`将物理引擎的sphereBody的位置,复制给渲染引擎的sphere`
	sphere.position.copy(sphereBody.position)
	
	renderer.render(scene, camera)
	requestAnimationFrame(render)
}
render()


window.addEventListener('resize', () => {
	// 重置相机的宽高比
	camera.aspect = window.innerWidth / window.innerHeight
	// 更新相机的投影矩阵
	camera.updateProjectionMatrix()
	// 重置渲染器的宽高比
	renderer.setSize(window.innerWidth, window.innerHeight)
	// 更新渲染器的像素比
	renderer.setPixelRatio(window.devicePixelRatio)
})

要实现自由落体的效果,可以使用 Three.js 中的物理引擎 Ammo.js 来模拟重力和碰撞。下面是一个简单的示例代码,实现一个球体自由落体的动画: ```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 physicsWorld = new Ammo.btDiscreteDynamicsWorld(new Ammo.btDefaultCollisionConfiguration(), new Ammo.btDbvtBroadphase(), new Ammo.btSequentialImpulseConstraintSolver(), new Ammo.btDefaultCollisionConfiguration()); physicsWorld.setGravity(new Ammo.btVector3(0, -9.8, 0)); // 设置重力 // 将球体添加到物理引擎中 const mass = 1; const localInertia = new Ammo.btVector3(0, 0, 0); const shape = new Ammo.btSphereShape(1); shape.calculateLocalInertia(mass, localInertia); const transform = new Ammo.btTransform(); transform.setIdentity(); const motionState = new Ammo.btDefaultMotionState(transform); const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, shape, localInertia); const body = new Ammo.btRigidBody(rbInfo); physicsWorld.addRigidBody(body); // 动画循环 function animate() { requestAnimationFrame(animate); // 模拟物理引擎 physicsWorld.stepSimulation(1 / 60, 10); // 更新球体位置 const transform = new Ammo.btTransform(); body.getMotionState().getWorldTransform(transform); const position = transform.getOrigin(); sphere.position.set(position.x(), position.y(), position.z()); renderer.render(scene, camera); } animate(); ``` 上述代码中,我们使用了 `Ammo.btDiscreteDynamicsWorld` 来创建物理世界,并设置了重力。然后将球体添加到物理引擎中,并使用 `physicsWorld.stepSimulation` 模拟物理引擎的运行。在动画循环中,通过 `body.getMotionState().getWorldTransform` 获取球体的位置,并更新球体的位置。 需要注意的是,为了让物理引擎运行更加稳定,我们需要在每一帧中调用 `physicsWorld.stepSimulation` 函数进行模拟,而不是直接修改球体的位置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值