Graphics Programming

단편 셰이더(Fragment Shader)와 프레임버퍼(Framebuffer) 본문

Season 1/OpenGL

단편 셰이더(Fragment Shader)와 프레임버퍼(Framebuffer)

minseoklee 2015. 10. 3. 14:54

전부 back end에 대한 이야기. 즉 래스터화(rasterization) 이후

- 단편 셰이더로 할 수 있는 흥미로운 것들

- 데이터가 단편 셰이더에 도착하면 일어나는 일들

- 그 데이터를 다시 애플리케이션으로 얻어오는 방법

- 이미지 품질을 향상시키는 방법

- HDR 렌더링

- 안티앨리어싱 기법들

- 다른 색공간들

 

보간(interpolation)

flat in vec4 foo // 보간 없음(default: smooth)

- 기본적으로 정수는 flat, float은 smooth

- 입력이 점이면 아무 문제 없다

- 선이나 삼각형이면 어느 정점을 택하는가?

  void glProvokingVertex(GLenum provokeMode)

  GL_FIRST_VERTEX_CONVENTION, GL_LAST_VERTEX_CONVENTION(기본)

- OpenGL은 perspective-correct interpolation 사용

  비활성화하려면 noperspective out vec2 texCoord 처럼

 

단편별 검사

- scissor test

glEnable(GL_SCISSOR_TEST)

glScissorIndexed(index, L,B,W,H)

* glClear()에도 적용됨

 

- stencil test

glEnable(GL_STENCIL_TEST)

glStencilFuncSeparate(face, func, ref, mask)

  - 스텐실 테스트가 성공/실패하는 조건을 제어

  - face: GL_FRONT, GL_BACK, GL_FRONT_AND_BACK

  - func: GL_NEVER, ALWAYS, LESS, LEQUAL, EQUAL, GEQUAL, GREATER, NOTEQUAL

  - (ref & mask)와 (현재스텐실값 & mask)를 비교

glStencilOpSeperate(face, sfail, dpfail, dppass)

  - 테스트가 성공/실패했을 때 무엇을 할 지를 제어

  - sfail: 스텐실 테스트 실패

  - dpfail: 깊이 버퍼 테스트 실패

  - dppass: 깊이 버퍼 테스트 성공

  - operations = GL_KEEP, ZERO, REPLACE, INCR, DECR, INVERT, INCR_WRAP, DECR_WRAP

glStencilFunc(), glStencilOp() : face = GL_FRONT_AND_BACK

glStencilMaskSeparate(face, mask)

 

- 깊이 테스트

glEnable(GL_DEPTH_TEST)

void glDepthFunc(GLenum func)

 

Early Testing

스텐실 테스트 & 깊이 테스트는 해당 단편의 색상이 정해진 후에 수행된다

대부분의 그래픽스 하드웨어는, 셰이더에 부수효과가 없고 테스트 결과에 영향을 주지 않으면, 셰이더 실행 전에 테스트를 수행할 수 있다

 

내장 변수: gl_FragDepth

 

블렌딩

glEnable(GL_BLEND)

glBlendFunc()

glBlendColor()

 

Off-Screen Rendering

- 단편 셰이더의 출력은 back buffer로 들어간다

- 이 버퍼는 OS 또는 윈도우 시스템 소유

- 직접 버퍼를 만들어서 여기에 그릴 수 있다 (FBO)

glGenFramebuffers(n, id_ary)

glBindFramebuffer(target, framebuffer)

  target: GL_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_WRITE_FRAMEBUFFER

프레임버퍼의 저장 공간: 텍스처

  glFramebufferTexture(target, attachment, texture, level)

  - attachment: GL_[DEPTH/STENCIL/COLOR]_ATTACHMENT

  - level: 밉맵 수준

하나의 FBO에 최소 8개의 텍스처를 붙일 수 있다

 

프레임버퍼 검사

glCheckFramebufferStatus(target)

 

지금까지 다룬 프레임버퍼

1. 기본 프레임버퍼

2. 프레임버퍼로서의 텍스처(GL_RGBA8 포맷)

  8비트 부호 없는 정규화된 정수 형식

  0.0 ~ 1.0을 256단계로 표현하는 것이 고작

- 하지만 단편 셰이더의 출력은 vec4

- 프레임버퍼 attachment는 1~4개의 성분을 가진다

  - 이 성분들은 부동소수점 수 또는 정수 형식

  - 음수를 저장할 수 있다

  - 8비트보다 클 수 있다

 

고급 프레임버퍼 포맷

attachment 없이 렌더링

- 텍스처 여러 개를 하나의 프레임버퍼에 붙이고 하나의 셰이더로 모든 텍스처에 렌더링할 수 있다

- 프레임버퍼를 만들고는 아무 텍스처도 붙이지 않는 것이 가능하다

  - 그럼 내 데이터는 어디로? -> 아무 효과 없음. 단편 셰이더에 선언된 출력들은 기각된다

  - 하지만 단편 셰이더는 출력 변수에 기록하는 것 외에도 부수효과를 가질 수 있다

    - imageStore 함수로 메모리에 기록

    - atomicCounterIncrement/Decrement로 아토믹 카운터 증감

- FBO에 하나 이상의 attachment가 있으면, 그것들로부터 최대 가로/세로, 레이어 카운트, 샘플 카운트 등을 도출해낸다

  - 이 속성들은 뷰포트를 클램핑할 크기를 결정한다

  - attachment가 없으면 텍스처의 가용 메모리로 인한 제약이 사라진다

  - 하지만 FBO는 이 정보들이 필요하다. 그 정보를 제공하는 다른 방법이 필요

    glFramebufferParameteri(GLenum target, GLenum pname, GLint param)

    - target: GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_FRAMEBUFFER

    - pname: GL_FRAMEBUFFER_DEFAULT, WIDTH, HEIGHT, LAYERS, SAMPLES, FIXED_SAMPLE_LOCATIONS

 

Floating-Point Framebuffers

- OpenGL 파이프라인 내부에서는 부동소수점 데이터를 이용

- 하지만 소스(텍스처)와 타겟(프레임버퍼 attachment)는 고정소수점 -> 정확도 손실

- 정점 셰이더에 전달되는 데이터는 대개 vec4

- 정점 셰이더의 출력이 기하구조를 따라 보간되어 단편 셰이더에 전달된다

- 256개 값 대신 1.1 * 10^(-38) ~ 3.4 * 10^38 에 이르는 값 사용 가능

  - 색상별로 8비트만 지원하는 윈도우나 모니터에서는 어떻게 되는가?

  - 출력이 [0, 1]로 잘리고 고정소수점 값으로 매핑됨

- 하지만 여전히 텍스처에 완전한 부동소수점 정확도로 렌더링하는 것이 가능 (HDR의 개념)

- Floating-point 포맷 사용

  glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA16F,32F, width, height)

  다른 포맷들: RGB32F, RGB16F, RG32F, RG16F, R32F, R16F, R11F_G11F_B10F, DEPTH_COMPONENT32F, DEPTH_COMPONENT32F_STENCIL8

- HDR: light bloom, lens flare, light reflection, light refraction, crepuscular ray...

- 톤 매핑

  - 0에서 255까지 값으로만 표시해야 하는 이미지를 부동소수점 데이터를 가지고 동적 생성하는 방법

  - y = 1 - exp(-xp)

Comments