adsense



[cocos2d-x] 3D 게임을 만들자!


왜 2D 게임엔진으로 3D 게임 만들려고 삽질을 합니까?





예 뭐 3D 게임 만드는데 좋은 엔진은 아닙니다. 셰이더도 부실하고 물리엔진 쓰기도 까다롭고.
요즘은 외부업체 SDK 인트하기도 점점 힘들어지고..

그래도 기왕 해 본 거,
여기까지 왔으니까
개발하면서 풀기 힘들어 끙끙댔던 문제들 해결하거나 찾아낸 것들 정리해 보았습니다.



1. 카메라
cocos2d-x 환경의 디폴트 카메라는 기본적으로 2D 요소를 나타내기 위한거라,
3D를 위해서는 별도의 카메라를 생성해 주는게 좋습니다.
디폴트 카메라를 갖고 해도 되지만 나중에 2D 스프라이트로 표시하는 UI요소와 분리하기 힘들기 때문에,
UI는 디폴트 카메라로, 3D는 새로운 카메라를 쓰는게 좋습니다.

[1] Size size = Director::getInstance()->getVisibleSize();
[2] auto camera = Camera::createPerspective(60, (GLfloat)visibleSize.width / visibleSize.height, 1, 10000);
[3] camera->lookAt(Vec3::ZERO, Vec3::ZERO);
[4] camera->setCameraFlag(CameraFlag::USER1);

[1] 보여지는 화면 크기를 구합니다
[2] 카메라를 생성합니다. 각 파라미터의 의미는
카메라 화각 (FOV)
투영면의 종횡비 (aspectRatio)
가장 가까운 투영면 거리. 이보다 가까운 오브젝트는 랜더링되지 않습니다.
가장 먼 투영면 거리. 이보다 멀면 보이지 않습니다.
[3] 카메라가 바라보는 방향.
이를 이용해 특정 모델을 지속적으로 (update나 schedule 등에서)바라보게 하면 해당 모델에 카메라 포커싱을 고정할 수 있습니다. (위치 지정과는 다릅니다)
[4] 새로 생성한 카메라의 플래그를 지정합니다.
이후 2D 또는 3D 오브젝트에 setCameraMask로 이 카메라 플래그를 지정하면 여기에 비춰지게 됩니다.
오브젝트마다 일일이 지정해야 하는게 불편.
3D 오브젝트 위에 다른 요소를 붙였을(addChild) 때도 해당 child에도 플래그를 지정해야 합니다.

카메라에도 위치position와 각도rotation를 지정할 수 있습니다.


2. cocos2d-x 환경의 3D 좌표
디폴트 카메라의 위치는 수직 위에서 화면을 똑바로 내려다보고 있는 상태입니다.
그래서 x, y 좌표는 2D 좌표계의 좌표를 따르고, z좌표계(*-1)가 화면 안쪽으로의 깊이(=카메라로부터의 거리)를 나타냅니다.

어지간하면 사용자 정의 카메라도 이 좌표계를 따르는게 좋다고 봅니다.
왜냐하면 3D 오브젝트를 터치해야 한다던가 할 때, 좌표환산(convertNodeSpace)의 문제 때문에. (3. 참조)



3. 3D 모델의 2D 범위 얻어오기
현재 화면에 투영(Projection)된 3D 모델의 2D 바운딩 박스를 얻어오는 방법입니다.


2D인 미사일 락 온 사이트와 3D인 적기가 겹쳤는지 판단하려면 어떻게 하면 될까요?


3D 모델을 getBoundingBox로 얻어오면 카메라와의 거리에 상관없이 정사이즈가 들어옵니다.
그것을 카메라와의 거리에 따라 달라진 사이즈로 환산하는 방법입니다.

Rect getProjectRect(Camera* camera, Rect src, float z)
{
    Vec2 LeftBottom = camera->projectGL(Vec3(src.origin.x, src.origin.y, z));
    Vec2 RightTop = camera->projectGL(Vec3(src.origin.x + src.size.width, src.origin.y + src.size.height, z));
    
    return Rect(LeftBottom.x, LeftBottom.y, RightTop.x - LeftBottom.x, RightTop.y - LeftBottom.y);
}

camera는 현재 해당 3D 모델을 비추고 있는 카메라.
src는 getBoundingBox로 얻어낸 Rect (3D 모델이 아니어도 3D 공간에 있다면 빌보드나 스프라이트같은 2D 요소도 가능)
z는 해당 목표의 z지점.

이렇게 얻어온 Rect값에 대해서
containsPoint나 intersectRect 등으로 터치점이나 다른 요소와의 겹침을 받아낼 수 있습니다.



4. 물리엔진을 쓰지 않고 3D 모델끼리의 충돌 검사하기
Sprite3D의 getAABB()를 사용합니다.
AABB는 Axis Aligned Bounding Box. 2D 바운딩박스와 같이 인터섹트를 판별할 수 있습니다.

auto aabb1 = enemy->getAABB();//적기
auto aabb2 = attack->getAABB();.//플레이어 총탄
if (aabb1.intersects(aabb2))
{
//적기에 총탄 명중 판정
}
대충 이렇게 합니다.

4-1. AABB를 사용할 경우의 주의점.
2D와 마찬가지로 바운딩박스는 공백에 대해서도 들어오기 때문에 공백끼리 충돌해도 충돌로 판정됩니다.
때문에 3D모델을 만들어서 가져올 때 불필요한 공백을 최소화할 필요가 있습니다.

보라매는 매지카복셀로 만든 복셀 모델을 사용하는데, 여기서 이렇게 공백이 남으면 이 공백까지 모두 바운딩박스에 들어옵니다.

위 모델의 경우 녹색육면체 공간이 바운딩박스에 포함됩니다.
obj로 내보내기 전에 매지카복셀의 Fit 기능으로 공백은 모두 잘라주도록 합니다.



5. Sprite3D 텍스처 변경하기
setTexture를 사용해서 특정 텍스처를 적용할 수 있습니다.

주로 두 가지
[1] 하나의 모델을 색(텍스처)을 바꿔 사용하기
[2] 다른 모델간에 같은 png 공유하기

[1] 말 그대로. 레가시 게임의 색만 다른 적캐릭터 같은 걸 표현하는데 쓸 수 있습니다.
기본팔레트 KF-21

블루팔레트 KF-21


[2] 매지카복셀에서 익스포트한 모델을 쓰려면 매지카복셀이 함께 생성하는 png모델을 포함시켜야 하는데,
서로 다른 모델이 매지카복셀에서 동일한 팔레트를 썼다면 내용은 같고 이름만 다른 png를 중복으로 가지게 됩니다.
팔레트 역할을 하는 png 하나만 갖고 이 팔레트를 setTexture로 적용하면 중복할 필요가 없습니다.



6. UI
1항에서 카메라를 설정했다면 카메라 플래그를 지정하지 않고 출력하는 요소는 사용자 카메라의 영향을 받지 않습니다.
처음부터 이랬다면 걱정할 필요 없는 부분. 저는 처음 모든걸 디폴트 카메라로 퉁치는 바람에 UI가 카메라 따라 이리저리 돌아가는걸 보고 어떻게 분리해야 하나 고민했었습니다.




7. 3D 모델의 앵커와 방향
매지카복셀에서 생성한 모델은 무조건 맨 아랫바닥 정중앙에 앵커가 옵니다.
obj로 익스포트 후 블렌더에서 불러서 앵커 위치를 적절하게 변경해주는게 좋습니다.
매지카 복셀에서 기본 익스포트한 경우의 앵커

블렌더에서 앵커 위치를 변경. (오리진을 질량의 중심으로 이동->선택을 커서에 스냅)


또, 모든 모델은 처음 모델링할 때부터 방향을 통일해주는게 좋습니다.
안그러면 같은 rotation 값인데 서로 다른 방향을 보게 되기 때문에.


8. 3D공간에서 겨냥하기


미사일이나 총알이 날아가는 방향을 보기 위해서 각도를 구하는 방법입니다.
목표 좌표가 정해져 있는 경우,

src : 기준이 되는 오브젝트 좌표
dst : 목표 좌표

Vec3 _dst = dst - src; //목표 좌표를 src = Vec3::ZERO로 보정

auto rad_1 = getAngle(Vec2::ZERO, Vec2(_dst.x, _dst.z));
auto rad_2 = getAngle(Vec2(_dst.y, _dst.z), Vec2::ZERO);
srcobject>setRotation3D(Vec3(rad_2, rad_1, 0));

//두 점이 이루는 각도를 계산하는 자작함수 (시계 12시 위치가 0도, 3시가 90도)
float getAngle(Vec2 pos1, Vec2 pos2)
{
    float vx = pos1.x - pos2.x;
    float vy = pos1.y - pos2.y;
    double rad = atan2(vx, vy);
    return (int)((rad * 180) / 3.1415f);
}

(※이때 좌표계는 디폴트 카메라와 같은 좌표계)




덧글

댓글 입력 영역


Books

Geek라이프

MSX&재믹스 퍼펙트 카탈로그
마에다 히로유키 저/조기현 역

미소녀 일러스트 테크닉
B-은하, pen스케, 카와이 저/정유진 역

핵심강좌! Cocos2d-x
이재환 저

피규어의 교과서 레진 키트 & 도색 입문 편
후지타 시게토시 저/김정규 역
예스24 | 애드온2
일본서적 전문사이트 NEPIC