[2023 동계 모각소] 알구자구 4주차

jungizz_·2024년 1월 30일
0

모각소

목록 보기
10/12
post-thumbnail
post-custom-banner

📝 4주차

  • Framebuffer Object
  • Screen-Space Perceptual Rendering of Human Skin

1. Frame buffer Object

  • Frame buffer: 렌더링의 최종 결과가 기록되는 buffer 집합
  • GLFW가 만들어둔 기본 frame buffer가 아닌, 사용자가 동적으로 생성한 임의의 frame buffer object(FBO)에 렌더링할 수 있음
  • 다른 frame buffer object에 렌더링하면, 씬에 거울을 만들거나 post processing 등 가능
  • 렌더링 전 bind되어있는 버퍼에 그려짐
glBindFramebuffer(GL_FRAMEBUFFER, 0) // 기본 framebuffer bind
glBindFramebuffer(GL_FRAMEBUFFER, (생성한 프레임버퍼 이름)) // 사용자 framebuffer bind
  • FBO를 생성 시 요구사항: 최소한 하나의 buffer(depth, stencil 등)와 최소한 하나의 color texture를 attach
  • FBO에 렌더링하면 화면에 보이진 않고(off-screen rendering) attach한 color texturedepth buffer에 결과 정보가 저장됨
  • 실제 윈도우 화면에 보이도록하기 위해서는 FBO에 렌더링하고 나온 color texture를 사용하여 기본 frame buffer에 그려야 함

make FBO and rendering

  • FBO를 생성하고 기존 렌더링 과정을 FBO에서 진행
  • FBO에서 생성된 color texture를 사용해서 기존 frame buffer에 띄우기
    -> 화면에 color texture 이미지 한 장을 띄우게 되므로, 이미지를 그릴 quad 모델을 기존 framebuffer에 그려야함

✔️ main.cpp

  • FBO를 생성하고, 비어있는 color texture buffer와 depth buffer를 framebuffer에 attach
  • FBO를 binding해줬기 때문에 기본 frame buffer가 아닌 새로운 FBO에 렌더링
    -> 기존 화면에 아무것도 뜨지 않음
void init() {

 . . .
 
    // FBO 생성 및 bind
    glGenFramebuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    
    // texture buffer object to be used for colorbuffer
    GLuint colorTexBuffer;
    glGenTextures(1, &colorTexBuffer);
    glBindTexture(GL_TEXTURE_2D, colorTexBuffer);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 640, 480, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); // image data를 load하여 연결할 필요 없으므로 마지막 인자에 NULL
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexBuffer, 0); // attachment

    // texture buffer object to be used for depth buffer
    GLuint depthBuffer = 0;
    glGenTextures(1, &depthBuffer);
    glBindTexture(GL_TEXTURE_2D, depthBuffer);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, 640, 480, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL); // image data를 load하여 연결할 필요 없으므로 마지막 인자에 NULL
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthBuffer, 0); // attachment

	// framebuffer object 생성 시 요구사항을 만족했는지 확인
    if(glCheckFramebufferStatus(GL_FRAMEBUFFER)!= GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
}

void render(GLFWwindow* window)
{
	glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    
    . . . (기존 렌더링 과정)
}

draw FBO color texture on default framebuffer

  • 기본 framebuffer를 binding하여 FBO의 color texture를 렌더링
  • texture를 적용시킬 quad plane 모델 및 새로운 shader code 필요

✔️ main.cpp

. . .

// quad plane
GLuint quadVertexBuffer = 0;
GLuint quadArrrayBuffer = 0;
float quadVertices[] = { // 화면 전체에 렌더링하기 위한 사각형 정점 데이터
    -1.0f,  1.0f, 0.0f,  // 왼쪽 상단
    -1.0f, -1.0f, 0.0f,  // 왼쪽 하단
     1.0f, -1.0f, 0.0f,  // 오른쪽 하단

    -1.0f,  1.0f, 0.0f,  // 왼쪽 상단
     1.0f, -1.0f, 0.0f,  // 오른쪽 하단
     1.0f,  1.0f, 0.0f   // 오른쪽 상단
};

// FBO 관련 변수 전역으로 이동
GLuint frameBuffer = 0;
GLuint colorTexBuffer = 0;
GLuint depthBuffer = 0;

Program program;
Program screenProgram; // 새로운 shader code를 사용하기 위한 program 생성

void init() {
    . . .
    
    program.loadShaders("shader.vert", "shader.frag");
    screenProgram.loadShaders("screenShader.vert", "screenShader.frag");
    
    . . .
    
    // (VBO)
    
    // (VAO)
    
    // (element Buffer)
    
    // (load Texture)
    
    // quad plane VAO
    glGenBuffers(1, &quadVertexBuffer);
    glGenVertexArrays(1, &quadArrrayBuffer);
    glBindVertexArray(quadArrrayBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, quadVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
    
    // (FBO)
}

void render(GLFWwindow* window) 
{
    // (1. draw on framebuffer object)
    
    . . .
    
    // 2. draw on default framebuffer (quad plane with the attached framebuffer color texture)
	glBindFramebuffer(GL_FRAMEBUFFER, 0); // 기존 framebuffer binding
    glViewport(0, 0, nowSize.x, nowSize.y);
    glClearColor(0.1, 0.1, 0.1, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUseProgram(screenProgram.programID); // screenShader 사용

	// FBO의 colortexure 정보를 fragment shader에게 넘겨주기
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, colorTexBuffer);
    GLuint colorTexLocation = glGetUniformLocation(screenProgram.programID, "colorTex");
    glUniform1i(colorTexLocation, 0);
	
    // window size 정보를 fragment shader에게 넘겨주기
    GLuint sizeLocation = glGetUniformLocation(gaussianProgram.programID, "size");
glUniform2f(sizeLocation, static_cast<float>(nowSize.x), static_cast<float>(nowSize.y));
	
    // quad VAO binding하여 vertex shader에게 quad vertex정보 넘겨주기
    glBindVertexArray(quadArrrayBuffer);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    glBindVertexArray(0);

    glBindTexture(GL_TEXTURE_2D, 0);
}

✔️ screenShader.vert

  • quad VAO의 position 정보를 fragment shader에게 넘겨줌
#version 410 core

layout(location=0) in vec3 in_Position;

void main(void)
{
	gl_Position = vec4(in_Position, 1.0);
}

✔️ screenShader.frag

  • quad 위에 texture 적용
#version 150 core

uniform sampler2D colorTex;
uniform vec2 size;

out vec4 out_Color;

void main(void)
{	
	out_Color = texture(colorTex, gl_FragCoord.xy / size);
}

2. Screen-Space Perceptual Rendering of Human Skin

  • subsurface scattering을 texture space가 아닌 screen space에서 하는 이유와 관련된 논문
🔗 Screen-Space Perceptual Rendering of Human Skin

Introduction

  • scattering effects from texture to screen space
    • 장점: reduce the problem of simulating translucency to a postprocess
    • 단점: have less information to work

The Diffusion Approximation

Diffuse Profile

  • 피부에 하얀색 라이트를 비췄을 때, 가운데 점을 중심으로 빛이 산란
    • x축: 빛의 입사 지점부터 산란된 거리
    • y축: 반사 강도
  • 파장마다 방출 강도가 다름, R>G>B 순서로 중심에서 거리가 멀어지더라도 빛이 표면에서 방출됨
  • 빛이 입사한 지점은 RGB 모두 값이 높아 하얀색 점이고, 거리가 멀어질 수록 빨간색 빛이 많이 남아 빨간색 빛이 보이는 것

Dipole model

  • R: diffusion profile
  • contribution of the incoming light ray는 두 개의 virtual source 중 하나로 간주
    1. 표면 아래 음수
    2. 표면 위의 양수
      → 이래서 dipole(양극의)이라고 하는 것

Bidirectional Scattering Surface Reflectance Distribution Function (BSSRDF)

  • Sd(xi,ωi;xo,ωo)=1πFt(xi,ωi)R(xixo2)Ft(xo,ωo)S_d (x_i, ω_i; x_o, ω_o) = \frac{1}{π}F_t(x_i, ω_i)R(||x_i − x_o||_2)F_t(x_o, ω_o)
    • xi,ωix_i, ω_i: incident light의 위치 및 각도
    • xo,ωox_o, ω_o: radiated light의 위치 및 각도
    • FtF_t: Fresnel transmittance
    • RR: diffusion profile of the material
  • dipole model을 multipole appriximation으로 확장하고, sum of dioples로 정의
    → better simulation of multilayered materials

Translucency

  • transparency처럼 빛이 통과할 수 있지만, scattering될 수 있는 성질
  • ex) 치아 끝부분에 약간 투명한 부분

Screen-space Algorithm

  • texture space가 아닌, screen space에서 diffusion approximation
    • 현재의 피부 실시간 렌더링 방법은 texture space에 기반하지만, texture space에서 irradiance map을 렌더링하긴 어렵다
  • SSS가 적용 안된 matte, diffuse, depth(rendered image)를 input으로 받고, diffusion profiles을 rendered diffuse image에 적용(=SSS 적용)
    • SSS는 specular highlight가 아닌 diffuse component of the illumination에만 적용되기 때문
    • diffuse와 specular components를 따로 저장

Two-Pass Rendering (고렌특 강노)

  • Geometry pass1
    • diffuse lighting을 계산하고 framebuffer에 저장
  • SSS pass (image space)
    • diffuse lighted image를 블러 (using diffusion profile as the blur kernel)
    • considering surface discontinuity
    • using sampling method
  • Geometry pass2
    • SSS의 결과를 diffuse lighting으로 사용
    • spcular lighting 추가
  • 이미지에서 필요한 부분에만 convolution을 적용하면 되므로, matte mask에 의존하여 선택적인 방법으로 pixel shader에 적용
  • Screen space에서 작업하려면, kernel 크기가 조절되야함
    • 멀리 떨어진 물체를 나타내는 픽셀일수록 좁은 커널
    • depth map에서 gradient가 클수록 좁은 커널 (edge에서는 작은 범위에서 convolution하여 피부/배경 픽셀이 섞이지 않도록)
  • kernel width에 아래 stretch factors를 곱해서 조절
    • sx=αd(x,y)+βabs(xd(x,y)),sy=αd(x,y)+βabs(yd(x,y))s_x = \frac{α}{d(x, y) + β · abs(∇_xd(x, y))}, s_y = \frac{α}{d(x, y) + β · abs(∇_yd(x, y))}

  • texture space skin shader(위) vs screen space skin shader(아래)
    • stretch map, irradiance map 필요 없고, convolution도 screen space에서 한번만 함
    • 마지막 bloom pass는 최적화도 안하고, 마지막 이미지에 적용되기 때문에 오브젝트 수가 많아져도 계산 시간이 늘어나지도 않음
profile
( •̀ .̫ •́ )✧
post-custom-banner

0개의 댓글