three.js cannon.js物理引擎之约束(二)
郭先生的博客 人气:0今天郭先生继续讲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); }
转载请注明地址:郭先生的博客
加载全部内容