three.js cannon.js物理引擎之约束(二)


今天郭先生继续讲cannon.js的物理约束,之前的一篇文章曾简单的提及过PointToPointConstraint约束,那么今天详细的说一说cannon.js的约束和使用方法。在线案例请点击博客原文

1. cannon.js约束的种类

1. PointToPointConstraint点对点约束

它的构造函数如下(之前可能介绍过了,这次统一说)

PointToPointConstraint ( bodyA  pivotA  bodyB  pivotB  maxForce )

 

  • bodyA — 刚体A。
  • pivotA — 相对于刚体A的质心的点,刚体A被约束到该点。
  • bodyB — 刚体B。
  • pivotB — 相对于刚体B的质心的点,刚体B被约束到该点。
  • maxForce — 约束物体应施加的最大力。

点对点约束顾名思义就是A刚体的某一点和B刚体的某一点形成约束,刚体之间仅通过约束点相连,如下图。

2. LockConstraint锁定约束

它的构造函数如下

LockConstraint ( bodyA  bodyB { maxForce } )
  • bodyA — 刚体A。
  • bodyB — 刚体B。
  • maxForce — 约束物体应施加的最大力。

为什么不需要设置约束点的位置呢,因为锁定约束其实就是点对点约束的简化版本,他们pivotA和pivotB默认为刚体的中心,如下图。

3. DistanceConstraint距离约束

它的构造函数如下

DistanceConstraint ( bodyA bodyB distance maxForce )
  • bodyA — 刚体A。
  • bodyB — 刚体B。
  • distance — 要保持的距离。如果未定义,它将被设置为刚体A和刚体B之间的当前距离。
  • maxForce — 约束物体应施加的最大力。

距离约束将两个物体约束为彼此重心的距离恒定,如下图是相邻小球保持恒定距离。

4. HingeConstraint铰链约束

它的构造函数如下

HingeConstraint ( bodyA  bodyB  { pivotA axisA pivotB axisB maxForce } )
  • bodyA — 刚体A。
  • bodyB — 刚体B。
  • pivotA — 相对于刚体A的质心的点,刚体A被约束到该点。
  • axisA — 在刚体A中局部定义的刚体A可以绕其旋转的轴。
  • pivotB — 相对于刚体B的质心的点,刚体B被约束到该点。
  • axisB — 在刚体B中局部定义的刚体B可以绕其旋转的轴。
  • maxForce — 约束物体应施加的最大力。

铰链又称合页,这个约束就像门的铰链一样,让两个物理只能在各自的点沿着固定的轴旋转。如下图。

2. 案例的主要代码

下面是案例的主要代码

var bodies = [], meshes = [];

initPoint() {
    var size = 0.5;
    var boxShape = new CANNON.Box(new CANNON.Vec3(size,size,size));
    var mass = 0;

    var N=10, last;

    for(var i=0; i<N; i++){
        // Create a box
        var boxbody = new CANNON.Body({
            mass: mass,
            shape: boxShape,
            position: new CANNON.Vec3(i * 0.6, (N - i) * Math.sqrt(size * size * 3) * 2, 0),
            quaternion: new CANNON.Quaternion().setFromEuler(-Math.PI / 4, -Math.PI / 4, 0),
            material: pubMaterial
        });
        boxbody.angularDamping = 0.3;
        bodies.push(boxbody);
        world.addBody(boxbody);

        if(i == 0) {
            mass = 1;
        } else {
            var c = new CANNON.PointToPointConstraint(boxbody, new CANNON.Vec3(size, size ,size), last, new CANNON.Vec3(-size, -size ,-size));
            world.addConstraint(c);
        }

        last = boxbody;
    }

    for(let i=0; i<10; i++) {
        let mesh = new THREE.Mesh(new THREE.BoxBufferGeometry(1), new THREE.MeshNormalMaterial());
        meshes.push(mesh);
        scene.add(mesh);
    }
    console.log(world)
}
initLock() {
    var size = 0.5;
    var boxShape = new CANNON.Box(new CANNON.Vec3(size,size,size));
    var mass = 1;
    var space = 0.1*size;

    var N=10, last;

    for(var i=0; i<N; i++){
        // Create a box
        var boxbody = new CANNON.Body({
            mass: mass,
            shape: boxShape,
            position: new CANNON.Vec3((N-i-N/2)*(size*2+2*space), size*6+space, 0),
            sleepSpeedLimit: 0,
            material: pubMaterial
        });
        bodies.push(boxbody);
        world.addBody(boxbody);


        if(last){
        // Connect the current body to the last one
            var c = new CANNON.LockConstraint(boxbody, last);
            world.addConstraint(c);
        }

        // To keep track of which body was added last
        last = boxbody;
    }
    var bodyA = new CANNON.Body({
        mass: 0,
        shape: boxShape,
        position: new CANNON.Vec3((-N/2+1)*(size*2+2*space), size*3-1, 0),
        material: pubMaterial
    });
    bodies.push(bodyA);
    world.addBody(bodyA);

    var bodyB = new CANNON.Body({
        mass: 0,
        shape: boxShape,
        position: new CANNON.Vec3((N/2)*(size*2+2*space), size*3-1, 0),
        material: pubMaterial
    });
    bodies.push(bodyB);
    world.addBody(bodyB);

    for(let i=0; i<12; i++) {
        let mesh = new THREE.Mesh(new THREE.BoxBufferGeometry(1), new THREE.MeshNormalMaterial());
        meshes.push(mesh);
        scene.add(mesh);
    }
}
initCloth() {
    var size = 0.2;
    var dis = 0.5;
    var sphereShape = new CANNON.Sphere(size);
    var mass = 1;

    var Nrows = 15, Ncols = 15;
    for(let i=0; i<Nrows; i++) {
        for(let j=0; j<Ncols; j++) {
            let body = new CANNON.Body({
                mass: mass,
                shape: sphereShape,
                position: new CANNON.Vec3((i - 0.5 * Nrows + 0.5) * dis, 9, (j - 0.5 * Ncols + 0.5) * dis),
                material: pubMaterial
            })
            bodies.push(body);
            world.addBody(body);
        }
    }

    let spherebody = new CANNON.Body({
        mass: 0,
        shape: new CANNON.Sphere(4),
        position: new CANNON.Vec3(0,4,0),
        material: pubMaterial
    })

    bodies.push(spherebody);
    world.add(spherebody);
    

    for(let i=0; i<Nrows * Ncols; i++) {
        let r = Math.floor(i / Nrows);
        let c = i % Nrows;
        if(r < Nrows - 1) {
            world.addConstraint(new CANNON.DistanceConstraint(bodies[r * Nrows + c], b2, dis, 5));
        }
        if(c < Ncols - 1) {
            world.addConstraint(new CANNON.DistanceConstraint(bodies[r * Nrows + c], bodies[r * Nrows + c + 1], dis, 5));
        }
    }

    for(let i=0; i<Nrows * Ncols; i++) {
        let mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(size), new THREE.MeshNormalMaterial());
        meshes.push(mesh);
        scene.add(mesh);
    }
    
    let mesh = new THREE.Mesh(new THREE.SphereBufferGeometry(4, 32, 16), new THREE.MeshNormalMaterial());
    meshes.push(mesh);
    scene.add(mesh);
}
initHinge() {
    let bodyA = new CANNON.Body({
        mass: 0,
        shape: new CANNON.Box(new CANNON.Vec3(0.2, 4, 0.2)),
        position: new CANNON.Vec3(-3.2, 5, 0),
        material: pubMaterial
    })
    let bodyB = new CANNON.Body({
        mass: 1,
        shape: new CANNON.Box(new CANNON.Vec3(3, 4, 0.2)),
        position: new CANNON.Vec3(0, 5, 0),
        // material: pubMaterial
    })

    bodyB.velocity.set(0, 0, -10);

    bodies.push(bodyA);
    bodies.push(bodyB);
    world.add(bodyA);
    world.add(bodyB);

    var c = new CANNON.HingeConstraint(bodyA, bodyB, { 
        pivotA: new CANNON.Vec3(0.3, 0, 0),
        axisA: new CANNON.Vec3(0, 1, 0),
        pivotB: new CANNON.Vec3(-3.1, 0, 0),
        axisB: new CANNON.Vec3(0, 1, 0),
        maxForce: 2
    });
    world.addConstraint(c);

    let meshA = new THREE.Mesh(new THREE.BoxBufferGeometry(0.4, 8, 0.4), new THREE.MeshNormalMaterial());
    let meshB = new THREE.Mesh(new THREE.BoxBufferGeometry(6, 8, 0.4), new THREE.MeshNormalMaterial());
    meshes.push(meshA);
    meshes.push(meshB);
    scene.add(meshA);
    scene.add(meshB);
}

 

转载请注明地址:郭先生的博客

本站声明:网站内容来源于网络,如有侵权,请联系我们,我们将及时处理。

  • 分享:
评论
还没有评论
    发表评论 说点什么