Threejs中的OimoPhysics插件为我们提供了一个三维的物理世界,它可以帮助我们实现物理效果(如重力、弹力、加速度、摩擦力、碰撞等),并将物理世界中运动的每一帧的位置信息都映射到我们通过Threejs创建的三维世界中,从而在三维世界中实现现实中的物理效果。下面通过一个小球下落的例子来了解下OimoPhysics插件
引入OimoPhysics插件
OimoPhysics插件位于three.js—examples—jsm—physics路径下,使用时需要先引入该插件
首先在index.html中以以下方式引入Threejs
//index.html
<body>
<script type="importmap">
{
"imports":{
"three":"../../three.js/build/three.module.js",
"three/addons/": "../../three.js/examples/jsm/"
}
}
</script>
<script type="module" src="./index.js"></script>
</body>
然后在index.js中引入OimoPhysics
import { OimoPhysics } from 'three/addons/physics/OimoPhysics.js';
创建场景、相机、渲染器等
创建三维场景,具体方式前面章节已经介绍过了,不了解的可以看其它章节,这里就不一一介绍了,只贴出代码部分
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { OimoPhysics } from 'three/addons/physics/OimoPhysics.js';
// 定义变量
let camera, scene, renderer
let axesHelper
let hesLight, dirLight
let controls
// 初始化渲染器
initRenderer()
// 初始化相机
initCamera()
// 初始化场景
initScene()
// 初始化灯光
initLight()
// 初始化辅助轴
initAxesHelper()
// 初始化轨道控制器
initControl()
// 打开阴影
enableShadow()
// 循环执行
animate()
// 窗体重置
window.addEventListener('resize', function () {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
})
// 初始化渲染器
function initRenderer() {
renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
}
// 初始化相机
function initCamera() {
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100)
camera.position.set(4, 4, 4)
}
// 初始化场景
function initScene() {
scene = new THREE.Scene()
scene.background = new THREE.Color(0x888888)
}
// 初始化辅助轴
function initAxesHelper() {
axesHelper = new THREE.AxesHelper(1)
scene.add(axesHelper)
}
// 初始化灯光
function initLight() {
//环境光
hesLight = new THREE.HemisphereLight() //白色光
hesLight.intensity = 0.3
scene.add(hesLight)
//平行光
dirLight = new THREE.DirectionalLight() //太阳光
dirLight.position.set(5, 5, -5)
scene.add(dirLight)
}
// 初始化轨道控制器
function initControl() {
controls = new OrbitControls(camera, renderer.domElement)
}
//打开阴影
function enableShadow() {
renderer.shadowMap.enabled = true
dirLight.castShadow = true
}
// 循环执行
function animate() {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}
创建物体
定义变量
定义一个变量ball,用于接收一个球形物体的实例
let ball
初始化物体
编写初始化物体 initMeshes() 函数
// 初始化物体
function initMeshes() {
ball = new THREE.Mesh(
new THREE.SphereGeometry(0.05,32,16),
new THREE.MeshLambertMaterial()
)
ball.position.set(0,2,0)
scene.add(ball)
}
调用初始化物体函数
// 初始化物体
initMeshes()
此时运行浏览器,发现我们创建的小球已经出现在了浏览器上
使用OimoPhysics物理引擎插件
OimoPhysics 提供的是一个异步函数,我们可以直接调用它
OimoPhysics 提供了一个addMesh方法,通过该方法,可以将物体添加到OimoPhysics 创建的物理世界中,addMesh有两个参数,第一个参数是我们创建的物体模型,第二个参数代表该物体是否参与物理世界的运动,默认为0,即不参与,设置为1表示参与
前面我们已经引入了 OimoPhysics 插件,这里我们来使用它实现小球下落的过程
由于其是异步函数,我们通过await在等待其执行结果
首先我们新建一个变量来接收OimoPhysics 执行的结果
let physics
创建一个 enablePhysics() 函数,并调用OimoPhysics
async function enablePhysics() {
physics = await OimoPhysics()
physics.addMesh(ball)
}
创建完成后,刷新浏览器,我们发现页面没有任何变化,这是因为我们在addMesh方法中,没有设置第二个参数,默认为0,即代表小球不参与物理世界的运动,我们把其设置为1,
async function enablePhysics() {
physics = await OimoPhysics()
//physics.addMesh(ball)
physics.addMesh(ball,1)
}
刷新浏览器,我们看到小球有了下落的效果,但是,我们发现小球会一直下落,这不是我们想要的,
我们希望实现小球落到地面的效果,所以,我们还要创建一个地面
创建变量floor
let floor
在initMeshes中创建地面
// 地面
floor = new THREE.Mesh(
new THREE.BoxGeometry(10,1,10),
new THREE.ShadowMaterial({color:0x111111}) //影子的颜色
)
floor.position.set(0,-1,0)
scene.add(floor)
在enablePhysics中将地面也加入到物理引擎中
async function enablePhysics() {
physics = await OimoPhysics()
physics.addMesh(floor) //添加一个地面 --(第二个参数不写,表示为刚体)
physics.addMesh(ball,1)
}
刷新浏览器,可以看到小球下落到地面时就不会继续下落了,实现了我们想要的效果
给我们添加阴影
为了使效果更真实,我们给小球添加阴影
在enableShadow()中开启地面接收阴影和小球投射阴影效果
floor.receiveShadow = true
ball.castShadow = true
刷新浏览器,看效果
好了,关于OimoPhysics插件的使用,就到这里吧,喜欢的朋友点赞关注收藏哦