物理エンジンを使って
3Dに息を吹き込む

13年12月12日木曜日
自己紹介
• 面白法人カヤック
HTMLファイ部所属
比留間 和也

• 最近は3D/JS/Unityばかりで、
あんまりHTML書いてません;

13年12月12日木曜日
JavaScriptの
新しい教科書
本を書きました

13年12月12日木曜日
最近作ったもの

13年12月12日木曜日
Agenda
• 作ったもの紹介
• 物理エンジンの仕組み(超簡易)
• CANNON.jsで物理演算
• Three.jsのCSS3DRendererで3D
13年12月12日木曜日
CSSでレンダリングされた
ほんとに投げれるサイコロ
13年12月12日木曜日
http://hookmark.in/
13年12月12日木曜日
物理エンジンの仕組み
1. 剛体に外力(重力など)を働かせる
2. ブロードフェーズ(剛体同士の大まかな衝突検出)
3. ナローフェーズ(剛体同士の詳細な衝突検出)
4. 衝突応答
5. 剛体の更新
6. 1に戻る

13年12月12日木曜日
剛体に外力を働かせる
13年12月12日木曜日
ブロードフェーズ
13年12月12日木曜日
ブロードフェーズ
13年12月12日木曜日
ナローフェーズ
13年12月12日木曜日
衝突応答
13年12月12日木曜日
衝突応答
13年12月12日木曜日
剛体の更新
13年12月12日木曜日
CANNON.jsで
物理演算

13年12月12日木曜日
世界を作る

13年12月12日木曜日
//Create a CANNON world.
world = new CANNON.World();
//Set gravity.
world.gravity.set(0, -98.2, 0);
//Set a way of broad phase
world.broadphase =
new CANNON.NaiveBroadphase();

13年12月12日木曜日
剛体を作る

13年12月12日木曜日
//Define a shape of rigid body.
var box =
new CANNON.Box(
new CANNON.Vec3(
cubeSize, cubeSize, cubeSize));
//Create a rigid body.
var dice =
new CANNON.RigidBody(0.3/* mass */,
box);
//Set a position of rigid body.
dice.position.y = 50;
//Add a rigid body to a world.
world.add(dice);
13年12月12日木曜日
//Create a plane as a ground.
var plane = new CANNON.Plane();
//Create a ground with mass 0.
var ground =
new CANNON.RigidBody(0, plane);
//Rotate 90 degree. (as a ground)
ground.quaternion.setFromAxisAngle(
new CANNON.Vec3(1, 0, 0),
-Math.PI / 2);
//Add a rigid body to a world.
world.add(ground);

13年12月12日木曜日
Three.jsの
CSS3DRendererで3D

13年12月12日木曜日
地面を作る

13年12月12日木曜日
//Create a ground with CSS3DObject
var textureSize = 800;
var floorEle = doc.createElement('div');
floorEle.style.width = textureSize + 'px';
floorEle.style.height = textureSize + 'px';
floorEle.style.background = 'url(ground.png)
left top repeat';
floorEle.style.backgroundSize = textureSize /
20 + 'px ' + textureSize / 20 + 'px';
floorObj = new THREE.CSS3DObject(floorEle);
floorObj.position.fromArray([0, 0, 0]);
floorObj.rotation.fromArray([Math.PI/2,0,0]);
scene.add(floorObj);
13年12月12日木曜日
//Create a ground with CSS3DObject
var textureSize = 800;
var floorEle = doc.createElement('div');
floorEle.style.width = textureSize + 'px';
floorEle.style.height = textureSize + 'px';
floorEle.style.background = 'url(ground.png)
left top repeat';
floorEle.style.backgroundSize = textureSize /
20 + 'px ' + textureSize / 20 + 'px';
floorObj = new THREE.CSS3DObject(floorEle);
floorObj.position.fromArray([0, 0, 0]);
floorObj.rotation.fromArray([Math.PI/2,0,0]);
scene.add(floorObj);
13年12月12日木曜日
サイコロを作る

13年12月12日木曜日
var boxInfo, el, dice, info, img, face;
boxInfo = [{ url: '2.png', position: [-cubeSize,0,0], rotation:
[0,Math.PI/2,0] },
{ url: '5.png', position: [cubeSize,0,0], rotation: [0,-Math.PI/2,0] },
{ url: '1.png', position: [0,cubeSize,0], rotation: [Math.PI/
2,0,Math.PI] },
{ url: '6.png', position: [0,-cubeSize,0], rotation: [-Math.PI/
2,0,Math.PI] },
{ url: '3.png', position: [0,0,cubeSize], rotation: [0,Math.PI,0] },
{ url: '4.png', position: [0,0,-cubeSize], rotation: [0,0,0] }];
el = document.createElement('div');
el.style.width = cubeSize * 2 + 'px';
el.style.height = cubeSize * 2 + 'px';
dice = new THREE.CSS3DObject(el);
for (var i = 0; i < boxInfo.length; i++) {
info = boxInfo[i];
img = document.createElement('img');
img.width = cubeSize * 2;
img.src = info.url;
face = new THREE.CSS3DObject(img);
face.position.fromArray(info.position);
face.rotation.fromArray(info.rotation);
dice.add(face);
}
13年12月12日木曜日
var boxInfo, el, dice, info, img, face;
boxInfo = [{ url: '2.png', position: [-cubeSize,0,0], rotation:
[0,Math.PI/2,0] },
{ url: '5.png', position: [cubeSize,0,0], rotation: [0,-Math.PI/2,0] },
{ url: '1.png', position: [0,cubeSize,0], rotation: [Math.PI/
2,0,Math.PI] },
{ url: '6.png', position: [0,-cubeSize,0], rotation: [-Math.PI/
2,0,Math.PI] },
{ url: '3.png', position: [0,0,cubeSize], rotation: [0,Math.PI,0] },
{ url: '4.png', position: [0,0,-cubeSize], rotation: [0,0,0] }];
el = document.createElement('div');
el.style.width = cubeSize * 2 + 'px';
el.style.height = cubeSize * 2 + 'px';
dice = new THREE.CSS3DObject(el);
for (var i = 0; i < boxInfo.length; i++) {
info = boxInfo[i];
img = document.createElement('img');
img.width = cubeSize * 2;
img.src = info.url;
face = new THREE.CSS3DObject(img);
face.position.fromArray(info.position);
face.rotation.fromArray(info.rotation);
dice.add(face);
}
13年12月12日木曜日
var boxInfo, el, dice, info, img, face;
boxInfo = [{ url: '2.png', position: [-cubeSize,0,0], rotation:
[0,Math.PI/2,0] },
{ url: '5.png', position: [cubeSize,0,0], rotation: [0,-Math.PI/2,0] },
{ url: '1.png', position: [0,cubeSize,0], rotation: [Math.PI/
2,0,Math.PI] },
{ url: '6.png', position: [0,-cubeSize,0], rotation: [-Math.PI/
2,0,Math.PI] },
{ url: '3.png', position: [0,0,cubeSize], rotation: [0,Math.PI,0] },
{ url: '4.png', position: [0,0,-cubeSize], rotation: [0,0,0] }];
el = document.createElement('div');
el.style.width = cubeSize * 2 + 'px';
el.style.height = cubeSize * 2 + 'px';
dice = new THREE.CSS3DObject(el);
for (var i = 0; i < boxInfo.length; i++) {
info = boxInfo[i];
img = document.createElement('img');
img.width = cubeSize * 2;
img.src = info.url;
face = new THREE.CSS3DObject(img);
face.position.fromArray(info.position);
face.rotation.fromArray(info.rotation);
dice.add(face);
}
13年12月12日木曜日
時間を進める

13年12月12日木曜日
function updatePhysics() {
//Step to a next time.
world.step(timeStep);
//Copy a position of rigid body to a mesh.
if (diceRigid) {
diceRigid.position.copy(dice.position);
diceRigid.quaternion.copy(dice.quaternion);
diceRigid.position.copy(camera.position);
camera.position.y += 50;
camera.position.x += 100;
camera.lookAt(diceRigid.position.copy(new
THREE.Vector3(0, 0, 0)));
}
}

13年12月12日木曜日
もう一回見てみます
13年12月12日木曜日
ご清聴ありがとうご
ざいました

13年12月12日木曜日

物理エンジンを使って 3Dに息を吹き込む