碰撞体
碰撞体定义物体响应碰撞的实际物理性状,通常在渲染层是不可见的。通过碰撞体组件的设定,物理系统可以判定两个物体是否相交,从而产生碰撞效果。
碰撞体组件概览
我们封装了以下几个常见的碰撞体形状类型,方便用户使用:
- 盒型碰撞体
ts
import { ColliderComponent, BoxColliderShape } from '@orillusion/core'
// some codes here to create object...
let collider = object.addComponent(ColliderComponent);
collider.shape = new BoxColliderShape();
// set shape parameters...
collider.shape.size = new Vector3(2, 2, 2);
import { ColliderComponent, BoxColliderShape } from '@orillusion/core'
// some codes here to create object...
let collider = object.addComponent(ColliderComponent);
collider.shape = new BoxColliderShape();
// set shape parameters...
collider.shape.size = new Vector3(2, 2, 2);
参数 | 类型 | 描述 |
---|---|---|
size | Vector3 | 盒型碰撞体的大小。默认以物体中心为长方体中心,通过新建Vector3实例分别指定长方体沿x、y、z坐标轴的长度大小 |
- 球形碰撞体
ts
import { ColliderComponent, BoxColliderShape } from '@orillusion/core'
// some codes here to create object...
let collider = object.addComponent(ColliderComponent);
collider.shape = new SphereColliderShape();
// set shape parameters...
collider.radius = 5;
import { ColliderComponent, BoxColliderShape } from '@orillusion/core'
// some codes here to create object...
let collider = object.addComponent(ColliderComponent);
collider.shape = new SphereColliderShape();
// set shape parameters...
collider.radius = 5;
参数 | 类型 | 描述 |
---|---|---|
radius | number | 球形碰撞体的半径。默认以物体中心为球体中心 |
- 胶囊碰撞体
ts
import { ColliderComponent, BoxColliderShape } from '@orillusion/core'
// some codes here to create object...
let collider = object.addComponent(ColliderComponent);
collider.shape = new CapsuleColliderShape();
// set shape parameters...
collider.radius = 2.5;
collider.height = 10;
import { ColliderComponent, BoxColliderShape } from '@orillusion/core'
// some codes here to create object...
let collider = object.addComponent(ColliderComponent);
collider.shape = new CapsuleColliderShape();
// set shape parameters...
collider.radius = 2.5;
collider.height = 10;
参数 | 类型 | 描述 |
---|---|---|
radius | number | 胶囊碰撞体上下半球体的半径 |
height | number | 胶囊碰撞体的高度,默认以物体中心为胶囊体中心 |
碰撞体组件应用示例
在为对象添加了刚体组件后,我们再为它添加一个碰撞体,并指定碰撞体的形状类型,便可以让该对象响应碰撞了:
ts
import { Vector3D, Object3D, ColliderComponent, BoxColliderShape } from '@orillusion/core'
import { Rigidbody } from '@orillusion/physics'
let object = new Object3D();
object.addComponent(Rigidbody);
let collider = obj.addComponent(ColliderComponent);
collider.shape = new BoxColliderShape();
collider.shape.size = new Vector3(2, 2, 2);
import { Vector3D, Object3D, ColliderComponent, BoxColliderShape } from '@orillusion/core'
import { Rigidbody } from '@orillusion/physics'
let object = new Object3D();
object.addComponent(Rigidbody);
let collider = obj.addComponent(ColliderComponent);
collider.shape = new BoxColliderShape();
collider.shape.size = new Vector3(2, 2, 2);
利用碰撞组件,我们可以模拟出逼真的物理效果,下面我们通过展示一个更复杂的示例,进一步了解物理系统可以实现的效果。
ts
import { BoxColliderShape, BoxGeometry, Camera3D, ColliderComponent, Color, ComponentBase, DirectLight, Engine3D, AtmosphericComponent, View3D, LitMaterial, HoverCameraController, MeshRenderer, Object3D, PlaneGeometry, Scene3D, Vector2, Vector3 } from '@orillusion/core'
import { Physics, Rigidbody } from '@orillusion/physics'
export class Sample_colliders {
constructor() {}
addPlane(scene: Scene3D, size: Vector2, pos: Vector3, rot: Vector3) {
const obj = new Object3D()
let mr = obj.addComponent(MeshRenderer)
mr.geometry = new PlaneGeometry(size.x, size.y)
mr.material = new LitMaterial()
mr.material.baseColor = new Color(0.04, 0.42, 0.45, 1)
obj.localPosition = pos
obj.localRotation = rot
// add a rigidbody with no mass - static body
let rigidbody = obj.addComponent(Rigidbody)
rigidbody.mass = 0
// add a box collider shape with small y value
let collider = obj.addComponent(ColliderComponent)
collider.shape = new BoxColliderShape()
collider.shape.size = new Vector3(size.x, 0.1, size.y)
scene.addChild(obj)
return obj
}
loop() {
if (Physics.isInited) {
Physics.update()
}
}
async run() {
// Init physics engine
await Physics.init()
// Init Engine3D
await Engine3D.init({
canvasConfig: { devicePixelRatio: 1 },
renderLoop: () => this.loop()
})
let scene3D = new Scene3D()
scene3D.addComponent(AtmosphericComponent)
let cameraObj = new Object3D()
let mainCamera = cameraObj.addComponent(Camera3D)
mainCamera.lookAt(new Vector3(0, 0, 10), new Vector3(0, 0, 0))
mainCamera.perspective(60, Engine3D.aspect, 1, 5000.0)
let controller = mainCamera.object3D.addComponent(HoverCameraController)
controller.setCamera(45, -15, 150, new Vector3(0, 30, 0))
scene3D.addChild(cameraObj)
let light: Object3D = new Object3D()
let component = light.addComponent(DirectLight)
light.rotationX = 45
light.rotationY = 30
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0)
component.intensity = 20
scene3D.addChild(light)
this.addPlane(scene3D, new Vector2(100, 100), new Vector3(0, 0, 0), new Vector3(0, 0, 0))
scene3D.addComponent(BoxGenerator)
let view = new View3D()
view.scene = scene3D
view.camera = mainCamera
// start render
Engine3D.startRenderView(view)
}
}
class BoxGenerator extends ComponentBase {
// save last time
private _lastTime: number = performance.now()
// a simple loop update
public onUpdate(): void {
// get current time
let now: number = performance.now()
// add a box every 300ms
if (now - this._lastTime > 300) {
// add a box
this._addBox()
// remove the first box after 500 boxes
if (this.object3D.entityChildren.length > 500) this.object3D.removeChildByIndex(4)
// save current time
this._lastTime = now
}
}
// add a box
private _addBox(): void {
const obj = new Object3D()
let mr = obj.addComponent(MeshRenderer)
mr.geometry = new BoxGeometry(5, 5, 5)
mr.material = new LitMaterial()
mr.material.baseColor = new Color(Math.random(), Math.random(), Math.random(), 1.0)
obj.localPosition = new Vector3(Math.random() * 70 - 35, 50, Math.random() * 70 - 35)
obj.localRotation = new Vector3(Math.random() * 360, Math.random() * 360, Math.random() * 360)
// add a rigidbody with mass 10
let rigidbody = obj.addComponent(Rigidbody)
rigidbody.mass = 10
// add a box collider shape
let collider = obj.addComponent(ColliderComponent)
collider.shape = new BoxColliderShape()
collider.shape.size = new Vector3(5, 5, 5)
this.object3D.addChild(obj)
}
}
new Sample_colliders().run()
import { BoxColliderShape, BoxGeometry, Camera3D, ColliderComponent, Color, ComponentBase, DirectLight, Engine3D, AtmosphericComponent, View3D, LitMaterial, HoverCameraController, MeshRenderer, Object3D, PlaneGeometry, Scene3D, Vector2, Vector3 } from '@orillusion/core'
import { Physics, Rigidbody } from '@orillusion/physics'
export class Sample_colliders {
constructor() {}
addPlane(scene: Scene3D, size: Vector2, pos: Vector3, rot: Vector3) {
const obj = new Object3D()
let mr = obj.addComponent(MeshRenderer)
mr.geometry = new PlaneGeometry(size.x, size.y)
mr.material = new LitMaterial()
mr.material.baseColor = new Color(0.04, 0.42, 0.45, 1)
obj.localPosition = pos
obj.localRotation = rot
// add a rigidbody with no mass - static body
let rigidbody = obj.addComponent(Rigidbody)
rigidbody.mass = 0
// add a box collider shape with small y value
let collider = obj.addComponent(ColliderComponent)
collider.shape = new BoxColliderShape()
collider.shape.size = new Vector3(size.x, 0.1, size.y)
scene.addChild(obj)
return obj
}
loop() {
if (Physics.isInited) {
Physics.update()
}
}
async run() {
// Init physics engine
await Physics.init()
// Init Engine3D
await Engine3D.init({
canvasConfig: { devicePixelRatio: 1 },
renderLoop: () => this.loop()
})
let scene3D = new Scene3D()
scene3D.addComponent(AtmosphericComponent)
let cameraObj = new Object3D()
let mainCamera = cameraObj.addComponent(Camera3D)
mainCamera.lookAt(new Vector3(0, 0, 10), new Vector3(0, 0, 0))
mainCamera.perspective(60, Engine3D.aspect, 1, 5000.0)
let controller = mainCamera.object3D.addComponent(HoverCameraController)
controller.setCamera(45, -15, 150, new Vector3(0, 30, 0))
scene3D.addChild(cameraObj)
let light: Object3D = new Object3D()
let component = light.addComponent(DirectLight)
light.rotationX = 45
light.rotationY = 30
component.lightColor = new Color(1.0, 1.0, 1.0, 1.0)
component.intensity = 20
scene3D.addChild(light)
this.addPlane(scene3D, new Vector2(100, 100), new Vector3(0, 0, 0), new Vector3(0, 0, 0))
scene3D.addComponent(BoxGenerator)
let view = new View3D()
view.scene = scene3D
view.camera = mainCamera
// start render
Engine3D.startRenderView(view)
}
}
class BoxGenerator extends ComponentBase {
// save last time
private _lastTime: number = performance.now()
// a simple loop update
public onUpdate(): void {
// get current time
let now: number = performance.now()
// add a box every 300ms
if (now - this._lastTime > 300) {
// add a box
this._addBox()
// remove the first box after 500 boxes
if (this.object3D.entityChildren.length > 500) this.object3D.removeChildByIndex(4)
// save current time
this._lastTime = now
}
}
// add a box
private _addBox(): void {
const obj = new Object3D()
let mr = obj.addComponent(MeshRenderer)
mr.geometry = new BoxGeometry(5, 5, 5)
mr.material = new LitMaterial()
mr.material.baseColor = new Color(Math.random(), Math.random(), Math.random(), 1.0)
obj.localPosition = new Vector3(Math.random() * 70 - 35, 50, Math.random() * 70 - 35)
obj.localRotation = new Vector3(Math.random() * 360, Math.random() * 360, Math.random() * 360)
// add a rigidbody with mass 10
let rigidbody = obj.addComponent(Rigidbody)
rigidbody.mass = 10
// add a box collider shape
let collider = obj.addComponent(ColliderComponent)
collider.shape = new BoxColliderShape()
collider.shape.size = new Vector3(5, 5, 5)
this.object3D.addChild(obj)
}
}
new Sample_colliders().run()