Direct3D : 월드행렬 (World Matrix) 1 - 이동행렬 Direct 3D


이번 주제는 렌더링 파이프라인의 2번째 단계인 월드 스페이스 단계의 
설정값으로 사용되는 월드 행렬입니다.

월드 스페이스라는 것은, 특정 객체를 실제 월드에 배치하는
역할을 해 줍니다. 간단하게 특정 세계에 유닛들을 배치하는 것을 생각해 봅시다.
어떤 정보가 필요할까요?



▲ 스타크래프트 2 메쉬 리소스를 사용하여 포트폴리오로 작업했던 맵툴입니다.


게임의 맵툴을 한번 생각해보면서 접근해 봅시다.
일단 맵툴을 켜고... 유닛을 선택하고... 월드맵에 배치를 하겠지요.
배치를 한다는것은, 유닛의 좌표를 결정한다는 의미가 아니겠습니까?
이런 식으로 진행해 봅시다.. 




1. 객체의 좌표

    좌표는 모든 객체가 기본적으로 가져야 할 정보일 것입니다. 세계에서 특정 객체는
    자신이 배치될 좌표를 기본적으로 가지고 있어야 합니다. 모든 객체가
    동일한 곳에 위치할 리는 없지 않겠습니까?

    3D 오브젝트를 생각해 보면, 이 경우 기본적으로 존재하는 객체의 "버텍스" 정점들을
    특정 좌표만큼 더해주는 처리를 한다면, 좌표 값만큼 객체를 이동시키는 처리가
    가능할 것입니다.


2. 객체의 회전값

    객체는 한 방향만 바라보지 않습니다. 객체들은 회전을 할 수 있습니다.
    이러한 회전에 대한 정보 역시 객체를 구성할 때에 필요한 정보들입니다.
    
    이들 정보는 기본적으로 X,Y,Z 축에 대해서 회전할 수 있으며,
    필요에 따라, 두 지점 사이의 벡터 연산으로 임의의 축을 구하고,
    구해낸 임의의 축에 대한 회전 처리 역시 가능합니다.

    회전은 스스로 회전하는 자전 이외에, 공전 처리도 포함합니다.


3. 객체의 크기

    게임에서의 보스 몬스터를 생각해 주십시오. 보스 몬스터는 일반 객체들보다
    상당히 크게 구성됩니다. 이러한 크기를 변경하는 처리도 필요합니다.
    
    물론 처음부터 3D 리소스 데이터를 만들때 크기를 조절해서 만들면 되지 않느냐?
    하고 생각할 수도 있겠습니다만, 크게 만들었던 리소스를 나중에 작게 만들어
    재사용하고 싶은 경우에는 어떻게 하겠습니까? 똑같은 리소스인데 작은 리소스를
    새로 만들어 사용하시겠습니까? 이왕이면 준비된 리소스의 크기를 원하는 대로
    변환해가며 작업하는 편이 효율적일 것입니다.

    실시간으로 크기를 변형할 수 있으므로, 보다 효과적인 처리도 할 수 있습니다.
    이를테면 버프를 받으면 객체의 크기가 일시적으로 커진다던가, 객체가 사라질때
    작아지면서 사라지는 식의 처리도 크기를 실시간으로 변형할 수 있을때 쉽게 구성할
    수 있는 효과들이 되겠지요.




일단 필요한 처리는 이렇게 크게 3가지로 분류됩니다. 
Direct 내부에서 월드 스페이스 구성 시에, 출력할 객체는 이와 같은 정보들이 설정되어
구성됩니다. 이 설정은 반드시 필요한 설정으로, 별도의 설정을 하지 않는다면 디폴트
설정값을 가지며, 이에 따라서 월드 스페이스가 구성됩니다.

(물론 디폴트 설정을 그대로 둔다면, 출력할 모든 객체가 동일한 설정이 적용될 것이므로...
 모두 같은 위치에 출력되며, 난장판이 되는 모습을 볼 수 있겠지요...^^)

이러한 일련의 정보들은, "행렬"을 사용해 구성됩니다. 단순히 이동시킬 좌표,
이동 후 회전, 회전 후 크기설정... 등에 대한 작업을 위한 수치를 구성하는 정도라면,
굳이 행렬 개념까지 사용될 필요가 없다고 생각될지 모르겠으나,

행렬을 사용하고, 각각의 설정값들을 행렬 연산을 통해 통합 관리하는 것으로 많은 
연산상의 이점을 얻을 수 있습니다. 
그러면 지금부터 Direct 에서 사용되는 행렬을 살펴보겠습니다. 3D 세계를 표현하기
위한 행렬은 기본적으로 4 x 4 행렬이 사용됩니다. 



이 구조체가 D3D에서 사용되는 행렬입니다. 각각의 원소는 float 형 변수로 만들어져 있으며,
 
행렬에 값을 설정한 뒤에, 디바이스에 무슨 행렬을 전달하는 것인지 플래그를 전달하고,
연산된 행렬을 넘겨 주는 것으로, 필요한 설정을 할 수 있습니다.

이 행렬은 3D 오브젝트의 정점들을 원하는 위치의 좌표로 변환하기 위해서 사용됩니다.
이번에 언급할 이동행렬은 _41 ~ _43 값을 다루는 내용이므로, 1 과 곱해져서
넣어준 인자의 값이 그대로 나오며, 이전 연산 결과에 단순히 수치를 더하는 결과를
주는 형식입니다.

디바이스에 월드행렬을 전달할때는 이런 식으로 전달합니다.

ex) m_pDevice->SetTransform(D3DTS_WORLD,&matWorld);
//행렬 객체를 넘겨줍니다. 이때 플래그는 D3DTS_WORLD 로 설정합니다.




이동행렬은 객체의 좌표값을 반영하기 위한 값을 설정하는 역할을 합니다.
기본적으로 설정하고자 하는 월드행렬의 _41,_42,_43 값이 이동값에 해당되며,
각각 X좌표, Y좌표, Z좌표를 나타냅니다. 값 자체가 일종의 좌표를 나타내는 것으로
이해하면 됩니다.

더불어, 이 값은 객체의 로컬 좌표의 중심좌표를 변경시켜 주는 것이기도 합니다.
3D 오브젝트들은, 각각 여러 버텍스 정점을 통해서 구성되어 있습니다. 이 버텍스 
정점들은, 로컬 좌표상에서 객체의 중심값에서 얼마만큼씩 거리를 가진다는 상대적
좌표를 가지고 있습니다.

그러므로, 월드 스페이스에서는 특정 3D 객체의 중심 좌표를 지정하게 되고,
이 객체에 소속된 버텍스들은 해당 중심으로부터 상대적 좌표값만큼 거리를 가진
상태로 설정되는 것이지요. 더불어 이 값은 회전행렬의 연산값으로부터,
독립적입니다.

(정확하게는 회전행렬 연산으로 원점을 기준으로 한 좌표를 구한 후,
 덧셈처리되어 모든 정점들을 이동값만큼 옮겨주는 식으로 처리되는 것이죠^^)



행렬 구조체를 선언하고, 이 행렬의 이동값을 설정하는 것으로, 
출력하고자 하는 객체의 위치를 변경할 수 있습니다.

사용된 함수는 다음과 같습니다.



D3DXMatrixIdentity

행렬의 원소 중 _11,_22,_33,_44 값을 1로 초기화하고,
나머지 원소를 모두 0으로 초기화해주는 함수입니다.
실제 사용될 행렬을 연산하기 전에 초기화를 해 두는 것으로,
연산시 오류를 발생하지 않도록 준비하는데 사용되었습니다.

그러니까 요약해서 항등행렬로 만들어준다 뭐 이런얘기입니다^^
항등행렬은 행렬연산시 곱하더라도 원본 행렬이 변하지 않습니다.
곱셈으로 따져보면 1을 곱하면 값이 변하지 않죠?
이렇게 특정 연산에 대해 결과값이 변하지 않는 것을 항등원이라고 하죠?

때문이 행렬도 이러한 역할을 하는 행렬을 항등행렬이라 부르며,
곱의 교환법칙도 성립합니다. 말하자면 행렬계의 숫자 "1"
같은 존재라고 할 수 있습니다.

때문에 행렬을 항등행렬로 만들어주는 처리를 하고(초기화하고)
작업을 하는 것입니다. 

(항등행렬을 Identity Matrix 라고 부르죠. 함수 이름도 항등행렬에서
 따 왔다는게 느껴지지 않습니까?)
  

D3DXMatrixTranslation

이동행렬을 설정해 주는 함수입니다. 인자로 대상이 되는 행렬의 주소와
좌표를 받습니다. 대상이 되는 행렬 값의 _41,_42,_43 값을
좌표값으로 설정하여 반환하는 기능을 합니다.




이런 식으로 직접 수치를 대입하여, 설정하면 동일한 결과를 볼 수 있습니다.
함수의 기능이 이러한 역할을 해 주는 것으로 생각하면 되겠습니다.




위 스크린샷은, 이동행렬을 통해 월드행렬값을 설정하고, 
이 정보를 디바이스에 전달하여, 출력된 결과를 표현하고 있습니다.

(0,-5,10) 으로 좌표가 설정된 결과를 보면,
(0,0,0) 에 비해서 우주선이 좀 더 아래로 내려갔으며, 뒤로 이동된 상태라는 것을
알 수 있을 것입니다.
모든 정점이 넣어준 좌표값만큼 이동하게 된 것이죠.

여기까지가 이동행렬에 대한 소개였습니다.
다음 글에서는 이어서 회전행렬과 크기변환 행렬에 대한 주제를 다루어 볼 것입니다.




덧글

댓글 입력 영역


라운드 시계