OpenGL

[OpenGL] 후면 컬링(back face culling)와 CCW(오른손법칙)

usingsystem 2024. 4. 17. 14:39
728x90


후면 컬링(Back-face culling)은 카메라를 향하지 않는 즉 화면에 보이지 않는 뒷면을 렌더링 하지 않고 건너뛰는 것을 말합니다. 이 기법은 뒷면이 보이지 않는 객체의 렌더링 성능을 향상하는 데 사용됩니다.

일반적으로 3D 객체는 양면을 가지며, 이것은 객체의 정면과 후면을 의미합니다. 정면은 관찰자나 카메라 쪽으로 향하는 면이고, 후면은 그 반대쪽 면입니다. 보통 우리는 정면만을 보고 객체를 관찰하게 됩니다. 후면은 보이지 않기 때문에 렌더링 할 필요가 없습니다.

후면 컬링은 다음과 같은 단계로 이루어집니다:

 

후면컬링은 오른손법칙(CCW)에 따라서 전면과 후면을 나눈다. 

  1. 화면 공간 변환: 객체의 모든 정점은 모델 좌표계에서 월드 좌표계, 뷰 좌표계를 거쳐 화면 좌표계로 변환됩니다.
  2. 폴리곤의 정면과 후면 판별: 변환된 폴리곤의 정점들을 이용하여 폴리곤의 표면 법선 벡터를 계산합니다. 표면 법선 벡터는 폴리곤의 표면이 어느 방향으로 향하는지를 나타냅니다.
  3. 폴리곤의 렌더링 여부 결정: 폴리곤의 표면 법선법선 벡터가 카메라나 관찰자 쪽을 향하면, 이 폴리곤은 정면입니다. 그러나 표면 법선 벡터가 카메라나 관찰자 쪽과 반대 방향으로 향하면, 이 폴리곤은 후면입니다. 후면 컬링은 보통 후면을 렌더링 대상에서 제외합니다.
  4. 후면 제외 렌더링: 후면 컬링을 사용하는 그래픽스 엔진은 후면 폴리곤을 렌더링 대상에서 제외합니다. 이렇게 함으로써 렌더링 파이프라인의 다음 단계에서 이러한 폴리곤을 처리하지 않아도 되므로 렌더링 성능이 향상됩니다.

후면 컬링은 렌더링 성능을 향상시키고 불필요한 폴리곤 처리를 줄이는 데 유용한 기법입니다. 그러나 모든 상황에서 후면 컬링을 사용하는 것이 항상 적절하지는 않습니다. 예를 들어, 객체가 투명하거나 양면을 가지는 경우에는 후면 컬링을 사용할 수 없습니다.

 

오클루젼 컬링(시야에 보이지 않는 오브젝트는 그리지 않는 컬링 기법)과도 비슷하다고 볼 수 있다. 

시계방향으로 변경하면 전면을 보이지 않도록 제거할 수 있다.

 

장점

  • 평균적으로 face개수의 절반이 컬링(추출)되어 이론상 속도가 2배 빨리질 수 있다.

못 쓰는 경우

  • 투명한 물체
  • 완전히 둘러싸이지 않은 물체

OpenGL에서 Z-후면 컬링사용하기

  • void glFrontFace(Glenum mode)
    • 삼각형에 어떤 법칙을 적용할것 인지 설정가능
    • mode : GL_CCW(오른손법칙), GL_CW(왼손법칙)
  • void glCullFace(GLenum mode);
    • openGL에서 컬링(추출)할 때  전면만 추출할 것 인지 후면만 추출할 것 인지 혹은 모두 추출하지 않을 것 인지 선택한다. 모두 추출하지 않을 때는 오브젝트의 선만 추출가능
    • mode : GL_BACK(default), GL_FRONT, GL_FRONT _AND_BACK(line만 추출하고 싶을 때)
  • glEnable(GL_CULL_FACE)
    • 백페이스컬링적용
  • glDisable(GL_CULL_FACE)
int cullMode = 0;

void drawFunc(void) {
	glEnable(GL_DEPTH_TEST);
	glDepthRange(0.0F, 1.0F);
	glClearDepthf(1.0F);
	switch (cullMode) {
	default:
	case 0:
		break;
	case 1: // back-face culling, CCW facing
		glEnable(GL_CULL_FACE);
		glFrontFace(GL_CCW);
		glCullFace(GL_BACK);
		break;
	case 2: // front-face culling, CCW facing
		glEnable(GL_CULL_FACE);
		glFrontFace(GL_CCW);
		glCullFace(GL_FRONT);
		break;
	case 11: // back-face culling, CW facing
		glEnable(GL_CULL_FACE);
		glFrontFace(GL_CW);
		glCullFace(GL_BACK);
		break;
	case 12: // front-face culling, CW facing
		glEnable(GL_CULL_FACE);
		glFrontFace(GL_CW);
		glCullFace(GL_FRONT);
		break;
	}
	// clear in gray color
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	// provide the vertex attributes
	GLuint locPos = glGetAttribLocation(prog, "aPos");
	glEnableVertexAttribArray(locPos);
	glVertexAttribPointer(locPos, 4, GL_FLOAT, GL_FALSE, 0, glm::value_ptr(vertPos[0]));
	GLuint locColor = glGetAttribLocation(prog, "aColor");
	glEnableVertexAttribArray(locColor);
	glVertexAttribPointer(locColor, 4, GL_FLOAT, GL_FALSE, 0, glm::value_ptr(vertColor[0]));
	// draw the pyramid
	glDrawArrays(GL_TRIANGLES, 0, 18); // 18 vertices
	// done
	glFinish();
}
728x90