From 77e70ce9459a4633f4e5870cf1e0a4507a4aef14 Mon Sep 17 00:00:00 2001 From: knightcrawler25 Date: Wed, 30 Dec 2020 22:17:31 +0530 Subject: [PATCH] Russian Roulette, Conditional Compilation --- src/Main.cpp | 15 ++++++++- src/core/Program.cpp | 2 +- src/core/Renderer.cpp | 7 ++-- src/core/Renderer.h | 11 ++++++- src/core/Shader.cpp | 11 +++---- src/core/Shader.h | 3 +- src/core/ShaderIncludes.h | 17 +++++++--- src/core/TiledRenderer.cpp | 51 ++++++++++++++++++++++++++--- src/loaders/Loader.cpp | 8 +++++ src/shaders/common/closest_hit.glsl | 2 ++ src/shaders/common/pathtrace.glsl | 34 ++++++++++++++++--- src/shaders/common/sampling.glsl | 6 ++++ src/shaders/common/uniforms.glsl | 1 + 13 files changed, 140 insertions(+), 28 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index f0b8eea..f99590b 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -283,9 +283,22 @@ void MainLoop(void* arg) if (ImGui::CollapsingHeader("Render Settings")) { + bool requiresReload = false; + Vec3* bgCol = &renderOptions.bgColor; + optionsChanged |= ImGui::SliderInt("Max Depth", &renderOptions.maxDepth, 1, 10); - optionsChanged |= ImGui::Checkbox("Use envmap", &renderOptions.useEnvMap); + requiresReload |= ImGui::Checkbox("Enable HDR", &renderOptions.useEnvMap); optionsChanged |= ImGui::SliderFloat("HDR multiplier", &renderOptions.hdrMultiplier, 0.1f, 10.0f); + requiresReload |= ImGui::Checkbox("Enable RR", &renderOptions.enableRR); + requiresReload |= ImGui::SliderInt("RR Depth", &renderOptions.RRDepth, 1, 10); + requiresReload |= ImGui::Checkbox("Enable Constant BG", &renderOptions.useConstantBg); + optionsChanged |= ImGui::ColorEdit3("Background Color", (float*)bgCol, 0); + + if (requiresReload) + { + scene->renderOptions = renderOptions; + InitRenderer(); + } } if (ImGui::CollapsingHeader("Camera")) diff --git a/src/core/Program.cpp b/src/core/Program.cpp index d9293b5..31889c8 100644 --- a/src/core/Program.cpp +++ b/src/core/Program.cpp @@ -56,7 +56,7 @@ namespace GLSLPT glDeleteProgram(object); object = 0; printf("Error %s\n", msg.c_str()); - throw std::runtime_error(msg); + throw std::runtime_error(msg.c_str()); } } diff --git a/src/core/Renderer.cpp b/src/core/Renderer.cpp index 6103478..eb9622f 100644 --- a/src/core/Renderer.cpp +++ b/src/core/Renderer.cpp @@ -29,15 +29,16 @@ #include "Config.h" #include "Renderer.h" +#include "ShaderIncludes.h" #include "Scene.h" namespace GLSLPT { - Program *LoadShaders(const std::string& vertShaderFilename, const std::string& fragShaderFilename) + Program *LoadShaders(const ShaderInclude::ShaderSource& vertShaderObj, const ShaderInclude::ShaderSource& fragShaderObj) { std::vector shaders; - shaders.push_back(Shader(vertShaderFilename, GL_VERTEX_SHADER)); - shaders.push_back(Shader(fragShaderFilename, GL_FRAGMENT_SHADER)); + shaders.push_back(Shader(vertShaderObj, GL_VERTEX_SHADER)); + shaders.push_back(Shader(fragShaderObj, GL_FRAGMENT_SHADER)); return new Program(shaders); } diff --git a/src/core/Renderer.h b/src/core/Renderer.h index a872d6c..082895a 100644 --- a/src/core/Renderer.h +++ b/src/core/Renderer.h @@ -32,12 +32,13 @@ #include "Quad.h" #include "Program.h" #include +#include #include namespace GLSLPT { - Program *LoadShaders(const std::string &vertShaderFilename, const std::string &fragShaderFilename); + Program* LoadShaders(const ShaderInclude::ShaderSource& vertShaderObj, const ShaderInclude::ShaderSource& fragShaderObj); struct RenderOptions { @@ -49,13 +50,21 @@ namespace GLSLPT useEnvMap = false; resolution = iVec2(1280, 720); hdrMultiplier = 1.0f; + enableRR = true; + useConstantBg = false; + RRDepth = 2; + bgColor = Vec3(1.0f, 1.0f, 1.0f); } iVec2 resolution; int maxDepth; int tileWidth; int tileHeight; bool useEnvMap; + bool enableRR; + bool useConstantBg; + int RRDepth; float hdrMultiplier; + Vec3 bgColor; }; class Scene; diff --git a/src/core/Shader.cpp b/src/core/Shader.cpp index 72817a4..9bedb21 100644 --- a/src/core/Shader.cpp +++ b/src/core/Shader.cpp @@ -28,20 +28,17 @@ */ #include "Shader.h" -#include "ShaderIncludes.h" #include #include #include namespace GLSLPT { - Shader::Shader(const std::string& filePath, GLenum shaderType) + Shader::Shader(const ShaderInclude::ShaderSource& sourceObj, GLenum shaderType) { - std::string source = GLSLPT::ShaderInclude::load(filePath); - object = glCreateShader(shaderType); - printf("Compiling Shader %s -> %d\n", filePath.c_str(), int(object)); - const GLchar *src = (const GLchar *)source.c_str(); + printf("Compiling Shader %s -> %d\n", sourceObj.path.c_str(), int(object)); + const GLchar *src = (const GLchar *)sourceObj.src.c_str(); glShaderSource(object, 1, &src, 0); glCompileShader(object); GLint success = 0; @@ -53,7 +50,7 @@ namespace GLSLPT glGetShaderiv(object, GL_INFO_LOG_LENGTH, &logSize); char *info = new char[logSize + 1]; glGetShaderInfoLog(object, logSize, NULL, info); - msg += filePath; + msg += sourceObj.path; msg += "\n"; msg += info; delete[] info; diff --git a/src/core/Shader.h b/src/core/Shader.h index 9302c6e..06c4e14 100644 --- a/src/core/Shader.h +++ b/src/core/Shader.h @@ -30,6 +30,7 @@ #pragma once #include +#include "ShaderIncludes.h" #include "Config.h" namespace GLSLPT @@ -39,7 +40,7 @@ namespace GLSLPT private: GLuint object; public: - Shader(const std::string& filePath, GLuint shaderType); + Shader(const ShaderInclude::ShaderSource& sourceObj, GLuint shaderType); GLuint getObject() const; }; } \ No newline at end of file diff --git a/src/core/ShaderIncludes.h b/src/core/ShaderIncludes.h index 6107d34..2271cde 100644 --- a/src/core/ShaderIncludes.h +++ b/src/core/ShaderIncludes.h @@ -67,8 +67,15 @@ namespace GLSLPT class ShaderInclude { public: + + struct ShaderSource + { + std::string src; + std::string path; + }; + // Return the source code of the complete shader - static std::string load(std::string path, std::string includeIndentifier = "#include") + static ShaderSource load(std::string path, std::string includeIndentifier = "#include") { includeIndentifier += ' '; static bool isRecursiveCall = false; @@ -79,7 +86,7 @@ namespace GLSLPT if (!file.is_open()) { std::cerr << "ERROR: could not open the shader at: " << path << "\n" << std::endl; - return fullSourceCode; + return ShaderSource{ fullSourceCode, path }; } std::string lineBuffer; @@ -99,7 +106,7 @@ namespace GLSLPT // By using recursion, the new include file can be extracted // and inserted at this location in the shader source code isRecursiveCall = true; - fullSourceCode += load(lineBuffer); + fullSourceCode += load(lineBuffer).src; // Do not add this line to the shader source code, as the include // path would generate a compilation issue in the final source code @@ -116,9 +123,11 @@ namespace GLSLPT file.close(); - return fullSourceCode; + return ShaderSource{ fullSourceCode, path };; } + + private: static void getFilePath(const std::string& fullPath, std::string& pathWithoutFileName) { diff --git a/src/core/TiledRenderer.cpp b/src/core/TiledRenderer.cpp index 05c8c6e..2b6038d 100644 --- a/src/core/TiledRenderer.cpp +++ b/src/core/TiledRenderer.cpp @@ -87,11 +87,49 @@ namespace GLSLPT // Shaders //---------------------------------------------------------- - pathTraceShader = LoadShaders(shadersDirectory + "common/vertex.glsl", shadersDirectory + "tiled.glsl"); - pathTraceShaderLowRes = LoadShaders(shadersDirectory + "common/vertex.glsl", shadersDirectory + "progressive.glsl"); - accumShader = LoadShaders(shadersDirectory + "common/vertex.glsl", shadersDirectory + "accumulation.glsl"); - tileOutputShader = LoadShaders(shadersDirectory + "common/vertex.glsl", shadersDirectory + "tileOutput.glsl"); - outputShader = LoadShaders(shadersDirectory + "common/vertex.glsl", shadersDirectory + "output.glsl"); + ShaderInclude::ShaderSource vertexShaderSrcObj = ShaderInclude::load(shadersDirectory + "common/vertex.glsl"); + ShaderInclude::ShaderSource pathTraceShaderSrcObj = ShaderInclude::load(shadersDirectory + "tiled.glsl"); + ShaderInclude::ShaderSource pathTraceShaderLowResSrcObj = ShaderInclude::load(shadersDirectory + "progressive.glsl"); + ShaderInclude::ShaderSource accumShaderSrcObj = ShaderInclude::load(shadersDirectory + "accumulation.glsl"); + ShaderInclude::ShaderSource tileOutputShaderSrcObj = ShaderInclude::load(shadersDirectory + "tileOutput.glsl"); + ShaderInclude::ShaderSource outputShaderSrcObj = ShaderInclude::load(shadersDirectory + "output.glsl"); + + // Add preprocessor defines for conditional compilation + std::string defines = ""; + if (scene->renderOptions.useEnvMap && scene->hdrData != nullptr) + defines += "#define ENVMAP\n"; + if (!scene->lights.empty()) + defines += "#define LIGHTS\n"; + if (scene->renderOptions.enableRR) + { + defines += "#define RR\n"; + defines += "#define RR_DEPTH " + std::to_string(scene->renderOptions.RRDepth) + "\n"; + } + if (scene->renderOptions.useConstantBg) + defines += "#define CONSTANT_BG\n"; + + if (defines.size() > 0) + { + size_t idx = pathTraceShaderSrcObj.src.find("#version"); + if (idx != -1) + idx = pathTraceShaderSrcObj.src.find("\n", idx); + else + idx = 0; + pathTraceShaderSrcObj.src.insert(idx + 1, defines); + + idx = pathTraceShaderLowResSrcObj.src.find("#version"); + if (idx != -1) + idx = pathTraceShaderLowResSrcObj.src.find("\n", idx); + else + idx = 0; + pathTraceShaderLowResSrcObj.src.insert(idx + 1, defines); + } + + pathTraceShader = LoadShaders(vertexShaderSrcObj, pathTraceShaderSrcObj); + pathTraceShaderLowRes = LoadShaders(vertexShaderSrcObj, pathTraceShaderLowResSrcObj); + accumShader = LoadShaders(vertexShaderSrcObj, accumShaderSrcObj); + tileOutputShader = LoadShaders(vertexShaderSrcObj, tileOutputShaderSrcObj); + outputShader = LoadShaders(vertexShaderSrcObj, outputShaderSrcObj); printf("Debug sizes : %d %d - %d %d\n", tileWidth, tileHeight, screenSize.x, screenSize.y); //---------------------------------------------------------- @@ -414,6 +452,7 @@ namespace GLSLPT glUniform1i(glGetUniformLocation(shaderObject, "maxDepth"), scene->renderOptions.maxDepth); glUniform1i(glGetUniformLocation(shaderObject, "tileX"), tileX); glUniform1i(glGetUniformLocation(shaderObject, "tileY"), tileY); + glUniform3f(glGetUniformLocation(shaderObject, "bgColor"), scene->renderOptions.bgColor.x, scene->renderOptions.bgColor.y, scene->renderOptions.bgColor.z); pathTraceShader->StopUsing(); pathTraceShaderLowRes->Use(); @@ -428,6 +467,8 @@ namespace GLSLPT glUniform1i(glGetUniformLocation(shaderObject, "useEnvMap"), scene->hdrData == nullptr ? false : scene->renderOptions.useEnvMap); glUniform1f(glGetUniformLocation(shaderObject, "hdrMultiplier"), scene->renderOptions.hdrMultiplier); glUniform1i(glGetUniformLocation(shaderObject, "maxDepth"), scene->camera->isMoving || scene->instancesModified ? 2: scene->renderOptions.maxDepth); + glUniform3f(glGetUniformLocation(shaderObject, "camera.position"), scene->camera->position.x, scene->camera->position.y, scene->camera->position.z); + glUniform3f(glGetUniformLocation(shaderObject, "bgColor"), scene->renderOptions.bgColor.x, scene->renderOptions.bgColor.y, scene->renderOptions.bgColor.z); pathTraceShaderLowRes->StopUsing(); outputShader->Use(); diff --git a/src/loaders/Loader.cpp b/src/loaders/Loader.cpp index 225e81c..d9633ea 100644 --- a/src/loaders/Loader.cpp +++ b/src/loaders/Loader.cpp @@ -213,6 +213,7 @@ namespace GLSLPT if (strstr(line, "Renderer")) { char envMap[200] = "None"; + char enableRR[10] = "None"; while (fgets(line, kMaxLineLength, file)) { @@ -226,6 +227,8 @@ namespace GLSLPT sscanf(line, " maxDepth %i", &renderOptions.maxDepth); sscanf(line, " tileWidth %i", &renderOptions.tileWidth); sscanf(line, " tileHeight %i", &renderOptions.tileHeight); + sscanf(line, " enableRR %s", enableRR); + sscanf(line, " RRDepth %i", &renderOptions.RRDepth); } if (strcmp(envMap, "None") != 0) @@ -233,6 +236,11 @@ namespace GLSLPT scene->AddHDR(path + envMap); renderOptions.useEnvMap = true; } + + if (strcmp(enableRR, "False") == 0) + renderOptions.enableRR = false; + else if (strcmp(enableRR, "True") == 0) + renderOptions.enableRR = true; } diff --git a/src/shaders/common/closest_hit.glsl b/src/shaders/common/closest_hit.glsl index a4890b9..560743b 100644 --- a/src/shaders/common/closest_hit.glsl +++ b/src/shaders/common/closest_hit.glsl @@ -34,6 +34,7 @@ float ClosestHit(Ray r, inout State state, inout LightSampleRec lightSampleRec) float t = INFINITY; float d; +#ifdef LIGHTS // Intersect Emitters for (int i = 0; i < numOfLights; i++) { @@ -81,6 +82,7 @@ float ClosestHit(Ray r, inout State state, inout LightSampleRec lightSampleRec) } } } +#endif int stack[64]; int ptr = 0; diff --git a/src/shaders/common/pathtrace.glsl b/src/shaders/common/pathtrace.glsl index 67f6301..498bb89 100644 --- a/src/shaders/common/pathtrace.glsl +++ b/src/shaders/common/pathtrace.glsl @@ -142,7 +142,8 @@ vec3 DirectLight(in Ray r, in State state) vec3 surfacePos = state.fhp + state.ffnormal * EPS; // Environment Light - if (useEnvMap) +#ifdef ENVMAP +#ifndef CONSTANT_BG { vec3 color; vec4 dirPdf = EnvSample(color); @@ -165,9 +166,11 @@ vec3 DirectLight(in Ray r, in State state) } } } +#endif +#endif // Analytic Lights - if (numOfLights > 0) +#ifdef LIGHTS { LightSampleRec lightSampleRec; Light light; @@ -204,8 +207,8 @@ vec3 DirectLight(in Ray r, in State state) L += powerHeuristic(lightPdf, bsdfPdf) * f * abs(dot(state.ffnormal, lightDir)) * lightSampleRec.emission / lightPdf; } - } +#endif return L; } @@ -228,7 +231,10 @@ vec3 PathTrace(Ray r) if (t == INFINITY) { - if (useEnvMap) +#ifdef CONSTANT_BG + radiance += bgColor * throughput; +#else +#ifdef ENVMAP { float misWeight = 1.0f; vec2 uv = vec2((PI + atan(r.direction.z, r.direction.x)) * (1.0 / TWO_PI), acos(r.direction.y) * (1.0 / PI)); @@ -240,6 +246,8 @@ vec3 PathTrace(Ray r) } radiance += misWeight * texture(hdrTex, uv).xyz * throughput * hdrMultiplier; } +#endif +#endif return radiance; } @@ -248,12 +256,13 @@ vec3 PathTrace(Ray r) radiance += state.mat.emission * throughput; +#ifdef LIGHTS if (state.isEmitter) { radiance += EmitterSample(r, state, lightSampleRec, bsdfSampleRec) * throughput; break; } - +#endif radiance += DirectLight(r, state) * throughput; bsdfSampleRec.bsdfDir = DisneySample(r, state); @@ -263,6 +272,21 @@ vec3 PathTrace(Ray r) throughput *= DisneyEval(r, state, bsdfSampleRec.bsdfDir) * abs(dot(state.ffnormal, bsdfSampleRec.bsdfDir)) / bsdfSampleRec.pdf; else break; + +#ifdef RR + // Russian roulette + if (depth >= RR_DEPTH) + { + float q = max(max(throughput.x, max(throughput.y, throughput.z)), 0.001); + if (rand() > q) + break; + + throughput *= 1.0 / q; + } +#endif + + + r.direction = bsdfSampleRec.bsdfDir; r.origin = state.fhp + r.direction * EPS; diff --git a/src/shaders/common/sampling.glsl b/src/shaders/common/sampling.glsl index 06628df..f2caae3 100644 --- a/src/shaders/common/sampling.glsl +++ b/src/shaders/common/sampling.glsl @@ -179,6 +179,9 @@ void sampleLight(in Light light, inout LightSampleRec lightSampleRec) sampleSphereLight(light, lightSampleRec); } +#ifdef ENVMAP +#ifndef CONSTANT_BG + //----------------------------------------------------------------------- float EnvPdf(in Ray r) //----------------------------------------------------------------------- @@ -211,6 +214,9 @@ vec4 EnvSample(inout vec3 color) return vec4(-sin(theta) * cos(phi), cos(theta), -sin(theta)*sin(phi), (pdf * hdrResolution) / (2.0 * PI * PI * sin(theta))); } +#endif +#endif + //----------------------------------------------------------------------- vec3 EmitterSample(in Ray r, in State state, in LightSampleRec lightSampleRec, in BsdfSampleRec bsdfSampleRec) //----------------------------------------------------------------------- diff --git a/src/shaders/common/uniforms.glsl b/src/shaders/common/uniforms.glsl index 373c324..358de7a 100644 --- a/src/shaders/common/uniforms.glsl +++ b/src/shaders/common/uniforms.glsl @@ -53,6 +53,7 @@ uniform sampler2D hdrCondDistTex; uniform float hdrResolution; uniform float hdrMultiplier; +uniform vec3 bgColor; uniform int numOfLights; uniform int maxDepth; uniform int topBVHIndex;