web物理引擎Oimo.js初探

勿忘初心2018-09-04 09:06
作者:李昱晨

本次webgl游戏项目在开发过程中发现layabox本身的物理引擎并不好用,经过多方寻找,最终我们选择了一款目前web应用里,非常轻量好用的一款物理引擎Oimo.js作为项目的物理计算相关的处理,鉴于目前网上对于这款引擎并没有太多的资料,我总结了一下我们在这次项目中所踩的坑。

引入:
Oimo的引入非常简单,只要直接
<script src="js/oimo.min.js"></script>
就可以了
新建:
创建一个Oimo物理世界
world = new OIMO.World({ 
    timestep: 1/60, 
    iterations: 8, 
    broadphase: 2, // 1 brute force, 2 sweep and prune, 3 volume tree
    worldscale: 1, // scale full world 
    random: true,  // randomize sample
    info: false,   // calculate statistic or not
    gravity: [0,-9.8,0] 
});
timestep ------ 物理世界的刷新频率,通常为60帧每秒,之前在项目中为了提高性能,降低cpu的消耗,将此值改为1/30即30帧每秒,导致原先计算准确的物理碰撞发生计算不灵敏的情况,尤其是在开启重力感应后,和重力感应相关的物理碰撞计算,建议尽量维持60帧,除非你所需要计算的内容对精度要求真的不高,只要模拟个大概。
broadphase ------ 碰撞检测算法类型,1 暴力算法 2 及/或扫掠裁减(sweep and prune)算法,这是目前市面上最常见的碰撞检测算法 3 volume tree算法(中文名不详)目前探究发现,使用2号算法是最稳定的,但是所要花费的性能也是最高的
volume tree ------- 物理世界的缩放
random ------ 是否使用随机样本
gravity ------ 重力加速度的大小,x,y,z三个方向可设置

向物理世界添加物理物体:
var body = world.add({ 
    type:'sphere', // type of shape : sphere, box, cylinder 
    size:[1,1,1], // size of shape
    pos:[0,0,0], // start position in degree
    rot:[0,0,90], // start rotation in degree
    move:true, // dynamic or statique
    density: 1,
    friction: 0.2,
    restitution: 0.2,
    belongsTo: 1, // The bits of the collision groups to which the shape belongs.
    collidesWith: 0xffffffff; // The bits of the collision groups with which the shape collides.
});
type ------ 物理物体的类型,球体、长方体、圆柱体
size ------ 物理物体的大小
pos ------ 物理物体的位置
rot ------ 物理物体的旋转角度
move ------ 物理物体是否是静态的
density ------ 物理物体的密度,可以用来增加物体的质量
friction ------ 物理物体的摩擦系数
restitution ------ 物理物体的弹性系数
belongsTo ------ 物理物体所属的组别
物理物体的常用属性:
body.prototype
allowSleep ----- 是否允许刚体休眠
currentRotation ------ 当前的旋转角度(使用欧拉角表示)
isStatic ------ 是否静态
newOrientation ------ 用来更新物理物体的四元数时的暂存
newPosition ------ 用来位置更新,功能同上
newRotation ------ 用来角度更新,功能同上
orientation ------ 当前的四元数,可以直接修改
parent ------ 物理节点的父节点
position ------ 当前的位置,可以直接修改
rotation ------ 当前旋转角度,可以直接修改
sleeping ------ 当前休眠状态

常用方法:
addShape ------ 给刚体添加一个形状,添加完以后必须调用setupMass才能生效
awake ------ 强行唤醒休眠中的刚体,防止当物体进入休眠后就不会再动的问题
getAxis ------ 获取物理物体的旋转轴
getPosition ------ 获取物理物体的位置
getQuaternion ------ 获取物理物体的四元数
isLonely ------- 判断物理物体是否和别的物体没有接触
remove ---- 删除物理物体
removeShape ------ 删除形状
resetPosition ------ 重置位置
resetQuaternion ------ 重置四元数
resetRotation ------ 重置角度
setPosition ------ 设置位置
setParent ------ 设置父级
setRotation ------ 设置角度
setQuaternion ------ 设置四元数
sleep ------ 强制进入刚体休眠
world.getContact(xxx,xxx) ------ 碰撞检测函数,只返回true和false,无法知晓是谁碰了谁

目前遇到的坑的总结
1.物理世界尽量保持60帧的刷新频率才能计算精准
2.物理世界的算法尽量使用2号算法,比较稳定
3.物理世界改变物体时必须每帧调用 world.step() 否则不会生效
4.当物理物体进入刚体休眠是,必须重新唤醒或使用另一个非休眠的刚体与之发生碰撞才可以唤醒
5.所有在赋值四元数类型或欧拉角类型的变量时,必须使用oimo自己定义的四元数和欧拉角(new OIMO.Quat,new OIMO.Vec3)
6.当物体设置为静态时,不会产生物理变化,必须设置为动态
7.尽量让物理世界的坐标系和实际坐标系的构建方式一样,否则使用起来会有很多坑
8.看实际的物理表现时,需要实时的将物理物体的属性赋值给可见物体
9.当物理世界暂时不需要时请及时关闭物理世界的计算,以免引起不必要性能开销
10.当开启重力时,物理世界的所有物体都会受到重力影响,如需去掉影响,需要手动调整该物体的表现
11.注意无效物理物体的即时回收


网易云大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者李昱晨授权发布。