FBO를 잘 이해하기 위해서는 아래 챕터 내용을 먼저 보고 오자.
이전 챕터에서 원이 반복적으로 있는 패턴의 모양 ( 폴카닷 )을 렌더링 했었다.
https://graphicsimon.tistory.com/114
폴카닷을 렌더링 할때 FrameBuffer Object를 사용하여 텍스처로 렌더링 하는 코드 설명한다.
objModel->Render() 함수를 수행하면 폴카닷을 1 프레임 렌더링 한다고 이해하자.
텍스처 렌더링도 아래 챕터를 참고한다.
https://graphicsimon.tistory.com/115
결과
FBO (Framebuffer Object)란?
**FBO (Framebuffer Object)**는 OpenGL에서 **오프스크린 렌더링(Offscreen Rendering)**을 위한 기능입니다. 즉, 화면에 직접 출력하지 않고, 텍스처나 렌더버퍼에 렌더링할 수 있게 해줍니다.
FBO의 주요 특징
- 오프스크린 렌더링:
- 렌더링 결과를 화면 대신 텍스처나 렌더버퍼에 저장할 수 있습니다.
- 이를 통해 그림자 매핑, 포스트 프로세싱, 반사 효과와 같은 다양한 그래픽 효과를 구현할 수 있습니다.
- 사용자 정의 렌더 타겟:
- 기본 프레임버퍼 대신, 사용자가 정의한 FBO로 렌더링할 수 있습니다.
- FBO에 연결된 텍스처나 렌더버퍼는 이후에 텍스처 맵핑이나 후처리에 활용할 수 있습니다.
- 성능 향상:
- 화면에 직접 렌더링하지 않고, 텍스처에 렌더링하면 필요한 작업만 수행할 수 있어 성능을 최적화할 수 있습니다.
FBO의 구조
- FBO는 다음과 같은 **어태치먼트(Attachment)**로 구성됩니다:
- 컬러 어태치먼트: 렌더링된 결과의 색상 데이터를 저장하는 컬러 텍스처.
- 깊이 어태치먼트: 깊이 정보를 저장하는 깊이 텍스처 또는 렌더버퍼.
- 스텐실 어태치먼트(옵션): 스텐실 테스트에 사용되는 데이터를 저장.
FBO의 일반적인 사용 흐름
- FBO 생성 및 바인드:
- glGenFramebuffers()와 glBindFramebuffer()로 FBO를 생성하고 바인드합니다.
- 어태치먼트 설정:
- glFramebufferTexture2D()로 컬러 텍스처를 연결하고, glFramebufferRenderbuffer()로 깊이 버퍼를 연결합니다.
- 렌더링 수행:
- FBO가 바인드된 상태에서 렌더링 작업을 수행합니다.
- 기본 프레임버퍼로 전환:
- 작업이 끝나면 기본 프레임버퍼로 전환(glBindFramebuffer(GL_FRAMEBUFFER, 0))합니다.
- 렌더링 결과 활용:
- FBO에 저장된 텍스처를 사용해 포스트 프로세싱이나 텍스처 맵핑 작업을 수행합니다.
-----------------------------------------------------------------------------------------------
Initialize
//! DemoFBO 클래스 생성자
DemoFBO::DemoFBO(Renderer* parent)
{
// 부모 객체가 없을 경우, 함수 종료
if (!parent)
return;
// 1. 렌더러 핸들러 설정
RendererHandler = parent;
ProgramManagerObj = parent->RendererProgramManager(); // 프로그램 매니저 객체 설정
TransformObj = parent->RendererTransform(); // 변환 객체 설정
// 2. 3D 모델과 텍스처 쿼드 객체 생성
objModel = new ObjLoader(RendererHandler); // 3D 객체 로더 초기화
textureQuad = new SimpleTexture(RendererHandler); // 텍스처가 맵핑된 쿼드 초기화
}
//! DemoFBO 모델 초기화 함수
void DemoFBO::InitModel()
{
// 1. 3D 객체 모델 초기화
objModel->InitModel();
// 2. 텍스처 쿼드 모델 초기화
textureQuad->InitModel();
// 3. FBO 생성
GenerateFBO();
}
//! 텍스처 생성 함수: 컬러 텍스처 또는 깊이 텍스처를 생성합니다.
unsigned int DemoFBO::generateTexture(int width, int height, bool isDepth, bool isStencil)
{
unsigned int texId;
// 1. 텍스처 객체 생성 및 바인드
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
// 2. 텍스처 필터링 설정
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 텍스처 확대 필터: GL_LINEAR
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // 텍스처 축소 필터: Mipmap 사용
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // S축 래핑 모드: GL_CLAMP_TO_EDGE
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // T축 래핑 모드: GL_CLAMP_TO_EDGE
// 3. 텍스처 데이터 할당 (깊이 텍스처 또는 컬러 텍스처)
if (isDepth) {
// 깊이 텍스처 생성
glTexImage2D(GL_TEXTURE_2D, // 텍스처 타겟: GL_TEXTURE_2D
0, // Mipmap 레벨: 0 (기본 레벨)
GL_DEPTH_COMPONENT32F, // 내부 포맷: 32비트 깊이 컴포넌트
width, height, // 텍스처의 너비와 높이
0, // 경계선: 0
GL_DEPTH_COMPONENT, // 포맷: 깊이 컴포넌트
GL_FLOAT, // 데이터 타입: GL_FLOAT
0); // 데이터 포인터: NULL (비어 있는 텍스처)
}
else if (isStencil) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
}
else {
// 컬러 텍스처 생성
glTexImage2D(GL_TEXTURE_2D, // 텍스처 타겟: GL_TEXTURE_2D
0, // Mipmap 레벨: 0 (기본 레벨)
GL_RGBA, // 내부 포맷: RGBA
width, height, // 텍스처의 너비와 높이
0, // 경계선: 0
GL_RGBA, // 포맷: RGBA
GL_UNSIGNED_BYTE, // 데이터 타입: GL_UNSIGNED_BYTE
0); // 데이터 포인터: NULL (비어 있는 텍스처)
}
// 4. 오류 체크
int error = glGetError();
if (error != 0) {
std::cout << "Error: Fail to generate texture. Error code: " << error << std::endl;
}
// 5. 텍스처 바인딩 해제
glBindTexture(GL_TEXTURE_2D, 0);
// 6. 생성된 텍스처 ID 반환
return texId;
}
GenerateFBO()와 GenerateFBOWithRenderBuffer()의 차이점
두 함수 모두 OpenGL에서 **FBO(Frame Buffer Object)**를 생성하지만, 깊이(Depth) 어태치먼트를 어떻게 설정하느냐에 차이가 있습니다.
- GenerateFBO()
- 깊이 어태치먼트로 깊이 텍스처를 사용합니다.
- 깊이 정보는 텍스처에 저장되며, 이후 다른 렌더링 단계에서 텍스처 맵핑으로 사용할 수 있습니다.
- 장점:
- 깊이 텍스처를 사용하면 그림자 매핑이나 포스트 프로세싱에서 깊이 정보를 직접 활용할 수 있습니다.
- 단점:
- 깊이 텍스처는 메모리 사용이 높을 수 있으며, 성능이 렌더버퍼보다 떨어질 수 있습니다.
- GenerateFBOWithRenderBuffer()
- 깊이 어태치먼트로 렌더버퍼를 사용합니다.
- 깊이 정보는 렌더버퍼에 저장되며, 이후 텍스처로 사용되지 않고 깊이 테스트에만 사용됩니다.
- 장점:
- 렌더버퍼는 성능이 더 좋고 메모리 사용이 적습니다.
- 렌더링 속도가 더 빠르며, 깊이 정보가 필요한 경우에만 사용됩니다.
- 단점:
- 렌더버퍼에 저장된 깊이 정보를 텍스처로 직접 접근할 수 없습니다.
- 텍스처 맵핑에 사용할 수 없기 때문에, 그림자 매핑 등에서는 적합하지 않습니다.
//! Render Buffer의 깊이 버퍼를 사용하는 FBO 생성 함수
void DemoFBO::GenerateFBOWithRenderBuffer()
{
// 1. 프레임버퍼 객체 생성 및 바인드
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
// 2. 텍스처 생성 및 FBO의 컬러 어태치먼트에 연결
textureId = generateTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT);
glFramebufferTexture2D(GL_FRAMEBUFFER, // FBO 타겟: GL_FRAMEBUFFER
GL_COLOR_ATTACHMENT0, // 컬러 어태치먼트 포인트
GL_TEXTURE_2D, // 텍스처 타겟: GL_TEXTURE_2D
textureId, // 텍스처 ID
0); // Mipmap 레벨: 0 (기본 레벨)
// 3. 깊이 정보를 저장할 렌더버퍼 객체 생성 및 설정
glGenRenderbuffers(1, &rboId);
glBindRenderbuffer(GL_RENDERBUFFER, rboId);
glRenderbufferStorage(GL_RENDERBUFFER, // 렌더버퍼 타겟: GL_RENDERBUFFER
GL_DEPTH_COMPONENT16, // 깊이 포맷: GL_DEPTH_COMPONENT16
TEXTURE_WIDTH, // 텍스처의 너비
TEXTURE_HEIGHT); // 텍스처의 높이
// 4. 렌더버퍼를 FBO의 깊이 어태치먼트에 연결
glFramebufferRenderbuffer(GL_FRAMEBUFFER, // FBO 타겟: GL_FRAMEBUFFER
GL_DEPTH_ATTACHMENT, // 깊이 어태치먼트 포인트
GL_RENDERBUFFER, // 렌더버퍼 타겟: GL_RENDERBUFFER
rboId); // 렌더버퍼 ID
// 5. FBO 상태 체크
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
printf("Framebuffer creation failed: %d\n", status);
}
// 6. FBO 바인딩 해제
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Depth Buffer를 텍스처로 구현 예정.
//! FBO 생성 함수: 프레임버퍼의 깊이 텍스처를 사용하여 깊이 테스트를 수행
void DemoFBO::GenerateFBO()
{
// 1. 프레임버퍼 객체(FBO) 생성 및 바인드
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
// 2. 컬러 텍스처와 깊이 텍스처 생성
textureId = generateTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT); // 컬러 텍스처 생성
depthTextureId = generateTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT, true); // 깊이 텍스처 생성 (depth = true)
// 3. 컬러 텍스처를 FBO의 컬러 어태치먼트에 연결
glFramebufferTexture2D(GL_FRAMEBUFFER, // FBO 타겟: GL_FRAMEBUFFER
GL_COLOR_ATTACHMENT0, // 컬러 어태치먼트 포인트
GL_TEXTURE_2D, // 텍스처 타겟: GL_TEXTURE_2D
textureId, // 컬러 텍스처 ID
0); // Mipmap 레벨: 0 (기본 레벨)
// 4. 깊이 텍스처를 FBO의 깊이 어태치먼트에 연결
glFramebufferTexture2D(GL_FRAMEBUFFER, // FBO 타겟: GL_FRAMEBUFFER
GL_DEPTH_ATTACHMENT, // 깊이 어태치먼트 포인트
GL_TEXTURE_2D, // 텍스처 타겟: GL_TEXTURE_2D
depthTextureId, // 깊이 텍스처 ID
0); // Mipmap 레벨: 0 (기본 레벨)
/*
// 스텐실 enable 하니깐 오류나네..
// heckFramebufferCompleteness: stencil attachment not complete: 0x8cd6 ERROR 발생.
glFramebufferTexture2D(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER
GL_DEPTH_STENCIL_ATTACHMENT, // 2. Depth attachment point
GL_TEXTURE_2D, // 3. tex target: GL_TEXTURE_2D
stencilTextureId, // 4. stencil texture ID
0); // 5. mipmap level: 0(base)
*/
// 5. FBO 상태 체크
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
printf("Framebuffer creation failed: %d\n", status);
}
// 6. FBO 바인딩 해제 (기본 프레임버퍼로 전환)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
매개변수 설명
- target (GLenum):
- FBO의 타겟을 지정합니다.
- 일반적으로 **GL_FRAMEBUFFER**를 사용합니다.
- GL_READ_FRAMEBUFFER 또는 GL_DRAW_FRAMEBUFFER로도 설정할 수 있지만, 대부분의 경우 GL_FRAMEBUFFER가 사용됩니다.
- attachment (GLenum):
- 텍스처를 연결할 어태치먼트 포인트를 지정합니다.
- 일반적으로 다음과 같은 값이 사용됩니다:
- GL_COLOR_ATTACHMENT0: 컬러 어태치먼트.
- GL_DEPTH_ATTACHMENT: 깊이(Depth) 어태치먼트.
- GL_STENCIL_ATTACHMENT: 스텐실(Stencil) 어태치먼트.
- GL_DEPTH_STENCIL_ATTACHMENT: 깊이와 스텐실이 결합된 어태치먼트.
- textarget (GLenum):
- 텍스처의 타겟을 지정합니다.
- 일반적으로 **GL_TEXTURE_2D**가 사용됩니다.
- 큐브 맵 텍스처의 경우, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X 등으로 설정할 수 있습니다.
- texture (GLuint):
- 연결할 텍스처의 ID입니다.
- **glGenTextures()**로 생성된 텍스처 ID를 전달합니다.
- 텍스처를 제거하려면 **0**을 전달할 수 있습니다.
- level (GLint):
- 연결할 텍스처의 Mipmap 레벨을 지정합니다.
- 일반적으로 기본 레벨인 **0**이 사용됩니다.
Rendering
void DemoFBO::Render()
{
// 1. 현재 바인딩된 프레임버퍼를 저장
int CurrentFbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &CurrentFbo);
// 2. FBO로 렌더링 시작
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glViewport(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT); // FBO 크기에 맞게 뷰포트 설정
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 컬러와 깊이 버퍼 클리어
objModel->Render(); // 3D 객체 렌더링 (텍스처에 렌더링)
// 3. 기본 프레임버퍼로 다시 전환
glBindFramebuffer(GL_FRAMEBUFFER, CurrentFbo);
TransformObj->TransformError(); // 변환 오류 체크 (디버깅 용도)
// 4. 텍스처가 맵핑된 쿼드 렌더링
glViewport(0, 0, RendererHandler->screenWidthPixel() * 2, RendererHandler->screenHeightPixel() * 2); // 전체 화면 뷰포트 설정
glClearColor(0.710, 0.610, 0.30, 1.0); // 화면 배경색 설정
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 컬러와 깊이 버퍼 클리어
glActiveTexture(GL_TEXTURE0); // 텍스처 유닛 0 활성화
glBindTexture(GL_TEXTURE_2D, textureId); // 렌더된 텍스처 바인드
textureQuad->Render(); // 텍스처가 맵핑된 쿼드 렌더링
TransformObj->TransformError(); // 변환 오류 체크 (디버깅 용도)
}
Texture Rendering
// 텍스처 좌표 (2D 텍스처 맵핑)
float texCoords[8] = {
0.0f, 0.0f, // 왼쪽 아래
1.0f, 0.0f, // 오른쪽 아래
0.0f, 1.0f, // 왼쪽 위
1.0f, 1.0f // 오른쪽 위
};
// 쿼드 정점 좌표 (2D 평면)
float quad[12] = {
-1.0f, -1.0f, 0.0f, // 왼쪽 아래
1.0f, -1.0f, 0.0f, // 오른쪽 아래
-1.0f, 1.0f, 0.0f, // 왼쪽 위
1.0f, 1.0f, 0.0f // 오른쪽 위
};
void SimpleTexture::InitModel()
{
ProgramManager* ProgramManagerObj = RendererHandler->RendererProgramManager();
Transform* TransformObj = RendererHandler->RendererTransform();
// 1. 셰이더 프로그램 초기화
if (!(program = ProgramManagerObj->Program((char*)"square"))) {
program = ProgramManagerObj->ProgramInit((char*)"square");
ProgramManagerObj->AddProgram(program);
}
// 2. 셰이더 컴파일
program->VertexShader = ShaderManager::ShaderInit(VERTEX_SHADER_PRG, GL_VERTEX_SHADER);
program->FragmentShader = ShaderManager::ShaderInit(FRAGMENT_SHADER_PRG, GL_FRAGMENT_SHADER);
// 3. 정점 셰이더 컴파일
CACHE* m = reserveCache(VERTEX_SHADER_PRG, true);
if (m) {
if (!ShaderManager::ShaderCompile(program->VertexShader, (char*)m->buffer, 1)) exit(1);
freeCache(m);
}
// 4. 프래그먼트 셰이더 컴파일
m = reserveCache(FRAGMENT_SHADER_PRG, true);
if (m) {
if (!ShaderManager::ShaderCompile(program->FragmentShader, (char*)m->buffer, 1)) exit(2);
freeCache(m);
}
// 5. 셰이더 프로그램 링크
if (!ProgramManagerObj->ProgramLink(program, 1)) exit(3);
glUseProgram(program->ProgramID);
// 6. 유니폼 위치 가져오기
MVP = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"MODELVIEWPROJECTIONMATRIX");
TEX = ProgramManagerObj->ProgramGetUniformLocation(program, (char*)"Tex1");
}
void SimpleTexture::Render()
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisable(GL_CULL_FACE); // 백페이스 컬링 비활성화
glUseProgram(program->ProgramID); // 셰이더 프로그램 사용
glEnable(GL_BLEND); // 블렌딩 활성화
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// 1. 변환 적용 (회전)
TransformObj->TransformPushMatrix();
TransformObj->TransformRotate(rotationX, 0.0, 1.0, 0.0);
TransformObj->TransformRotate(rotationY, 1.0, 0.0, 0.0);
// 2. 텍스처 필터링 및 래핑 설정
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// 3. 텍스처 유니폼 설정
glUniform1i(TEX, 0);
// 4. 정점 속성 활성화 및 설정
glEnableVertexAttribArray(VERTEX_POSITION);
glEnableVertexAttribArray(TEX_COORD);
glVertexAttribPointer(TEX_COORD, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
glVertexAttribPointer(VERTEX_POSITION, 3, GL_FLOAT, GL_FALSE, 0, quad);
// 5. MVP 행렬 설정
glUniformMatrix4fv(MVP, 1, GL_FALSE, (float*)TransformObj->TransformGetModelViewProjectionMatrix());
TransformObj->TransformPopMatrix();
// 6. 쿼드 렌더링
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// 7. 정점 속성 비활성화
glDisableVertexAttribArray(VERTEX_POSITION);
glDisableVertexAttribArray(TEX_COORD);
// 8. 회전 애니메이션 업데이트
if (deltaX != 0.0) {
if (deltaX > 0.0) deltaX -= DecelerationFactor;
else deltaX += DecelerationFactor;
rotationX += deltaX;
}
if (deltaY != 0.0) {
if (deltaY > 0.0) deltaY -= DecelerationFactor;
else deltaY += DecelerationFactor;
rotationY += deltaY;
}
}
Vertex Shader
#version 300 es
// 1. 정점 정보 입력 (버텍스 속성)
layout(location = 0) in vec3 VertexPosition; // 정점의 위치 (layout(location = 0))
layout(location = 1) in vec2 VertexTexCoord; // 정점의 텍스처 좌표 (layout(location = 1))
// 2. 출력 변수
out vec2 TexCoord; // 텍스처 좌표 출력 (프래그먼트 셰이더로 전달)
// 3. 유니폼 변수 (모델-뷰-프로젝션 행렬)
uniform mat4 MODELVIEWPROJECTIONMATRIX; // MVP 행렬 (모델, 뷰, 프로젝션 합성)
void main(void) {
// 4. 텍스처 좌표 전달
TexCoord = VertexTexCoord;
// 5. 변환된 정점 위치 계산 (클립 공간)
gl_Position = MODELVIEWPROJECTIONMATRIX * vec4(VertexPosition, 1.0);
}
Fragment Shader
#version 300 es
// 1. 정밀도 설정
precision mediump float; // 부동 소수점 연산의 정밀도를 중간(mediump)으로 설정
// 2. 입력 변수 (정점 셰이더에서 전달된 텍스처 좌표)
in vec2 TexCoord; // 텍스처 좌표 입력
// 3. 유니폼 변수 (샘플러)
uniform sampler2D Tex1; // 2D 텍스처 샘플러 (GL_TEXTURE_2D)
// 4. 출력 변수 (프래그먼트 셰이더의 최종 출력 색상)
layout(location = 0) out vec4 soutColor; // 출력 색상 (layout(location = 0))
void main() {
// 5. 텍스처 샘플링
// - `texture()` 함수는 텍스처(Tex1)에서 텍스처 좌표(TexCoord)를 사용해 색상을 샘플링합니다.
soutColor = texture(Tex1, TexCoord);
}
참고 스텐실 버퍼
이유: 깊이-스텐실 렌더버퍼를 함께 사용하는 이유
- 성능 향상 및 메모리 효율성:
- 깊이와 스텐실 데이터를 하나의 렌더버퍼에 저장하면, 메모리 접근이 줄어들고 성능이 향상됩니다.
- 하드웨어에서 깊이와 스텐실 데이터를 동시에 처리할 수 있기 때문에, 메모리 대역폭과 성능 측면에서 유리합니다.
- 대부분의 GPU는 깊이-스텐실 버퍼를 하나의 버퍼로 처리하도록 최적화되어 있습니다.
- 깊이 테스트와 스텐실 테스트는 자주 함께 사용됨:
- **깊이 테스트(Depth Test)**와 **스텐실 테스트(Stencil Test)**는 보통 함께 사용됩니다.
- 예를 들어, **다중 패스 렌더링(Multi-pass Rendering)**에서는 깊이와 스텐실 테스트를 동시에 수행하여, 렌더링 결과를 제어합니다.
- 그림자 매핑(Shadow Mapping), 포스트 프로세싱 효과에서도 깊이와 스텐실 정보를 동시에 사용하는 경우가 많습니다.
- 깊이-스텐실 포맷이 표준화되어 있음:
- OpenGL에서는 깊이-스텐실 포맷(GL_DEPTH24_STENCIL8, GL_DEPTH32F_STENCIL8)이 표준화되어 있으며, 대부분의 하드웨어에서 지원합니다.
- 이 포맷은 깊이 값과 스텐실 값을 효율적으로 저장할 수 있는 포맷으로, 메모리 사용을 줄이고 성능을 최적화합니다.
스텐실 버퍼의 사용 사례
- 스텐실 테스트: 객체의 특정 부분에만 렌더링하거나, 다중 패스 렌더링에서 사용.
- 마스킹 효과: 특정 영역을 마스킹하여 후속 렌더링 작업에서 제외.
- 윤곽선 렌더링: 스텐실 버퍼를 사용해 객체의 윤곽선만 렌더링.
- 스텐실 테스트는 보통 비교 연산, 증가/감소, 비트 연산 등의 간단한 연산으로 이루어집니다.
- 이러한 연산에서는 8비트면 충분합니다.
- 예를 들어, 객체의 윤곽선 렌더링에서는 **1비트(0 또는 1)**만 사용되기도 합니다.
- 마스킹 효과에서는 0부터 255 사이의 값을 사용하여, 여러 단계의 마스크를 표현할 수 있습니다
'Opengles 3.0 with Android' 카테고리의 다른 글
10.1 Scene Graph (Transformation Graph) (0) | 2025.01.30 |
---|---|
9_4 엠보싱 효과 (0) | 2024.12.29 |
9.3 툰 셰이딩: 엣지 디텍팅과 카툰화 (0) | 2024.12.25 |
Chapter 9.2 Gawsian Blur ( 2 step ) (0) | 2024.12.01 |
Chapter 7.5. displace map (0) | 2024.11.18 |