GBuffer
)texelFetchoffset
함수로 알 수 있어서 필요 없긴함)texelFetch
: texCoord[-1, 1]로 텍스처 정보를 들고오는 texture
함수와 다르게 픽셀로 텍스처 정보를 들고오는 함수texelFetchoffset
: offset을 지정하여 원하는 위치의 texel값을 읽어올 수 있는 함수Pass 1
Pass
를 1로 설정void SceneEdge::pass1()
{
prog.setUniform("Pass", 1);
glBindFramebuffer(GL_FRAMEBUFFER, fboHandle);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
view = glm::lookAt(vec3(7.0f * cos(angle),4.0f,7.0f * sin(angle)), vec3(0.0f,0.0f,0.0f), vec3(0.0f,1.0f,0.0f));
projection = glm::perspective(glm::radians(60.0f), (float)width/height, 0.3f, 100.0f);
. . . (draw)
}
Pass 2
Pass
를 2로 설정void SceneEdge::pass2()
{
prog.setUniform("Pass", 2);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderTex);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
model = mat4(1.0f);
view = mat4(1.0f);
projection = mat4(1.0f);
setMatrices();
// Render the full-screen quad
glBindVertexArray(fsQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
두 pass 사이에 blur pass를 추가하면 noise를 줄여 더 좋은 결과를 얻을 수 있음
◾ Helper Textures
- 한 픽셀당 9개의 texture data를 접근하고 있어서 좀 느림
-> 추가 텍스처(helper image)를 사용해 각 채널에 하나의 texel만 저장한다
weight * pixel value
를 한 픽셀당 81번weight * pixel value
를 한 픽셀당 18번Pass 1
Pass
를 1로 설정void SceneBlur::pass1()
{
prog.setUniform("Pass", 1);
glBindFramebuffer(GL_FRAMEBUFFER, renderFBO);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
view = glm::lookAt(vec3(7.0f * cos(angle),4.0f,7.0f * sin(angle)), vec3(0.0f,0.0f,0.0f), vec3(0.0f,1.0f,0.0f));
projection = glm::perspective(glm::radians(60.0f), (float)width/height, 0.3f, 100.0f);
. . . (draw)
}
Pass 2
Pass
를 2로 설정void SceneBlur::pass2()
{
prog.setUniform("Pass", 2);
glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderTex);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
model = mat4(1.0f);
view = mat4(1.0f);
projection = mat4(1.0f);
setMatrices();
// Render the full-screen quad
glBindVertexArray(fsQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
Pass 3
void SceneBlur::pass3()
{
prog.setUniform("Pass", 3);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, intermediateTex);
glClear(GL_COLOR_BUFFER_BIT);
model = mat4(1.0f);
view = mat4(1.0f);
projection = mat4(1.0f);
setMatrices();
// Render the full-screen quad
glBindVertexArray(fsQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
void SceneToneMap::setupFBO()
{
GLuint depthBuf;
// Create and bind the FBO
glGenFramebuffers(1, &hdrFBO);
glBindFramebuffer(GL_FRAMEBUFFER, hdrFBO);
// The depth buffer
glGenRenderbuffers(1, &depthBuf);
glBindRenderbuffer(GL_RENDERBUFFER, depthBuf);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
// The HDR color buffer
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &hdrTex);
glBindTexture(GL_TEXTURE_2D, hdrTex);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB32F, width, height); // 여기!!!
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Attach the images to the framebuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuf);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdrTex, 0);
GLenum drawBuffers[] = {GL_NONE, GL_COLOR_ATTACHMENT0};
glDrawBuffers(2, drawBuffers);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// Bind the depth buffer to the FBO
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depthBuf);
// Set the targets for the fragment output variables
GLenum drawBuffers[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, drawBuffers);
// Create an FBO for the bright-pass filter and blur
glGenFramebuffers(1, &blurFbo);
glBindFramebuffer(GL_FRAMEBUFFER, blurFbo);
// Create two texture objects to ping-pong for the bright-pass filter
// and the two-pass blur
bloomBufWidth = width / 8;
bloomBufHeight = height / 8;
glGenTextures(1, &tex1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex1);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB32F, bloomBufWidth, bloomBufHeight);
glActiveTexture(GL_TEXTURE2);
glGenTextures(1, &tex2);
glBindTexture(GL_TEXTURE_2D, tex2);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGB32F, bloomBufWidth, bloomBufHeight);
// Bind tex1 to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex1, 0);
glDrawBuffers(1, drawBuffers);
// Set up two sampler objects for linear and nearest filtering
GLuint samplers[2];
glGenSamplers(2, samplers);
linearSampler = samplers[0];
nearestSampler = samplers[1];
GLfloat border[] = {0.0f,0.0f,0.0f,0.0f};
// Set up the nearest sampler
glSamplerParameteri(nearestSampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glSamplerParameteri(nearestSampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glSamplerParameteri(nearestSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glSamplerParameteri(nearestSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glSamplerParameterfv(nearestSampler, GL_TEXTURE_BORDER_COLOR, border);
// Set up the linear sampler
glSamplerParameteri(linearSampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(linearSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glSamplerParameteri(linearSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glSamplerParameteri(linearSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glSamplerParameterfv(linearSampler, GL_TEXTURE_BORDER_COLOR, border);
// We want nearest sampling except for the last pass.
glBindSampler(0, nearestSampler);
glBindSampler(1, nearestSampler);
glBindSampler(2, nearestSampler);
void SceneHdrBloom::pass5()
{
prog.setUniform("Pass", 5);
// Bind to the default framebuffer, this time we're going to
// actually draw to the screen!
glBindFramebuffer(GL_FRAMEBUFFER,0);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0,0,width,height);
// In this pass, we're reading from tex1 (unit 1) and we want
// linear sampling to get an extra blur
glBindSampler(1, linearSampler);
// Render the full-screen quad
glBindVertexArray(fsQuad);
glDrawArrays(GL_TRIANGLES, 0, 6);
// Revert to nearest sampling
glBindSampler(1, nearestSampler);
}
P
은 실제 픽셀값I
의 제곱 (보통 는 2.0~2.4 범위를 가지고 주어짐)