OpenGL 쉐이더 프로그래밍 - 3D 뷰잉 개념

타입·2025년 9월 11일

컴퓨터 그래픽스

목록 보기
19/24

OpenGL 관점의 Viewing

World Frame: 감독 관점, 물체를 배치하기 위해 필요
Object Frame: 물체 디자인을 위해 필요 (Model Frame이라고도 함)
View Frame: 카메라를 시뮬레이션하기 위해 필요

  • Model Transform
    Object Frame 기준으로 정의된 물체를 World Frame 기준으로 배치(회전/이동)
  • View Transform
    World Frame 전체를 View Frame으로 변환
    카메라 기준으로 물체를 재해석

View Transform의 필요성

  • Panning 기법
    카메라가 움직이며 촬영
    카메라의 이동 경로는 World Frame 기준으로 설정하는 것이 쉬움

3D 씬의 설정

  • 큐브 만들기
    8개의 꼭짓점과 12개의 삼각형으로 정육면체를 만듦

  • 피라미드 만들기
    5개의 꼭짓점과 6개의 삼각형으로 사각뿔을 만듦

  • Model Transform
    물체를 배치하기 위해 월드 좌표계 기준으로 Scale/Rotate/Translate 적용

모델링 변환

M_model: Model Transform 행렬
q_model: Model Frame 상의 물체의 좌표

물체의 좌표 q_model에 대해 M_model 행렬 연산을 진행하면 World Frame 기준의 좌표로 변환됨

  • 큐브와 피라미드 좌표 행렬
// 한 면을 2개의 삼각형으로 표현
// 좌표와 색상을 구조체로 묶어 사용
glm::vec4 vertCube[] = { // 12 * 3 = 36 (vertices + color)
	// face 0,1: v0-v3-v2, v0-v2-v1, red
	{ -0.5F, -0.5F, +0.5F, 1.0F }, { 1.0F, 0.3F, 0.3F, 1.0F }, // v0
	{ -0.5F, -0.5F, -0.5F, 1.0F }, { 1.0F, 0.3F, 0.3F, 1.0F }, // v3
	{ +0.5F, -0.5F, -0.5F, 1.0F }, { 1.0F, 0.3F, 0.3F, 1.0F }, // v2
	{ -0.5F, -0.5F, +0.5F, 1.0F }, { 1.0F, 0.3F, 0.3F, 1.0F }, // v0
	{ +0.5F, -0.5F, -0.5F, 1.0F }, { 1.0F, 0.3F, 0.3F, 1.0F }, // v2
	{ +0.5F, -0.5F, +0.5F, 1.0F }, { 1.0F, 0.3F, 0.3F, 1.0F }, // v1
    ...
};

glm::vec4 vertPyramid[] = { // 6 * 3 = 18 (vertices + color)
	// face 0: v0-v1-v2, red
	{ 0.0F, 0.5F, 0.0F, 1.0F }, { 1.0F, 0.3F, 0.3F, 1.0F, }, // v0
	{ 0.5F, -0.3F, 0.0F, 1.0F }, { 1.0F, 0.3F, 0.3F, 1.0F, }, // v1
	{ 0.0F, -0.3F, -0.5F, 1.0F }, { 1.0F, 0.3F, 0.3F, 1.0F, }, // v2
    ...
};
  • Model Transform 행렬
    큐브와 피라미드에 대한 Model Transform 행렬 정의
// 단위행렬로 초기화
glm::mat4 matPyramid = glm::mat4( 1.0F );
glm::mat4 matCube = glm::mat4( 1.0F );

void updateFunc(void) {
	...
    
    // 변환을 적용하는 순서와 함수를 호출하는 순서는 반대
    // Scale -> Rotate -> Translate 순서대로 변환이 적용됨
	matPyramid = glm::mat4( 1.0F );
	matPyramid = glm::translate( matPyramid, glm::vec3(-0.4F, 0.0F, 0.0F));
	matPyramid = glm::rotate( matPyramid, theta, glm::vec3(0.0F, 1.0F, 0.0F));
	matPyramid = glm::scale( matPyramid, glm::vec3(0.5F, 0.5F, 0.5F));
    
	matCube = glm::mat4( 1.0F );
	matCube = glm::translate( matCube, glm::vec3(0.4F, 0.0F, 0.0F));
	matCube = glm::rotate( matCube, theta, glm::vec3(1.0F, 0.0F, 0.0F));
	matCube = glm::scale( matCube, glm::vec3(0.3F, 0.3F, 0.3F));
}
  • drawFunc 함수
void drawFunc(void) {
	...
    
	GLuint locPos = glGetAttribLocation(prog, "aPos");
	GLuint locColor = glGetAttribLocation(prog, "aColor");
	GLuint locMat = glGetUniformLocation(prog, "uMat");
	glEnableVertexAttribArray(locPos);
	glEnableVertexAttribArray(locColor);
    
    // 포지션을 설정
	glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), glm::value_ptr(vertPyramid[0]));
    // 컬러를 지정
	glVertexAttribPointer(locColor, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), glm::value_ptr(vertPyramid[1]));
    // 유니폼 변수에 Model Transform 행렬 적용
	glUniformMatrix4fv(locMat, 1, GL_FALSE, glm::value_ptr(matPyramid));
	glDrawArrays(GL_TRIANGLES, 0, 18); // 18 vertices
    
	glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), glm::value_ptr(vertCube[0]));
	glVertexAttribPointer(locColor, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), glm::value_ptr(vertCube[1]));
	glUniformMatrix4fv(locMat, 1, GL_FALSE, glm::value_ptr(matCube));
    // 각자 다른 변환 행렬을 적용하고 있으므로 회전 방향도 다르게 적용
	glDrawArrays(GL_TRIANGLES, 0, 36); // 36 vertices
    
    ...
}

피라미드와 큐브 별로 각자의 변환 행렬이 적용되는 것을 확인
(피라미드는 y축, 큐브는 x축 회전)

profile
주니어 언리얼 프로그래머

0개의 댓글