From a8dc75e46b7c374b079386d6ba00c3c4df46981c Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 1 Oct 2019 22:35:35 +0100 Subject: [PATCH] Tonemapping --- CMakeLists.txt | 34 +++--- src/common.hpp | 17 +-- src/definitions/primatives/triangle.cpp | 64 +++++------ src/definitions/scene.cpp | 4 +- src/display/framebuffer.cpp | 140 +++++++++++++++++------- src/engine/progressiverenderer.cpp | 6 +- src/util/assetloader.cpp | 72 ++++++------ test/main.cpp | 6 +- test/stanford_dragon_cornell.cpp | 21 ++-- 9 files changed, 213 insertions(+), 151 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c136d8d..8fb4a81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,8 @@ find_package(OpenGL REQUIRED) find_package(OpenMP) if (OPENMP_FOUND) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() if (UNIX) @@ -48,31 +48,31 @@ if (UNIX) endif (UNIX) include_directories(${executable} - #${PNG_INCLUDE_DIR} - #${JPEG_INCLUDE_DIR} - ${IncludeDIR} + #${PNG_INCLUDE_DIR} + #${JPEG_INCLUDE_DIR} + ${IncludeDIR} ) file(GLOB SourceFiles ${SrcDIR}/* - ${SrcDIR}/acceleration/* - ${SrcDIR}/core/* - ${SrcDIR}/engine/* - ${SrcDIR}/display/* - ${SrcDIR}/definitions/* - ${SrcDIR}/definitions/materials/* - ${SrcDIR}/definitions/primatives/* - ${SrcDIR}/denoise/* + ${SrcDIR}/acceleration/* + ${SrcDIR}/core/* + ${SrcDIR}/engine/* + ${SrcDIR}/display/* + ${SrcDIR}/definitions/* + ${SrcDIR}/definitions/materials/* + ${SrcDIR}/definitions/primatives/* + ${SrcDIR}/denoise/* ${SrcDIR}/util/* ${SrcDIR}/util/imgui/* - ${TestDIR}/${CurrentTest} + ${TestDIR}/${CurrentTest} ) add_executable(${executable} ${SourceFiles}) set_target_properties(${executable} PROPERTIES - CXX_STANDARD 17 - CXX_EXTENSIONS OFF + CXX_STANDARD 17 + CXX_EXTENSIONS OFF ) if (UNIX) @@ -102,5 +102,5 @@ if (WIN32) endif (WIN32) target_link_libraries(${executable} - ${CMAKE_DL_LIBS} + ${CMAKE_DL_LIBS} ) diff --git a/src/common.hpp b/src/common.hpp index 3cce325..f7db4dc 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -14,16 +14,16 @@ #include enum OperationMode { - MODE_OPERATION_PROGRESSIVE_GUI, - MODE_OPERATION_PROGRESSIVE_IMG, - MODE_OPERATION_SAMPLES_IMG, + MODE_OPERATION_PROGRESSIVE_GUI, + MODE_OPERATION_PROGRESSIVE_IMG, + MODE_OPERATION_SAMPLES_IMG, }; enum AccelerationMode { - MODE_ACCELERATION_NONE, - MODE_ACCELERATION_KD, - MODE_ACCELERATION_KD_SLOW, - MODE_ACCELERATION_BVH, + MODE_ACCELERATION_NONE, + MODE_ACCELERATION_KD, + MODE_ACCELERATION_KD_SLOW, + MODE_ACCELERATION_BVH, }; enum RenderMode { @@ -35,7 +35,8 @@ enum RenderMode { enum ToneMapMode { MODE_TONEMAP_REINHARD, - MODE_TONEMAP_EXP, + MODE_TONEMAP_ACES_FILMATIC, + MODE_TONEMAP_UNCHARTED2, MODE_TONEMAP_CLAMP, MODE_TONEMAP_BASIC }; diff --git a/src/definitions/primatives/triangle.cpp b/src/definitions/primatives/triangle.cpp index 7a3ab61..b82ca8b 100644 --- a/src/definitions/primatives/triangle.cpp +++ b/src/definitions/primatives/triangle.cpp @@ -2,32 +2,32 @@ #include "../ray.hpp" bool Triangle::Intersect(Ray& ray, float& t) { - glm::vec3 vertex0 = points[0]; - glm::vec3 vertex1 = points[1]; - glm::vec3 vertex2 = points[2]; - glm::vec3 edge1, edge2, h, s, q; - float a,f,u,v; - edge1 = vertex1 - vertex0; - edge2 = vertex2 - vertex0; - h = glm::cross(ray.direction, edge2); - a = glm::dot(edge1, h); - if (a > -EPSILON && a < EPSILON) - return false; // This ray is parallel to this triangle. - f = 1.0/a; - s = ray.origin - vertex0; - u = f * glm::dot(s, h); - if (u < 0.0 || u > 1.0) - return false; - q = glm::cross(s, edge1); - v = f * glm::dot(ray.direction, q); - if (v < 0.0 || u + v > 1.0) - return false; - // At this stage we can compute t to find out where the intersection point is on the line. - t = f * glm::dot(edge2, q); - if (t > EPSILON) // ray intersection - return true; - else // This means that there is a line intersection but not a ray intersection. - return false; + glm::vec3 vertex0 = points[0]; + glm::vec3 vertex1 = points[1]; + glm::vec3 vertex2 = points[2]; + glm::vec3 edge1, edge2, h, s, q; + float a,f,u,v; + edge1 = vertex1 - vertex0; + edge2 = vertex2 - vertex0; + h = glm::cross(ray.direction, edge2); + a = glm::dot(edge1, h); + if (a > -EPSILON && a < EPSILON) + return false; // This ray is parallel to this triangle. + f = 1.0/a; + s = ray.origin - vertex0; + u = f * glm::dot(s, h); + if (u < 0.0 || u > 1.0) + return false; + q = glm::cross(s, edge1); + v = f * glm::dot(ray.direction, q); + if (v < 0.0 || u + v > 1.0) + return false; + // At this stage we can compute t to find out where the intersection point is on the line. + t = f * glm::dot(edge2, q); + if (t > EPSILON) // ray intersection + return true; + else // This means that there is a line intersection but not a ray intersection. + return false; } glm::vec3 Triangle::SurfaceTangent(glm::vec3 normal) { @@ -35,19 +35,19 @@ glm::vec3 Triangle::SurfaceTangent(glm::vec3 normal) { } glm::vec3 Triangle::SurfaceNormal(glm::vec3 hitPoint) { - return ((normals[0] + normals[1] + normals[2]) / 3.0f); + return ((normals[0] + normals[1] + normals[2]) / 3.0f); } glm::vec2 Triangle::TexCoords(glm::vec3 hitPoint) { - return { 0.0f, 0.0f }; + return { 0.0f, 0.0f }; } void Triangle::Translate(glm::vec3 trans) { - points[0] += trans; - points[1] += trans; - points[2] += trans; + points[0] += trans; + points[1] += trans; + points[2] += trans; } glm::vec3 Triangle::Midpoint() { - return (points[0] + points[1] + points[2]) / 3.0f; + return (points[0] + points[1] + points[2]) / 3.0f; } diff --git a/src/definitions/scene.cpp b/src/definitions/scene.cpp index 09f7e2f..b9053c9 100644 --- a/src/definitions/scene.cpp +++ b/src/definitions/scene.cpp @@ -22,8 +22,8 @@ glm::vec3 GradientSky::Sample(Ray& ray) { } Scene::Scene(int width, int height) { - w = width; - h = height; + w = width; + h = height; } glm::vec3 Scene::SampleSky(Ray& ray) { diff --git a/src/display/framebuffer.cpp b/src/display/framebuffer.cpp index 86c54e1..b60b690 100644 --- a/src/display/framebuffer.cpp +++ b/src/display/framebuffer.cpp @@ -66,55 +66,113 @@ void FrameBuffer::PostProcess(ToneMapMode mode) { switch (mode) { case MODE_TONEMAP_REINHARD: - { - for (int x = 0; x < XRes; x++) - for (int y = 0; y < YRes; y++) { - m_swapBuffer[y * this->XRes + x] = RenderPostProcess[y * this->XRes + x] / - (RenderPostProcess[y * this->XRes + x] + 1.0f); - } - - break; + { + for (int x = 0; x < XRes; x++) + for (int y = 0; y < YRes; y++) { + m_swapBuffer[y * this->XRes + x] = RenderPostProcess[y * this->XRes + x] / + (RenderPostProcess[y * this->XRes + x] + 1.0f); } - case MODE_TONEMAP_EXP: - { - for (int x = 0; x < XRes; x++) - for (int y = 0; y < YRes; y++) { - m_swapBuffer[y * this->XRes + x] = 1.0f - exp2(RenderPostProcess[y * this->XRes + x] * 1.0f); - } + + break; + } + case MODE_TONEMAP_ACES_FILMATIC: + { - break; - } - case MODE_TONEMAP_CLAMP: - { - for (int x = 0; x < XRes; x++) - for (int y = 0; y < YRes; y++) { - m_swapBuffer[y * this->XRes + x] = Clamp(RenderPostProcess[y * this->XRes + x], 1.0f, 0.0f); - } + static const glm::mat3 inputMat{ + {0.59719, 0.35458, 0.04823}, + {0.07600, 0.90834, 0.01566}, + {0.02840, 0.13383, 0.83777} + }; - break; - } - case MODE_TONEMAP_BASIC: - { - float max = 0.0f; + static const glm::mat3 outputMat{ + { 1.60475, -0.53108, -0.07367}, + {-0.10208, 1.10813, -0.00605}, + {-0.00327, -0.07276, 1.07602} + }; - for (int x = 0; x < XRes; x++) - for (int y = 0; y < YRes; y++) { - if (RenderPostProcess[y * this->XRes + x].r > max) max = RenderPostProcess[y * this->XRes + x].r; - if (RenderPostProcess[y * this->XRes + x].g > max) max = RenderPostProcess[y * this->XRes + x].g; - if (RenderPostProcess[y * this->XRes + x].b > max) max = RenderPostProcess[y * this->XRes + x].b; - } + auto ACES = [&](glm::vec3 v) -> glm::vec3 { + glm::vec3 a = v * (v + 0.0245786f) - 0.000090537f; + glm::vec3 b = v * (0.983729f * v + 0.4329510f) + 0.238081f; + return a / b; + }; - for (int x = 0; x < XRes; x++) - for (int y = 0; y < YRes; y++) { - m_swapBuffer[y * this->XRes + x] = RenderPostProcess[y * this->XRes + x] / max; - } + for (int x = 0; x < XRes; x++) + for (int y = 0; y < YRes; y++) { + glm::vec3 col = RenderPostProcess[y * this->XRes + x]; - break; + col = col * inputMat; + col = ACES(col); + col = col * outputMat; + col = Clamp(col, 1.0f, 0.0f); + + m_swapBuffer[y * this->XRes + x] = col; } + + break; + } + case MODE_TONEMAP_UNCHARTED2: + { + static const float exposure = 2.0f; + static const glm::vec3 W = { 11.2f, 11.2f, 11.2f }; + + auto Uncharted2 = [&](glm::vec3 x) -> glm::vec3 { + float A = 0.15f; + float B = 0.50f; + float C = 0.10f; + float D = 0.20f; + float E = 0.02f; + float F = 0.30f; + return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; + }; + + glm::vec3 white = glm::vec3{ 1.0f, 1.0f, 1.0f } / Uncharted2(W); + + + for (int x = 0; x < XRes; x++) + for (int y = 0; y < YRes; y++) { + glm::vec3 col = RenderPostProcess[y * this->XRes + x]; + + glm::vec3 cur = Uncharted2(col * exposure); + + col = cur * white; + col = Clamp(col, 1.0f, 0.0f); + + m_swapBuffer[y * this->XRes + x] = col; + } + + break; + } + case MODE_TONEMAP_CLAMP: + { + for (int x = 0; x < XRes; x++) + for (int y = 0; y < YRes; y++) { + m_swapBuffer[y * this->XRes + x] = Clamp(RenderPostProcess[y * this->XRes + x], 1.0f, 0.0f); + } + + break; + } + case MODE_TONEMAP_BASIC: + { + float max = 0.0f; + + for (int x = 0; x < XRes; x++) + for (int y = 0; y < YRes; y++) { + if (RenderPostProcess[y * this->XRes + x].r > max) max = RenderPostProcess[y * this->XRes + x].r; + if (RenderPostProcess[y * this->XRes + x].g > max) max = RenderPostProcess[y * this->XRes + x].g; + if (RenderPostProcess[y * this->XRes + x].b > max) max = RenderPostProcess[y * this->XRes + x].b; + } + + for (int x = 0; x < XRes; x++) + for (int y = 0; y < YRes; y++) { + m_swapBuffer[y * this->XRes + x] = RenderPostProcess[y * this->XRes + x] / max; + } + + break; + } default: - { - break; - } + { + break; + } } for (int x = 0; x < XRes; x++) diff --git a/src/engine/progressiverenderer.cpp b/src/engine/progressiverenderer.cpp index 35f64df..482e73f 100644 --- a/src/engine/progressiverenderer.cpp +++ b/src/engine/progressiverenderer.cpp @@ -21,7 +21,7 @@ #include "../definitions/ray.hpp" ProgressiveRenderer::ProgressiveRenderer() { - + } void ProgressiveRenderer::Init(DisplayInterface* interface, Scene* scene) { @@ -29,7 +29,7 @@ void ProgressiveRenderer::Init(DisplayInterface* interface, Scene* scene) { m_engine = new RenderEngine(); m_engine->Mode = MODE_RENDER_PATHTRACE; m_engine->SetScene(scene); - m_interface = interface; + m_interface = interface; m_scene = scene; } @@ -79,7 +79,7 @@ void ProgressiveRenderer::Input() { ImGui::Combo("Render Mode", &m_renderModeSelected, renderItems, IM_ARRAYSIZE(renderItems)); m_mode = (RenderMode)m_renderModeSelected; - const char* toneMapItems[] = { "Reinhard Tonamap", "Exponential Tonemap", "Clamp", "Basic Tonemap" }; + const char* toneMapItems[] = { "Reinhard Tonamap", "ACES Filmatic Tonemap", "Uncharted 2", "Clamp", "Basic Tonemap" }; ImGui::Combo("ToneMap Mode", &m_toneMapModeSelected, toneMapItems, IM_ARRAYSIZE(toneMapItems)); ImGui::SliderFloat("Gamma", &m_gamma, 1.0f, 4.0f); diff --git a/src/util/assetloader.cpp b/src/util/assetloader.cpp index b885172..34ced36 100644 --- a/src/util/assetloader.cpp +++ b/src/util/assetloader.cpp @@ -10,41 +10,41 @@ #include "../maths.hpp" glm::vec3 getNormal(glm::vec3 p0, glm::vec3 p1, glm::vec3 p2) { - glm::vec3 u = p1 - p0; - glm::vec3 v = p2 - p0; + glm::vec3 u = p1 - p0; + glm::vec3 v = p2 - p0; - glm::vec3 normal; - normal.x = u.y * v.z - u.z * v.y; - normal.y = u.z * v.x - u.x * v.z; - normal.z = u.x * v.y - u.y * v.x; + glm::vec3 normal; + normal.x = u.y * v.z - u.z * v.y; + normal.y = u.z * v.x - u.x * v.z; + normal.z = u.x * v.y - u.y * v.x; return normal; } std::vector LoadTrianglesBasic(std::string path, std::string basePath, Material* baseMaterial) { - tinyobj::attrib_t attrib; - std::vector shapes; - std::vector materials; + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; - std::string warn, err; + std::string warn, err; bool canLoad = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, path.c_str(), basePath.c_str()); if (!err.empty() || !canLoad) { std::cerr << "Cannot load obj: '" << path << "': " << err << std::endl; - exit(0); + exit(0); } if (!warn.empty()) { std::cerr << "Warning from obj loader while loading obj: '" << path << "': " << warn << std::endl; } - std::vector triangles; + std::vector triangles; - for (size_t s = 0; s < shapes.size(); s++) { - size_t index_offset = 0; - for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) { - int fv = shapes[s].mesh.num_face_vertices[f]; + for (size_t s = 0; s < shapes.size(); s++) { + size_t index_offset = 0; + for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) { + int fv = shapes[s].mesh.num_face_vertices[f]; if (fv == 3) { tinyobj::real_t avx[3]; tinyobj::real_t avy[3]; @@ -77,30 +77,30 @@ std::vector LoadTrianglesBasic(std::string path, std::string basePath mtl = baseMaterial; } - // glm::vec3 normal = getNormal( - // {avx[0], avy[0], avz[0]}, - // {avx[1], avy[1], avz[1]}, - // {avx[2], avy[2], avz[2]} - // ); + // glm::vec3 normal = getNormal( + // {avx[0], avy[0], avz[0]}, + // {avx[1], avy[1], avz[1]}, + // {avx[2], avy[2], avz[2]} + // ); - Triangle* tmp = new Triangle { - {avx[0], avy[0], avz[0]}, - {avx[1], avy[1], avz[1]}, - {avx[2], avy[2], avz[2]}, + Triangle* tmp = new Triangle { + {avx[0], avy[0], avz[0]}, + {avx[1], avy[1], avz[1]}, + {avx[2], avy[2], avz[2]}, - // normal, normal, normal - {anx[0], any[0], anz[0]}, - {anx[1], any[1], anz[1]}, - {anx[2], any[2], anz[2]}, + // normal, normal, normal + {anx[0], any[0], anz[0]}, + {anx[1], any[1], anz[1]}, + {anx[2], any[2], anz[2]}, mtl, - }; + }; - triangles.push_back(tmp); - } - + triangles.push_back(tmp); + } + index_offset += fv; - } - } - return triangles; + } + } + return triangles; } diff --git a/test/main.cpp b/test/main.cpp index 250f23f..f8f9313 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -21,7 +21,7 @@ int main(int argc, char** argv) { Sky* sky = new GradientSky({ 35.0f / 255.0f, 148.0f / 255.0f, 235.0f / 255.0f }, { 1.0f, 1.0f, 1.0f }, 5.0f); scene->sky = sky; - scene->camera = new Camera(width, height); + scene->camera = new Camera(width, height); //Sphere sphere1({ 1.3f, -0.8f, -5.0f }, 0.2f, new Material({ 0.817f, 0.374, 0.574 })); //scene->objects.push_back(&sphere1); @@ -41,8 +41,8 @@ int main(int argc, char** argv) { inferno.SetScene(scene); - inferno.Ready(); - inferno.Render(); + inferno.Ready(); + inferno.Render(); return 0; } diff --git a/test/stanford_dragon_cornell.cpp b/test/stanford_dragon_cornell.cpp index f43028b..e932c18 100644 --- a/test/stanford_dragon_cornell.cpp +++ b/test/stanford_dragon_cornell.cpp @@ -2,8 +2,8 @@ #include "../src/inferno.hpp" -static const int width = 2000; -static const int height = 2000; +static const int width = 600; +static const int height = 600; int main(int argc, char** argv) { InfernoEngine inferno; @@ -18,20 +18,23 @@ int main(int argc, char** argv) { Sky* sky = new SolidSky({ 0.0f, 0.0f, 0.0f }, 0.0f); scene->sky = sky; - Sphere* sphere = new Sphere({ -0.302, -0.385999, -3.74202 }, 0.03f, new Material({ 0.345f, 0.133f, 0.050f }, 300.0f, 0.0f, 0.0f, 0.0f, false, true)); - scene->objects.push_back(sphere); + //Sphere* sphere = new Sphere({ -0.302, -0.385999, -3.74202 }, 0.03f, new Material({ 0.345f, 0.133f, 0.050f }, 300.0f, 0.0f, 0.0f, 0.0f, false, true)); + //scene->objects.push_back(sphere); Plane* plane = new Plane({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 1.0f }, new Material({ 1.0f, 1.0f, 1.0f }, 0.0f, 0.0f, 0.0f, 0.0f, false, false)); scene->objects.push_back(plane); Material* mat = new GlossyMaterial({ 1.3f, 1.3f, 1.3f }, 0.2f, fastDegreetoRadian(30.0f)); - std::vector tris = LoadTrianglesBasic("E://Projects//Inferno//resources//models//dragon-cornell-size.obj", "E://Projects//Inferno//resources//models", mat); + //std::vector tris = LoadTrianglesBasic("E://Projects//Inferno//resources//models//dragon-cornell-size.obj", "E://Projects//Inferno//resources//models", mat); // std::vector tris = LoadTrianglesBasic("/home/ben/programming/inferno/resources/models/dragon-cornell-size.obj", "/home/ben/programming/inferno/resources/models/", mat); - Mesh* mesh = new Mesh(tris); - mesh->Translate({ 0.01f, -1.0, -3.6f }); - mesh->Optimise(); - scene->meshs.push_back(mesh); + Sphere* sphere = new Sphere({ 0.0f, -0.6f, -4.0f }, 0.4f, mat); + scene->objects.push_back(sphere); + + //Mesh* mesh = new Mesh(tris); + //mesh->Translate({ 0.01f, -1.0, -3.6f }); + //mesh->Optimise(); + //scene->meshs.push_back(mesh); std::vector tris1 = LoadTrianglesBasic("E://Projects//Inferno//resources//models//cornell-box.obj", "E://Projects//Inferno//resources//models//"); //std::vector tris1 = LoadTrianglesBasic("/home/ben/programming/inferno/resources/models/cornell-box.obj", "/home/ben/programming/inferno/resources/models/");