Make pbr bloom example compile

This commit is contained in:
alexpanter
2022-05-27 21:00:48 +02:00
parent 0bc8312a14
commit 4ab092ec96
2 changed files with 294 additions and 8 deletions

View File

@@ -42,7 +42,7 @@ void main()
result = bloom_none(); break; result = bloom_none(); break;
} }
// tone mapping // tone mapping
vec3 result = vec3(1.0) - exp(-hdrColor * exposure); result = vec3(1.0) - exp(-result * exposure);
// also gamma correct while we're at it // also gamma correct while we're at it
const float gamma = 2.2; const float gamma = 2.2;
result = pow(result, vec3(1.0 / gamma)); result = pow(result, vec3(1.0 / gamma));

View File

@@ -12,6 +12,7 @@
#include <learnopengl/model.h> #include <learnopengl/model.h>
#include <iostream> #include <iostream>
#include <vector>
void framebuffer_size_callback(GLFWwindow* window, int width, int height); void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void mouse_callback(GLFWwindow* window, double xpos, double ypos); void mouse_callback(GLFWwindow* window, double xpos, double ypos);
@@ -27,6 +28,7 @@ const unsigned int SCR_HEIGHT = 600;
bool bloom = true; bool bloom = true;
float exposure = 1.0f; float exposure = 1.0f;
int programChoice = 1; int programChoice = 1;
float bloomFilterRadius = 0.005f;
// camera // camera
Camera camera(glm::vec3(0.0f, 0.0f, 5.0f)); Camera camera(glm::vec3(0.0f, 0.0f, 5.0f));
@@ -38,6 +40,283 @@ bool firstMouse = true;
float deltaTime = 0.0f; float deltaTime = 0.0f;
float lastFrame = 0.0f; float lastFrame = 0.0f;
// bloom stuff
struct bloomMip
{
glm::vec2 size;
glm::ivec2 intSize;
unsigned int texture;
};
class bloomFBO
{
public:
bloomFBO();
~bloomFBO();
bool Init(unsigned int windowWidth, unsigned int windowHeight, unsigned int mipChainLength);
void Destroy();
void BindForWriting();
const std::vector<bloomMip>& MipChain() const;
private:
bool mInit;
unsigned int mFBO;
std::vector<bloomMip> mMipChain;
};
bloomFBO::bloomFBO() : mInit(false) {}
bloomFBO::~bloomFBO() {}
bool bloomFBO::Init(unsigned int windowWidth, unsigned int windowHeight, unsigned int mipChainLength)
{
if (mInit) return true;
glGenFramebuffers(1, &mFBO);
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glm::vec2 mipSize((float)windowWidth, (float)windowHeight);
glm::ivec2 mipIntSize((int)windowWidth, (int)windowHeight);
// Safety check
if (windowWidth > (unsigned int)INT_MAX || windowHeight > (unsigned int)INT_MAX) {
std::cerr << "Window size conversion overflow - cannot build bloom FBO!" << std::endl;
return false;
}
for (GLuint i = 0; i < mipChainLength; i++)
{
bloomMip mip;
mipSize *= 0.5f;
mipIntSize /= 2;
mip.size = mipSize;
mip.intSize = mipIntSize;
glGenTextures(1, &mip.texture);
glBindTexture(GL_TEXTURE_2D, mip.texture);
// we are downscaling an HDR color buffer, so we need a float texture format
glTexImage2D(GL_TEXTURE_2D, 0, GL_R11F_G11F_B10F,
(int)mipSize.x, (int)mipSize.y,
0, GL_RGB, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
std::cout << "Created bloom mip " << mipIntSize.x << 'x' << mipIntSize.y << std::endl;
mMipChain.emplace_back(mip);
}
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, mMipChain[0].texture, 0);
// setup attachments
unsigned int attachments[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, attachments);
// check completion status
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
printf("gbuffer FBO error, status: 0x%x\n", status);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return false;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
mInit = true;
return true;
}
void bloomFBO::Destroy()
{
for (int i = 0; i < (int)mMipChain.size(); i++) {
glDeleteTextures(1, &mMipChain[i].texture);
mMipChain[i].texture = 0;
}
glDeleteFramebuffers(1, &mFBO);
mFBO = 0;
mInit = false;
}
void bloomFBO::BindForWriting()
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
}
const std::vector<bloomMip>& bloomFBO::MipChain() const
{
return mMipChain;
}
class BloomRenderer
{
public:
BloomRenderer();
~BloomRenderer();
bool Init(unsigned int windowWidth, unsigned int windowHeight);
void Destroy();
void RenderBloomTexture(unsigned int srcTexture, float filterRadius);
unsigned int BloomTexture();
unsigned int BloomMip_i(int index);
private:
void RenderDownsamples(unsigned int srcTexture);
void RenderUpsamples(float filterRadius);
bool mInit;
bloomFBO mFBO;
glm::ivec2 mSrcViewportSize;
glm::vec2 mSrcViewportSizeFloat;
Shader* mDownsampleShader;
Shader* mUpsampleShader;
bool mKarisAverageOnDownsample = true;
};
BloomRenderer::BloomRenderer() : mInit(false) {}
BloomRenderer::~BloomRenderer() {}
bool BloomRenderer::Init(unsigned int windowWidth, unsigned int windowHeight)
{
if (mInit) return true;
mSrcViewportSize = glm::ivec2(windowWidth, windowHeight);
mSrcViewportSizeFloat = glm::vec2((float)windowWidth, (float)windowHeight);
// Framebuffer
const unsigned int num_bloom_mips = 6; // TODO: Play around with this value
bool status = mFBO.Init(windowWidth, windowHeight, num_bloom_mips);
if (!status) {
std::cerr << "Failed to initialize bloom FBO - cannot create bloom renderer!\n";
return false;
}
// Shaders
mDownsampleShader = new Shader("6.new_downsample.vs", "6.new_downsample.fs");
mUpsampleShader = new Shader("6.new_upsample.vs", "6.new_upsample.fs");
// Downsample
mDownsampleShader->use();
mDownsampleShader->setInt("srcTexture", 0);
glUseProgram(0);
// Upsample
mUpsampleShader->use();
mUpsampleShader->setInt("srcTexture", 0);
glUseProgram(0);
return true;
}
void BloomRenderer::Destroy()
{
mFBO.Destroy();
delete mDownsampleShader;
delete mUpsampleShader;
}
void BloomRenderer::RenderDownsamples(unsigned int srcTexture)
{
const std::vector<bloomMip>& mipChain = mFBO.MipChain();
mDownsampleShader->use();
mDownsampleShader->setVec2("srcResolution", mSrcViewportSizeFloat);
if (mKarisAverageOnDownsample) {
mDownsampleShader->setInt("mipLevel", 0);
}
// Bind srcTexture (HDR color buffer) as initial texture input
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, srcTexture);
// Progressively downsample through the mip chain
for (int i = 0; i < (int)mipChain.size(); i++)
{
const bloomMip& mip = mipChain[i];
glViewport(0, 0, mip.size.x, mip.size.y);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, mip.texture, 0);
// Render screen-filled quad of resolution of current mip
renderQuad();
// Set current mip resolution as srcResolution for next iteration
mDownsampleShader->setVec2("srcResolution", mip.size);
// Set current mip as texture input for next iteration
glBindTexture(GL_TEXTURE_2D, mip.texture);
// Disable Karis average for consequent downsamples
if (i == 0) { mDownsampleShader->setInt("mipLevel", 1); }
}
glUseProgram(0);
}
void BloomRenderer::RenderUpsamples(float filterRadius)
{
const std::vector<bloomMip>& mipChain = mFBO.MipChain();
mUpsampleShader->use();
mUpsampleShader->setFloat("filterRadius", filterRadius);
// Enable additive blending
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
for (int i = (int)mipChain.size() - 1; i > 0; i--)
{
const bloomMip& mip = mipChain[i];
const bloomMip& nextMip = mipChain[i-1];
// Bind viewport and texture from where to read
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mip.texture);
// Set framebuffer render target (we write to this texture)
glViewport(0, 0, nextMip.size.x, nextMip.size.y);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, nextMip.texture, 0);
// Render screen-filled quad of resolution of current mip
renderQuad();
}
// Disable additive blending
//glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
glUseProgram(0);
}
void BloomRenderer::RenderBloomTexture(unsigned int srcTexture, float filterRadius)
{
mFBO.BindForWriting();
this->RenderDownsamples(srcTexture);
this->RenderUpsamples(filterRadius);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Restore viewport
glViewport(0, 0, mSrcViewportSize.x, mSrcViewportSize.y);
}
GLuint BloomRenderer::BloomTexture()
{
return mFBO.MipChain()[0].texture;
}
GLuint BloomRenderer::BloomMip_i(int index)
{
const std::vector<bloomMip>& mipChain = mFBO.MipChain();
int size = (int)mipChain.size();
return mipChain[(index > size-1) ? size-1 : (index < 0) ? 0 : index].texture;
}
int main() int main()
{ {
// glfw: initialize and configure // glfw: initialize and configure
@@ -87,9 +366,6 @@ int main()
Shader shaderBlur("6.old_blur.vs", "6.old_blur.fs"); Shader shaderBlur("6.old_blur.vs", "6.old_blur.fs");
Shader shaderBloomFinal("6.bloom_final.vs", "6.bloom_final.fs"); Shader shaderBloomFinal("6.bloom_final.vs", "6.bloom_final.fs");
Shader shaderDownsample("6.new_downsample.vs", "6.new_downsample.fs");
Shader shaderUpsample("6.new_upsample.vs", "6.new_upsample.fs");
// load textures // load textures
// ------------- // -------------
unsigned int woodTexture = loadTexture(FileSystem::getPath("resources/textures/wood.png").c_str(), true); // note that we're loading the texture as an SRGB texture unsigned int woodTexture = loadTexture(FileSystem::getPath("resources/textures/wood.png").c_str(), true); // note that we're loading the texture as an SRGB texture
@@ -174,6 +450,11 @@ int main()
shaderBloomFinal.setInt("scene", 0); shaderBloomFinal.setInt("scene", 0);
shaderBloomFinal.setInt("bloomBlur", 1); shaderBloomFinal.setInt("bloomBlur", 1);
// bloom renderer
// --------------
BloomRenderer bloomRenderer;
bloomRenderer.Init(SCR_WIDTH, SCR_HEIGHT);
// render loop // render loop
// ----------- // -----------
while (!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
@@ -275,6 +556,7 @@ int main()
if (programChoice < 1 || programChoice > 3) { programChoice = 1; } if (programChoice < 1 || programChoice > 3) { programChoice = 1; }
bloom = (programChoice == 1) ? false : true; bloom = (programChoice == 1) ? false : true;
bool horizontal = true;
// 2.A) bloom is disabled // 2.A) bloom is disabled
// ---------------------- // ----------------------
@@ -287,7 +569,7 @@ int main()
// ------------------------------------------------------ // ------------------------------------------------------
else if (programChoice == 2) else if (programChoice == 2)
{ {
bool horizontal = true, first_iteration = true; bool first_iteration = true;
unsigned int amount = 10; unsigned int amount = 10;
shaderBlur.use(); shaderBlur.use();
for (unsigned int i = 0; i < amount; i++) for (unsigned int i = 0; i < amount; i++)
@@ -307,7 +589,7 @@ int main()
// ------------------------------------------------------------------- // -------------------------------------------------------------------
else if (programChoice == 3) else if (programChoice == 3)
{ {
bloomRenderer.RenderBloomTexture(colorBuffers[1], bloomFilterRadius);
} }
// 3. now render floating point color buffer to 2D quad and tonemap HDR colors to default framebuffer's (clamped) color range // 3. now render floating point color buffer to 2D quad and tonemap HDR colors to default framebuffer's (clamped) color range
@@ -317,13 +599,16 @@ int main()
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorBuffers[0]); glBindTexture(GL_TEXTURE_2D, colorBuffers[0]);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
if (programChoice == 1) {
glBindTexture(GL_TEXTURE_2D, 0); // trick to bind invalid texture "0", we don't care either way!
}
if (programChoice == 2) { if (programChoice == 2) {
glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[!horizontal]); glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[!horizontal]);
} }
else if (programChoice == 3) { else if (programChoice == 3) {
glBindTexture(GL_TEXTURE_2D, bloomRenderer.Get...) glBindTexture(GL_TEXTURE_2D, bloomRenderer.BloomTexture());
} }
shaderBloomFinal.setInt("programChoice", programChoice)); shaderBloomFinal.setInt("programChoice", programChoice);
shaderBloomFinal.setFloat("exposure", exposure); shaderBloomFinal.setFloat("exposure", exposure);
renderQuad(); renderQuad();
@@ -335,6 +620,7 @@ int main()
glfwPollEvents(); glfwPollEvents();
} }
bloomRenderer.Destroy();
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }