2022. 2. 22. 22:58ㆍTechnology[Front]
이번 게시글에서는 Three.js에서 물리엔진을 지원하지 않기 때문에 별도로 물리엔진을 구현하고 있는 JS라이브러리를 사용하여 scene에 물리충돌을 구현하고자 할 때 cannon.js를 사용하여 구현하는 방법에 대해 알아보겠습니다.
(1) index.html
<script src="./data/cannon.js"></script>
index.html에서 script 태그로 cannon.js의 파일을 로드합니다.
(2) test.js
import {CannonDebugRenderer} from './data/CannonDebugRenderer.js';
let world;
let wall1;
let wall1Body;
let concreteMaterial;
let plasticMaterial;
let CannonDebugRenderer_1;
concreteMaterial = new CANNON.Material('concrete');
plasticMaterial = new CANNON.Material('plastic');
const concretePlasticContactMaterial = new CANNON.ContactMaterial(
concreteMaterial,
plasticMaterial,
{
friction: 0.1,
restitution: 0.7
}
);
world = new CANNON.World();
world.gravity.set(0, -9.82, 0);
world.addContactMaterial(concretePlasticContactMaterial);
CannonDebugRenderer_1 = new CannonDebugRenderer(scene, world);
const floorShape = new CANNON.Box(new CANNON.Vec3(plane.scale.x*100, 0.1, plane.scale.z*100));
const floorBody = new CANNON.Body();
floorBody.mass = 0;
floorBody.addShape(floorShape);
floorBody.material = plasticMaterial;
world.addBody(floorBody);
const wall1Shape = new CANNON.Box(new CANNON.Vec3(wall1.scale.x, wall1.scale.y*10, wall1.scale.z*100));
wall1Body = new CANNON.Body({
mass : 0,
position : new CANNON.Vec3(wall1.position.x, wall1.position.y, wall1.position.z),
shape : wall1Shape,
material: concreteMaterial,
});
wall1Body.collisionResponse = 0.1;
wall1Body.addEventListener("collide", () => {
// console.log("collide");
})
world.addBody(wall1Body);
CannonDebugRenderer_1.update();
renderer.render( scene, camera );
RAF();
function RAF() {
requestAnimationFrame((t) => {
if (previousRAF === null) {
previousRAF = t;
}
RAF();
renderer.render(scene, camera);
Step(t - previousRAF);
previousRAF = t;
});
}
function Step(timeElapsed) {
const timeElapsedS = timeElapsed * 0.001;
const deltaTime = timeElapsed - oldElapsedTime;
oldElapsedTime = timeElapsed;
world.step(1 / 60, deltaTime, 3);
}
위의 코드는 실제 프로젝트에서 일부 발췌한 것으로 실제 사용시 수정해서 사용하시면 됩니다. cannon.js의 구현을 눈으로 직접 보고 제어하기 위해 CannonDebugRenderer를 import해서 사용합니다. world라는 변수에 cannon.js에서의 world를 새롭게 생성하고(Three.js에서의 scene은 물리엔진이 없는 세상인 반면 Cannon.js에서의 world는 물리엔진이 구현된 세상이므로 두 세계를 모두 구현해야합니다.) 해당 world의 중력을 -9.82로 설정합니다. 이후 concreteMaterial과 plasticMaterial 두 종류의 재료를 선언하고 두 재료 간의 충돌을 구현하고 이를 world에 add합니다. 이후 CannonDebugRenderer을 scene과 world를 파라미터로 전달하여 생성하고 이를 지속적으로 update합니다. 3D 맵에서의 바닥과 벽은 모두 Cannon.js의 Box를 이용해서 크기를 지정하고 Body에서 position으로 해당 Box가 위치될 좌표를 제공하고 mass로 질량을 부여해 0보다 크다면 충돌 시 움직이게 됩니다. shape 속성으로 Box 모양임을 전달하고 material로 해당 Box의 재료를 선정하고 이는 충돌 구현 시 사용됩니다. 이후 collisionResponse로 충돌 시 힘을 가할지를 결정하고(0이면 충돌해도 방탄력을 제공하지 않기 때문에 서로 밀리지 않습니다.) addEventListener를 통해 collider 시 해야할 일을 지정할 수 있습니다. 모든 설정이 끝났다면 world.addBody를 통해 world라는 물리세상에 추가합니다. 이후 render하게 되면 물리세상이 구현되고 Step이라는 메서드에서 world.step을 통해 시간개념을 추가해서 시간의 흐름에 따라 충돌이 발생하게끔 구현하였습니다.
이번 게시글에서는 cannon.js를 이용해 물리세상에 물질을 추가하고 물질 간 충돌을 정의하는 방법에 대해 살펴보았습니다.
'Technology[Front]' 카테고리의 다른 글
3D맵 구현하기 - 유리재질 벽 구현하기 (1) | 2022.02.25 |
---|---|
3D맵 구현하기 - cannon.js로 물리엔진 구현하기(2) (1) | 2022.02.23 |
3D맵 구현하기 - 캐릭터가 움직일 때 fbx 파일로 움직임 구현하기 (1) | 2022.02.21 |
3D맵 구현하기 - 3인칭 카메라 구현하기(카메라 조종, 캐릭터가 카메라를 따라서 이동, 카메라가 보는 방향을 캐릭터가 응시) (1) | 2022.02.20 |
3D맵 구현하기 - 키보드로 카메라 이동시키기 (1) | 2022.02.19 |