Skip to content

Instantly share code, notes, and snippets.

@edom18
Created August 18, 2013 18:04
Show Gist options
  • Save edom18/6263033 to your computer and use it in GitHub Desktop.
Save edom18/6263033 to your computer and use it in GitHub Desktop.
Cannon.js x Three.jsで3D物理演算2
#Cannon.jsで物理演算Demo2
[こちらの記事を参考](http://www56.atwiki.jp/threejs/pages/85.html)に、勉強のためにちょっと手を加えたものです。
また、[質量などの設定はこれを参考](http://stackoverflow.com/questions/16424500/what-would-be-realistic-values-for-gravity-mass-and-contact-material-in-canno)にしました。
@import "compass/reset";
img, canvas {
vertical-align: top;
}
<div id="d0"></div>
<script src="http://jsrun.it/assets/f/J/B/D/fJBDQ"></script>
<script src="http://jsrun.it/assets/u/4/z/N/u4zNG"></script>
(function (win, doc) {
'use strict';
var fps = 60;
var w = win.innerWidth;
var h = win.innerHeight;
var world, timeStep = 1/fps, renderer, scene, camera;
var cPlane1Body, cPlane1Mesh, cPlane2Body, cPlane2Mesh, cPlane2Material, sphereGeometry, sphereMaterial;
var sphereShape, sphereBody, sphereMesh;
var boxShape, boxGeometry, boxMaterial;
var box1Mesh, box1Body, box2Mesh, box2Body;
var groundShape, groundBody, groundMesh;
var cp;
var flg = false, cnt = 0;
function sinit() {
initThree();
initCannon();
animate();
}
function initCannon(){
world = new CANNON.World();
world.gravity.set( 0, -100, 0);
world.broadphase = new CANNON.NaiveBroadphase();
world.solver.iterations = 16;
function convexPlaneShape(xSize, ySize) {
return new CANNON.ConvexPolyhedron([
// vertices
new CANNON.Vec3(-xSize/2, ySize/2, 0),
new CANNON.Vec3( xSize/2, ySize/2, 0),
new CANNON.Vec3( xSize/2, -ySize/2, 0),
new CANNON.Vec3(-xSize/2, -ySize/2, 0)
], [
// Faces
[3,2,1,0]
], [
// Normals
new CANNON.Vec3(0,0,1)
]);
}
var cPlanePhysMat = new CANNON.Material();
var cPlaneShape = convexPlaneShape(8, 8);
var qo, qo2, qo3;
cPlane1Body = new CANNON.RigidBody(0, cPlaneShape, cPlanePhysMat);
cPlane1Body.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
qo = new CANNON.Quaternion();
qo2 = new CANNON.Quaternion();
cPlane1Body.quaternion.copy(qo);
qo2.setFromAxisAngle(new CANNON.Vec3(0, 0, 1), -0.07);
cPlane1Body.quaternion = qo2.mult(qo);
cPlane1Body.position.set(-5, 14, 0);
world.add(cPlane1Body);
cPlane2Body = new CANNON.RigidBody(0, cPlaneShape, cPlanePhysMat);
cPlane2Body.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2);
qo = new CANNON.Quaternion();
qo2 = new CANNON.Quaternion();
qo3 = new CANNON.Quaternion();
cPlane2Body.quaternion.copy(qo);
qo2.setFromAxisAngle(new CANNON.Vec3(0, 0, 1), -Math.PI / 6);
qo3.setFromAxisAngle(new CANNON.Vec3(0, 1, 0), Math.PI / 4);
cPlane2Body.quaternion = qo3.mult(qo2.mult(qo));
cPlane2Body.position.set(4, 2, 2);
world.add(cPlane2Body);
var spherePhysMat = new CANNON.Material();
sphereShape = new CANNON.Sphere(2);
//Create a ball as a stone.
var density = 2515; // kg/m^3
var mass = density * sphereShape.volume();
sphereBody = new CANNON.RigidBody(mass, sphereShape, spherePhysMat);
sphereBody.position.set(-4, 34, 0);
sphereBody.quaternion.set(0, 0, 0, 1);
sphereBody.velocity.set(0, 0, 0);
sphereBody.angularVelocity.set(0, 0, 100);
world.add(sphereBody);
var boxPhysMat = new CANNON.Material();
boxShape = new CANNON.Box(new CANNON.Vec3(2, 2, 2));
density = 50;
mass = density * boxShape.volume();
box1Body = new CANNON.RigidBody(mass, boxShape, boxPhysMat);
box1Body.position.set(17,2,-11);
box1Body.quaternion.set(0,0,0,1);
box1Body.velocity.set(0,0,0);
box1Body.angularVelocity.set(0,0,0);
world.add(box1Body);
density = 30;
mass = density * boxShape.volume();
box2Body = new CANNON.RigidBody(mass, boxShape, boxPhysMat);
box2Body.position.set(17,6,-11);
box2Body.quaternion.set(0,0,0,1);
box2Body.velocity.set(0,0,0);
box2Body.angularVelocity.set(0,0,0);
world.add(box2Body);
var groundPhysMat = new CANNON.Material();
groundShape = new CANNON.Plane(new CANNON.Vec3(0, 0, 1));
groundBody = new CANNON.RigidBody(0, groundShape, groundPhysMat);
groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1,0,0), -Math.PI/2);
world.add(groundBody);
var friction = 0.0;
var restitution = 0.0;
var sphere_cPlane = new CANNON.ContactMaterial(cPlanePhysMat, spherePhysMat, friction, restitution);
var sphere_box = new CANNON.ContactMaterial(spherePhysMat, groundPhysMat, friction, restitution);
sphere_cPlane.contactEquationStiffness = 1e8;
sphere_cPlane.contactEquationRegularizationTime = 3;
sphere_cPlane.frictionEquationStiffness = 1e8;
sphere_cPlane.frictionEquationRegularizationTime = 3;
world.addContactMaterial(sphere_cPlane);
world.addContactMaterial(sphere_box);
}
function initThree() {
// scene
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0xffffff, 80, 150);
// camera
camera = new THREE.PerspectiveCamera(60, w / h, 1, 10000);
camera.position.set(-1, 14, 10).multiplyScalar(1.6);
camera.lookAt(new THREE.Vector3(3, 3, -10));
// light
var d = 10;
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(d, d, d);
light.castShadow = true;
//light.shadowCameraVisible = true;
light.shadowMapWidth = 1024;
light.shadowMapHeight = 1024;
light.shadowCameraLeft = -d * 3;
light.shadowCameraRight = d * 3;
light.shadowCameraTop = d;
light.shadowCameraBottom = -d;
light.shadowCameraNear = 1;
light.shadowCameraFar = 10000;
light.shadowDarkness = 0.5;
scene.add(light);
// floor
var oneWidth = 5,
oneHeight = 5,
wUnits = 70,
hUnits = 70,
groundGeo = new THREE.PlaneGeometry(oneWidth * wUnits, oneHeight * hUnits, wUnits, hUnits);
for(var i = 0, len = groundGeo.faces.length, f; i < len; i++){
f = -1;
if((i / wUnits | 0) % 2 == 1){
f = ~f;
}
if((i % wUnits) % 2 == 1){
f = ~f;
}
groundGeo.faces[i].materialIndex = f + 1;
}
groundMesh = new THREE.Mesh(
groundGeo,
new THREE.MeshFaceMaterial([
new THREE.MeshBasicMaterial({color: 0x999999 }),
new THREE.MeshBasicMaterial({color: 0x4d4d4d })
])
);
groundMesh.rotation.x = -Math.PI / 2;
groundMesh.castShadow = true;
groundMesh.receiveShadow = true;
scene.add(groundMesh);
// step plane
var cPlaneGeometry = new THREE.PlaneGeometry(8, 8);
// red step plane
var cPlane1Material = new THREE.MeshLambertMaterial({color: 0xffcccc});
cPlane1Mesh = new THREE.Mesh(cPlaneGeometry, cPlane1Material);
cPlane1Mesh.castShadow = true;
cPlane1Mesh.receiveShadow = true;
scene.add(cPlane1Mesh);
// blue step plane
cPlane2Material = new THREE.MeshLambertMaterial( { color: 0xccccff } );
cPlane2Mesh = new THREE.Mesh( cPlaneGeometry, cPlane2Material );
cPlane2Mesh.castShadow = true;
cPlane2Mesh.receiveShadow = true;
scene.add(cPlane2Mesh);
// red ball
sphereGeometry = new THREE.SphereGeometry(2, 25, 25);
sphereMaterial = new THREE.MeshPhongMaterial({color: 0xff0000, specular: 0xff8833});
sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial);
sphereMesh.castShadow = true;
sphereMesh.receiveShadow = true;
scene.add(sphereMesh);
// box 1
boxGeometry = new THREE.CubeGeometry(4, 4, 4);
boxMaterial = new THREE.MeshLambertMaterial({color: 0x00ff00});
box1Mesh = new THREE.Mesh(boxGeometry, boxMaterial);
box1Mesh.castShadow = true;
box1Mesh.receiveShadow = true;
scene.add(box1Mesh);
// box 2
box2Mesh = box1Mesh.clone();
scene.add(box2Mesh);
// renderer
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(w, h);
renderer.shadowMapEnabled = true;
var container = document.getElementById('d0');
container.appendChild(renderer.domElement);
var camBasePos = camera.position;
var camBaseLookAt = new THREE.Vector3(3, 3, -10);
document.addEventListener('mousemove', function(e){
if(flg){
cp = container.getBoundingClientRect();
camera.position = camBasePos.clone();
camera.position.subVectors(camera.position, camBaseLookAt);
camera.position.applyAxisAngle( new THREE.Vector3(0,1,0), (e.clientX-cp.left-160) / 72 );
camera.lookAt(scene.position);
camera.position.addVectors(camera.position, camBaseLookAt.clone());
flg = false;
}
}, false);
}
function animate() {
setTimeout(animate, 1000 / fps);
flg = true;
cnt++;
if(cnt / fps > 7) {
//return;
}
updatePhysics();
render();
}
function updatePhysics() {
// Step the physics world
world.step(timeStep);
// Copy FROM Cannon.js TO Three.js
cPlane1Body.position.copy(cPlane1Mesh.position);
cPlane1Body.quaternion.copy(cPlane1Mesh.quaternion);
cPlane2Body.position.copy(cPlane2Mesh.position);
cPlane2Body.quaternion.copy(cPlane2Mesh.quaternion);
sphereBody.position.copy(sphereMesh.position);
sphereBody.quaternion.copy(sphereMesh.quaternion);
box1Body.position.copy(box1Mesh.position);
box1Body.quaternion.copy(box1Mesh.quaternion);
box2Body.position.copy(box2Mesh.position);
box2Body.quaternion.copy(box2Mesh.quaternion);
groundBody.position.copy(groundMesh.position);
groundBody.quaternion.copy(groundMesh.quaternion);
}
function render() {
renderer.render(scene, camera);
}
sinit();
}(window, document));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment