OpenGL 쉐이더 프로그래밍 - Depth 처리

타입·2025년 7월 23일

컴퓨터 그래픽스

목록 보기
11/24

렌더링 순서 문제

서로 겹치는 삼각형

빨간색 삼각형과 파란색 삼각형이 서로 겹치도록 위치

glm::vec4 vertRed[] = { // will be painted in red
	{ -0.2F, -0.2F, 0.0F, 1.0F, },
	{ -0.2F, +0.8F, 0.0F, 1.0F, },
	{ +0.8F, -0.2F, 0.0F, 1.0F, },
};

glm::vec4 vertBlue[] = { // will be painted in blue
	{ +0.2F, +0.2F, 0.0F, 1.0F, },
	{ -0.8F, +0.2F, 0.0F, 1.0F, },
	{ +0.2F, -0.8F, 0.0F, 1.0F, },
};
  • fragment shader 프로그램
#version 330 core

uniform vec4 uColor; // uniform color: uniform
out vec4 FragColor; // fragment color: framebuffer

void main(void) {
	FragColor = uColor; // 색상을 받아와 입힘
}
  • red -> blue
void drawFunc(void) {
	...
    
	// draw the red triangle
	glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 0, glm::value_ptr(vertRed[0]));
	glUniform4f(locColor, 1.0F, 0.3F, 0.3F, 1.0F); // (light) red
	glDrawArrays(GL_TRIANGLES, 0, 3);
    
	// draw the blue triangle
	glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 0, glm::value_ptr(vertBlue[0]));
	glUniform4f(locColor, 0.3F, 0.0F, 1.3F, 1.0F); // (light) blue
	glDrawArrays(GL_TRIANGLES, 0, 3);
    
    ...
}
  • blue -> red
void drawFunc(void) {
	...
	// draw the blue triangle
	glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 0, glm::value_ptr(vertBlue[0]));
	glUniform4f(locColor, 1.0F, 0.3F, 0.3F, 1.0F); // (light) blue
	glDrawArrays(GL_TRIANGLES, 0, 3);
    
	// draw the red triangle
	glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 0, glm::value_ptr(vertRed[0]));
	glUniform4f(locColor, 0.3F, 0.0F, 1.3F, 1.0F); // (light) red
	glDrawArrays(GL_TRIANGLES, 0, 3);
    
    ...
}

나중에 그려진 삼각형이 덮어씌움
렌더링 순서에 따라 결과가 달라짐

Depth Processing

OpenGL Depth Concepts

  • z-coordinate
    [-1.0, +1.0]
    카메라에서 멀어질 수록 값이 커짐

  • OpenGL 정규 뷰 볼륨
    x, y, z: [-1, +1] x [-1, +1] x [-1, +1]

숨은 면 제거

  • Depth Value 기준
    뒤쪽에 있는 물체는 앞쪽 물체에 가려져야 함
  • Painter's Algorithm (Depth Sorting)
    Depth 기준으로 정렬
    제일 뒤에 있는 배경부터 앞쪽 물체를 순서로 그림
    (Depth가 꼬이는 문제 발생)

Z-buffer Method

  • 픽셀 단위 하드웨어 구현
    color 값: RGBA, depth 값: Z

Depth 값은 +1로 초기화
object를 그릴 때, 픽셀마다 Depth Test 진행
새로운 object가 더 가까우면, 새로운 object로 color와 depth 값 갱신
더 멀면 무시

  • 장점
    object를 정렬할 필요 없음
    하드웨어 구현으로 매우 빠름
  • 단점
    프레임버퍼 크기 정도의 추가 메모리 필요 (프레임버퍼: 픽셀 당 4바이트 - RGBA)
    Z-buffer(Depth Buffer): 픽셀당 24bit or 32bit

OpenGL Z-buffer 설정

Z-buffer 하드웨어 설계

  • 프레임버퍼 설계
    • 구성: RGBA 당 8bit (총 32bit)
    • View Volume x,y 좌표: [-1.0 ~ +1.0]
    • 색상 저장: RGBA [0.0 ~ 1.0]
    • 실제 저장: 0~255 integer 값
  • Z-buffer 설계
    • 구성: Z에 24bit (또는 32bit)
    • View Volume z좌표: [-1.0 ~ +1.0]
    • window 좌표: [0.0 ~ +1.0] (GPU는 프레임버퍼와 동일하게 처리하기 위해 RGBA 범위에 맞게 저장)
    • 실제 저장: 0~(2^24 - 1) integer 값

OpenGL에서 Z-buffer 사용하기

OpenGL은 디폴트로 Z-buffer를 사용하지 않음

  1. Z-buffer 활성화
    glEnable(GL_DEPTH_TEST);
  2. Z-buffer 값 세팅 (선택)
    glDepthRange(0.0, 1.0); // View Volume의 z좌표(-1~+1)를 매핑 (-1: nearVal, +1: farVal)
    glClearDepthf(1.0F);
  3. Z-buffer 초기화
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

Z-buffer 예제 프로그램

빨간색 삼각형의 z값은 0.8,
파란색 삼각형의 z값은 0.5로 세팅

glm::vec4 vertRed[] = { // will be painted in red
	{ -0.2F, -0.2F, 0.8F, 1.0F, },
	{ -0.2F, +0.8F, 0.8F, 1.0F, },
	{ +0.8F, -0.2F, 0.8F, 1.0F, },
};

glm::vec4 vertBlue[] = { // will be painted in blue
	{ +0.2F, +0.2F, 0.5F, 1.0F, },
	{ -0.8F, +0.2F, 0.5F, 1.0F, },
	{ +0.2F, -0.8F, 0.5F, 1.0F, },
};
  • drawFunc()
    파란색 삼각형을 먼저 그리고 빨간색 삼각형을 그림
void drawFunc(void) {
	// Z-buffer 사용
	glEnable(GL_DEPTH_TEST);
	glDepthRange(0.0F, 1.0F);
	glClearDepthf(1.0F);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    ...
    
	// draw the blue triangle
	glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 0, glm::value_ptr(vertBlue[0]));
	glUniform4f(locColor, 0.3F, 0.0F, 1.3F, 1.0F); // (light) blue
	glDrawArrays(GL_TRIANGLES, 0, 3);
    
	// draw the red triangle
	glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 0, glm::value_ptr(vertRed[0]));
	glUniform4f(locColor, 1.0F, 0.3F, 0.3F, 1.0F); // (light) red
	glDrawArrays(GL_TRIANGLES, 0, 3);
    
    ...
}

나중에 그려진 빨간색 삼각형이 Depth Test에 의해 파란색 삼각형을 덮어씌우지 않음

Tangled Rectangles

좀 더 복잡한 서로 얽힌 사각형
한쪽 면의 z값은 +0.5, 반대쪽 면의 z값은 -0.5
OpenGL의 Rasterizer는 z값도 보간해줌

glm::vec4 vertRed[] = {
	{ +0.4F, -0.8F, -0.5F, 1.0F, },
	{ +0.6F, -0.8F, -0.5F, 1.0F, },
	{ +0.6F, +0.8F, +0.5F, 1.0F, },
	{ +0.6F, +0.8F, +0.5F, 1.0F, },
	{ +0.4F, +0.8F, +0.5F, 1.0F, },
	{ +0.4F, -0.8F, -0.5F, 1.0F, },
};

glm::vec4 vertGreen[] = {
	{ +0.8F, +0.4F, -0.5F, 1.0f, },
	{ +0.8F, +0.6F, -0.5F, 1.0f, },
	{ -0.8F, +0.6F, +0.5F, 1.0f, },
	{ -0.8F, +0.6F, +0.5F, 1.0f, },
	{ -0.8F, +0.4F, +0.5F, 1.0f, },
	{ +0.8F, +0.4F, -0.5F, 1.0f, },
};

glm::vec4 vertBlue[] = {
	{ -0.4F, +0.8F, -0.5F, 1.0F, },
	{ -0.6F, +0.8F, -0.5F, 1.0F, },
	{ -0.6F, -0.8F, +0.5F, 1.0F, },
	{ -0.6F, -0.8F, +0.5F, 1.0F, },
	{ -0.4F, -0.8F, +0.5F, 1.0F, },
	{ -0.4F, +0.8F, -0.5F, 1.0F, },
};

glm::vec4 vertYellow[] = {
	{ -0.8F, -0.4F, -0.5F, 1.0f, },
	{ -0.8F, -0.6F, -0.5F, 1.0f, },
	{ +0.8F, -0.6F, +0.5F, 1.0f, },
	{ +0.8F, -0.6F, +0.5F, 1.0f, },
	{ +0.8F, -0.4F, +0.5F, 1.0f, },
	{ -0.8F, -0.4F, -0.5F, 1.0f, },
};

서로의 Depth가 얽혀 있지만, 픽셀 단위로 Depth Test 하기에 정상적으로 그릴 수 있음

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

0개의 댓글