• Three Ammo实现物理作用实例


    在这里插入图片描述

    基础环境搭建:

    当Ammo.js库初始化完成后进入我们代码:

    Ammo().then(() => {
        initGraphicUniverse()
        initPhysicsUniverse()
        render()
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    bullet基础环境配置,初始化物理世界:

    btDefaultCollisionConfiguration配置通过Bullet(Ammo.js)检测碰撞。
    btCollisionDispatcher负责管理凸和凹碰撞的算法。
    btsequentialimpulse seconstraintsolver允许在我们的宇宙中解决物理规则的约束(重力,力…)
    btdiscretedynamicsworld对应我们的动态世界; 我们的可变物理宇宙就是这种类型。

    function initPhysicsUniverse() {
        const collisionConfiguration = new Ammo.btDefaultCollisionConfiguration()
        const dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration)
        const overlappingPairCache = new Ammo.btDbvtBroadphase()
        const solver = new Ammo.btSequentialImpulseConstraintSolver()
        physicsUniverse = new Ammo.btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration)
        physicsUniverse.setGravity(new Ammo.btVector3(0, -75, 0))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    three基础环境配置在initGraphics()中。

    在这里插入图片描述
    在这里插入图片描述

    创建场景中具有物理特性的立方体:

    function createCube(scale, position, mass, rot_quaternion) {
        let quaternion
        console.log(position)
        if (rot_quaternion == null) {
            quaternion = { x: 0, y: 0, z: 0, w: 0 }
        }
        else {
            quaternion = rot_quaternion
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    图形端,正常创建网格模型并添加到场景中:

        //graphic world
        const cube = new THREE.Mesh(
            new THREE.BoxGeometry(scale, scale, scale),
            new THREE.MeshPhongMaterial({ color: Math.random() * 0xffffff })
        )
        cube.position.set(position.x, position.y, position.z)
        scene.add(cube)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    物理端,创建刚体:

    刚体和碰撞的几何结构概念

    我们称物理世界中受动态力影响的所有实体为刚体(具有质量、速度和能够进行碰撞等)。
    因此,为了正确地模拟动力有必要在我们的物理世界中创建刚体。为此,我们希望包含在物理模拟中的每个3D对象(图像世界中的)都将拥有自己的刚体(在物理世界中)。
    然而,模拟的每个3D对象并不具有相同的形式,因此并不会在相同的物理作用场景中做出相同的反应。例如,将立方形刚体堆起来比堆球形刚体更容易!
    这就是为什么刚体并不都具有相同的几何形式。 这就是我们所说的碰撞的几何结构。
    让我们用一个简单的例子说明:我们希望创建一个对物理有反应的3D立方体。在图形端我们将创建一个由BoxGeometry几何体对象和材质对象组成的网格模型。接下来,在物理端创建一个具有立方体碰撞几何结构、类型为btBoxShape刚体。

    创建默认运动状态,定义物理世界对象初始位置和旋转角度:

        //physics world
        let transform = new Ammo.btTransform()
        transform.setIdentity()
        transform.setOrigin(new Ammo.btVector3(position.x, position.y, position.z))
        transform.setRotation(new Ammo.btQuaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w))
        let defaultMotionState = new Ammo.btDefaultMotionState(transform)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    定义对象的碰撞几何体结构:

        let structColShape = new Ammo.btBoxShape(new Ammo.btVector3(scale * 0.5, scale * 0.5, scale * 0.5))
        structColShape.setMargin(0.05)
    
    • 1
    • 2

    处理初始惯性的计算(如果定义了一个初始旋转,这很重要):

        let localInertia = new Ammo.btVector3(0, 0, 0)
        structColShape.calculateLocalInertia(mass, localInertia)
    
    • 1
    • 2

    使用我们刚刚初始化的元素创建刚体:

        let RBody_Info = new Ammo.btRigidBodyConstructionInfo(mass, defaultMotionState, structColShape, localInertia)
        let Rbody = new Ammo.btRigidBody(RBody_Info)
    
    • 1
    • 2

    添加刚体到物理世界中:

        physicsUniverse.addRigidBody(Rbody)
    
    • 1

    将这个新刚体定义为立方体的userData.physicsBody属性值(这就是物理和图形世界之间的联系):

        cube.userData.physicsBody = Rbody
        rigidBody_list.push(cube)
    
    • 1
    • 2

    调用createCube():

    function createObjects() {
        createCube(40, new THREE.Vector3(15, -30, 15), 0, null)
        createCube(4, new THREE.Vector3(0, 10, 0), 1, null)
        createCube(2, new THREE.Vector3(10, 30, 0), 1, null);
        createCube(4, new THREE.Vector3(10, 20, 10), 1, null);
        createCube(6, new THREE.Vector3(5, 40, 20), 1, null);
        createCube(8, new THREE.Vector3(25, 100, 5), 1, null);
        createCube(8, new THREE.Vector3(20, 60, 25), 1, null);
        createCube(4, new THREE.Vector3(20, 100, 25), 1, null);
        createCube(2, new THREE.Vector3(20, 200, 25), 1, null);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    更新针对时间的物理模拟:

    使用stepSimulation()将动态模拟作为运行时间的函数来更新:

    function updatePhysicsUniverse(delta) {
        physicsUniverse.stepSimulation(delta, 10)
    }
    
    • 1
    • 2
    • 3

    创建针对rigidBody_List数组的循环,分别获取当前循环的图形对象和物理对象:

        for (let i = 0; i < rigidBody_list.length; i++) {
            let graphicObj = rigidBody_list[i]
            let physicsObj = rigidBody_list[i].userData.physicsBody
        }
    
    • 1
    • 2
    • 3
    • 4

    从物理世界中提取位置和旋转属性,通过动态模拟更新,并将它们注入到图形世界中。这样通过物理世界的模拟带来的属性变化将在图形世界中可见:
    创建全局变量tmpTransformation暂时存储应用在每次循环中的变化:

    let tmpTranformation
    ...
    Ammo().then(() => {
        tmpTranformation = new Ammo.btTransform()
        ...
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    提取每个物理对象的位置和旋转属性并注入到对应的图形对象中:

            let motionState = physicsObj.getMotionState()
            if (motionState) {
                motionState.getWorldTransform(tmpTranformation)
                let newPos = tmpTranformation.getOrigin()
                let newQua = tmpTranformation.getRotation()
                graphicObj.position.set(newPos.x(), newPos.y(), newPos.z())
                graphicObj.rotation.set(newQua.x(), newQua.y(), newQua.z(), newQua.w())
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    从现在起,在每次调用updatePhysicsUniverse时,物理和图形世界将同步。
    渲染、调用:

    function render()
    {
            let deltaTime = clock.getDelta();
            updatePhysicsUniverse( deltaTime );
                    
            renderer.render( scene, camera );
            requestAnimationFrame( render );
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    Ammo().then(function () {
        tmpTransformation = new Ammo.btTransform()
        initGraphicUniverse()
        initPhysicsUniverse()
        createObjects()
        render()
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    实现立方体自由落体:
    在这里插入图片描述

  • 相关阅读:
    软件工程测试与度量课程学习---基本测试过程----线性模型
    I2C 验证中需要注意的问题
    Java 学习笔记
    电容笔和Apple pencil有啥区别?电容笔四大口碑比较好的品牌推荐
    leetcode 45
    WHAT - 容器化系列(二)- docker
    MyBatis 查询数据库
    dicom镜像反转90度
    Excel 宏录制与VBA编程 —— 13、Excel内置函数的调用
    3 .NET Core笔试题
  • 原文地址:https://blog.csdn.net/lqiqil/article/details/127667966