Direct3D12

[Direct3D12] 과제1

태현123 2019. 11. 1. 11:34
728x90
반응형
SMALL

[과제 소개]

교수님이 WinAPI를 가지고 3D 게임의 프레임워크를 만들어서 학생들에게 뿌려주셨다. 우리는 그 프레임워크의 기본적인 구조만 가지고 비행기 게임을 만들어야 했다. 과제의 내용은 이러했다.

 

플레이어가 움직일 때 상///우 방향에 사각형들을 그려 공간의 입체감을 표현해야 함.

플레이어와 적은 이 공간을 벗어날 수 없음

공간의 반대쪽 끝에 적 보스가 있음.  

적 보스는 플레이어를 향하여 총을 발사할 수 있음.(적 보스의 모양 ,이동, 무기 등은 각자 설정)

플레이어가 보스를 제거하면 게임이 종료 됨.

적은 4종류이며 색상은(Red,Blue,Green,Pink)으로 구분함.  

모양은 육면체이고 크기가 다를 수 있음.  

(Blue,Green,Pink)색상의 적은 플레이어 진행방향 100m 앞에서 1초마다 생성  

(Red) 색상의 적은 플레이어 진행 방향 100미터 앞에서 10초마다 생성  

적의 생성 위치와 이동방향은 무작위 이며, 항상 회전하며 이동함. 회전속력과 이동속력은 각자 설정

적은 직육면체 공간에 부딪치면 반사 벡터의 방향으로 이동해야 함.  

적은 플레이어가 발사한 총알에 맞으면 100조각 이상으로 폭발하면서 사라져야 함.

W/A/S/D를 사용하여 앞///우 방향으로 이동할 수 있음.

Q/E를 사용하여 위 아랫방향으로 이동할 수 있음.

마우스를 사용하여 플레이어를 x-, y-, z-축으로 회전할 수 있음

플레이어와 적이 충돌하면 게임이 새로 시작됨

Ctrl 키를 누를 때마다 플레이어가 향하는 방향으로 총알을 발사할 수 있음.

플레이어는 최소 20발 이상 총알을 갖고 있음.  

총알은 항상 회전하면서 이동함.  

플레이어가 직육면체 공간에 부딪히면 색상이 바뀌어야 함.  

플레이어의 뒤에서 접근하는 적이 있으면 플레이어의 색이 Pink색으로 바뀌어야 함.  

총알이 Red색상의 적과 충돌할 때마다 특수 아이템을 가지게 됨.  

자동 조준할 적을 마우스로 선택(Picking)할 수 있음.

 

굉장히 많은 내용이 있었고, 나는 이 중에서 피킹 알고리즘 구현이 가장 어려웠었다. OpenGL 배울 때도 구현해 본 적이 없었기 때문에 인터넷을 미친듯이 뒤졌다. 그렇게 얻어낸 결론으로는

1. 로컬(모델) 좌표계 상에서 정의된 3D 객체의 정점들을 화면 좌표계 기준으로 변환한다.

 

2. 마우스의 위치를 얻는다.( 물론 화면 좌표계 기준으로 )  

 

3. 변환된 3D 객체의 화면 좌표계 상의 범위( 다각형들 )와 마우스 의 위치( 점 )를 비교해

   점이 다각형 안에 포함됐는지를 판별 한다.

 

와 같은 방식으로 구현해야 했다. 

 

그래서 나는 이렇게 구현했다.

-Ray(광선) 구조체(광선의 위치벡터와 방향벡터가 존재함.)를 만들었다. 그리고 스크린좌표-> 화면의 역변환-> 투영 역변환 -> 카메라 좌표가 되도록 해서 광선에 정규화된 방향벡터와 위치벡터를 얻었다. 그리고 이 광선에 대해 부딪히는 모든 큐브 오브젝트 중에서 가장 distance가 가까운 오브젝트를 m_pickedObject에 넣고, Ctrl키를 누를 때마다 PickedObject를 조준해서 총알을 쏘도록 하였다.


float dist = 100000000;
float intersectDist=10000000; // 최소 플레이어와 오브젝트간 거리
float vx, vy, vz;
mx = LOWORD(lParam); //xScreen
my = HIWORD(lParam); //yScreen
vx = (((((mx - 0/*뷰포트의 left*/)*2.0f / 640/*뷰포트의 width*/) - 1.0f)) - m_pPlayer->m_pCamera->m_xmf4x4Projection._31) / m_pPlayer->m_pCamera->m_xmf4x4Projection._11;
vy = ((-(((my - 0/*뷰포트의 top*/)*2.0f / 480) - 1.0f/*뷰포트의 height*/)) - m_pPlayer->m_pCamera->m_xmf4x4Projection._32) / m_pPlayer->m_pCamera->m_xmf4x4Projection._22;
vz = 1.0f;
XMFLOAT4X4 m = Matrix4x4::Inverse(m_pPlayer->m_pCamera->m_xmf4x4View);
ray.dirX = vx * m._11 + vy * m._21 + vz * m._31;
ray.dirY = vx * m._12 + vy * m._22 + vz * m._32;
ray.dirZ = vx * m._13 + vy * m._23 + vz * m._33;
ray.posX = m._41;
ray.posY = m._42;
ray.posZ = m._43;
picked = false;
for (auto &p : m_ppObjects)
{
if (p.m_xmOOBB.Intersects(XMLoadFloat3(&XMFLOAT3(ray.posX, ray.posY, ray.posZ)), XMLoadFloat3(&Vector3::Normalize(XMFLOAT3(ray.dirX, ray.dirY, ray.dirZ))), dist))
{
if (sqrt((p.GetPosition().x-m_pPlayer->GetPosition().x)*(p.GetPosition().x - m_pPlayer->GetPosition().x)
+(p.GetPosition().y-m_pPlayer->GetPosition().y)*(p.GetPosition().y - m_pPlayer->GetPosition().y)
+ (p.GetPosition().z - m_pPlayer->GetPosition().z)*(p.GetPosition().z - m_pPlayer->GetPosition().z))<intersectDist)
{
intersectDist = sqrt((p.GetPosition().x - m_pPlayer->GetPosition().x)*(p.GetPosition().x - m_pPlayer->GetPosition().x)
+ (p.GetPosition().y - m_pPlayer->GetPosition().y)*(p.GetPosition().y - m_pPlayer->GetPosition().y)
+ (p.GetPosition().z - m_pPlayer->GetPosition().z)*(p.GetPosition().z - m_pPlayer->GetPosition().z));
m_pickedObject = &p;
picked = true;
}// 최고 작은 거리에서의 오브젝트 찾기.
}
}

관련 코드는 대충 이러했다.

 

[영상]

[후기]

3D게임을 API로 제작하는 과정도 굉장히 신기했고, 재미있었다. 다만 피킹알고리즘이 너무 어려워서 시간을 많이 잡아먹었었던 것 같다. 미니맵은 어렵지 않게 만들 수 있었던 것 같다.

반응형
LIST

'Direct3D12' 카테고리의 다른 글

[DirectX12] 렌더링 파이프라인  (0) 2021.07.11
[Direct3D12] 과제2  (1) 2019.11.01