GPU의 장점은 단순한 작업을 여러 개 많이 할 때 빠르다는 것이다. CPU 에서 GPU 로 값을 보내는 것이 느리니 가급적 단순하게 정리 되어있는 데이터를 보내줘야한다.
실제 게임에서의 캐릭터 움직임은 굉장히 복잡하다. Transformation 이 복잡하게 shader 에서 사용되어지면 그때는 오히려 gpu 의 장점이 사라지기 때문에 가장 간단한 하나의 행렬 형태 즉, 모든 움직임을 조합한 modelMatrix 를 이용해 shader 에서 작업하도록 만드는 실습을 한다.
// 쉐이더에서 공통적으로 사용하는 상수들
// 예) 모든 버텍스들을 같은 비율로 스케일
struct Constants {
// GPU로 Transformation 대신에 matrix 하나만 보냅니다.
// Transformation transformation;
mat4 modelMatrix; // worldMatrix라고 부르기도 합니다.
mat4 invTranspose; // Normal에 적용합니다.
// 그 외에 viewMatrix, projectionMatrix 등도 사용합니다.
Material material;
Light light;
int lightType = 0;
} constants;
레스터라이저 단계에서 행렬로 srt 를 표현한 방식이다. 다만, column major 니까 trs 순으로 행렬을 곱해준다.
normal 을 구할 때는 연산이 좀 다른데 이유는 아래 그림과 같이 설명한다.
인덱스 3번을 vec4 로 초기화 하는 것은 수치 에러가 나기 때문에 필연적으로 초기화한다. 이유는 normal 은 이동이 필요 없기 때문이다.
// 여기서 GPU에게 보내줄 변환 행렬을 만들어줘야 합니다.
// 순서 주의 (GLM은 column major 사용)
constants.modelMatrix = glm::translate(mesh->transformation.translation)*
glm::rotate(mesh->transformation.rotationX, vec3(1.f,0,0))*
glm::rotate(mesh->transformation.rotationY, vec3(0,1.f,0))*
glm::scale(mesh->transformation.scale);
// Non-uniform scale인 경우에만 필요
constants.invTranspose = constants.modelMatrix;
constants.invTranspose[3] = vec4(0,0,0,1);
constants.invTranspose = glm::inverseTranspose(constants.invTranspose);
역행렬의 전치해서 곱해주면 된다. 이유는 스케일링 시에는 아래 그림과 같은 문제가 생길 수 있기 때문에 그냥 일반적인 srt 를 normal 에 적용해서는 안되는 것이다. 따라서 srt 의 역행렬의 전치 행렬을 normal 에 곱해줘야한다.

이제 쉐이더 쪽 코드를 보면
vec3 를 받고 vec4 로 만들어준다. 이유는 cpu 에서 gpu 데이터 보내는게 느리니 vec3 로 보낸다음 간단하게 vec4 로 gpu 에서 만들어주어 속도를 조금이라도 올리는 것이다.
// 마지막에 1.0f 추가
vec4 point =
vec4(vsInput.position.x, vsInput.position.y, vsInput.position.z, 1.0f);
이 코드에서 봐야할것은 2가지인데 첫째 Column major 라서 point 연산이 뒤에 있다.
둘 째 물체의 srt 적용 시 normal 은 별도로 적용해줘야한다. 다만 아래에서는 별도로 적용하고 온걸 가져온거임!
// 여기서 여러가지 변환 가능
// vsOutput.position =
// RotateAboutX(
// RotateAboutY(vsInput.position * constants.transformation.scale,
// constants.transformation.rotationY),
// constants.transformation.rotationX) +
// constants.transformation.translation;
// 마지막에 1.0f 추가
vec4 point =
vec4(vsInput.position.x, vsInput.position.y, vsInput.position.z, 1.0f);
point = constants.modelMatrix * point; // 주의: column-major
vsOutput.position = vec3(point.x, point.y, point.z);
// 주의: 노멀 벡터도 물체와 같이 회전시켜줘야 합니다.
// 더 편하게 구현할 방법은 없을까요?
// vsOutput.normal = RotateAboutX(
// RotateAboutX(
// RotateAboutY(vsInput.normal, constants.transformation.rotationY),
// constants.transformation.rotationX),
// constants.transformation.rotationX);
// 마지막에 0.0f 추가
vec4 normal =
vec4(vsInput.normal.x, vsInput.normal.y, vsInput.normal.z, 0.0f);
// Unon-uniform transformation인 경우에는 보정 필요
normal = glm::normalize(constants.invTranspose * normal); // 주의: column-major'DX' 카테고리의 다른 글
| COM 과 D3D (0) | 2025.06.15 |
|---|---|
| DirectX Math (0) | 2025.06.06 |
| GLM (0) | 2025.06.06 |
| 좌표계 변환 (0) | 2025.05.11 |
| Affine Transformation (0) | 2025.05.11 |