├── cwl ├── README.md ├── CMakeLists.txt └── include │ └── cwl │ ├── texture.h │ ├── util.h │ └── buffer.h ├── optwl ├── README.md ├── src │ └── optwl.cpp ├── CMakeLists.txt └── include │ └── optwl │ └── optwl.h ├── fredholm ├── src │ └── renderer.cpp ├── kernels │ ├── CMakeLists.txt │ ├── include │ │ └── kernels │ │ │ └── post-process.h │ └── src │ │ └── post-process.cu ├── CMakeLists.txt ├── include │ └── fredholm │ │ ├── io.h │ │ ├── camera.h │ │ ├── scene.h │ │ ├── denoiser.h │ │ └── shared.h └── modules │ ├── camera.cu │ ├── cmj.cu │ ├── sampling.cu │ ├── math.cu │ └── arhosek.cu ├── .gitignore ├── img ├── gui.jpg └── rtcamp8.jpg ├── externals ├── stb_image.cpp ├── tinygltf.cpp ├── tinyobjloader.cpp ├── stb_image_write.cpp ├── sutil │ └── sutil │ │ ├── Record.h │ │ ├── Preprocessor.h │ │ ├── Camera.cpp │ │ ├── GLDisplay.h │ │ ├── sutilapi.h │ │ ├── PPMLoader.h │ │ ├── Camera.h │ │ ├── WorkDistribution.h │ │ ├── CMakeLists.txt │ │ ├── Trackball.h │ │ ├── Scene.h │ │ ├── Trackball.cpp │ │ ├── sutil.h │ │ ├── Quaternion.h │ │ ├── GLDisplay.cpp │ │ └── PPMLoader.cpp └── CMakeLists.txt ├── oglw ├── README.md ├── CMakeLists.txt └── include │ └── oglw │ ├── quad.h │ ├── buffer.h │ ├── framebuffer.h │ ├── vertex-array-object.h │ ├── camera.h │ ├── texture.h │ └── shader.h ├── .clang-format ├── app ├── shaders │ ├── quad.vert │ └── quad.frag ├── CMakeLists.txt ├── controller.h ├── rtcamp8.cpp └── controller.cpp ├── .gitmodules ├── LICENSE ├── CMakeLists.txt └── README.md /cwl/README.md: -------------------------------------------------------------------------------- 1 | # cwl(CUDA Wrapping Library) -------------------------------------------------------------------------------- /optwl/README.md: -------------------------------------------------------------------------------- 1 | # optwl(Optix Wrapping Library) -------------------------------------------------------------------------------- /fredholm/src/renderer.cpp: -------------------------------------------------------------------------------- 1 | #include "fredholm/renderer.h" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | .cache/ 3 | .vscode/ 4 | resources/ 5 | -------------------------------------------------------------------------------- /img/gui.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yumcyaWiz/fredholm/HEAD/img/gui.jpg -------------------------------------------------------------------------------- /externals/stb_image.cpp: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #include "stb_image.h" -------------------------------------------------------------------------------- /externals/tinygltf.cpp: -------------------------------------------------------------------------------- 1 | #define TINYGLTF_IMPLEMENTATION 2 | #include "tiny_gltf.h" -------------------------------------------------------------------------------- /oglw/README.md: -------------------------------------------------------------------------------- 1 | # oglw(OpenGL Wrapping Library) 2 | 3 | OpenGL wrapping library. -------------------------------------------------------------------------------- /img/rtcamp8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yumcyaWiz/fredholm/HEAD/img/rtcamp8.jpg -------------------------------------------------------------------------------- /externals/tinyobjloader.cpp: -------------------------------------------------------------------------------- 1 | #define TINYOBJLOADER_IMPLEMENTATION 2 | #include "tiny_obj_loader.h" -------------------------------------------------------------------------------- /optwl/src/optwl.cpp: -------------------------------------------------------------------------------- 1 | #include "optwl/optwl.h" 2 | 3 | #include -------------------------------------------------------------------------------- /externals/stb_image_write.cpp: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_WRITE_IMPLEMENTATION 2 | #include "stb_image_write.h" -------------------------------------------------------------------------------- /fredholm/kernels/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(kernels 2 | "src/post-process.cu" 3 | ) 4 | target_include_directories(kernels PUBLIC 5 | "include/" 6 | ) 7 | target_link_libraries(kernels PUBLIC 8 | sutil 9 | cwl 10 | ) -------------------------------------------------------------------------------- /oglw/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # oglw 2 | add_library(oglw INTERFACE) 3 | target_include_directories(oglw INTERFACE "include/") 4 | target_link_libraries(oglw INTERFACE 5 | OpenGL::GL 6 | glad 7 | glm 8 | stb_image 9 | spdlog::spdlog 10 | ) -------------------------------------------------------------------------------- /optwl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(optwl 2 | "src/optwl.cpp" 3 | ) 4 | target_include_directories(optwl PUBLIC 5 | ${OptiX_INCLUDE} 6 | "include/" 7 | ) 8 | target_link_libraries(optwl PUBLIC 9 | CUDA::cudart 10 | spdlog::spdlog 11 | ) -------------------------------------------------------------------------------- /cwl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # cwl 2 | add_library(cwl INTERFACE) 3 | target_include_directories(cwl INTERFACE 4 | ${OptiX_INCLUDE} 5 | "include/" 6 | ) 7 | target_link_libraries(cwl INTERFACE 8 | CUDA::cudart 9 | CUDA::cuda_driver 10 | oglw 11 | ) -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | Standard: Cpp11 3 | IndentWidth: 4 4 | TabWidth: 4 5 | UseTab: Never 6 | ColumnLimit: 80 7 | 8 | AlignTrailingComments: true 9 | AllowShortBlocksOnASingleLine: true 10 | AlwaysBreakTemplateDeclarations: true 11 | BreakBeforeBraces: Linux 12 | Cpp11BracedListStyle: true 13 | PointerAlignment: Left 14 | -------------------------------------------------------------------------------- /app/shaders/quad.vert: -------------------------------------------------------------------------------- 1 | #version 460 core 2 | layout (location = 0) in vec3 vPosition; 3 | layout (location = 1) in vec2 vTexCoords; 4 | 5 | out gl_PerVertex { 6 | vec4 gl_Position; 7 | float gl_PointSize; 8 | float gl_ClipDistance[]; 9 | }; 10 | 11 | out vec2 texCoords; 12 | 13 | void main() { 14 | texCoords = vTexCoords; 15 | gl_Position = vec4(vPosition, 1.0); 16 | } -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "externals/tinyobjloader"] 2 | path = externals/tinyobjloader 3 | url = git@github.com:tinyobjloader/tinyobjloader.git 4 | [submodule "externals/glm"] 5 | path = externals/glm 6 | url = git@github.com:g-truc/glm.git 7 | [submodule "externals/glfw"] 8 | path = externals/glfw 9 | url = git@github.com:glfw/glfw.git 10 | [submodule "externals/imgui"] 11 | path = externals/imgui 12 | url = git@github.com:ocornut/imgui.git 13 | [submodule "externals/spdlog"] 14 | path = externals/spdlog 15 | url = git@github.com:gabime/spdlog.git 16 | [submodule "externals/stb"] 17 | path = externals/stb 18 | url = git@github.com:nothings/stb.git 19 | [submodule "externals/tinygltf"] 20 | path = externals/tinygltf 21 | url = git@github.com:syoyo/tinygltf.git 22 | [submodule "externals/argparse"] 23 | path = externals/argparse 24 | url = git@github.com:p-ranav/argparse.git 25 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # rtcamp8 2 | # add_executable(rtcamp8 3 | # "rtcamp8.cpp" 4 | # ) 5 | # target_link_libraries(rtcamp8 PRIVATE 6 | # fredholm 7 | # kernels 8 | # ) 9 | 10 | # controller 11 | add_library(controller 12 | "controller.cpp" 13 | ) 14 | target_link_libraries(controller PRIVATE 15 | spdlog::spdlog 16 | OpenGL::GL 17 | glad 18 | oglw 19 | glfw 20 | stb_image_write 21 | cwl 22 | optwl 23 | fredholm 24 | kernels 25 | ) 26 | 27 | # gui 28 | add_executable(gui 29 | "gui.cpp" 30 | ) 31 | target_link_libraries(gui PRIVATE 32 | spdlog::spdlog 33 | oglw 34 | cwl 35 | optwl 36 | imgui 37 | imgui_glfw_opengl3 38 | fredholm 39 | controller 40 | ) 41 | 42 | # set cmake source dir macro 43 | target_compile_definitions(gui PRIVATE CMAKE_SOURCE_DIR="${CMAKE_SOURCE_DIR}" CMAKE_CURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}") -------------------------------------------------------------------------------- /fredholm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # compile modules into PTX 2 | add_library(modules OBJECT 3 | "modules/pt.cu" 4 | ) 5 | 6 | set_target_properties(modules PROPERTIES 7 | CUDA_PTX_COMPILATION ON 8 | ) 9 | target_compile_options(modules PRIVATE 10 | --optix-ir 11 | ) 12 | target_include_directories(modules PRIVATE 13 | ${OptiX_INCLUDE} 14 | "include/" 15 | ) 16 | target_link_libraries(modules PRIVATE 17 | sutil 18 | ) 19 | 20 | # kernels 21 | add_subdirectory("kernels/") 22 | 23 | # fredholm 24 | add_library(fredholm 25 | "src/renderer.cpp" 26 | "src/scene.cpp" 27 | ) 28 | target_include_directories(fredholm PUBLIC 29 | "include/" 30 | ) 31 | target_link_libraries(fredholm PUBLIC 32 | cwl 33 | optwl 34 | tinyobjloader 35 | tinygltf 36 | sutil 37 | glm 38 | stb_image 39 | spdlog::spdlog 40 | kernels 41 | ) 42 | 43 | # set modules source dir macro 44 | target_compile_definitions(fredholm PUBLIC MODULES_SOURCE_DIR="${CMAKE_BINARY_DIR}/fredholm/CMakeFiles/modules.dir/modules") -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 yumcyawiz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | project(fredholm LANGUAGES C CXX CUDA) 3 | 4 | # set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 5 | 6 | # C++ version and std 7 | if(NOT DEFINED CMAKE_CXX_STANDARD) 8 | set(CMAKE_CXX_STANDARD 20) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | endif() 11 | 12 | # CUDA C++ version and std 13 | if(NOT DEFINED CMAKE_CUDA_STANDARD) 14 | set(CMAKE_CUDA_STANDARD 20) 15 | set(CMAKE_CUDA_STANDARD_REQUIRED ON) 16 | set(CMAKE_CUDA_SEPARABLE_COMPILATION ON) 17 | endif() 18 | 19 | # OptiX path 20 | set(CMAKE_MODULE_PATH 21 | "/opt/NVIDIA-OptiX-SDK-8.0.0-linux64-x86_64/SDK/CMake/" 22 | ${CMAKE_MODULE_PATH} 23 | ) 24 | 25 | # CUDA Toolkit 26 | find_package(CUDAToolkit REQUIRED) 27 | 28 | # OptiX 29 | set(OptiX_INSTALL_DIR "/opt/NVIDIA-OptiX-SDK-8.0.0-linux64-x86_64") 30 | find_package(OptiX REQUIRED) 31 | 32 | # OpenGL 33 | find_package(OpenGL REQUIRED) 34 | 35 | # external 36 | add_subdirectory("externals/") 37 | 38 | # oglw 39 | add_subdirectory("oglw/") 40 | 41 | # cwl 42 | add_subdirectory("cwl/") 43 | 44 | # optwl 45 | add_subdirectory("optwl/") 46 | 47 | # fredholm 48 | add_subdirectory("fredholm/") 49 | 50 | # app 51 | add_subdirectory("app/") -------------------------------------------------------------------------------- /fredholm/include/fredholm/io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // #include "device/texture.h" 10 | 11 | namespace fredholm 12 | { 13 | 14 | // inline void write_ppm(const Texture2D& texture, 15 | // const std::filesystem::path& filepath) 16 | // { 17 | // std::ofstream file(filepath); 18 | // if (!file.is_open()) { 19 | // throw std::runtime_error("failed to open " + filepath.generic_string()); 20 | // } 21 | 22 | // const int width = texture.get_width(); 23 | // const int height = texture.get_height(); 24 | 25 | // file << "P3" << std::endl; 26 | // file << width << " " << height << std::endl; 27 | // file << "255" << std::endl; 28 | // for (int j = 0; j < height; ++j) { 29 | // for (int i = 0; i < width; ++i) { 30 | // float4 v = texture.get_value(i, j); 31 | // const uint32_t R = 32 | // static_cast(std::clamp(255.0f * v.x, 0.0f, 255.0f)); 33 | // const uint32_t G = 34 | // static_cast(std::clamp(255.0f * v.y, 0.0f, 255.0f)); 35 | // const uint32_t B = 36 | // static_cast(std::clamp(255.0f * v.z, 0.0f, 255.0f)); 37 | // file << R << " " << G << " " << B << std::endl; 38 | // } 39 | // } 40 | 41 | // file.close(); 42 | // } 43 | 44 | } // namespace fredholm -------------------------------------------------------------------------------- /oglw/include/oglw/quad.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "glad/gl.h" 5 | // 6 | #include "buffer.h" 7 | #include "shader.h" 8 | #include "vertex-array-object.h" 9 | 10 | namespace oglw 11 | { 12 | 13 | class Quad 14 | { 15 | private: 16 | VertexArrayObject VAO; 17 | Buffer VBO; 18 | Buffer EBO; 19 | 20 | public: 21 | Quad() 22 | { 23 | // setup VBO 24 | // position and texcoords 25 | const std::vector vertices = { 26 | -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 27 | 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f}; 28 | VBO.setData(vertices, GL_STATIC_DRAW); 29 | 30 | // setup EBO 31 | const std::vector indices = {0, 1, 2, 2, 3, 0}; 32 | EBO.setData(indices, GL_STATIC_DRAW); 33 | 34 | // setup VAO 35 | VAO.bindVertexBuffer(VBO, 0, 0, 5 * sizeof(GLfloat)); 36 | VAO.bindElementBuffer(EBO); 37 | 38 | // position 39 | VAO.activateVertexAttribution(0, 0, 3, GL_FLOAT, 0); 40 | 41 | // texcoords 42 | VAO.activateVertexAttribution(0, 1, 2, GL_FLOAT, 3 * sizeof(GLfloat)); 43 | } 44 | 45 | void draw(const Pipeline& pipeline) const 46 | { 47 | pipeline.activate(); 48 | VAO.activate(); 49 | glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); 50 | VAO.deactivate(); 51 | pipeline.deactivate(); 52 | } 53 | }; 54 | 55 | } // namespace oglw -------------------------------------------------------------------------------- /app/shaders/quad.frag: -------------------------------------------------------------------------------- 1 | #version 460 core 2 | 3 | layout(std430, binding = 0) buffer layout_beauty { 4 | vec4 beauty[]; 5 | }; 6 | layout(std430, binding = 1) buffer layout_denoised { 7 | vec4 denoised[]; 8 | }; 9 | layout(std430, binding = 2) buffer layout_position { 10 | vec4 position[]; 11 | }; 12 | layout(std430, binding = 3) buffer layout_normal { 13 | vec4 normal[]; 14 | }; 15 | layout(std430, binding = 4) buffer layout_depth { 16 | float depth[]; 17 | }; 18 | layout(std430, binding = 5) buffer layout_texcoord { 19 | vec4 texcoord[]; 20 | }; 21 | layout(std430, binding = 6) buffer layout_albedo { 22 | vec4 albedo[]; 23 | }; 24 | 25 | in vec2 texCoords; 26 | 27 | out vec4 fragColor; 28 | 29 | uniform vec2 resolution; 30 | uniform int aov_type; 31 | 32 | void main() { 33 | ivec2 xy = ivec2(texCoords * resolution); 34 | xy.y = int(resolution.y) - xy.y - 1; 35 | int idx = int(xy.x + resolution.x * xy.y); 36 | 37 | vec3 color; 38 | // beauty 39 | if(aov_type == 0) { 40 | color = beauty[idx].xyz; 41 | } 42 | // denoised 43 | if(aov_type == 1) { 44 | color = denoised[idx].xyz; 45 | } 46 | // position 47 | else if(aov_type == 2) { 48 | color = position[idx].xyz; 49 | } 50 | // normal 51 | else if(aov_type == 3) { 52 | color = normal[idx].xyz; 53 | color = 0.5 * (color + 1.0); 54 | } 55 | // depth 56 | else if(aov_type == 4) { 57 | color = vec3(depth[idx]); 58 | } 59 | // texcoord 60 | else if(aov_type == 5) { 61 | color = texcoord[idx].xyz; 62 | } 63 | // albedo 64 | else if(aov_type == 6) { 65 | color = albedo[idx].xyz; 66 | } 67 | 68 | fragColor = vec4(color, 1.0); 69 | } -------------------------------------------------------------------------------- /oglw/include/oglw/buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "glad/gl.h" 5 | #include "spdlog/spdlog.h" 6 | 7 | namespace oglw 8 | { 9 | 10 | template 11 | class Buffer 12 | { 13 | private: 14 | GLuint buffer; 15 | uint32_t size; 16 | 17 | public: 18 | Buffer() : buffer{0}, size{0} 19 | { 20 | glCreateBuffers(1, &buffer); 21 | 22 | spdlog::info("[Buffer] created buffer {:x}", buffer); 23 | } 24 | 25 | Buffer(const Buffer& buffer) = delete; 26 | 27 | Buffer(Buffer&& other) : buffer(other.buffer), size(other.size) 28 | { 29 | other.buffer = 0; 30 | } 31 | 32 | ~Buffer() { release(); } 33 | 34 | Buffer& operator=(const Buffer& buffer) = delete; 35 | 36 | Buffer& operator=(Buffer&& other) 37 | { 38 | if (this != &other) { 39 | release(); 40 | 41 | buffer = other.buffer; 42 | size = other.size; 43 | 44 | other.buffer = 0; 45 | } 46 | 47 | return *this; 48 | } 49 | 50 | void release() 51 | { 52 | if (buffer) { 53 | spdlog::info("[Buffer] release buffer {:x}", buffer); 54 | 55 | glDeleteBuffers(1, &buffer); 56 | this->buffer = 0; 57 | } 58 | } 59 | 60 | GLuint getName() const { return buffer; } 61 | 62 | uint32_t getLength() const { return size; } 63 | 64 | void setData(const std::vector& data, GLenum usage) 65 | { 66 | glNamedBufferData(this->buffer, sizeof(T) * data.size(), data.data(), 67 | usage); 68 | this->size = data.size(); 69 | } 70 | 71 | void bindToShaderStorageBuffer(GLuint binding_point_index) const 72 | { 73 | glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding_point_index, buffer); 74 | } 75 | }; 76 | 77 | } // namespace oglw -------------------------------------------------------------------------------- /oglw/include/oglw/framebuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "glad/gl.h" 3 | #include "spdlog/spdlog.h" 4 | // 5 | #include "texture.h" 6 | 7 | namespace oglw 8 | { 9 | 10 | class FrameBuffer 11 | { 12 | private: 13 | GLuint framebuffer; 14 | std::vector attachments; 15 | 16 | public: 17 | FrameBuffer(const std::vector& attachments) : attachments(attachments) 18 | { 19 | glCreateFramebuffers(1, &framebuffer); 20 | glNamedFramebufferDrawBuffers(framebuffer, this->attachments.size(), 21 | this->attachments.data()); 22 | 23 | spdlog::info("[FrameBuffer] create framebuffer {:x}", framebuffer); 24 | } 25 | 26 | FrameBuffer(const FrameBuffer& other) = delete; 27 | 28 | FrameBuffer(FrameBuffer&& other) 29 | : framebuffer(other.framebuffer), attachments(other.attachments) 30 | { 31 | other.framebuffer = 0; 32 | } 33 | 34 | ~FrameBuffer() { release(); } 35 | 36 | FrameBuffer& operator=(const FrameBuffer& other) = delete; 37 | 38 | FrameBuffer& operator=(FrameBuffer&& other) 39 | { 40 | if (this != &other) { 41 | release(); 42 | 43 | framebuffer = other.framebuffer; 44 | attachments = std::move(other.attachments); 45 | 46 | other.framebuffer = 0; 47 | } 48 | 49 | return *this; 50 | } 51 | 52 | void release() 53 | { 54 | if (framebuffer) { 55 | spdlog::info("[FrameBuffer] release framebuffer {:x}", framebuffer); 56 | 57 | glDeleteFramebuffers(1, &framebuffer); 58 | this->framebuffer = 0; 59 | } 60 | } 61 | 62 | void bindTexture(const Texture& texture, std::size_t attachment_index) const 63 | { 64 | glNamedFramebufferTexture(framebuffer, attachments.at(attachment_index), 65 | texture.getTextureName(), 0); 66 | } 67 | 68 | void activate() const { glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); } 69 | 70 | void deactivate() const { glBindFramebuffer(GL_FRAMEBUFFER, 0); } 71 | }; 72 | 73 | } // namespace oglw -------------------------------------------------------------------------------- /externals/sutil/sutil/Record.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | #include 29 | 30 | 31 | namespace sutil 32 | { 33 | 34 | template 35 | struct Record 36 | { 37 | __align__( OPTIX_SBT_RECORD_ALIGNMENT ) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; 38 | T data; 39 | }; 40 | 41 | struct EmptyData {}; 42 | 43 | typedef Record EmptyRecord; 44 | 45 | } // end namespace sutil 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fredholm 2 | 3 | Research oriented GPU offline renderer. 4 | 5 | ![](img/rtcamp8.jpg) 6 | ![](img/gui.jpg) 7 | 8 | ## Requirements 9 | 10 | * C++ 17 11 | * CUDA 11.7 12 | * OptiX 7.5 13 | * OpenGL 4.6(for GUI app, optional) 14 | 15 | ## Features 16 | 17 | * Path tracing integrator with multi importance sampling 18 | * [Arnold Standard Surface](https://autodesk.github.io/standard-surface/) 19 | * [Correlated Multi Jittered Sampling](https://graphics.pixar.com/library/MultiJitteredSampling/#:~:text=Abstract%3A,to%20which%20they%20are%20prone.) 20 | * [Hosek Sky Model](https://cgg.mff.cuni.cz/projects/SkylightModelling/) 21 | * `.obj`, `.gltf` scene file 22 | * Post process kernels(Bloom, Chromatic aberration, Tone mapping) 23 | 24 | ## Build 25 | 26 | ``` 27 | git submodule update --init 28 | mkdir build 29 | cd build 30 | cmake -DCMAKE_BUILD_TYPE=Release .. 31 | make 32 | ``` 33 | 34 | ## Run 35 | 36 | ``` 37 | cd build 38 | ./app/gui 39 | ``` 40 | 41 | ## References 42 | 43 | * [Arnold Standard Surface](https://autodesk.github.io/standard-surface/) 44 | * [Estevez, A. C., & Kulla, C. (2017). Production Friendly Microfacet Sheen BRDF. ACM SIGGRAPH 2017.](http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf) 45 | * [Gulbrandsen, O. (2014). Artist friendly metallic fresnel. Journal of Computer Graphics Techniques, 3(4).](https://jcgt.org/published/0003/04/03/) 46 | * [Heitz, E. (2018). Sampling the GGX distribution of visible normals. Journal of Computer Graphics Techniques (JCGT), 7(4), 1-13.](https://jcgt.org/published/0007/04/01/) 47 | * [Hosek, L., & Wilkie, A. (2012). An analytic model for full spectral sky-dome radiance. ACM Transactions on Graphics (TOG), 31(4), 1-9.](https://cgg.mff.cuni.cz/projects/SkylightModelling/) 48 | * [Kensler, A. (2013). Correlated multi-jittered sampling.](https://graphics.pixar.com/library/MultiJitteredSampling/#:~:text=Abstract%3A,to%20which%20they%20are%20prone.) 49 | * https://www.shadertoy.com/view/wl2SDt 50 | * https://www.shadertoy.com/view/llXyWr 51 | * https://github.com/ingowald/optix7course -------------------------------------------------------------------------------- /oglw/include/oglw/vertex-array-object.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "glad/gl.h" 3 | #include "spdlog/spdlog.h" 4 | // 5 | #include "buffer.h" 6 | 7 | namespace oglw 8 | { 9 | 10 | class VertexArrayObject 11 | { 12 | private: 13 | GLuint array; 14 | 15 | public: 16 | VertexArrayObject() { glCreateVertexArrays(1, &array); } 17 | 18 | VertexArrayObject(const VertexArrayObject& other) = delete; 19 | 20 | VertexArrayObject(VertexArrayObject&& other) : array(other.array) 21 | { 22 | other.array = 0; 23 | } 24 | 25 | ~VertexArrayObject() { release(); } 26 | 27 | VertexArrayObject& operator=(const VertexArrayObject& other) = delete; 28 | 29 | VertexArrayObject& operator=(VertexArrayObject&& other) 30 | { 31 | if (this != &other) { 32 | release(); 33 | 34 | array = other.array; 35 | 36 | other.array = 0; 37 | } 38 | 39 | return *this; 40 | } 41 | 42 | template 43 | void bindVertexBuffer(const Buffer& buffer, GLuint binding, 44 | GLintptr offset, GLsizei stride) const 45 | { 46 | glVertexArrayVertexBuffer(array, binding, buffer.getName(), offset, stride); 47 | } 48 | 49 | template 50 | void bindElementBuffer(const Buffer& buffer) const 51 | { 52 | glVertexArrayElementBuffer(array, buffer.getName()); 53 | } 54 | 55 | void activateVertexAttribution(GLuint binding, GLuint attrib, GLint size, 56 | GLenum type, GLsizei offset) const 57 | { 58 | glEnableVertexArrayAttrib(array, attrib); 59 | glVertexArrayAttribBinding(array, attrib, binding); 60 | glVertexArrayAttribFormat(array, attrib, size, type, GL_FALSE, offset); 61 | } 62 | 63 | void activate() const { glBindVertexArray(array); } 64 | 65 | void deactivate() const { glBindVertexArray(0); } 66 | 67 | void release() 68 | { 69 | if (array) { 70 | spdlog::info("[VertexArrayObject] release VAO {:x}", array); 71 | glDeleteVertexArrays(1, &array); 72 | } 73 | } 74 | }; 75 | 76 | } // namespace oglw -------------------------------------------------------------------------------- /externals/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # sutil 2 | add_library(sutil INTERFACE) 3 | target_include_directories(sutil INTERFACE "sutil/") 4 | 5 | # tinyobjloader 6 | add_library(tinyobjloader 7 | "tinyobjloader.cpp" 8 | ) 9 | target_include_directories(tinyobjloader PUBLIC "tinyobjloader/") 10 | 11 | # glm 12 | add_subdirectory("glm/") 13 | 14 | # glad 15 | add_library(glad glad/src/gl.c) 16 | target_include_directories(glad SYSTEM PUBLIC glad/include) 17 | 18 | # glfw 19 | set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE) 20 | set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) 21 | set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) 22 | add_subdirectory(glfw) 23 | 24 | # imgui 25 | add_library(imgui imgui/imgui.cpp imgui/imgui_widgets.cpp imgui/imgui_tables.cpp imgui/imgui_draw.cpp imgui/imgui_demo.cpp) 26 | target_include_directories(imgui SYSTEM PUBLIC imgui) 27 | 28 | # imgui backend 29 | add_library(imgui_glfw_opengl3 imgui/backends/imgui_impl_glfw.cpp imgui/backends/imgui_impl_opengl3.cpp) 30 | target_compile_definitions(imgui_glfw_opengl3 PRIVATE IMGUI_IMPL_OPENGL_LOADER_GLAD) 31 | target_link_libraries(imgui_glfw_opengl3 imgui) 32 | target_link_libraries(imgui_glfw_opengl3 glad) 33 | target_link_libraries(imgui_glfw_opengl3 glfw) 34 | target_include_directories(imgui_glfw_opengl3 SYSTEM PUBLIC imgui/backends) 35 | 36 | # spdlog 37 | SET(SPDLOG_MASTER_PROJECT ON CACHE BOOL "" FORCE) 38 | add_subdirectory(spdlog) 39 | 40 | # stb_image 41 | add_library(stb_image 42 | "stb_image.cpp" 43 | ) 44 | target_include_directories(stb_image SYSTEM PUBLIC "stb/") 45 | 46 | # stb_image_write 47 | add_library(stb_image_write 48 | "stb_image_write.cpp" 49 | ) 50 | target_include_directories(stb_image_write SYSTEM PUBLIC "stb/") 51 | 52 | # tinygltf 53 | add_library(tinygltf 54 | "tinygltf.cpp" 55 | ) 56 | target_include_directories(tinygltf SYSTEM PUBLIC "tinygltf/") 57 | target_link_libraries(tinygltf PUBLIC 58 | stb_image 59 | stb_image_write 60 | ) 61 | 62 | # argparse 63 | add_library(argparse INTERFACE) 64 | target_include_directories(argparse SYSTEM INTERFACE "argparse/include") -------------------------------------------------------------------------------- /externals/sutil/sutil/Preprocessor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | 30 | #pragma once 31 | 32 | #if defined(__CUDACC__) || defined(__CUDABE__) 33 | # define SUTIL_HOSTDEVICE __host__ __device__ 34 | # define SUTIL_INLINE __forceinline__ 35 | # define CONST_STATIC_INIT( ... ) 36 | #else 37 | # define SUTIL_HOSTDEVICE 38 | # define SUTIL_INLINE inline 39 | # define CONST_STATIC_INIT( ... ) = __VA_ARGS__ 40 | #endif 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /fredholm/modules/camera.cu: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "fredholm/shared.h" 3 | #include "sampling.cu" 4 | #include "sutil/vec_math.h" 5 | 6 | using namespace fredholm; 7 | 8 | static __forceinline__ __device__ void sample_ray_pinhole_camera( 9 | const CameraParams& params, const float2& uv, float3& origin, 10 | float3& direction, float& pdf) 11 | { 12 | const float f = 1.0f / tanf(0.5f * params.fov); 13 | const float3 p_sensor = make_float3(uv.x, uv.y, 0); 14 | const float3 p_pinhole = make_float3(0, 0, f); 15 | 16 | origin = transform_position(params.transform, p_pinhole); 17 | float3 dir = normalize(p_pinhole - p_sensor); 18 | // TODO: remove this adhoc fix 19 | dir.z *= -1.0f; 20 | direction = transform_direction(params.transform, dir); 21 | pdf = 1.0f / abs(dir.z); 22 | } 23 | 24 | static __forceinline__ __device__ void sample_ray_thinlens_camera( 25 | const CameraParams& params, const float2& uv, const float2& u, 26 | float3& origin, float3& direction, float& pdf) 27 | { 28 | const float f = 1.0f / tanf(0.5f * params.fov); 29 | 30 | const float b = params.focus; 31 | const float a = 1.0f / (1.0f + f - 1.0f / b); 32 | const float lens_radius = 2.0f * f / params.F; 33 | 34 | const float3 p_sensor = make_float3(uv.x, uv.y, 0); 35 | const float3 p_lens_center = make_float3(0, 0, f); 36 | 37 | const float2 p_disk = lens_radius * sample_concentric_disk(u); 38 | const float3 p_lens = p_lens_center + make_float3(p_disk.x, p_disk.y, 0); 39 | const float3 sensor_to_lens = normalize(p_lens - p_sensor); 40 | 41 | const float3 sensor_to_lens_center = normalize(p_lens_center - p_sensor); 42 | const float3 p_object = 43 | p_sensor + ((a + b) / sensor_to_lens_center.z) * sensor_to_lens_center; 44 | 45 | origin = transform_position(params.transform, p_lens); 46 | float3 dir = normalize(p_object - p_lens); 47 | // TODO: remove this adhoc fix 48 | dir.z *= -1.0f; 49 | direction = transform_direction(params.transform, dir); 50 | const float pdf_area = 1.0f / (M_PIf * lens_radius * lens_radius); 51 | // pdf = length2(p_lens - p_sensor) / abs(sensor_to_lens.z) * pdf_area; 52 | pdf = 1.0f / (dir.z * dir.z); 53 | } -------------------------------------------------------------------------------- /externals/sutil/sutil/Camera.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | 30 | #include 31 | 32 | namespace sutil { 33 | 34 | void Camera::UVWFrame(float3& U, float3& V, float3& W) const 35 | { 36 | W = m_lookat - m_eye; // Do not normalize W -- it implies focal length 37 | float wlen = length(W); 38 | U = normalize(cross(W, m_up)); 39 | V = normalize(cross(U, W)); 40 | 41 | float vlen = wlen * tanf(0.5f * m_fovY * M_PIf / 180.0f); 42 | V *= vlen; 43 | float ulen = vlen * m_aspectRatio; 44 | U *= ulen; 45 | } 46 | 47 | } // namespace sutil 48 | -------------------------------------------------------------------------------- /cwl/include/cwl/texture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | 6 | #include "cwl/util.h" 7 | 8 | namespace cwl 9 | { 10 | 11 | // RAII wrapper for CUDA texture object 12 | template 13 | class CUDATexture 14 | { 15 | public: 16 | CUDATexture(uint32_t width, uint32_t height, const T* data, 17 | bool srgb_to_linear = false) 18 | : size(make_uint2(width, height)) 19 | { 20 | cudaChannelFormatDesc channel_desc; 21 | channel_desc = cudaCreateChannelDesc(); 22 | 23 | // create array 24 | CUDA_CHECK(cudaMallocArray(&m_array, &channel_desc, width, height)); 25 | 26 | // copy image data to array 27 | const uint32_t pitch = width * sizeof(T); 28 | CUDA_CHECK(cudaMemcpy2DToArray(m_array, 0, 0, data, pitch, pitch, 29 | height, cudaMemcpyHostToDevice)); 30 | 31 | cudaResourceDesc res_desc = {}; 32 | res_desc.resType = cudaResourceTypeArray; 33 | res_desc.res.array.array = m_array; 34 | 35 | cudaTextureDesc tex_desc = {}; 36 | tex_desc.addressMode[0] = cudaAddressModeWrap; 37 | tex_desc.addressMode[1] = cudaAddressModeWrap; 38 | tex_desc.filterMode = cudaFilterModeLinear; 39 | tex_desc.readMode = std::is_same::value 40 | ? cudaReadModeNormalizedFloat 41 | : cudaReadModeElementType; 42 | tex_desc.normalizedCoords = 1; 43 | tex_desc.maxAnisotropy = 1; 44 | tex_desc.maxMipmapLevelClamp = 99; 45 | tex_desc.minMipmapLevelClamp = 0; 46 | tex_desc.mipmapFilterMode = cudaFilterModePoint; 47 | tex_desc.sRGB = srgb_to_linear ? 1 : 0; 48 | 49 | // create texture object 50 | CUDA_CHECK(cudaCreateTextureObject(&m_texture_object, &res_desc, 51 | &tex_desc, nullptr)); 52 | } 53 | 54 | CUDATexture(const CUDATexture& other) = delete; 55 | 56 | CUDATexture(CUDATexture&& other) 57 | : m_array(other.m_array), m_texture_object(other.m_texture_object) 58 | { 59 | } 60 | 61 | ~CUDATexture() noexcept(false) 62 | { 63 | CUDA_CHECK(cudaDestroyTextureObject(m_texture_object)); 64 | CUDA_CHECK(cudaFreeArray(m_array)); 65 | } 66 | 67 | uint2 get_size() const { return size; } 68 | 69 | cudaTextureObject_t get_texture_object() const { return m_texture_object; } 70 | 71 | private: 72 | uint2 size; 73 | cudaArray_t m_array = {}; 74 | cudaTextureObject_t m_texture_object = {}; 75 | }; 76 | 77 | } // namespace cwl -------------------------------------------------------------------------------- /externals/sutil/sutil/GLDisplay.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | 30 | 31 | #pragma once 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | namespace sutil 42 | { 43 | 44 | class GLDisplay 45 | { 46 | public: 47 | SUTILAPI GLDisplay( 48 | BufferImageFormat format = sutil::BufferImageFormat::UNSIGNED_BYTE4); 49 | 50 | SUTILAPI void display( 51 | const int32_t screen_res_x, 52 | const int32_t screen_res_y, 53 | const int32_t framebuf_res_x, 54 | const int32_t framebuf_res_y, 55 | const uint32_t pbo) const; 56 | 57 | private: 58 | GLuint m_render_tex = 0u; 59 | GLuint m_program = 0u; 60 | GLint m_render_tex_uniform_loc = -1; 61 | GLuint m_quad_vertex_buffer = 0; 62 | 63 | sutil::BufferImageFormat m_image_format; 64 | 65 | static const std::string s_vert_source; 66 | static const std::string s_frag_source; 67 | }; 68 | 69 | } // end namespace sutil 70 | -------------------------------------------------------------------------------- /fredholm/modules/cmj.cu: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "fredholm/shared.h" 3 | #include "sutil/vec_math.h" 4 | 5 | #define CMJ_M 4 6 | #define CMJ_N 4 7 | 8 | using namespace fredholm; 9 | 10 | // https://graphics.pixar.com/library/MultiJitteredSampling/ 11 | 12 | __forceinline__ __device__ unsigned int cmj_permute(unsigned int i, 13 | unsigned int l, 14 | unsigned int p) 15 | { 16 | unsigned int w = l - 1; 17 | w |= w >> 1; 18 | w |= w >> 2; 19 | w |= w >> 4; 20 | w |= w >> 8; 21 | w |= w >> 16; 22 | do { 23 | i ^= p; 24 | i *= 0xe170893d; 25 | i ^= p >> 16; 26 | i ^= (i & w) >> 4; 27 | i ^= p >> 8; 28 | i *= 0x0929eb3f; 29 | i ^= p >> 23; 30 | i ^= (i & w) >> 1; 31 | i *= 1 | p >> 27; 32 | i *= 0x6935fa69; 33 | i ^= (i & w) >> 11; 34 | i *= 0x74dcb303; 35 | i ^= (i & w) >> 2; 36 | i *= 0x9e501cc3; 37 | i ^= (i & w) >> 2; 38 | i *= 0xc860a3df; 39 | i &= w; 40 | i ^= i >> 5; 41 | } while (i >= l); 42 | return (i + p) % l; 43 | } 44 | 45 | __forceinline__ __device__ float cmj_randfloat(unsigned int i, unsigned int p) 46 | { 47 | i ^= p; 48 | i ^= i >> 17; 49 | i ^= i >> 10; 50 | i *= 0xb36534e5; 51 | i ^= i >> 12; 52 | i ^= i >> 21; 53 | i *= 0x93fc4795; 54 | i ^= 0xdf6e307f; 55 | i ^= i >> 17; 56 | i *= 1 | p >> 18; 57 | return i * (1.0f / 4294967808.0f); 58 | } 59 | 60 | __forceinline__ __device__ float2 cmj(unsigned int index, unsigned int scramble) 61 | { 62 | index = cmj_permute(index, CMJ_M * CMJ_N, scramble * 0x51633e2d); 63 | unsigned int sx = cmj_permute(index % CMJ_M, CMJ_M, scramble * 0xa511e9b3); 64 | unsigned int sy = cmj_permute(index / CMJ_M, CMJ_N, scramble * 0x63d83595); 65 | float jx = cmj_randfloat(index, scramble * 0xa399d265); 66 | float jy = cmj_randfloat(index, scramble * 0x711ad6a5); 67 | return make_float2((index % CMJ_M + (sy + jx) / CMJ_N) / CMJ_M, 68 | (index / CMJ_M + (sx + jy) / CMJ_M) / CMJ_N); 69 | } 70 | 71 | static __forceinline__ __device__ float2 cmj_2d(CMJState& state) 72 | { 73 | const unsigned int index = state.n_spp % (CMJ_M * CMJ_N); 74 | const unsigned int scramble = 75 | xxhash32(make_uint4(state.n_spp / (CMJ_M * CMJ_N), state.image_idx, 76 | state.depth, state.scramble)); 77 | const float2 result = cmj(index, scramble); 78 | state.depth++; 79 | return result; 80 | } 81 | 82 | static __forceinline__ __device__ float cmj_1d(CMJState& state) 83 | { 84 | return cmj_2d(state).x; 85 | } 86 | 87 | static __forceinline__ __device__ float3 cmj_3d(CMJState& state) 88 | { 89 | return make_float3(cmj_2d(state), cmj_1d(state)); 90 | } 91 | 92 | static __forceinline__ __device__ float4 cmj_4d(CMJState& state) 93 | { 94 | return make_float4(cmj_2d(state), cmj_2d(state)); 95 | } -------------------------------------------------------------------------------- /cwl/include/cwl/util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | // 7 | #include 8 | #include 9 | #include 10 | 11 | #define CUDA_CHECK(call) \ 12 | do { \ 13 | cudaError_t error = call; \ 14 | if (error != cudaSuccess) { \ 15 | std::stringstream ss; \ 16 | ss << "CUDA call (" << #call << " ) failed with error: '" \ 17 | << cudaGetErrorString(error) << "' (" __FILE__ << ":" \ 18 | << __LINE__ << ")\n"; \ 19 | throw std::runtime_error(ss.str().c_str()); \ 20 | } \ 21 | } while (0) 22 | 23 | #define CUDA_SYNC_CHECK() \ 24 | do { \ 25 | cudaDeviceSynchronize(); \ 26 | cudaError_t error = cudaGetLastError(); \ 27 | if (error != cudaSuccess) { \ 28 | std::stringstream ss; \ 29 | ss << "CUDA error on synchronize with error '" \ 30 | << cudaGetErrorString(error) << "' (" __FILE__ << ":" \ 31 | << __LINE__ << ")\n"; \ 32 | throw std::runtime_error(ss.str().c_str()); \ 33 | } \ 34 | } while (0) 35 | 36 | namespace cwl 37 | { 38 | 39 | inline void cudaCheckError( 40 | const CUresult& result, 41 | const std::source_location& loc = std::source_location::current()) 42 | { 43 | if (result == CUDA_SUCCESS) return; 44 | 45 | const char* errorName = nullptr; 46 | cuGetErrorName(result, &errorName); 47 | const char* errorString = nullptr; 48 | cuGetErrorString(result, &errorString); 49 | 50 | // TODO: use std::format 51 | std::stringstream ss; 52 | ss << loc.file_name() << "(" << loc.line() << ":" << loc.column() << ") " 53 | << loc.function_name() << ": " << errorName << ": " << errorString 54 | << std::endl; 55 | throw std::runtime_error(ss.str()); 56 | } 57 | 58 | // RAII wrapper for objects on device 59 | template 60 | class DeviceObject 61 | { 62 | public: 63 | DeviceObject(const T& object) 64 | { 65 | CUDA_CHECK( 66 | cudaMalloc(reinterpret_cast(&m_device_ptr), sizeof(T))); 67 | 68 | CUDA_CHECK(cudaMemcpy(m_device_ptr, &object, sizeof(T), 69 | cudaMemcpyHostToDevice)); 70 | } 71 | 72 | ~DeviceObject() noexcept(false) 73 | { 74 | CUDA_CHECK(cudaFree(reinterpret_cast(m_device_ptr))); 75 | } 76 | 77 | T* get_device_ptr() const { return m_device_ptr; } 78 | 79 | private: 80 | T* m_device_ptr; 81 | }; 82 | 83 | } // namespace cwl -------------------------------------------------------------------------------- /externals/sutil/sutil/sutilapi.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | #ifndef __samples_util_sutilapi_h__ 30 | #define __samples_util_sutilapi_h__ 31 | 32 | #ifndef SUTILAPI 33 | # if sutil_7_sdk_EXPORTS /* Set by CMAKE */ 34 | # if defined( _WIN32 ) || defined( _WIN64 ) 35 | # define SUTILAPI __declspec(dllexport) 36 | # define SUTILCLASSAPI 37 | # elif defined( linux ) || defined( __linux__ ) || defined ( __CYGWIN__ ) 38 | # define SUTILAPI __attribute__ ((visibility ("default"))) 39 | # define SUTILCLASSAPI SUTILAPI 40 | # elif defined( __APPLE__ ) && defined( __MACH__ ) 41 | # define SUTILAPI __attribute__ ((visibility ("default"))) 42 | # define SUTILCLASSAPI SUTILAPI 43 | # else 44 | # error "CODE FOR THIS OS HAS NOT YET BEEN DEFINED" 45 | # endif 46 | 47 | # else /* sutil_7_sdk_EXPORTS */ 48 | 49 | # if defined( _WIN32 ) || defined( _WIN64 ) 50 | # define SUTILAPI __declspec(dllimport) 51 | # define SUTILCLASSAPI 52 | # elif defined( linux ) || defined( __linux__ ) || defined ( __CYGWIN__ ) 53 | # define SUTILAPI __attribute__ ((visibility ("default"))) 54 | # define SUTILCLASSAPI SUTILAPI 55 | # elif defined( __APPLE__ ) && defined( __MACH__ ) 56 | # define SUTILAPI __attribute__ ((visibility ("default"))) 57 | # define SUTILCLASSAPI SUTILAPI 58 | # elif defined( __CUDACC_RTC__ ) 59 | # define SUTILAPI 60 | # define SUTILCLASSAPI 61 | # else 62 | # error "CODE FOR THIS OS HAS NOT YET BEEN DEFINED" 63 | # endif 64 | 65 | # endif /* sutil_7_sdk_EXPORTS */ 66 | #endif 67 | 68 | #endif /* __samples_util_sutilapi_h__ */ 69 | -------------------------------------------------------------------------------- /externals/sutil/sutil/PPMLoader.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | 30 | #pragma once 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | 37 | //----------------------------------------------------------------------------- 38 | // 39 | // Utility functions 40 | // 41 | //----------------------------------------------------------------------------- 42 | 43 | // Creates a TextureSampler object for the given PPM file. If filename is 44 | // empty or PPMLoader fails, a 1x1 texture is created with the provided default 45 | // texture color. 46 | SUTILAPI sutil::Texture loadPPMTexture( const std::string& ppm_filename, const float3& default_color, cudaTextureDesc* tex_desc ); 47 | 48 | //----------------------------------------------------------------------------- 49 | // 50 | // PPMLoader class declaration 51 | // 52 | //----------------------------------------------------------------------------- 53 | 54 | class PPMLoader 55 | { 56 | public: 57 | SUTILAPI PPMLoader( const std::string& filename, const bool vflip = false ); 58 | SUTILAPI ~PPMLoader(); 59 | 60 | SUTILAPI sutil::Texture loadTexture( const float3& default_color, cudaTextureDesc* tex_desc ); 61 | 62 | SUTILAPI bool failed() const; 63 | SUTILAPI unsigned int width() const; 64 | SUTILAPI unsigned int height() const; 65 | SUTILAPI unsigned char* raster() const; 66 | 67 | private: 68 | unsigned int m_nx; 69 | unsigned int m_ny; 70 | unsigned int m_max_val; 71 | unsigned char* m_raster; 72 | bool m_is_ascii; 73 | 74 | static void getLine( std::ifstream& file_in, std::string& s ); 75 | }; 76 | -------------------------------------------------------------------------------- /externals/sutil/sutil/Camera.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | #pragma once 30 | 31 | #include 32 | #include 33 | 34 | 35 | namespace sutil { 36 | 37 | // implementing a perspective camera 38 | class Camera { 39 | public: 40 | SUTILAPI Camera() 41 | : m_eye(make_float3(1.0f)), m_lookat(make_float3(0.0f)), m_up(make_float3(0.0f, 1.0f, 0.0f)), m_fovY(35.0f), m_aspectRatio(1.0f) 42 | { 43 | } 44 | 45 | SUTILAPI Camera(const float3& eye, const float3& lookat, const float3& up, float fovY, float aspectRatio) 46 | : m_eye(eye), m_lookat(lookat), m_up(up), m_fovY(fovY), m_aspectRatio(aspectRatio) 47 | { 48 | } 49 | 50 | SUTILAPI float3 direction() const { return normalize(m_lookat - m_eye); } 51 | SUTILAPI void setDirection(const float3& dir) { m_lookat = m_eye + length(m_lookat - m_eye) * dir; } 52 | 53 | SUTILAPI const float3& eye() const { return m_eye; } 54 | SUTILAPI void setEye(const float3& val) { m_eye = val; } 55 | SUTILAPI const float3& lookat() const { return m_lookat; } 56 | SUTILAPI void setLookat(const float3& val) { m_lookat = val; } 57 | SUTILAPI const float3& up() const { return m_up; } 58 | SUTILAPI void setUp(const float3& val) { m_up = val; } 59 | SUTILAPI const float& fovY() const { return m_fovY; } 60 | SUTILAPI void setFovY(const float& val) { m_fovY = val; } 61 | SUTILAPI const float& aspectRatio() const { return m_aspectRatio; } 62 | SUTILAPI void setAspectRatio(const float& val) { m_aspectRatio = val; } 63 | 64 | // UVW forms an orthogonal, but not orthonormal basis! 65 | SUTILAPI void UVWFrame(float3& U, float3& V, float3& W) const; 66 | 67 | private: 68 | float3 m_eye; 69 | float3 m_lookat; 70 | float3 m_up; 71 | float m_fovY; 72 | float m_aspectRatio; 73 | }; 74 | 75 | } 76 | -------------------------------------------------------------------------------- /optwl/include/optwl/optwl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "spdlog/spdlog.h" 10 | 11 | #define OPTIX_CHECK(call) \ 12 | do { \ 13 | OptixResult res = call; \ 14 | if (res != OPTIX_SUCCESS) { \ 15 | std::stringstream ss; \ 16 | ss << "Optix call '" << #call << "' failed: " __FILE__ ":" << __LINE__ \ 17 | << ")\n"; \ 18 | throw std::runtime_error(ss.str().c_str()); \ 19 | } \ 20 | } while (0) 21 | 22 | #define OPTIX_CHECK_LOG(call) \ 23 | do { \ 24 | OptixResult res = call; \ 25 | const size_t sizeof_log_returned = sizeof_log; \ 26 | sizeof_log = sizeof(log); /* reset sizeof_log for future calls */ \ 27 | if (res != OPTIX_SUCCESS) { \ 28 | std::stringstream ss; \ 29 | ss << "Optix call '" << #call << "' failed: " __FILE__ ":" << __LINE__ \ 30 | << ")\nLog:\n" \ 31 | << log << (sizeof_log_returned > sizeof(log) ? "" : "") \ 32 | << "\n"; \ 33 | throw std::runtime_error(ss.str().c_str()); \ 34 | } \ 35 | } while (0) 36 | 37 | namespace optwl 38 | { 39 | 40 | // RAII wrapper for Optix Context 41 | struct Context { 42 | OptixDeviceContext m_context = {}; 43 | 44 | Context(CUcontext cu_cxt = 0) 45 | { 46 | #ifdef NDEBUG 47 | bool enable_validation_mode = false; 48 | #else 49 | bool enable_validation_mode = true; 50 | #endif 51 | 52 | OPTIX_CHECK(optixInit()); 53 | 54 | OptixDeviceContextOptions options = {}; 55 | options.validationMode = enable_validation_mode 56 | ? OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_ALL 57 | : OPTIX_DEVICE_CONTEXT_VALIDATION_MODE_OFF; 58 | options.logCallbackFunction = &log_callback; 59 | options.logCallbackLevel = 4; 60 | OPTIX_CHECK(optixDeviceContextCreate(cu_cxt, &options, &m_context)); 61 | } 62 | 63 | ~Context() noexcept(false) 64 | { 65 | if (m_context) { OPTIX_CHECK(optixDeviceContextDestroy(m_context)); } 66 | } 67 | 68 | static void log_callback(unsigned int level, const char* tag, 69 | const char* message, void* cbdata) 70 | { 71 | if (level == 4) { 72 | spdlog::info("[OptiX][{}] {}", tag, message); 73 | } else if (level == 3) { 74 | spdlog::warn("[OptiX][{}] {}", tag, message); 75 | } else if (level == 2) { 76 | spdlog::error("[OptiX][{}] {}", tag, message); 77 | } else if (level == 1) { 78 | spdlog::critical("[OptiX][{}] {}", tag, message); 79 | } 80 | } 81 | }; 82 | 83 | } // namespace optwl -------------------------------------------------------------------------------- /oglw/include/oglw/camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "glm/glm.hpp" 3 | #include "glm/gtc/matrix_transform.hpp" 4 | 5 | namespace oglw 6 | { 7 | 8 | enum class CameraMovement { 9 | FORWARD, 10 | BACKWARD, 11 | RIGHT, 12 | LEFT, 13 | UP, 14 | DOWN, 15 | }; 16 | 17 | class Camera 18 | { 19 | private: 20 | glm::vec3 camPos; 21 | glm::vec3 camForward; 22 | glm::vec3 camRight; 23 | glm::vec3 camUp; 24 | 25 | float fov; 26 | float znear; 27 | float zfar; 28 | 29 | float movementSpeed; 30 | float lookAroundSpeed; 31 | 32 | float phi; 33 | float theta; 34 | 35 | public: 36 | Camera() 37 | : camPos{0.0f, 0.0f, 1.0f}, 38 | camForward{0.0f, 0.0f, -1.0f}, 39 | camRight{1.0f, 0.0f, 0.0f}, 40 | camUp{0.0f, 1.0f, 0.0f}, 41 | fov{45.0f}, 42 | znear{0.1f}, 43 | zfar{10000.0f}, 44 | movementSpeed{1.0f}, 45 | lookAroundSpeed{0.1f}, 46 | phi{270.0f}, 47 | theta{90.0f} 48 | { 49 | } 50 | 51 | glm::mat4 computeViewMatrix() const 52 | { 53 | return glm::lookAt(camPos, camPos + camForward, camUp); 54 | } 55 | 56 | glm::mat4 computeProjectionMatrix(uint32_t width, uint32_t height) const 57 | { 58 | return glm::perspective(glm::radians(fov), 59 | static_cast(width) / height, znear, zfar); 60 | } 61 | 62 | glm::mat4 computeViewProjectionmatrix(uint32_t width, uint32_t height) const 63 | { 64 | return computeProjectionMatrix(width, height) * computeViewMatrix(); 65 | } 66 | 67 | void reset() { *this = Camera(); } 68 | 69 | void move(const CameraMovement& direction, float dt) 70 | { 71 | const float velocity = movementSpeed * dt; 72 | switch (direction) { 73 | case CameraMovement::FORWARD: 74 | camPos += velocity * camForward; 75 | break; 76 | case CameraMovement::BACKWARD: 77 | camPos -= velocity * camForward; 78 | break; 79 | case CameraMovement::RIGHT: 80 | camPos += velocity * camRight; 81 | break; 82 | case CameraMovement::LEFT: 83 | camPos -= velocity * camRight; 84 | break; 85 | case CameraMovement::UP: 86 | camPos += velocity * camUp; 87 | break; 88 | case CameraMovement::DOWN: 89 | camPos -= velocity * camUp; 90 | break; 91 | } 92 | } 93 | 94 | void lookAround(float d_phi, float d_theta) 95 | { 96 | // update phi, theta 97 | phi += lookAroundSpeed * d_phi; 98 | if (phi < 0.0f) phi = 360.0f; 99 | if (phi > 360.0f) phi = 0.0f; 100 | 101 | theta += lookAroundSpeed * d_theta; 102 | if (theta < 0.0f) theta = 180.0f; 103 | if (theta > 180.0f) theta = 0.0f; 104 | 105 | // set camera directions 106 | const float phiRad = glm::radians(phi); 107 | const float thetaRad = glm::radians(theta); 108 | camForward = 109 | glm::vec3(std::cos(phiRad) * std::sin(thetaRad), std::cos(thetaRad), 110 | std::sin(phiRad) * std::sin(thetaRad)); 111 | camRight = glm::normalize(glm::cross(camForward, glm::vec3(0, 1.0f, 0))); 112 | camUp = glm::normalize(glm::cross(camRight, camForward)); 113 | } 114 | 115 | void getRay(const glm::vec2& window, const glm::uvec2& resolution, 116 | glm::vec3& origin, glm::vec3& direction) const 117 | { 118 | const glm::mat4 view = computeViewMatrix(); 119 | const glm::mat4 projection = 120 | computeProjectionMatrix(resolution.x, resolution.y); 121 | const glm::vec4 viewport = glm::vec4(0, 0, resolution.x, resolution.y); 122 | 123 | const glm::vec3 p1 = 124 | glm::unProject(glm::vec3(window, 0), view, projection, viewport); 125 | const glm::vec3 p2 = 126 | glm::unProject(glm::vec3(window, 1), view, projection, viewport); 127 | 128 | origin = p1; 129 | direction = glm::normalize(p2 - p1); 130 | } 131 | }; 132 | 133 | } // namespace oglw -------------------------------------------------------------------------------- /fredholm/include/fredholm/camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "glm/ext/matrix_transform.hpp" 6 | #include "glm/glm.hpp" 7 | #include "spdlog/fmt/bundled/core.h" 8 | #include "sutil/vec_math.h" 9 | 10 | namespace fredholm 11 | { 12 | 13 | enum class CameraMovement { 14 | FORWARD, 15 | BACKWARD, 16 | RIGHT, 17 | LEFT, 18 | UP, 19 | DOWN, 20 | }; 21 | 22 | struct Camera { 23 | glm::mat4 m_transform; 24 | 25 | float m_fov; 26 | float m_F; // F number 27 | float m_focus; // focus distance 28 | 29 | float m_movement_speed; 30 | float m_look_around_speed; 31 | 32 | glm::vec3 m_origin; 33 | glm::vec3 m_forward; 34 | glm::vec3 m_right; 35 | glm::vec3 m_up; 36 | float m_phi; 37 | float m_theta; 38 | 39 | Camera() 40 | : m_fov(0.5f * M_PI), 41 | m_F(8.0f), 42 | m_focus(10000.0f), 43 | m_movement_speed(10.0f), 44 | m_look_around_speed(0.1f), 45 | m_phi(270.0f), 46 | m_theta(90.0f) 47 | { 48 | m_transform = glm::identity(); 49 | } 50 | 51 | Camera(const float3& origin, float fov = 0.5f * M_PI, float F = 8.0f, 52 | float focus = 10000.0f, float movement_speed = 1.0f, 53 | float look_around_speed = 0.1f) 54 | : m_fov(fov), 55 | m_F(F), 56 | m_focus(focus), 57 | m_movement_speed(movement_speed), 58 | m_look_around_speed(look_around_speed), 59 | m_phi(270.0f), 60 | m_theta(90.0f) 61 | { 62 | m_origin = glm::vec3(origin.x, origin.y, origin.z); 63 | m_forward = glm::vec3(0, 0, -1); 64 | m_right = glm::normalize(glm::cross(m_forward, glm::vec3(0, 1, 0))); 65 | m_up = glm::normalize(glm::cross(m_right, m_forward)); 66 | 67 | m_transform = 68 | glm::inverse(glm::lookAt(m_origin, m_origin + 0.01f * m_forward, m_up)); 69 | } 70 | 71 | float3 get_origin() const 72 | { 73 | return make_float3(m_origin.x, m_origin.y, m_origin.z); 74 | } 75 | 76 | void set_origin(const float3& origin) 77 | { 78 | m_origin = glm::vec3(origin.x, origin.y, origin.z); 79 | m_transform = 80 | glm::inverse(glm::lookAt(m_origin, m_origin + 0.01f * m_forward, m_up)); 81 | } 82 | 83 | void move(const CameraMovement& direction, float dt) 84 | { 85 | const float velocity = m_movement_speed * dt; 86 | 87 | switch (direction) { 88 | case CameraMovement::FORWARD: { 89 | m_origin += velocity * m_forward; 90 | } break; 91 | case CameraMovement::BACKWARD: { 92 | m_origin -= velocity * m_forward; 93 | } break; 94 | case CameraMovement::RIGHT: { 95 | m_origin += velocity * m_right; 96 | } break; 97 | case CameraMovement::LEFT: { 98 | m_origin -= velocity * m_right; 99 | } break; 100 | case CameraMovement::UP: { 101 | m_origin += velocity * m_up; 102 | } break; 103 | case CameraMovement::DOWN: { 104 | m_origin -= velocity * m_up; 105 | } break; 106 | } 107 | 108 | m_transform = 109 | glm::inverse(glm::lookAt(m_origin, m_origin + 0.01f * m_forward, m_up)); 110 | } 111 | 112 | void lookAround(float d_phi, float d_theta) 113 | { 114 | // update phi, theta 115 | m_phi += m_look_around_speed * d_phi; 116 | if (m_phi < 0.0f) m_phi = 360.0f; 117 | if (m_phi > 360.0f) m_phi = 0.0f; 118 | 119 | m_theta += m_look_around_speed * d_theta; 120 | if (m_theta < 0.0f) m_theta = 180.0f; 121 | if (m_theta > 180.0f) m_theta = 0.0f; 122 | 123 | // set camera directions 124 | const float phi_rad = m_phi / 180.0f * M_PI; 125 | const float theta_rad = m_theta / 180.0f * M_PI; 126 | m_forward = 127 | glm::vec3(std::cos(phi_rad) * std::sin(theta_rad), std::cos(theta_rad), 128 | std::sin(phi_rad) * std::sin(theta_rad)); 129 | m_right = 130 | glm::normalize(glm::cross(m_forward, glm::vec3(0.0f, 1.0f, 0.0f))); 131 | m_up = glm::normalize(glm::cross(m_right, m_forward)); 132 | 133 | m_transform = 134 | glm::inverse(glm::lookAt(m_origin, m_origin + 0.01f * m_forward, m_up)); 135 | } 136 | }; 137 | 138 | } // namespace fredholm -------------------------------------------------------------------------------- /externals/sutil/sutil/WorkDistribution.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | #pragma once 29 | 30 | #include 31 | 32 | #include 33 | 34 | class StaticWorkDistribution 35 | { 36 | public: 37 | SUTIL_INLINE SUTIL_HOSTDEVICE void setRasterSize( int width, int height ) 38 | { 39 | m_width = width; 40 | m_height = height; 41 | } 42 | 43 | 44 | SUTIL_INLINE SUTIL_HOSTDEVICE void setNumGPUs( int32_t num_gpus ) 45 | { 46 | m_num_gpus = num_gpus; 47 | } 48 | 49 | 50 | SUTIL_INLINE SUTIL_HOSTDEVICE int32_t numSamples( int32_t gpu_idx ) 51 | { 52 | const int tile_strip_width = TILE_WIDTH*m_num_gpus; 53 | const int tile_strip_height = TILE_HEIGHT; 54 | const int num_tile_strip_cols = m_width /tile_strip_width + ( m_width %tile_strip_width == 0 ? 0 : 1 ); 55 | const int num_tile_strip_rows = m_height/tile_strip_height + ( m_height%tile_strip_height == 0 ? 0 : 1 ); 56 | return num_tile_strip_rows*num_tile_strip_cols*TILE_WIDTH*TILE_HEIGHT; 57 | } 58 | 59 | 60 | SUTIL_INLINE SUTIL_HOSTDEVICE int2 getSamplePixel( int32_t gpu_idx, int32_t sample_idx ) 61 | { 62 | const int tile_strip_width = TILE_WIDTH*m_num_gpus; 63 | const int tile_strip_height = TILE_HEIGHT; 64 | const int num_tile_strip_cols = m_width /tile_strip_width + ( m_width % tile_strip_width == 0 ? 0 : 1 ); 65 | 66 | const int tile_strip_idx = sample_idx / (TILE_WIDTH*TILE_HEIGHT ); 67 | const int tile_strip_y = tile_strip_idx / num_tile_strip_cols; 68 | const int tile_strip_x = tile_strip_idx - tile_strip_y * num_tile_strip_cols; 69 | const int tile_strip_x_start = tile_strip_x * tile_strip_width; 70 | const int tile_strip_y_start = tile_strip_y * tile_strip_height; 71 | 72 | const int tile_pixel_idx = sample_idx - ( tile_strip_idx * TILE_WIDTH*TILE_HEIGHT ); 73 | const int tile_pixel_y = tile_pixel_idx / TILE_WIDTH; 74 | const int tile_pixel_x = tile_pixel_idx - tile_pixel_y * TILE_WIDTH; 75 | 76 | const int tile_offset_x = ( gpu_idx + tile_strip_y % m_num_gpus ) % m_num_gpus * TILE_WIDTH; 77 | 78 | const int pixel_y = tile_strip_y_start + tile_pixel_y; 79 | const int pixel_x = tile_strip_x_start + tile_pixel_x + tile_offset_x ; 80 | return make_int2( pixel_x, pixel_y ); 81 | } 82 | 83 | 84 | private: 85 | int32_t m_num_gpus = 0; 86 | int32_t m_width = 0; 87 | int32_t m_height = 0; 88 | 89 | static const int32_t TILE_WIDTH = 8; 90 | static const int32_t TILE_HEIGHT = 4; 91 | }; 92 | -------------------------------------------------------------------------------- /cwl/include/cwl/buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "cwl/util.h" 7 | // 8 | #include "oglw/buffer.h" 9 | // 10 | #include 11 | #include 12 | 13 | namespace cwl 14 | { 15 | 16 | // RAII buffer object which is on device 17 | template 18 | class CUDABuffer 19 | { 20 | public: 21 | CUDABuffer(uint32_t buffer_size) : m_buffer_size(buffer_size) 22 | { 23 | if (buffer_size == 0) return; 24 | cudaCheckError(cuMemAlloc(&m_d_ptr, m_buffer_size * sizeof(T))); 25 | } 26 | 27 | CUDABuffer(uint32_t buffer_size, uint32_t value) 28 | : CUDABuffer(buffer_size) 29 | { 30 | if (buffer_size == 0) return; 31 | cudaCheckError(cuMemsetD32( 32 | m_d_ptr, value, m_buffer_size * sizeof(T) / sizeof(uint32_t))); 33 | } 34 | 35 | CUDABuffer(const std::vector& values) : CUDABuffer(values.size()) 36 | { 37 | if (values.size() == 0) return; 38 | copy_from_host_to_device(values); 39 | } 40 | 41 | CUDABuffer(const CUDABuffer& other) = delete; 42 | 43 | CUDABuffer(CUDABuffer&& other) 44 | : m_d_ptr(other.m_d_ptr), m_buffer_size(other.m_buffer_size) 45 | { 46 | other.m_d_ptr = nullptr; 47 | other.m_buffer_size = 0; 48 | } 49 | 50 | ~CUDABuffer() { cudaCheckError(cuMemFree(m_d_ptr)); } 51 | 52 | void clear() const 53 | { 54 | cudaCheckError(cuMemsetD32( 55 | m_d_ptr, 0, m_buffer_size * sizeof(T) / sizeof(uint32_t))); 56 | } 57 | 58 | void copy_from_host_to_device(const std::vector& value) const 59 | { 60 | cudaCheckError( 61 | cuMemcpyHtoD(m_d_ptr, value.data(), m_buffer_size * sizeof(T))); 62 | } 63 | 64 | void copy_from_device_to_host(std::vector& value) const 65 | { 66 | value.resize(m_buffer_size); 67 | cudaCheckError( 68 | cuMemcpyDtoH(value.data(), m_d_ptr, m_buffer_size * sizeof(T))); 69 | } 70 | 71 | T* get_device_ptr() { return reinterpret_cast(m_d_ptr); } 72 | 73 | const T* get_const_device_ptr() const 74 | { 75 | return reinterpret_cast(m_d_ptr); 76 | } 77 | 78 | uint32_t get_size() const { return m_buffer_size; } 79 | 80 | uint32_t get_size_in_bytes() const { return m_buffer_size * sizeof(T); } 81 | 82 | private: 83 | CUdeviceptr m_d_ptr = 0; 84 | uint32_t m_buffer_size = 0; 85 | }; 86 | 87 | template 88 | struct CUDAGLBuffer { 89 | CUDAGLBuffer(uint32_t buffer_size) : m_buffer_size(buffer_size) 90 | { 91 | // create gl buffer 92 | std::vector data(m_buffer_size); 93 | memset(data.data(), 0, m_buffer_size * sizeof(T)); 94 | m_buffer.setData(data, GL_STATIC_DRAW); 95 | 96 | // get cuda device ptr from OpenGL texture 97 | cudaCheckError( 98 | cuGraphicsGLRegisterBuffer(&m_resource, m_buffer.getName(), 99 | CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE)); 100 | cudaCheckError(cuGraphicsMapResources(1, &m_resource, 0)); 101 | 102 | size_t size = 0; 103 | cudaCheckError( 104 | cuGraphicsResourceGetMappedPointer(&m_d_buffer, &size, m_resource)); 105 | } 106 | 107 | CUDAGLBuffer(const CUDAGLBuffer& other) = delete; 108 | 109 | CUDAGLBuffer(CUDAGLBuffer&& other) 110 | : m_buffer(std::move(other.m_buffer)), 111 | m_resource(other.m_resource), 112 | m_d_buffer(other.m_d_buffer) 113 | { 114 | } 115 | 116 | ~CUDAGLBuffer() 117 | { 118 | cudaCheckError(cuGraphicsUnmapResources(1, &m_resource, 0)); 119 | cudaCheckError(cuGraphicsUnregisterResource(m_resource)); 120 | } 121 | 122 | void clear() 123 | { 124 | cudaCheckError(cuMemsetD32( 125 | m_d_buffer, 0, m_buffer_size * sizeof(T) / sizeof(uint32_t))); 126 | } 127 | 128 | void copy_from_device_to_host(std::vector& value) 129 | { 130 | value.resize(m_buffer_size); 131 | cudaCheckError( 132 | cuMemcpyDtoH(value.data(), m_d_buffer, m_buffer_size * sizeof(T))); 133 | } 134 | 135 | const oglw::Buffer& get_gl_buffer() const { return m_buffer; } 136 | 137 | T* get_device_ptr() const { return reinterpret_cast(m_d_buffer); } 138 | 139 | oglw::Buffer m_buffer; 140 | uint32_t m_buffer_size = 0; 141 | CUgraphicsResource m_resource = nullptr; 142 | CUdeviceptr m_d_buffer = 0; 143 | }; 144 | 145 | } // namespace cwl -------------------------------------------------------------------------------- /externals/sutil/sutil/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions 6 | # are met: 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # * Redistributions in binary form must reproduce the above copyright 10 | # notice, this list of conditions and the following disclaimer in the 11 | # documentation and/or other materials provided with the distribution. 12 | # * Neither the name of NVIDIA CORPORATION nor the names of its 13 | # contributors may be used to endorse or promote products derived 14 | # from this software without specific prior written permission. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | # 28 | 29 | set(sources 30 | ${CMAKE_CURRENT_BINARY_DIR}/../sampleConfig.h 31 | ${SAMPLES_CUDA_DIR}/sphere.cu 32 | ${SAMPLES_CUDA_DIR}/whitted.cu 33 | ${SAMPLES_CUDA_DIR}/BufferView.h 34 | ${SAMPLES_CUDA_DIR}/GeometryData.h 35 | ${SAMPLES_CUDA_DIR}/Light.h 36 | ${SAMPLES_CUDA_DIR}/LocalGeometry.h 37 | ${SAMPLES_CUDA_DIR}/MaterialData.h 38 | ${SAMPLES_CUDA_DIR}/util.h 39 | ${SAMPLES_CUDA_DIR}/helpers.h 40 | Aabb.h 41 | Camera.cpp 42 | Camera.h 43 | CUDAOutputBuffer.h 44 | Exception.h 45 | GLDisplay.cpp 46 | GLDisplay.h 47 | Matrix.h 48 | PPMLoader.cpp 49 | PPMLoader.h 50 | Preprocessor.h 51 | Quaternion.h 52 | Record.h 53 | Scene.cpp 54 | Scene.h 55 | sutilapi.h 56 | sutil.cpp 57 | sutil.h 58 | Trackball.cpp 59 | Trackball.h 60 | vec_math.h 61 | ) 62 | 63 | 64 | 65 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 66 | 67 | if(NOT CUDA_NVRTC_ENABLED) 68 | OPTIX_sutil_compile_to_optix_input(ptx_files ${sources}) 69 | else() 70 | set(ptx_files) 71 | endif() 72 | 73 | OPTIX_add_source_groups() 74 | 75 | # Make the library. 76 | set(sutil_target "sutil_7_sdk") 77 | add_library(${sutil_target} ${sources} ${ptx_files}) 78 | if( WIN32 ) 79 | target_compile_definitions( ${sutil_target} PUBLIC GLAD_GLAPI_EXPORT ) 80 | endif() 81 | 82 | target_link_libraries(${sutil_target} LINK_PRIVATE 83 | ${GLFW_LIB_NAME} 84 | glad 85 | imgui 86 | ${CUDA_LIBRARIES} 87 | ) 88 | 89 | # Use gcc rather than g++ to link if we are linking statically against libgcc_s and libstdc++ 90 | if(USING_GNU_C OR USING_GNU_CXX) 91 | if(GCC_LIBSTDCPP_HACK) 92 | set_target_properties(${sutil_target} PROPERTIES LINKER_LANGUAGE "C") 93 | target_link_libraries(${sutil_target} LINK_PRIVATE ${STATIC_LIBSTDCPP}) 94 | endif() 95 | endif() 96 | 97 | 98 | if(CUDA_NVRTC_ENABLED) 99 | target_link_libraries(${sutil_target} LINK_PRIVATE ${CUDA_nvrtc_LIBRARY}) 100 | endif() 101 | if(WIN32) 102 | target_link_libraries(${sutil_target} LINK_PRIVATE winmm.lib) 103 | endif() 104 | 105 | # Make the list of sources available to the parent directory for installation needs. 106 | set(sutil_sources "${sources}" PARENT_SCOPE) 107 | 108 | set_property(TARGET ${sutil_target} PROPERTY FOLDER "${OPTIX_IDE_FOLDER}") 109 | 110 | # Disable until we get binary samples 111 | if(0 AND RELEASE_INSTALL_BINARY_SAMPLES AND NOT RELEASE_STATIC_BUILD) 112 | # If performing a release install, we want to use rpath for our install name. 113 | # The executables' rpaths will then be set to @executable_path so we can invoke 114 | # the samples from an arbitrary location and it will still find this library. 115 | set_target_properties(${sutil_target} PROPERTIES 116 | INSTALL_NAME_DIR "@rpath" 117 | BUILD_WITH_INSTALL_RPATH ON 118 | ) 119 | install(TARGETS ${sutil_target} 120 | RUNTIME DESTINATION ${SDK_BINARY_INSTALL_DIR} 121 | LIBRARY DESTINATION ${SDK_BINARY_INSTALL_DIR} 122 | ) 123 | endif() 124 | -------------------------------------------------------------------------------- /fredholm/modules/sampling.cu: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "blue-noise.cu" 4 | #include "cmj.cu" 5 | #include "fredholm/shared.h" 6 | #include "math.cu" 7 | #include "sobol.cu" 8 | #include "sutil/vec_math.h" 9 | 10 | #define DISCRETE_DISTRIBUTION_1D_MAX_SIZE 16 11 | 12 | using namespace fredholm; 13 | 14 | static __forceinline__ __device__ float funiform(PCGState& state) 15 | { 16 | return pcg32_random_r(&state) * (1.0f / (1ULL << 32)); 17 | } 18 | 19 | static __forceinline__ __device__ float sample_1d(SamplerState& state) 20 | { 21 | return fsobol_owen(state.sobol_state); 22 | } 23 | 24 | static __forceinline__ __device__ float2 sample_2d(SamplerState& state) 25 | { 26 | // return make_float2(fsobol_owen(state.sobol_state), 27 | // fsobol_owen(state.sobol_state)); 28 | return cmj_2d(state.cmj_state); 29 | } 30 | 31 | static __forceinline__ __device__ float3 sampler_3d(SamplerState& state) 32 | { 33 | // return make_float3(fsobol_owen(state.sobol_state), 34 | // fsobol_owen(state.sobol_state), 35 | // fsobol_owen(state.sobol_state)); 36 | return make_float3(cmj_2d(state.cmj_state), cmj_1d(state.cmj_state)); 37 | } 38 | 39 | static __forceinline__ __device__ float4 sample_4d(SamplerState& state) 40 | { 41 | // return make_float4( 42 | // fsobol_owen(state.sobol_state), fsobol_owen(state.sobol_state), 43 | // fsobol_owen(state.sobol_state), fsobol_owen(state.sobol_state)); 44 | return make_float4(cmj_2d(state.cmj_state), cmj_2d(state.cmj_state)); 45 | } 46 | 47 | static __forceinline__ __device__ float2 sample_uniform_disk(const float2& u) 48 | { 49 | const float r = sqrtf(u.x); 50 | const float theta = 2.0f * M_PIf * u.y; 51 | return make_float2(r * cosf(theta), r * sinf(theta)); 52 | } 53 | 54 | static __forceinline__ __device__ float2 sample_concentric_disk(const float2& u) 55 | { 56 | const float2 u0 = 2.0f * u - 1.0f; 57 | if (u0.x == 0.0f && u0.y == 0.0f) return make_float2(0.0f); 58 | 59 | const float r = fabsf(u0.x) > fabsf(u0.y) ? u0.x : u0.y; 60 | const float theta = fabsf(u0.x) > fabsf(u0.y) 61 | ? 0.25f * M_PIf * u0.y / u0.x 62 | : 0.5f * M_PIf - 0.25f * M_PIf * u0.x / u0.y; 63 | return make_float2(r * cosf(theta), r * sinf(theta)); 64 | } 65 | 66 | static __forceinline__ __device__ float3 67 | sample_cosine_weighted_hemisphere(const float2& u) 68 | { 69 | const float2 p_disk = sample_concentric_disk(u); 70 | 71 | float3 p; 72 | p.x = p_disk.x; 73 | p.z = p_disk.y; 74 | // Project up to hemisphere. 75 | p.y = sqrtf(fmaxf(0.0f, 1.0f - p.x * p.x - p.z * p.z)); 76 | 77 | return p; 78 | } 79 | 80 | static __forceinline__ __device__ float2 sample_triangle(const float2& u) 81 | { 82 | const float su0 = sqrtf(u.x); 83 | return make_float2(1.0f - su0, u.y * su0); 84 | } 85 | 86 | // https://jcgt.org/published/0007/04/01/ 87 | static __device__ float3 sample_vndf(const float3& wo, const float2& alpha, 88 | const float2& u) 89 | { 90 | const float3 Vh = 91 | normalize(make_float3(alpha.x * wo.x, wo.y, alpha.y * wo.z)); 92 | 93 | const float lensq = Vh.x * Vh.x + Vh.z * Vh.z; 94 | const float3 T1 = lensq > 0 ? make_float3(Vh.z, 0, -Vh.x) / sqrtf(lensq) 95 | : make_float3(0, 0, 1); 96 | const float3 T2 = cross(Vh, T1); 97 | 98 | const float r = sqrtf(u.x); 99 | const float phi = 2.0f * M_PI * u.y; 100 | const float t1 = r * cosf(phi); 101 | float t2 = r * sinf(phi); 102 | const float s = 0.5f * (1.0f + Vh.y); 103 | t2 = (1.0f - s) * sqrtf(fmax(1.0f - t1 * t1, 0.0f)) + s * t2; 104 | const float3 Nh = 105 | t1 * T1 + t2 * T2 + sqrtf(fmax(1.0f - t1 * t1 - t2 * t2, 0.0f)) * Vh; 106 | const float3 Ne = 107 | normalize(make_float3(alpha.x * Nh.x, fmax(0.0f, Nh.y), alpha.y * Nh.z)); 108 | 109 | return Ne; 110 | } 111 | 112 | struct DiscreteDistribution1D { 113 | __device__ DiscreteDistribution1D() {} 114 | 115 | __device__ void init(const float* values, int size) 116 | { 117 | m_size = size; 118 | 119 | float sum = 0.0f; 120 | for (int i = 0; i < size; ++i) { sum += values[i]; } 121 | 122 | // compute cdf 123 | m_cdf[0] = 0.0f; 124 | for (int i = 1; i < size + 1; ++i) { 125 | m_cdf[i] = m_cdf[i - 1] + values[i - 1] / sum; 126 | } 127 | } 128 | 129 | __device__ int sample(float u, float& pmf) const 130 | { 131 | float cdf = 0.0f; 132 | for (int i = 1; i <= m_size; ++i) { 133 | cdf += m_cdf[i] - m_cdf[i - 1]; 134 | if (u < cdf) { 135 | pmf = m_cdf[i] - m_cdf[i - 1]; 136 | return i - 1; 137 | } 138 | } 139 | 140 | pmf = m_cdf[m_size] - m_cdf[m_size - 1]; 141 | return m_size - 1; 142 | } 143 | 144 | __device__ float eval_pmf(int idx) const 145 | { 146 | return m_cdf[idx + 1] - m_cdf[idx]; 147 | } 148 | 149 | float m_cdf[DISCRETE_DISTRIBUTION_1D_MAX_SIZE + 1]; 150 | int m_size; 151 | }; -------------------------------------------------------------------------------- /fredholm/modules/math.cu: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "sutil/vec_math.h" 4 | 5 | // Duff, T., Burgess, J., Christensen, P., Hery, C., Kensler, A., Liani, M., & 6 | // Villemin, R. (2017). Building an orthonormal basis, revisited. JCGT, 6(1). 7 | static __forceinline__ __device__ void orthonormal_basis(const float3& normal, 8 | float3& tangent, 9 | float3& bitangent) 10 | { 11 | float sign = copysignf(1.0f, normal.z); 12 | const float a = -1.0f / (sign + normal.z); 13 | const float b = normal.x * normal.y * a; 14 | tangent = make_float3(1.0f + sign * normal.x * normal.x * a, sign * b, 15 | -sign * normal.x); 16 | bitangent = make_float3(b, sign + normal.y * normal.y * a, -normal.y); 17 | } 18 | 19 | static __forceinline__ __device__ float3 world_to_local(const float3& v, 20 | const float3& t, 21 | const float3& n, 22 | const float3& b) 23 | { 24 | return make_float3(dot(v, t), dot(v, n), dot(v, b)); 25 | } 26 | 27 | static __forceinline__ __device__ float3 local_to_world(const float3& v, 28 | const float3& t, 29 | const float3& n, 30 | const float3& b) 31 | { 32 | return make_float3(v.x * t.x + v.y * n.x + v.z * b.x, 33 | v.x * t.y + v.y * n.y + v.z * b.y, 34 | v.x * t.z + v.y * n.z + v.z * b.z); 35 | } 36 | 37 | static __forceinline__ __device__ float length2(const float3& v) 38 | { 39 | return dot(v, v); 40 | } 41 | 42 | static __forceinline__ __device__ float3 square(const float3& v) 43 | { 44 | return make_float3(v.x * v.x, v.y * v.y, v.z * v.z); 45 | } 46 | 47 | static __forceinline__ __device__ float3 sqrtf(const float3& v) 48 | { 49 | return make_float3(sqrtf(v.x), sqrtf(v.y), sqrtf(v.z)); 50 | } 51 | 52 | static __forceinline__ __device__ float3 sinf(const float3& v) 53 | { 54 | return make_float3(sinf(v.x), sinf(v.y), sinf(v.z)); 55 | } 56 | 57 | static __forceinline__ __device__ float3 cosf(const float3& v) 58 | { 59 | return make_float3(cosf(v.x), cosf(v.y), cosf(v.z)); 60 | } 61 | 62 | static __forceinline__ float3 tanf(const float3& v) 63 | { 64 | return make_float3(tanf(v.x), tanf(v.y), tanf(v.z)); 65 | } 66 | 67 | static __forceinline__ __device__ float3 atan2f(const float3& v1, 68 | const float3& v2) 69 | { 70 | return make_float3(atan2f(v1.x, v2.x), atan2f(v1.y, v2.y), 71 | atan2f(v1.z, v2.z)); 72 | } 73 | 74 | static __forceinline__ __device__ bool isnan(const float3& v) 75 | { 76 | return isnan(v.x) || isnan(v.y) || isnan(v.z); 77 | } 78 | 79 | static __forceinline__ __device__ bool isinf(const float3& v) 80 | { 81 | return isinf(v.x) || isinf(v.y) || isinf(v.z); 82 | } 83 | 84 | static __forceinline__ __device__ float deg_to_rad(float deg) 85 | { 86 | return deg * M_PIf / 180.0f; 87 | } 88 | 89 | // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html 90 | static __forceinline__ __device__ float rgb_to_luminance(const float3& rgb) 91 | { 92 | return dot(rgb, make_float3(0.2126729f, 0.7151522f, 0.0721750f)); 93 | } 94 | 95 | // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html 96 | static __forceinline__ __device__ float3 rgb_to_xyz(const float3& rgb) 97 | { 98 | return make_float3(dot(rgb, make_float3(0.4887180f, 0.3106803f, 0.2006017f)), 99 | dot(rgb, make_float3(0.1762044f, 0.8129847f, 0.0108109f)), 100 | dot(rgb, make_float3(0.0000000f, 0.0102048f, 0.9897952f))); 101 | } 102 | 103 | // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html 104 | static __forceinline__ __device__ float3 xyz_to_rgb(const float3& xyz) 105 | { 106 | return make_float3(dot(xyz, make_float3(2.3706743, -0.9000405, -0.4706338)), 107 | dot(xyz, make_float3(-0.5138850, 1.4253036, 0.0885814)), 108 | dot(xyz, make_float3(0.0052982, -0.0146949, 1.0093968))); 109 | } 110 | 111 | static __forceinline__ __device__ float2 cartesian_to_spherical(const float3& w) 112 | { 113 | float2 ret; 114 | ret.x = acosf(clamp(w.y, -1.0f, 1.0f)); 115 | ret.y = atan2f(w.z, w.x); 116 | if (ret.y < 0) ret.y += 2.0f * M_PIf; 117 | return ret; 118 | } 119 | 120 | template 121 | static __forceinline__ __device__ int binary_search(T* values, int size, 122 | float value) 123 | { 124 | int idx_min = 0; 125 | int idx_max = size - 1; 126 | while (idx_max >= idx_min) { 127 | const int idx_mid = (idx_min + idx_max) / 2; 128 | const T mid = values[idx_mid]; 129 | if (value < mid) { 130 | idx_max = idx_mid - 1; 131 | } else if (value > mid) { 132 | idx_min = idx_mid + 1; 133 | } else { 134 | return idx_mid; 135 | } 136 | } 137 | return idx_max; 138 | } -------------------------------------------------------------------------------- /fredholm/include/fredholm/scene.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define GLM_ENABLE_EXPERIMENTAL 13 | #include "glm/glm.hpp" 14 | #include "glm/gtx/hash.hpp" 15 | #include "spdlog/spdlog.h" 16 | #include "stb_image.h" 17 | #include "sutil/vec_math.h" 18 | #include "tiny_gltf.h" 19 | #include "tiny_obj_loader.h" 20 | // 21 | #include "fredholm/shared.h" 22 | 23 | namespace fredholm 24 | { 25 | 26 | // https://vulkan-tutorial.com/Loading_models 27 | // vertex deduplication 28 | struct Vertex { 29 | glm::vec3 position; 30 | glm::vec3 normal; 31 | glm::vec2 texcoord; 32 | 33 | bool operator==(const Vertex& other) const 34 | { 35 | return position == other.position && normal == other.normal && 36 | texcoord == other.texcoord; 37 | } 38 | }; 39 | 40 | } // namespace fredholm 41 | 42 | namespace std 43 | { 44 | template <> 45 | struct hash { 46 | size_t operator()(fredholm::Vertex const& vertex) const 47 | { 48 | return ((hash()(vertex.position) ^ 49 | (hash()(vertex.normal) << 1)) >> 50 | 1) ^ 51 | (hash()(vertex.texcoord) << 1); 52 | } 53 | }; 54 | 55 | } // namespace std 56 | 57 | namespace fredholm 58 | { 59 | 60 | enum class TextureType { COLOR, NONCOLOR }; 61 | 62 | struct Texture { 63 | uint32_t m_width; 64 | uint32_t m_height; 65 | std::vector m_data; 66 | TextureType m_texture_type; 67 | 68 | Texture(); 69 | Texture(const std::filesystem::path& filepath, 70 | const TextureType& texture_type); 71 | }; 72 | 73 | struct FloatTexture { 74 | uint32_t m_width; 75 | uint32_t m_height; 76 | std::vector m_data; 77 | 78 | FloatTexture(const std::filesystem::path& filepath); 79 | }; 80 | 81 | struct Node { 82 | int idx; // tinygltf node index 83 | std::vector children; 84 | glm::mat4 transform; 85 | int camera_id; 86 | int submesh_id; 87 | }; 88 | 89 | struct Animation { 90 | Node* node; // target node 91 | 92 | std::vector translation_input; // key frame time 93 | std::vector translation_output; // key frame translation 94 | 95 | std::vector rotation_input; // key frame time 96 | std::vector rotation_output; // key frame rotation 97 | 98 | std::vector scale_input; // key frame time 99 | std::vector scale_output; // key frame scale 100 | }; 101 | 102 | // TODO: add transform in each submesh 103 | struct Scene { 104 | bool m_has_camera_transform = false; 105 | glm::mat4 m_camera_transform = {}; 106 | 107 | // vertex data 108 | std::vector m_vertices = {}; 109 | std::vector m_indices = {}; 110 | std::vector m_texcoords = {}; 111 | std::vector m_normals = {}; 112 | std::vector m_tangents = {}; 113 | 114 | // per-face material id 115 | std::vector m_material_ids = {}; 116 | 117 | std::vector m_materials; 118 | 119 | std::vector m_textures; 120 | 121 | // offset of each sub-mesh in index buffer 122 | std::vector m_submesh_offsets = {}; 123 | // number of faces in each sub-mesh 124 | std::vector m_submesh_n_faces = {}; 125 | 126 | // per-face instance id 127 | std::vector m_instance_ids = {}; 128 | 129 | // per-instance transform 130 | std::vector m_transforms = {}; 131 | 132 | std::vector m_nodes = {}; // root nodes 133 | 134 | std::vector m_animations = {}; 135 | 136 | Scene(); 137 | 138 | bool is_valid() const; 139 | 140 | void clear(); 141 | 142 | void load_model(const std::filesystem::path& filepath, bool do_clear); 143 | 144 | void load_obj(const std::filesystem::path& filepath); 145 | 146 | void load_gltf(const std::filesystem::path& filepath); 147 | 148 | Node load_gltf_node(const tinygltf::Model& model, int node_idx, 149 | int& indices_offset, int& prev_indices_size); 150 | 151 | void update_transform(); 152 | void update_transform_node(const Node& node, glm::mat4& transform); 153 | 154 | void update_animation(float time); 155 | 156 | Node* find_node(int node_idx); 157 | Node* find_node_node(Node& node, int node_idx); 158 | 159 | static const unsigned char* get_gltf_buffer(const tinygltf::Model& model, 160 | int accessor_id, int& stride, 161 | int& count); 162 | 163 | template 164 | static T animation_linear_interpolate(const std::vector& input, 165 | const std::vector& output, 166 | float time) 167 | { 168 | const float t = std::fmod(time, input[input.size() - 1]); 169 | const int idx1 = 170 | std::lower_bound(input.begin(), input.end(), t) - input.begin(); 171 | const int idx0 = std::max(idx1 - 1, 0); 172 | 173 | // linear interpolation 174 | const float h = t - input[idx0]; 175 | const T output0 = output[idx0]; 176 | const T output1 = output[idx1]; 177 | return glm::mix(output0, output1, h); 178 | } 179 | }; 180 | 181 | } // namespace fredholm -------------------------------------------------------------------------------- /fredholm/include/fredholm/denoiser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include "cwl/buffer.h" 8 | #include "cwl/util.h" 9 | #include "optwl/optwl.h" 10 | 11 | namespace fredholm 12 | { 13 | 14 | class Denoiser 15 | { 16 | public: 17 | Denoiser(OptixDeviceContext context, uint32_t width, uint32_t height, 18 | const float4* d_beauty, const float4* d_normal, 19 | const float4* d_albedo, const float4* d_denoised, 20 | bool upscale = false) 21 | : m_context(context), 22 | m_width(width), 23 | m_height(height), 24 | m_d_beauty(d_beauty), 25 | m_d_normal(d_normal), 26 | m_d_albedo(d_albedo), 27 | m_d_denoised(d_denoised), 28 | m_upscale(upscale) 29 | { 30 | init_denoiser(); 31 | init_layers(); 32 | } 33 | 34 | ~Denoiser() noexcept(false) { OPTIX_CHECK(optixDenoiserDestroy(m_denoiser)); } 35 | 36 | void init_denoiser() 37 | { 38 | OptixDenoiserOptions options = {}; 39 | options.guideAlbedo = 1; 40 | options.guideNormal = 1; 41 | 42 | // create denoiser 43 | OptixDenoiserModelKind model_kind = 44 | m_upscale ? OPTIX_DENOISER_MODEL_KIND_UPSCALE2X 45 | : OPTIX_DENOISER_MODEL_KIND_HDR; 46 | OPTIX_CHECK( 47 | optixDenoiserCreate(m_context, model_kind, &options, &m_denoiser)); 48 | 49 | // compute required memory size 50 | OptixDenoiserSizes denoiser_sizes; 51 | OPTIX_CHECK(optixDenoiserComputeMemoryResources(m_denoiser, m_width, 52 | m_height, &denoiser_sizes)); 53 | m_scratch_size = 54 | static_cast(denoiser_sizes.withoutOverlapScratchSizeInBytes); 55 | m_state_size = static_cast(denoiser_sizes.stateSizeInBytes); 56 | 57 | // allocate state, scratch buffer 58 | m_scratch = std::make_unique>(m_scratch_size); 59 | m_state = std::make_unique>(m_state_size); 60 | 61 | // setup denoiser 62 | OPTIX_CHECK(optixDenoiserSetup( 63 | m_denoiser, nullptr, m_width, m_height, 64 | reinterpret_cast(m_state->get_device_ptr()), m_state_size, 65 | reinterpret_cast(m_scratch->get_device_ptr()), 66 | m_scratch_size)); 67 | 68 | // set denoiser params 69 | // m_params.denoiseAlpha = 0; 70 | // m_params.blendFactor = 0 71 | // TODO: set these 72 | m_params.hdrIntensity = reinterpret_cast(nullptr); 73 | m_params.hdrAverageColor = reinterpret_cast(nullptr); 74 | } 75 | 76 | void init_layers() 77 | { 78 | m_guide_layer.normal = create_optix_image_2d(m_width, m_height, m_d_normal); 79 | m_guide_layer.albedo = create_optix_image_2d(m_width, m_height, m_d_albedo); 80 | 81 | m_layer.input = create_optix_image_2d(m_width, m_height, m_d_beauty); 82 | m_layer.output = create_optix_image_2d(m_upscale ? 2 * m_width : m_width, 83 | m_upscale ? 2 * m_height : m_height, 84 | m_d_denoised); 85 | } 86 | 87 | void denoise() 88 | { 89 | OPTIX_CHECK(optixDenoiserInvoke( 90 | m_denoiser, nullptr, &m_params, 91 | reinterpret_cast(m_state->get_device_ptr()), m_state_size, 92 | &m_guide_layer, &m_layer, 1, 0, 0, 93 | reinterpret_cast(m_scratch->get_device_ptr()), 94 | m_scratch_size)); 95 | } 96 | 97 | void wait_for_completion() const { CUDA_SYNC_CHECK(); } 98 | 99 | static void log_callback(unsigned int level, const char* tag, 100 | const char* message, void* cbdata) 101 | { 102 | if (level == 4) { 103 | spdlog::info("[Denoiser][{}] {}", tag, message); 104 | } else if (level == 3) { 105 | spdlog::warn("[Denoiser][{}] {}", tag, message); 106 | } else if (level == 2) { 107 | spdlog::error("[Denoiser][{}] {}", tag, message); 108 | } else if (level == 1) { 109 | spdlog::critical("[Denoiser][{}] {}", tag, message); 110 | } 111 | } 112 | 113 | private: 114 | uint32_t m_width = 0; 115 | uint32_t m_height = 0; 116 | const float4* m_d_beauty = nullptr; 117 | const float4* m_d_normal = nullptr; 118 | const float4* m_d_albedo = nullptr; 119 | const float4* m_d_denoised = nullptr; 120 | bool m_upscale = false; 121 | 122 | OptixDeviceContext m_context = nullptr; 123 | OptixDenoiser m_denoiser = nullptr; 124 | OptixDenoiserParams m_params = {}; 125 | OptixDenoiserGuideLayer m_guide_layer = {}; 126 | OptixDenoiserLayer m_layer = {}; 127 | 128 | uint32_t m_state_size = 0; 129 | uint32_t m_scratch_size = 0; 130 | std::unique_ptr> m_state; 131 | std::unique_ptr> m_scratch; 132 | 133 | static OptixImage2D create_optix_image_2d(uint32_t width, uint32_t height, 134 | const float4* d_image) 135 | { 136 | OptixImage2D oi; 137 | oi.width = width; 138 | oi.height = height; 139 | oi.rowStrideInBytes = width * sizeof(float4); 140 | oi.pixelStrideInBytes = sizeof(float4); 141 | oi.format = OPTIX_PIXEL_FORMAT_FLOAT4; 142 | oi.data = reinterpret_cast(d_image); 143 | 144 | return oi; 145 | } 146 | }; 147 | 148 | } // namespace fredholm -------------------------------------------------------------------------------- /oglw/include/oglw/texture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "glad/gl.h" 6 | #include "glm/glm.hpp" 7 | 8 | // #define STB_IMAGE_IMPLEMENTATION 9 | #include "stb_image.h" 10 | // 11 | #include "spdlog/spdlog.h" 12 | 13 | namespace oglw 14 | { 15 | class Texture 16 | { 17 | private: 18 | glm::uvec2 resolution; 19 | GLuint texture; 20 | GLint internalFormat; 21 | GLenum format; 22 | GLenum type; 23 | 24 | public: 25 | Texture() 26 | { 27 | // init texture 28 | glCreateTextures(GL_TEXTURE_2D, 1, &texture); 29 | glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 30 | glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 31 | glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 32 | glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 33 | 34 | spdlog::info("[Texture] texture {:x} created", this->texture); 35 | } 36 | 37 | Texture(const glm::uvec2& resolution, GLint internalFormat, GLenum format, 38 | GLenum type) 39 | : Texture() 40 | { 41 | initImage(resolution, internalFormat, format, type); 42 | } 43 | 44 | Texture(const Texture& other) = delete; 45 | 46 | Texture(Texture&& other) 47 | : resolution(other.resolution), 48 | texture(other.texture), 49 | internalFormat(other.internalFormat), 50 | format(other.format), 51 | type(other.type) 52 | { 53 | other.texture = 0; 54 | } 55 | 56 | ~Texture() { release(); } 57 | 58 | Texture& operator=(const Texture& other) = delete; 59 | 60 | Texture& operator=(Texture&& other) 61 | { 62 | if (this != &other) { 63 | release(); 64 | 65 | resolution = std::move(other.resolution); 66 | texture = other.texture; 67 | internalFormat = other.internalFormat; 68 | format = other.format; 69 | type = other.type; 70 | 71 | other.texture = 0; 72 | } 73 | 74 | return *this; 75 | } 76 | 77 | glm::uvec2 getResolution() const { return this->resolution; } 78 | 79 | GLuint getTextureName() const { return this->texture; } 80 | 81 | GLint getInternalFormat() const { return this->internalFormat; } 82 | 83 | GLenum getFormat() const { return this->format; } 84 | 85 | GLenum getType() const { return this->type; } 86 | 87 | void initImage(const glm::uvec2& resolution, GLint internalFormat, 88 | GLenum format, GLenum type) 89 | { 90 | this->resolution = resolution; 91 | this->internalFormat = internalFormat; 92 | this->format = format; 93 | this->type = type; 94 | 95 | glBindTexture(GL_TEXTURE_2D, texture); 96 | glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, resolution.x, resolution.y, 97 | 0, format, type, nullptr); 98 | glBindTexture(GL_TEXTURE_2D, 0); 99 | } 100 | 101 | template 102 | void setImage(const std::vector& image, const glm::uvec2& resolution, 103 | GLint internalFormat, GLenum format, GLenum type) 104 | { 105 | this->resolution = resolution; 106 | this->internalFormat = internalFormat; 107 | this->format = format; 108 | this->type = type; 109 | 110 | glBindTexture(GL_TEXTURE_2D, texture); 111 | glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, resolution.x, resolution.y, 112 | 0, format, type, image.data()); 113 | glBindTexture(GL_TEXTURE_2D, 0); 114 | } 115 | 116 | template 117 | void setImage(const T* image, const glm::uvec2& resolution, 118 | GLint internalFormat, GLenum format, GLenum type) 119 | { 120 | this->resolution = resolution; 121 | this->internalFormat = internalFormat; 122 | this->format = format; 123 | this->type = type; 124 | 125 | glBindTexture(GL_TEXTURE_2D, texture); 126 | glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, resolution.x, resolution.y, 127 | 0, format, type, image); 128 | glBindTexture(GL_TEXTURE_2D, 0); 129 | } 130 | 131 | void resize(const glm::uvec2& resolution) 132 | { 133 | initImage(resolution, internalFormat, format, type); 134 | } 135 | 136 | void loadHDR(const std::filesystem::path& filepath) 137 | { 138 | const std::string filepath_str = filepath.generic_string(); 139 | int width, height, channels; 140 | stbi_set_flip_vertically_on_load(true); 141 | float* image = 142 | stbi_loadf(filepath_str.c_str(), &width, &height, &channels, 4); 143 | if (!image) { spdlog::error("[Texture] failed to load {}", filepath_str); } 144 | 145 | this->internalFormat = GL_RGBA32F; 146 | this->format = GL_RGBA; 147 | this->type = GL_FLOAT; 148 | setImage(image, glm::uvec2(width, height), GL_RGBA32F, GL_RGBA, GL_FLOAT); 149 | 150 | stbi_image_free(image); 151 | } 152 | 153 | // bind texture to the specified texture unit 154 | void bindToTextureUnit(GLuint texture_unit_number) const 155 | { 156 | glBindTextureUnit(texture_unit_number, texture); 157 | } 158 | 159 | // bind texture to the specified image unit 160 | void bindToImageUnit(GLuint image_unit_number, GLenum access) const 161 | { 162 | glBindImageTexture(image_unit_number, this->texture, 0, GL_FALSE, 0, access, 163 | this->internalFormat); 164 | } 165 | 166 | void release() 167 | { 168 | if (texture) { 169 | spdlog::info("[Texture] release texture {:x}", this->texture); 170 | 171 | glDeleteTextures(1, &this->texture); 172 | this->texture = 0; 173 | } 174 | } 175 | }; 176 | 177 | } // namespace oglw -------------------------------------------------------------------------------- /fredholm/modules/arhosek.cu: -------------------------------------------------------------------------------- 1 | /* 2 | This source is published under the following 3-clause BSD license. 3 | 4 | Copyright (c) 2012 - 2013, Lukas Hosek and Alexander Wilkie 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | * None of the names of the contributors may be used to endorse or promote 16 | products derived from this software without specific prior written 17 | permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | /* ============================================================================ 32 | 33 | This file is part of a sample implementation of the analytical skylight and 34 | solar radiance models presented in the SIGGRAPH 2012 paper 35 | 36 | 37 | "An Analytic Model for Full Spectral Sky-Dome Radiance" 38 | 39 | and the 2013 IEEE CG&A paper 40 | 41 | "Adding a Solar Radiance Function to the Hosek Skylight Model" 42 | 43 | both by 44 | 45 | Lukas Hosek and Alexander Wilkie 46 | Charles University in Prague, Czech Republic 47 | 48 | 49 | Version: 1.4a, February 22nd, 2013 50 | 51 | Version history: 52 | 53 | 1.4a February 22nd, 2013 54 | Removed unnecessary and counter-intuitive solar radius parameters 55 | from the interface of the colourspace sky dome initialisation functions. 56 | 57 | 1.4 February 11th, 2013 58 | Fixed a bug which caused the relative brightness of the solar disc 59 | and the sky dome to be off by a factor of about 6. The sun was too 60 | bright: this affected both normal and alien sun scenarios. The 61 | coefficients of the solar radiance function were changed to fix this. 62 | 63 | 1.3 January 21st, 2013 (not released to the public) 64 | Added support for solar discs that are not exactly the same size as 65 | the terrestrial sun. Also added support for suns with a different 66 | emission spectrum ("Alien World" functionality). 67 | 68 | 1.2a December 18th, 2012 69 | Fixed a mistake and some inaccuracies in the solar radiance function 70 | explanations found in ArHosekSkyModel.h. The actual source code is 71 | unchanged compared to version 1.2. 72 | 73 | 1.2 December 17th, 2012 74 | Native RGB data and a solar radiance function that matches the turbidity 75 | conditions were added. 76 | 77 | 1.1 September 2012 78 | The coefficients of the spectral model are now scaled so that the output 79 | is given in physical units: W / (m^-2 * sr * nm). Also, the output of the 80 | XYZ model is now no longer scaled to the range [0...1]. Instead, it is 81 | the result of a simple conversion from spectral data via the CIE 2 degree 82 | standard observer matching functions. Therefore, after multiplication 83 | with 683 lm / W, the Y channel now corresponds to luminance in lm. 84 | 85 | 1.0 May 11th, 2012 86 | Initial release. 87 | 88 | 89 | Please visit http://cgg.mff.cuni.cz/projects/SkylightModelling/ to check if 90 | an updated version of this code has been published! 91 | 92 | ============================================================================ */ 93 | 94 | /* 95 | 96 | All instructions on how to use this code are in the accompanying header file. 97 | 98 | */ 99 | 100 | #pragma once 101 | #include "fredholm/arhosek.h" 102 | 103 | __device__ float ArHosekSkyModel_GetRadianceInternal( 104 | ArHosekSkyModelConfiguration configuration, float theta, float gamma) 105 | { 106 | const float expM = expf(configuration[4] * gamma); 107 | const float rayM = cosf(gamma) * cosf(gamma); 108 | const float mieM = (1.0f + cosf(gamma) * cosf(gamma)) / 109 | powf((1.0f + configuration[8] * configuration[8] - 110 | 2.0f * configuration[8] * cosf(gamma)), 111 | 1.5f); 112 | const float zenith = sqrtf(cosf(theta)); 113 | 114 | return (1.0f + 115 | configuration[0] * expf(configuration[1] / (cosf(theta) + 0.01f))) * 116 | (configuration[2] + configuration[3] * expM + configuration[5] * rayM + 117 | configuration[6] * mieM + configuration[7] * zenith); 118 | } 119 | 120 | __device__ float arhosek_tristim_skymodel_radiance(ArHosekSkyModelState *state, 121 | float theta, float gamma, 122 | int channel) 123 | { 124 | return ArHosekSkyModel_GetRadianceInternal(state->configs[channel], theta, 125 | gamma) * 126 | state->radiances[channel]; 127 | } -------------------------------------------------------------------------------- /externals/sutil/sutil/Trackball.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | #pragma once 30 | 31 | #include 32 | 33 | namespace sutil 34 | { 35 | 36 | class Camera; 37 | 38 | class Trackball 39 | { 40 | public: 41 | SUTILAPI bool wheelEvent(int dir); 42 | 43 | SUTILAPI void startTracking(int x, int y); 44 | SUTILAPI void updateTracking(int x, int y, int canvasWidth, int canvasHeight); 45 | SUTILAPI void zoom(int direction); 46 | SUTILAPI float moveSpeed() const { return m_moveSpeed; } 47 | SUTILAPI void setMoveSpeed(const float& val) { m_moveSpeed = val; } 48 | 49 | // Set the camera that will be changed according to user input. 50 | // Warning, this also initializes the reference frame of the trackball from the camera. 51 | // The reference frame defines the orbit's singularity. 52 | SUTILAPI inline void setCamera(Camera* camera) { m_camera = camera; reinitOrientationFromCamera(); } 53 | SUTILAPI inline const Camera* currentCamera() const { return m_camera; } 54 | 55 | // Setting the gimbal lock to 'on' will fix the reference frame (i.e., the singularity of the trackball). 56 | // In most cases this is preferred. 57 | // For free scene exploration the gimbal lock can be turned off, which causes the trackball's reference frame 58 | // to be update on every camera update (adopted from the camera). 59 | SUTILAPI bool gimbalLock() const { return m_gimbalLock; } 60 | SUTILAPI void setGimbalLock(bool val) { m_gimbalLock = val; } 61 | 62 | // Adopts the reference frame from the camera. 63 | // Note that the reference frame of the camera usually has a different 'up' than the 'up' of the camera. 64 | // Though, typically, it is desired that the trackball's reference frame aligns with the actual up of the camera. 65 | SUTILAPI void reinitOrientationFromCamera(); 66 | 67 | // Specify the frame of the orbit that the camera is orbiting around. 68 | // The important bit is the 'up' of that frame as this is defines the singularity. 69 | // Here, 'up' is the 'w' component. 70 | // Typically you want the up of the reference frame to align with the up of the camera. 71 | // However, to be able to really freely move around, you can also constantly update 72 | // the reference frame of the trackball. This can be done by calling reinitOrientationFromCamera(). 73 | // In most cases it is not required though (set the frame/up once, leave it as is). 74 | SUTILAPI void setReferenceFrame(const float3& u, const float3& v, const float3& w); 75 | 76 | enum ViewMode 77 | { 78 | EyeFixed, 79 | LookAtFixed 80 | }; 81 | 82 | SUTILAPI ViewMode viewMode() const { return m_viewMode; } 83 | SUTILAPI void setViewMode(ViewMode val) { m_viewMode = val; } 84 | 85 | private: 86 | void updateCamera(); 87 | 88 | void moveForward(float speed); 89 | void moveBackward(float speed); 90 | void moveLeft(float speed); 91 | void moveRight(float speed); 92 | void moveUp(float speed); 93 | void moveDown(float speed); 94 | void rollLeft(float speed); 95 | void rollRight(float speed); 96 | 97 | private: 98 | bool m_gimbalLock = false; 99 | ViewMode m_viewMode = LookAtFixed; 100 | Camera* m_camera = nullptr; 101 | float m_cameraEyeLookatDistance = 0.0f; 102 | float m_zoomMultiplier = 1.1f; 103 | float m_moveSpeed = 1.0f; 104 | float m_rollSpeed = 0.5f; 105 | 106 | float m_latitude = 0.0f; // in radians 107 | float m_longitude = 0.0f; // in radians 108 | 109 | // mouse tracking 110 | int m_prevPosX = 0; 111 | int m_prevPosY = 0; 112 | bool m_performTracking = false; 113 | 114 | // trackball computes camera orientation (eye, lookat) using 115 | // latitude/longitude with respect to this frame local frame for trackball 116 | float3 m_u = { 0.0f, 0.0f, 0.0f }; 117 | float3 m_v = { 0.0f, 0.0f, 0.0f }; 118 | float3 m_w = { 0.0f, 0.0f, 0.0f }; 119 | 120 | 121 | }; 122 | 123 | } // namespace sutil 124 | -------------------------------------------------------------------------------- /fredholm/kernels/include/kernels/post-process.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "sutil/vec_math.h" 3 | 4 | struct PostProcessParams { 5 | bool use_bloom; 6 | float bloom_threshold; 7 | float bloom_sigma; 8 | float ISO; 9 | float chromatic_aberration; 10 | }; 11 | 12 | // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html 13 | static __forceinline__ __device__ float rgb_to_luminance(const float3& rgb) 14 | { 15 | return dot(rgb, make_float3(0.2126729f, 0.7151522f, 0.0721750f)); 16 | } 17 | 18 | static __forceinline__ __device__ float3 linear_to_srgb(const float3& rgb) 19 | { 20 | float3 ret; 21 | ret.x = rgb.x < 0.0031308 ? 12.92 * rgb.x 22 | : 1.055 * pow(rgb.x, 1.0f / 2.4f) - 0.055; 23 | ret.y = rgb.y < 0.0031308 ? 12.92 * rgb.y 24 | : 1.055 * pow(rgb.y, 1.0f / 2.4f) - 0.055; 25 | ret.z = rgb.z < 0.0031308 ? 12.92 * rgb.z 26 | : 1.055 * pow(rgb.z, 1.0f / 2.4f) - 0.055; 27 | return ret; 28 | } 29 | 30 | // https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ 31 | static __forceinline__ __device__ float3 aces_tone_mapping(const float3& color) 32 | { 33 | float a = 2.51f; 34 | float b = 0.03f; 35 | float c = 2.43f; 36 | float d = 0.59f; 37 | float e = 0.14f; 38 | return clamp((color * (a * color + b)) / (color * (c * color + d) + e), 39 | make_float3(0.0f), make_float3(1.0f)); 40 | } 41 | 42 | static __forceinline__ __device__ float step(float edge, float x) 43 | { 44 | return (x < edge) ? 0.0f : 1.0f; 45 | } 46 | 47 | static __forceinline__ __device__ float3 step(float edge, const float3& v) 48 | { 49 | return make_float3(step(edge, v.x), step(edge, v.y), step(edge, v.z)); 50 | } 51 | 52 | static __forceinline__ __device__ float smoothstep(float edge0, float edge1, 53 | float x) 54 | { 55 | if (x < edge0) 56 | return 0.0f; 57 | else if (x > edge1) 58 | return 1.0f; 59 | else { 60 | x = (x - edge0) / (edge1 - edge0); 61 | return x * x * (3.0f - 2.0f * x); 62 | } 63 | } 64 | 65 | static __forceinline__ __device__ float3 smoothstep(float edge0, float edge1, 66 | const float3& v) 67 | { 68 | return make_float3(smoothstep(edge0, edge1, v.x), 69 | smoothstep(edge0, edge1, v.y), 70 | smoothstep(edge0, edge1, v.z)); 71 | } 72 | 73 | // Uchimura 2017, "HDR theory and practice" 74 | // Math: https://www.desmos.com/calculator/gslcdxvipg 75 | // Source: https://www.slideshare.net/nikuque/hdr-theory-and-practicce-jp 76 | static __forceinline__ __device__ float3 uchimura(const float3& x, float P, 77 | float a, float m, float l, 78 | float c, float b) 79 | { 80 | float l0 = ((P - m) * l) / a; 81 | float L0 = m - m / a; 82 | float L1 = m + (1.0 - m) / a; 83 | float S0 = m + l0; 84 | float S1 = m + a * l0; 85 | float C2 = (a * P) / (P - S1); 86 | float CP = -C2 / P; 87 | 88 | float3 w0 = 1.0f - smoothstep(0.0, m, x); 89 | float3 w2 = step(m + l0, x); 90 | float3 w1 = 1.0f - w0 - w2; 91 | 92 | float3 T = 93 | m * make_float3(powf(x.x / m, c), powf(x.y / m, c), powf(x.z / m, c)) + b; 94 | float3 S = P - (P - S1) * expf(CP * (x - S0)); 95 | float3 L = m + a * (x - m); 96 | 97 | return T * w0 + L * w1 + S * w2; 98 | } 99 | 100 | static __forceinline__ __device__ float3 uchimura(const float3& x) 101 | { 102 | const float P = 1.0; // max display brightness 103 | const float a = 1.0; // contrast 104 | const float m = 0.22; // linear section start 105 | const float l = 0.4; // linear section length 106 | const float c = 1.33; // black 107 | const float b = 0.0; // pedestal 108 | 109 | return uchimura(x, P, a, m, l, c, b); 110 | } 111 | 112 | // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf 113 | static __forceinline__ __device__ float compute_EV100(float aperture, 114 | float shutter_time, 115 | float ISO) 116 | { 117 | return log2f(aperture * aperture / shutter_time * 100.0 / ISO); 118 | } 119 | 120 | static __forceinline__ __device__ float convert_EV100_to_exposure(float EV100) 121 | { 122 | float maxLuminance = 1.2 * powf(2.0, EV100); 123 | return 1.0f / maxLuminance; 124 | } 125 | 126 | void __host__ post_process_kernel_launch( 127 | const float4* beauty_in, float4* beauty_high_luminance, float4* beauty_temp, 128 | int width, int height, const PostProcessParams& params, float4* beauty_out); 129 | 130 | void __host__ tone_mapping_kernel_launch(const float4* beauty_in, 131 | const float4* denoised_in, int width, 132 | int height, float ISO, 133 | float chromatic_aberration, 134 | float4* beauty_out, 135 | float4* denoised_out); 136 | 137 | __global__ void copy_kernel(const float4* in, int width, int height, 138 | float4* out); 139 | 140 | __global__ void bloom_kernel_0(const float4* beauty_in, int width, int height, 141 | float bloom_threshold, float4* beauty_out); 142 | 143 | __global__ void bloom_kernel_1(const float4* beauty_in, 144 | const float4* beauty_high_luminance, int width, 145 | int height, float bloom_sigma, 146 | float4* beauty_out); 147 | 148 | __global__ void tone_mapping_kernel(const float4* beauty_in, int width, 149 | int height, float ISO, 150 | float chromatic_aberration, 151 | float4* beauty_out); -------------------------------------------------------------------------------- /fredholm/kernels/src/post-process.cu: -------------------------------------------------------------------------------- 1 | #include "cwl/util.h" 2 | #include "kernels/post-process.h" 3 | #include "sutil/vec_math.h" 4 | 5 | void __host__ post_process_kernel_launch( 6 | const float4* beauty_in, float4* beauty_high_luminance, float4* beauty_temp, 7 | int width, int height, const PostProcessParams& params, float4* beauty_out) 8 | { 9 | const dim3 threads_per_block(16, 16); 10 | const dim3 blocks(max(width / threads_per_block.x, 1), 11 | max(height / threads_per_block.y, 1)); 12 | 13 | if (params.use_bloom) { 14 | // extract high luminance pixels 15 | bloom_kernel_0<<>>(beauty_in, width, height, 16 | params.bloom_threshold, 17 | beauty_high_luminance); 18 | CUDA_SYNC_CHECK(); 19 | 20 | // gaussian blur 21 | bloom_kernel_1<<>>( 22 | beauty_in, beauty_high_luminance, width, height, params.bloom_sigma, 23 | beauty_temp); 24 | CUDA_SYNC_CHECK(); 25 | } else { 26 | copy_kernel<<>>(beauty_in, width, height, 27 | beauty_temp); 28 | CUDA_SYNC_CHECK(); 29 | } 30 | 31 | // tone mapping 32 | tone_mapping_kernel<<>>( 33 | beauty_temp, width, height, params.ISO, params.chromatic_aberration, 34 | beauty_out); 35 | } 36 | 37 | void __host__ tone_mapping_kernel_launch(const float4* beauty_in, int width, 38 | int height, float ISO, 39 | float chromatic_aberration, 40 | float4* beauty_out) 41 | { 42 | const dim3 threads_per_block(16, 16); 43 | const dim3 blocks(max(width / threads_per_block.x, 1), 44 | max(height / threads_per_block.y, 1)); 45 | tone_mapping_kernel<<>>( 46 | beauty_in, width, height, ISO, chromatic_aberration, beauty_out); 47 | } 48 | 49 | __global__ void copy_kernel(const float4* in, int width, int height, 50 | float4* out) 51 | { 52 | const int i = blockIdx.x * blockDim.x + threadIdx.x; 53 | const int j = blockIdx.y * blockDim.y + threadIdx.y; 54 | if (i >= width || j >= height) return; 55 | const int image_idx = i + width * j; 56 | 57 | out[image_idx] = in[image_idx]; 58 | } 59 | 60 | __global__ void bloom_kernel_0(const float4* beauty_in, int width, int height, 61 | float bloom_threshold, float4* beauty_out) 62 | { 63 | const int i = blockIdx.x * blockDim.x + threadIdx.x; 64 | const int j = blockIdx.y * blockDim.y + threadIdx.y; 65 | if (i >= width || j >= height) return; 66 | const int image_idx = i + width * j; 67 | 68 | const float4 beauty = beauty_in[image_idx]; 69 | 70 | const float beauty_luminance = rgb_to_luminance(make_float3(beauty)); 71 | 72 | beauty_out[image_idx] = 73 | beauty_luminance > bloom_threshold ? beauty : make_float4(0.0f); 74 | } 75 | 76 | __global__ void bloom_kernel_1(const float4* beauty_in, 77 | const float4* beauty_high_luminance, int width, 78 | int height, float bloom_sigma, 79 | float4* beauty_out) 80 | { 81 | const int i = blockIdx.x * blockDim.x + threadIdx.x; 82 | const int j = blockIdx.y * blockDim.y + threadIdx.y; 83 | if (i >= width || j >= height) return; 84 | const int image_idx = i + width * j; 85 | 86 | const float4 b0 = beauty_in[image_idx]; 87 | 88 | const int K = 16; 89 | const float sigma = 1.0f; 90 | 91 | float4 b_sum = make_float4(0.0f); 92 | float w_sum = 0.0f; 93 | for (int v = -K; v <= K; ++v) { 94 | for (int u = -K; u <= K; ++u) { 95 | const int x = clamp(i + u, 0, width - 1); 96 | const int y = clamp(j + v, 0, height - 1); 97 | 98 | const float4 b1 = beauty_high_luminance[x + width * y]; 99 | 100 | const float dist2 = u * u + v * v; 101 | const float h = expf(-dist2 / (2.0f * bloom_sigma)); 102 | 103 | b_sum += h * b1; 104 | w_sum += h; 105 | } 106 | } 107 | 108 | beauty_out[image_idx] = b0 + b_sum / w_sum; 109 | } 110 | 111 | __global__ void tone_mapping_kernel(const float4* beauty_in, int width, 112 | int height, float ISO, 113 | float chromatic_aberration, 114 | float4* beauty_out) 115 | { 116 | const int i = blockIdx.x * blockDim.x + threadIdx.x; 117 | const int j = blockIdx.y * blockDim.y + threadIdx.y; 118 | if (i >= width || j >= height) return; 119 | const int image_idx = i + width * j; 120 | 121 | // chromatic aberration 122 | const float2 uv = make_float2(static_cast(i) / width, 123 | static_cast(j) / height); 124 | const float2 d = 125 | (uv - make_float2(0.5f)) / (width * height) * chromatic_aberration; 126 | 127 | const float2 uv_r = 128 | clamp(uv - 0.0f * d, make_float2(0.0f), make_float2(1.0f)); 129 | const float2 uv_g = 130 | clamp(uv - 1.0f * d, make_float2(0.0f), make_float2(1.0f)); 131 | const float2 uv_b = 132 | clamp(uv - 2.0f * d, make_float2(0.0f), make_float2(1.0f)); 133 | 134 | const int image_idx_r = uv_r.x * width + width * (uv_r.y * height); 135 | const int image_idx_g = uv_g.x * width + width * (uv_g.y * height); 136 | const int image_idx_b = uv_b.x * width + width * (uv_b.y * height); 137 | 138 | float3 color = make_float3(beauty_in[image_idx_r].x, beauty_in[image_idx_g].y, 139 | beauty_in[image_idx_b].z); 140 | 141 | // exposure adjustment 142 | const float EV100 = compute_EV100(1.0f, 1.0f, ISO); 143 | const float exposure = convert_EV100_to_exposure(EV100); 144 | color *= exposure; 145 | 146 | // tone mapping 147 | // color = aces_tone_mapping(color); 148 | color = uchimura(color); 149 | 150 | // linear to sRGB conversion 151 | color = linear_to_srgb(color); 152 | 153 | beauty_out[image_idx] = make_float4(color, 1.0f); 154 | } -------------------------------------------------------------------------------- /app/controller.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | // 6 | #include "cwl/buffer.h" 7 | // 8 | #include "optwl/optwl.h" 9 | // 10 | #include "fredholm/camera.h" 11 | #include "fredholm/denoiser.h" 12 | #include "fredholm/renderer.h" 13 | #include "fredholm/scene.h" 14 | #include "fredholm/shared.h" 15 | 16 | inline float deg2rad(float deg) { return deg / 180.0f * M_PI; } 17 | 18 | enum class AOVType : int { 19 | BEAUTY, 20 | DENOISED, 21 | POSITION, 22 | NORMAL, 23 | TEXCOORD, 24 | DEPTH, 25 | ALBEDO 26 | }; 27 | 28 | enum class SkyType : int { CONSTANT, IBL, ARHOSEK }; 29 | 30 | static std::vector scene_filepaths = { 31 | "../resources/cornellbox/CornellBox.obj", 32 | "../resources/rtcamp8/rtcamp8.obj", 33 | "../resources/sponza/sponza.obj", 34 | "../resources/pbr_sponza/Sponza.gltf", 35 | "../resources/modern_sponza/NewSponza_Main_Blender_glTF.gltf", 36 | "../resources/modern_sponza_small/NewSponza_Main_Blender_glTF.gltf", 37 | "../resources/salle_de_bain/salle_de_bain.obj", 38 | "../resources/sibenik/sibenik.obj", 39 | "../resources/san_miguel/san-miguel.obj", 40 | "../resources/rungholt/rungholt.obj", 41 | "../resources/vokselia/vokselia_spawn.obj", 42 | "../resources/bmw/bmw.obj", 43 | "../resources/bmw_gltf/bmw.gltf", 44 | "../resources/specular_test/spheres_test_scene.obj", 45 | "../resources/specular_roughness_test/spheres_test_scene.obj", 46 | "../resources/metal_test/spheres_test_scene.obj", 47 | "../resources/coat_test/spheres_test_scene.obj", 48 | "../resources/transmission_test/spheres_test_scene.obj", 49 | "../resources/transmission_roughness_test/spheres_test_scene.obj", 50 | "../resources/transmission_test_sphere/sphere.obj", 51 | "../resources/specular_transmission_test/spheres_test_scene.obj", 52 | "../resources/specular_transmission_roughness_test/spheres_test_scene.obj", 53 | "../resources/sheen_test/spheres_test_scene.obj", 54 | "../resources/diffuse_test/spheres_test_scene.obj", 55 | "../resources/diffuse_transmission_test/spheres_test_scene.obj", 56 | "../resources/texture_test/plane.obj", 57 | "../resources/normalmap_test/normalmap_test.obj", 58 | "../resources/specular_white_furnace_test/spheres.obj", 59 | "../resources/coat_white_furnace_test/spheres.obj", 60 | "../resources/metal_rough_spheres/MetalRoughSpheres.gltf", 61 | "../resources/clear_coat_test/ClearCoatTest.gltf", 62 | "../resources/emission_texture_test/emission_texture_test.gltf", 63 | "../resources/instance_test/instance_test.gltf", 64 | "../resources/animation_test/animation_test.gltf", 65 | "../resources/camera_animation_test/camera_animation_test.gltf", 66 | "../resources/box/Box.gltf", 67 | "../resources/cube/Cube.gltf", 68 | "../resources/animated_cube/AnimatedCube.gltf", 69 | "../resources/gltf_test/gltf_test.gltf", 70 | "../resources/gltf_test2/gltf_test2.gltf"}; 71 | 72 | static std::vector ibl_filepaths = { 73 | "../resources/ibl/PaperMill_Ruins_E/PaperMill_E_3k.hdr"}; 74 | 75 | class Controller 76 | { 77 | public: 78 | int m_imgui_scene_id = 0; 79 | int m_imgui_resolution[2] = {1920, 1080}; 80 | int m_imgui_n_samples = 0; 81 | int m_imgui_max_samples = 100; 82 | int m_imgui_max_depth = 10; 83 | AOVType m_imgui_aov_type = AOVType::BEAUTY; 84 | float m_imgui_time = 0.0f; 85 | bool m_imgui_play_animation = false; 86 | float m_imgui_timestep = 0.01f; 87 | char m_imgui_filename[256] = "output.png"; 88 | 89 | float m_imgui_origin[3] = {0, 1, 5}; 90 | float m_imgui_fov = 90.0f; 91 | float m_imgui_F = 100.0f; 92 | float m_imgui_focus = 10000.0f; 93 | float m_imgui_movement_speed = 1.0f; 94 | float m_imgui_rotation_speed = 0.1f; 95 | 96 | float m_imgui_directional_light_le[3] = {0, 0, 0}; 97 | float m_imgui_directional_light_dir[3] = {0, 1, 0}; 98 | float m_imgui_directional_light_angle = 0.0f; 99 | 100 | SkyType m_imgui_sky_type = SkyType::CONSTANT; 101 | float m_imgui_bg_color[3] = {0, 0, 0}; 102 | float m_imgui_sky_intensity = 1.0f; 103 | int m_imgui_ibl_id = 0; 104 | float m_imgui_arhosek_turbidity = 3.0f; 105 | float m_imgui_arhosek_albedo = 0.3f; 106 | 107 | bool m_imgui_use_bloom = false; 108 | float m_imgui_bloom_threshold = 1.0f; 109 | float m_imgui_bloom_sigma = 1.0f; 110 | float m_imgui_iso = 400.0f; 111 | float m_imgui_chromatic_aberration = 1.0f; 112 | 113 | std::unique_ptr m_camera = nullptr; 114 | 115 | std::unique_ptr> m_layer_beauty = nullptr; 116 | std::unique_ptr> m_layer_position = nullptr; 117 | std::unique_ptr> m_layer_normal = nullptr; 118 | std::unique_ptr> m_layer_depth = nullptr; 119 | std::unique_ptr> m_layer_texcoord = nullptr; 120 | std::unique_ptr> m_layer_albedo = nullptr; 121 | std::unique_ptr> m_layer_denoised = nullptr; 122 | 123 | // post processed layer 124 | std::unique_ptr> m_beauty_high_luminance = nullptr; 125 | std::unique_ptr> m_denoised_high_luminance = nullptr; 126 | std::unique_ptr> m_beauty_temp = nullptr; 127 | std::unique_ptr> m_denoised_temp = nullptr; 128 | std::unique_ptr> m_layer_beauty_pp = nullptr; 129 | std::unique_ptr> m_layer_denoised_pp = nullptr; 130 | 131 | std::unique_ptr m_context = nullptr; 132 | std::unique_ptr m_renderer = nullptr; 133 | std::unique_ptr m_denoiser = nullptr; 134 | 135 | Controller(); 136 | 137 | void init_camera(); 138 | void update_camera(); 139 | void move_camera(const fredholm::CameraMovement& direction, float dt); 140 | void rotate_camera(float dphi, float dtheta); 141 | 142 | void init_renderer(); 143 | 144 | void init_denoiser(); 145 | 146 | void init_render_layers(); 147 | void clear_render_layers(); 148 | 149 | void load_scene(); 150 | 151 | void update_directional_light(); 152 | 153 | void update_sky_type(); 154 | void set_sky_intensity(); 155 | 156 | void load_ibl(); 157 | 158 | void load_arhosek(); 159 | 160 | void set_time(); 161 | void advance_time(); 162 | 163 | void update_resolution(); 164 | 165 | void clear_render(); 166 | 167 | void render(); 168 | 169 | void denoise(); 170 | 171 | void post_process(); 172 | 173 | void save_image() const; 174 | }; -------------------------------------------------------------------------------- /oglw/include/oglw/shader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "glad/gl.h" 9 | #include "glm/glm.hpp" 10 | #include "glm/gtc/type_ptr.hpp" 11 | #include "spdlog/spdlog.h" 12 | // 13 | #include "texture.h" 14 | 15 | namespace oglw 16 | { 17 | 18 | class Shader 19 | { 20 | private: 21 | GLuint program; 22 | 23 | static std::string loadStringFromFile(const std::filesystem::path& filepath) 24 | { 25 | std::ifstream file(filepath); 26 | if (!file.is_open()) { 27 | spdlog::error("[Shader] failed to open {}", filepath.generic_string()); 28 | std::exit(EXIT_FAILURE); 29 | } 30 | return std::string(std::istreambuf_iterator(file), 31 | std::istreambuf_iterator()); 32 | } 33 | 34 | public: 35 | Shader(GLenum type, const std::filesystem::path& filepath) 36 | { 37 | const std::string shader_source = loadStringFromFile(filepath); 38 | const char* shader_source_c = shader_source.c_str(); 39 | program = glCreateShaderProgramv(type, 1, &shader_source_c); 40 | spdlog::info("[Shader] program {:x} created", program); 41 | 42 | // check compile and link error 43 | int success = 0; 44 | glGetProgramiv(program, GL_LINK_STATUS, &success); 45 | if (success == GL_FALSE) { 46 | spdlog::error("[Shader] failed to link program {:x}", program); 47 | 48 | GLint logSize = 0; 49 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logSize); 50 | std::vector errorLog(logSize); 51 | glGetProgramInfoLog(program, logSize, &logSize, &errorLog[0]); 52 | std::string errorLogStr(errorLog.begin(), errorLog.end()); 53 | spdlog::error("[Shader] {}", errorLogStr); 54 | } 55 | } 56 | 57 | virtual ~Shader() { release(); } 58 | 59 | Shader(const Shader& other) = delete; 60 | 61 | Shader(Shader&& other) : program(other.program) { other.program = 0; } 62 | 63 | Shader& operator=(const Shader& other) = delete; 64 | 65 | Shader& operator=(Shader&& other) 66 | { 67 | if (this != &other) { 68 | release(); 69 | 70 | program = other.program; 71 | 72 | other.program = 0; 73 | } 74 | 75 | return *this; 76 | } 77 | 78 | void release() 79 | { 80 | if (program) { 81 | spdlog::info("[Shader] release program {:x}", program); 82 | glDeleteProgram(program); 83 | } 84 | } 85 | 86 | GLuint getProgram() const { return program; } 87 | 88 | void setUniform(const std::string& uniform_name, 89 | const std::variant& value) const 91 | { 92 | // get location of uniform variable 93 | const GLint location = glGetUniformLocation(program, uniform_name.c_str()); 94 | 95 | // set value 96 | struct Visitor { 97 | GLuint program; 98 | GLint location; 99 | Visitor(GLuint program, GLint location) 100 | : program(program), location(location) 101 | { 102 | } 103 | 104 | void operator()(bool value) 105 | { 106 | glProgramUniform1i(program, location, value); 107 | } 108 | void operator()(GLint value) 109 | { 110 | glProgramUniform1i(program, location, value); 111 | } 112 | void operator()(GLuint value) 113 | { 114 | glProgramUniform1ui(program, location, value); 115 | } 116 | void operator()(GLfloat value) 117 | { 118 | glProgramUniform1f(program, location, value); 119 | } 120 | void operator()(const glm::vec2& value) 121 | { 122 | glProgramUniform2fv(program, location, 1, glm::value_ptr(value)); 123 | } 124 | void operator()(const glm::vec3& value) 125 | { 126 | glProgramUniform3fv(program, location, 1, glm::value_ptr(value)); 127 | } 128 | void operator()(const glm::mat4& value) 129 | { 130 | glProgramUniformMatrix4fv(program, location, 1, GL_FALSE, 131 | glm::value_ptr(value)); 132 | } 133 | }; 134 | std::visit(Visitor{program, location}, value); 135 | } 136 | }; 137 | 138 | class VertexShader : public Shader 139 | { 140 | public: 141 | VertexShader(const std::filesystem::path& filepath) 142 | : Shader(GL_VERTEX_SHADER, filepath) 143 | { 144 | } 145 | }; 146 | 147 | class GeometryShader : public Shader 148 | { 149 | public: 150 | GeometryShader(const std::filesystem::path& filepath) 151 | : Shader(GL_GEOMETRY_SHADER, filepath) 152 | { 153 | } 154 | }; 155 | 156 | class FragmentShader : public Shader 157 | { 158 | public: 159 | FragmentShader(const std::filesystem::path& filepath) 160 | : Shader(GL_FRAGMENT_SHADER, filepath) 161 | { 162 | } 163 | }; 164 | 165 | class ComputeShader : public Shader 166 | { 167 | public: 168 | ComputeShader(const std::filesystem::path& filepath) 169 | : Shader(GL_COMPUTE_SHADER, filepath) 170 | { 171 | } 172 | }; 173 | 174 | class Pipeline 175 | { 176 | public: 177 | GLuint pipeline; 178 | 179 | Pipeline() 180 | { 181 | glCreateProgramPipelines(1, &pipeline); 182 | spdlog::info("[Pipeline] pipeline {:x} created", pipeline); 183 | } 184 | 185 | Pipeline(const Pipeline& other) = delete; 186 | 187 | Pipeline(Pipeline&& other) : pipeline(other.pipeline) { other.pipeline = 0; } 188 | 189 | ~Pipeline() { release(); } 190 | 191 | Pipeline& operator=(const Pipeline& other) = delete; 192 | 193 | Pipeline& operator=(Pipeline&& other) 194 | { 195 | if (this != &other) { 196 | release(); 197 | 198 | pipeline = other.pipeline; 199 | 200 | other.pipeline = 0; 201 | } 202 | 203 | return *this; 204 | } 205 | 206 | void release() 207 | { 208 | if (pipeline) { 209 | spdlog::info("[Pipeline] release pipeline {:x}", pipeline); 210 | glDeleteProgramPipelines(1, &pipeline); 211 | } 212 | } 213 | 214 | void attachVertexShader(const VertexShader& shader) const 215 | { 216 | glUseProgramStages(pipeline, GL_VERTEX_SHADER_BIT, shader.getProgram()); 217 | } 218 | 219 | void attachFragmentShader(const FragmentShader& shader) const 220 | { 221 | glUseProgramStages(pipeline, GL_FRAGMENT_SHADER_BIT, shader.getProgram()); 222 | } 223 | 224 | void attachComputeShader(const ComputeShader& shader) const 225 | { 226 | glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, shader.getProgram()); 227 | } 228 | 229 | void activate() const { glBindProgramPipeline(pipeline); } 230 | 231 | void deactivate() const { glBindProgramPipeline(0); } 232 | }; 233 | 234 | } // namespace oglw -------------------------------------------------------------------------------- /externals/sutil/sutil/Scene.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | #pragma once 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #include 43 | 44 | #include 45 | #include 46 | #include 47 | 48 | 49 | namespace sutil 50 | { 51 | 52 | 53 | class Scene 54 | { 55 | public: 56 | SUTILAPI Scene(); 57 | SUTILAPI ~Scene(); 58 | struct MeshGroup 59 | { 60 | std::string name; 61 | Matrix4x4 transform; 62 | 63 | std::vector indices; 64 | std::vector > positions; 65 | std::vector > normals; 66 | std::vector > texcoords; 67 | 68 | std::vector material_idx; 69 | 70 | OptixTraversableHandle gas_handle = 0; 71 | CUdeviceptr d_gas_output = 0; 72 | 73 | Aabb object_aabb; 74 | Aabb world_aabb; 75 | }; 76 | 77 | 78 | SUTILAPI void addCamera ( const Camera& camera ) { m_cameras.push_back( camera ); } 79 | SUTILAPI void addMesh ( std::shared_ptr mesh ) { m_meshes.push_back( mesh ); } 80 | SUTILAPI void addMaterial( const MaterialData::Pbr& mtl ) { m_materials.push_back( mtl ); } 81 | SUTILAPI void addBuffer ( const uint64_t buf_size, const void* data ); 82 | SUTILAPI void addImage( 83 | const int32_t width, 84 | const int32_t height, 85 | const int32_t bits_per_component, 86 | const int32_t num_components, 87 | const void* data 88 | ); 89 | SUTILAPI void addSampler( 90 | cudaTextureAddressMode address_s, 91 | cudaTextureAddressMode address_t, 92 | cudaTextureFilterMode filter_mode, 93 | const int32_t image_idx 94 | ); 95 | 96 | SUTILAPI CUdeviceptr getBuffer ( int32_t buffer_index )const; 97 | SUTILAPI cudaArray_t getImage ( int32_t image_index )const; 98 | SUTILAPI cudaTextureObject_t getSampler( int32_t sampler_index )const; 99 | 100 | SUTILAPI void finalize(); 101 | SUTILAPI void cleanup(); 102 | 103 | SUTILAPI Camera camera()const; 104 | SUTILAPI OptixPipeline pipeline()const { return m_pipeline; } 105 | SUTILAPI const OptixShaderBindingTable* sbt()const { return &m_sbt; } 106 | SUTILAPI OptixTraversableHandle traversableHandle() const { return m_ias_handle; } 107 | SUTILAPI sutil::Aabb aabb() const { return m_scene_aabb; } 108 | SUTILAPI OptixDeviceContext context() const { return m_context; } 109 | SUTILAPI const std::vector& materials() const { return m_materials; } 110 | SUTILAPI const std::vector>& meshes() const { return m_meshes; } 111 | 112 | SUTILAPI void createContext(); 113 | SUTILAPI void buildMeshAccels( uint32_t triangle_input_flags = OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT ); 114 | SUTILAPI void buildInstanceAccel( int rayTypeCount = whitted::RAY_TYPE_COUNT ); 115 | 116 | private: 117 | void createPTXModule(); 118 | void createProgramGroups(); 119 | void createPipeline(); 120 | void createSBT(); 121 | 122 | // TODO: custom geometry support 123 | 124 | std::vector m_cameras; 125 | std::vector > m_meshes; 126 | std::vector m_materials; 127 | std::vector m_buffers; 128 | std::vector m_samplers; 129 | std::vector m_images; 130 | sutil::Aabb m_scene_aabb; 131 | 132 | OptixDeviceContext m_context = 0; 133 | OptixShaderBindingTable m_sbt = {}; 134 | OptixPipelineCompileOptions m_pipeline_compile_options = {}; 135 | OptixPipeline m_pipeline = 0; 136 | OptixModule m_ptx_module = 0; 137 | 138 | OptixProgramGroup m_raygen_prog_group = 0; 139 | OptixProgramGroup m_radiance_miss_group = 0; 140 | OptixProgramGroup m_occlusion_miss_group = 0; 141 | OptixProgramGroup m_radiance_hit_group = 0; 142 | OptixProgramGroup m_occlusion_hit_group = 0; 143 | OptixTraversableHandle m_ias_handle = 0; 144 | CUdeviceptr m_d_ias_output_buffer = 0; 145 | }; 146 | 147 | 148 | SUTILAPI void loadScene( const std::string& filename, Scene& scene ); 149 | 150 | } // end namespace sutil 151 | 152 | -------------------------------------------------------------------------------- /externals/sutil/sutil/Trackball.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | namespace sutil 36 | { 37 | 38 | namespace 39 | { 40 | float radians(float degrees) 41 | { 42 | return degrees * M_PIf / 180.0f; 43 | } 44 | float degrees(float radians) 45 | { 46 | return radians * M_1_PIf * 180.0f; 47 | } 48 | 49 | } // namespace 50 | 51 | void Trackball::startTracking(int x, int y) 52 | { 53 | m_prevPosX = x; 54 | m_prevPosY = y; 55 | m_performTracking = true; 56 | } 57 | 58 | void Trackball::updateTracking(int x, int y, int /*canvasWidth*/, int /*canvasHeight*/) 59 | { 60 | if(!m_performTracking) 61 | { 62 | startTracking(x, y); 63 | return; 64 | } 65 | 66 | int deltaX = x - m_prevPosX; 67 | int deltaY = y - m_prevPosY; 68 | 69 | m_prevPosX = x; 70 | m_prevPosY = y; 71 | m_latitude = radians(std::min(89.0f, std::max(-89.0f, degrees(m_latitude) + 0.5f*deltaY))); 72 | m_longitude = radians(fmod(degrees(m_longitude) - 0.5f*deltaX, 360.0f)); 73 | 74 | updateCamera(); 75 | 76 | if(!m_gimbalLock) { 77 | reinitOrientationFromCamera(); 78 | m_camera->setUp(m_w); 79 | } 80 | } 81 | 82 | void Trackball::updateCamera() 83 | { 84 | // use latlon for view definition 85 | float3 localDir; 86 | localDir.x = cos(m_latitude)*sin(m_longitude); 87 | localDir.y = cos(m_latitude)*cos(m_longitude); 88 | localDir.z = sin(m_latitude); 89 | 90 | float3 dirWS = m_u * localDir.x + m_v * localDir.y + m_w * localDir.z; 91 | 92 | if(m_viewMode == EyeFixed) 93 | { 94 | const float3& eye = m_camera->eye(); 95 | m_camera->setLookat(eye - dirWS * m_cameraEyeLookatDistance); 96 | } 97 | else // LookAtFixed 98 | { 99 | const float3& lookat = m_camera->lookat(); 100 | m_camera->setEye(lookat + dirWS * m_cameraEyeLookatDistance); 101 | } 102 | } 103 | 104 | void Trackball::setReferenceFrame(const float3& u, const float3& v, const float3& w) 105 | { 106 | m_u = u; 107 | m_v = v; 108 | m_w = w; 109 | float3 dirWS = -normalize(m_camera->lookat() - m_camera->eye()); 110 | float3 dirLocal; 111 | dirLocal.x = dot(dirWS, u); 112 | dirLocal.y = dot(dirWS, v); 113 | dirLocal.z = dot(dirWS, w); 114 | m_longitude = atan2(dirLocal.x, dirLocal.y); 115 | m_latitude = asin(dirLocal.z); 116 | } 117 | 118 | void Trackball::zoom(int direction) 119 | { 120 | float zoom = (direction > 0) ? 1 / m_zoomMultiplier : m_zoomMultiplier; 121 | m_cameraEyeLookatDistance *= zoom; 122 | const float3& lookat = m_camera->lookat(); 123 | const float3& eye = m_camera->eye(); 124 | m_camera->setEye(lookat + (eye - lookat) * zoom); 125 | } 126 | 127 | void Trackball::reinitOrientationFromCamera() 128 | { 129 | m_camera->UVWFrame(m_u, m_v, m_w); 130 | m_u = normalize(m_u); 131 | m_v = normalize(m_v); 132 | m_w = normalize(-m_w); 133 | std::swap(m_v, m_w); 134 | m_latitude = 0.0f; 135 | m_longitude = 0.0f; 136 | m_cameraEyeLookatDistance = length(m_camera->lookat() - m_camera->eye()); 137 | } 138 | 139 | void Trackball::moveForward(float speed) 140 | { 141 | float3 dirWS = normalize(m_camera->lookat() - m_camera->eye()); 142 | m_camera->setEye(m_camera->eye() + dirWS * speed); 143 | m_camera->setLookat(m_camera->lookat() + dirWS * speed); 144 | } 145 | void Trackball::moveBackward(float speed) 146 | { 147 | float3 dirWS = normalize(m_camera->lookat() - m_camera->eye()); 148 | m_camera->setEye(m_camera->eye() - dirWS * speed); 149 | m_camera->setLookat(m_camera->lookat() - dirWS * speed); 150 | } 151 | void Trackball::moveLeft(float speed) 152 | { 153 | float3 u, v, w; 154 | m_camera->UVWFrame(u, v, w); 155 | u = normalize(u); 156 | 157 | m_camera->setEye(m_camera->eye() - u * speed); 158 | m_camera->setLookat(m_camera->lookat() - u * speed); 159 | } 160 | void Trackball::moveRight(float speed) 161 | { 162 | float3 u, v, w; 163 | m_camera->UVWFrame(u, v, w); 164 | u = normalize(u); 165 | 166 | m_camera->setEye(m_camera->eye() + u * speed); 167 | m_camera->setLookat(m_camera->lookat() + u * speed); 168 | } 169 | void Trackball::moveUp(float speed) 170 | { 171 | float3 u, v, w; 172 | m_camera->UVWFrame(u, v, w); 173 | v = normalize(v); 174 | 175 | m_camera->setEye(m_camera->eye() + v * speed); 176 | m_camera->setLookat(m_camera->lookat() + v * speed); 177 | } 178 | void Trackball::moveDown(float speed) 179 | { 180 | float3 u, v, w; 181 | m_camera->UVWFrame(u, v, w); 182 | v = normalize(v); 183 | 184 | m_camera->setEye(m_camera->eye() - v * speed); 185 | m_camera->setLookat(m_camera->lookat() - v * speed); 186 | } 187 | 188 | void Trackball::rollLeft(float speed) 189 | { 190 | float3 u, v, w; 191 | m_camera->UVWFrame(u, v, w); 192 | u = normalize(u); 193 | v = normalize(v); 194 | 195 | m_camera->setUp(u * cos(radians(90.0f + speed)) + v * sin(radians(90.0f + speed))); 196 | } 197 | 198 | void Trackball::rollRight(float speed) 199 | { 200 | float3 u, v, w; 201 | m_camera->UVWFrame(u, v, w); 202 | u = normalize(u); 203 | v = normalize(v); 204 | 205 | m_camera->setUp(u * cos(radians(90.0f - speed)) + v * sin(radians(90.0f - speed))); 206 | } 207 | 208 | bool Trackball::wheelEvent(int dir) 209 | { 210 | zoom(dir); 211 | return true; 212 | } 213 | 214 | } // namespace sutil 215 | -------------------------------------------------------------------------------- /externals/sutil/sutil/sutil.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | 30 | #pragma once 31 | 32 | #include "sutilapi.h" 33 | #include "sampleConfig.h" 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | struct GLFWwindow; 43 | 44 | // Some helper macros to stringify the sample's name that comes in as a define 45 | #define OPTIX_STRINGIFY2(name) #name 46 | #define OPTIX_STRINGIFY(name) OPTIX_STRINGIFY2(name) 47 | #define OPTIX_SAMPLE_NAME OPTIX_STRINGIFY(OPTIX_SAMPLE_NAME_DEFINE) 48 | #define OPTIX_SAMPLE_DIR OPTIX_STRINGIFY(OPTIX_SAMPLE_DIR_DEFINE) 49 | 50 | namespace sutil 51 | { 52 | 53 | enum BufferImageFormat 54 | { 55 | UNSIGNED_BYTE4, 56 | FLOAT4, 57 | FLOAT3 58 | }; 59 | 60 | struct ImageBuffer 61 | { 62 | void* data = nullptr; 63 | unsigned int width = 0; 64 | unsigned int height = 0; 65 | BufferImageFormat pixel_format; 66 | }; 67 | 68 | struct Texture 69 | { 70 | cudaArray_t array; 71 | cudaTextureObject_t texture; 72 | }; 73 | 74 | // Return a path to a sample data file, or NULL if the file cannot be located. 75 | // The pointer returned may point to a static array. 76 | SUTILAPI const char* sampleDataFilePath( const char* relativeFilePath ); 77 | 78 | // Return a path to a sample file inside a sub directory, or NULL if the file cannot be located. 79 | // The pointer returned may point to a static array. 80 | SUTILAPI const char* sampleFilePath( const char* relativeSubDir, const char* relativePath ); 81 | 82 | SUTILAPI size_t pixelFormatSize( BufferImageFormat format ); 83 | 84 | // Create a cudaTextureObject_t for the given image file. If the filename is 85 | // empty or if loading the file fails, return 1x1 texture with default color. 86 | SUTILAPI Texture loadTexture( const char* filename, float3 default_color, cudaTextureDesc* tex_desc = nullptr ); 87 | 88 | // Floating point image buffers (see BufferImageFormat above) are assumed to be 89 | // linear and will be converted to sRGB when writing to a file format with 8 90 | // bits per channel. This can be skipped if disable_srgb is set to true. 91 | // Image buffers with format UNSIGNED_BYTE4 are assumed to be in sRGB already 92 | // and will be written like that. 93 | SUTILAPI void saveImage( const char* filename, const ImageBuffer& buffer, bool disable_srgb ); 94 | SUTILAPI ImageBuffer loadImage( const char* filename, int32_t force_components = 0 ); 95 | 96 | SUTILAPI void displayBufferWindow( const char* argv, const ImageBuffer& buffer ); 97 | 98 | 99 | SUTILAPI void initGL(); 100 | SUTILAPI void initGLFW(); 101 | SUTILAPI GLFWwindow* initGLFW( const char* window_title, int width, int height ); 102 | SUTILAPI void initImGui( GLFWwindow* window ); 103 | SUTILAPI GLFWwindow* initUI( const char* window_title, int width, int height ); 104 | SUTILAPI void cleanupUI( GLFWwindow* window ); 105 | 106 | SUTILAPI void beginFrameImGui(); 107 | SUTILAPI void endFrameImGui(); 108 | 109 | // Display frames per second, where the OpenGL context 110 | // is managed by the caller. 111 | SUTILAPI void displayFPS( unsigned total_frame_count ); 112 | 113 | SUTILAPI void displayStats( std::chrono::duration& state_update_time, 114 | std::chrono::duration& render_time, 115 | std::chrono::duration& display_time ); 116 | 117 | // Display a short string starting at x,y. 118 | SUTILAPI void displayText( const char* text, float x, float y ); 119 | 120 | // Blocking sleep call 121 | SUTILAPI void sleep( 122 | int seconds ); // Number of seconds to sleep 123 | 124 | 125 | // Parse the string of the form x and return numeric values. 126 | SUTILAPI void parseDimensions( 127 | const char* arg, // String of form x 128 | int& width, // [out] width 129 | int& height ); // [in] height 130 | 131 | 132 | SUTILAPI void calculateCameraVariables( 133 | float3 eye, 134 | float3 lookat, 135 | float3 up, 136 | float fov, 137 | float aspect_ratio, 138 | float3& U, 139 | float3& V, 140 | float3& W, 141 | bool fov_is_vertical ); 142 | 143 | // Get current time in seconds for benchmarking/timing purposes. 144 | double SUTILAPI currentTime(); 145 | 146 | // Get input data, either pre-compiled with NVCC or JIT compiled by NVRTC. 147 | SUTILAPI const char* getInputData( const char* sampleName, // Name of the sample, used to locate the input file. NULL = only search the common /cuda dir 148 | const char* sampleDir, // Directory name for the sample (typically the same as the sample name). 149 | const char* filename, // Cuda C input file name 150 | size_t& dataSize, 151 | const char** log = NULL, // (Optional) pointer to compiler log string. If *log == NULL there is no output. Only valid until the next getInputData call 152 | const std::vector& compilerOptions = {CUDA_NVRTC_OPTIONS} ); // Optional vector of compiler options. 153 | 154 | 155 | 156 | // Ensures that width and height have the minimum size to prevent launch errors. 157 | SUTILAPI void ensureMinimumSize( 158 | int& width, // Will be assigned the minimum suitable width if too small. 159 | int& height); // Will be assigned the minimum suitable height if too small. 160 | 161 | // Ensures that width and height have the minimum size to prevent launch errors. 162 | SUTILAPI void ensureMinimumSize( 163 | unsigned& width, // Will be assigned the minimum suitable width if too small. 164 | unsigned& height); // Will be assigned the minimum suitable height if too small. 165 | 166 | SUTILAPI void reportErrorMessage( const char* message ); 167 | 168 | } // end namespace sutil 169 | 170 | -------------------------------------------------------------------------------- /externals/sutil/sutil/Quaternion.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | #pragma once 29 | 30 | #include 31 | 32 | //------------------------------------------------------------------------------ 33 | // 34 | // Quaternion class 35 | // 36 | //------------------------------------------------------------------------------ 37 | 38 | namespace sutil 39 | { 40 | 41 | class Quaternion 42 | { 43 | public: 44 | Quaternion() 45 | { q[0] = q[1] = q[2] = q[3] = 0.0; } 46 | 47 | Quaternion( float w, float x, float y, float z ) 48 | { q[0] = w; q[1] = x; q[2] = y; q[3] = z; } 49 | 50 | Quaternion( const float3& from, const float3& to ); 51 | 52 | Quaternion( const Quaternion& a ) 53 | { q[0] = a[0]; q[1] = a[1]; q[2] = a[2]; q[3] = a[3]; } 54 | 55 | Quaternion ( float angle, const float3& axis ); 56 | 57 | // getters and setters 58 | void setW(float _w) { q[0] = _w; } 59 | void setX(float _x) { q[1] = _x; } 60 | void setY(float _y) { q[2] = _y; } 61 | void setZ(float _z) { q[3] = _z; } 62 | float w() const { return q[0]; } 63 | float x() const { return q[1]; } 64 | float y() const { return q[2]; } 65 | float z() const { return q[3]; } 66 | 67 | 68 | Quaternion& operator-=(const Quaternion& r) 69 | { q[0] -= r[0]; q[1] -= r[1]; q[2] -= r[2]; q[3] -= r[3]; return *this; } 70 | 71 | Quaternion& operator+=(const Quaternion& r) 72 | { q[0] += r[0]; q[1] += r[1]; q[2] += r[2]; q[3] += r[3]; return *this; } 73 | 74 | Quaternion& operator*=(const Quaternion& r); 75 | 76 | Quaternion& operator/=(const float a); 77 | 78 | Quaternion conjugate() 79 | { return Quaternion( q[0], -q[1], -q[2], -q[3] ); } 80 | 81 | void rotation( float& angle, float3& axis ) const; 82 | void rotation( float& angle, float& x, float& y, float& z ) const; 83 | Matrix4x4 rotationMatrix() const; 84 | 85 | float& operator[](int i) { return q[i]; } 86 | float operator[](int i)const { return q[i]; } 87 | 88 | // l2 norm 89 | float norm() const 90 | { return sqrtf(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]); } 91 | 92 | float normalize(); 93 | 94 | private: 95 | float q[4]; 96 | }; 97 | 98 | 99 | inline Quaternion::Quaternion( const float3& from, const float3& to ) 100 | { 101 | const float3 c = cross( from, to ); 102 | q[0] = dot(from, to); 103 | q[1] = c.x; 104 | q[2] = c.y; 105 | q[3] = c.z; 106 | } 107 | 108 | 109 | inline Quaternion::Quaternion( float angle, const float3& axis ) 110 | { 111 | const float n = length( axis ); 112 | const float inverse = 1.0f/n; 113 | const float3 naxis = axis*inverse; 114 | const float s = sinf(angle/2.0f); 115 | 116 | q[0] = naxis.x*s*inverse; 117 | q[1] = naxis.y*s*inverse; 118 | q[2] = naxis.z*s*inverse; 119 | q[3] = cosf(angle/2.0f); 120 | } 121 | 122 | 123 | inline Quaternion& Quaternion::operator*=(const Quaternion& r) 124 | { 125 | 126 | float w = q[0]*r[0] - q[1]*r[1] - q[2]*r[2] - q[3]*r[3]; 127 | float x = q[0]*r[1] + q[1]*r[0] + q[2]*r[3] - q[3]*r[2]; 128 | float y = q[0]*r[2] + q[2]*r[0] + q[3]*r[1] - q[1]*r[3]; 129 | float z = q[0]*r[3] + q[3]*r[0] + q[1]*r[2] - q[2]*r[1]; 130 | 131 | q[0] = w; 132 | q[1] = x; 133 | q[2] = y; 134 | q[3] = z; 135 | return *this; 136 | } 137 | 138 | 139 | inline Quaternion& Quaternion::operator/=(const float a) 140 | { 141 | float inverse = 1.0f/a; 142 | q[0] *= inverse; 143 | q[1] *= inverse; 144 | q[2] *= inverse; 145 | q[3] *= inverse; 146 | return *this; 147 | } 148 | 149 | inline void Quaternion::rotation( float& angle, float3& axis ) const 150 | { 151 | Quaternion n = *this; 152 | n.normalize(); 153 | axis.x = n[1]; 154 | axis.y = n[2]; 155 | axis.z = n[3]; 156 | angle = 2.0f * acosf(n[0]); 157 | } 158 | 159 | inline void Quaternion::rotation( 160 | float& angle, 161 | float& x, 162 | float& y, 163 | float& z 164 | ) const 165 | { 166 | Quaternion n = *this; 167 | n.normalize(); 168 | x = n[1]; 169 | y = n[2]; 170 | z = n[3]; 171 | angle = 2.0f * acosf(n[0]); 172 | } 173 | 174 | inline float Quaternion::normalize() 175 | { 176 | float n = norm(); 177 | float inverse = 1.0f/n; 178 | q[0] *= inverse; 179 | q[1] *= inverse; 180 | q[2] *= inverse; 181 | q[3] *= inverse; 182 | return n; 183 | } 184 | 185 | 186 | inline Quaternion operator*(const float a, const Quaternion &r) 187 | { return Quaternion(a*r[0], a*r[1], a*r[2], a*r[3]); } 188 | 189 | 190 | inline Quaternion operator*(const Quaternion &r, const float a) 191 | { return Quaternion(a*r[0], a*r[1], a*r[2], a*r[3]); } 192 | 193 | 194 | inline Quaternion operator/(const Quaternion &r, const float a) 195 | { 196 | float inverse = 1.0f/a; 197 | return Quaternion( r[0]*inverse, r[1]*inverse, r[2]*inverse, r[3]*inverse); 198 | } 199 | 200 | 201 | inline Quaternion operator/(const float a, const Quaternion &r) 202 | { 203 | float inverse = 1.0f/a; 204 | return Quaternion( r[0]*inverse, r[1]*inverse, r[2]*inverse, r[3]*inverse); 205 | } 206 | 207 | 208 | inline Quaternion operator-(const Quaternion& l, const Quaternion& r) 209 | { return Quaternion(l[0]-r[0], l[1]-r[1], l[2]-r[2], l[3]-r[3]); } 210 | 211 | 212 | inline bool operator==(const Quaternion& l, const Quaternion& r) 213 | { return ( l[0] == r[0] && l[1] == r[1] && l[2] == r[2] && l[3] == r[3] ); } 214 | 215 | 216 | inline bool operator!=(const Quaternion& l, const Quaternion& r) 217 | { return !(l == r); } 218 | 219 | 220 | inline Quaternion operator+(const Quaternion& l, const Quaternion& r) 221 | { return Quaternion(l[0]+r[0], l[1]+r[1], l[2]+r[2], l[3]+r[3]); } 222 | 223 | 224 | inline Quaternion operator*(const Quaternion& l, const Quaternion& r) 225 | { 226 | float w = l[0]*r[0] - l[1]*r[1] - l[2]*r[2] - l[3]*r[3]; 227 | float x = l[0]*r[1] + l[1]*r[0] + l[2]*r[3] - l[3]*r[2]; 228 | float y = l[0]*r[2] + l[2]*r[0] + l[3]*r[1] - l[1]*r[3]; 229 | float z = l[0]*r[3] + l[3]*r[0] + l[1]*r[2] - l[2]*r[1]; 230 | return Quaternion( w, x, y, z ); 231 | } 232 | 233 | inline float dot( const Quaternion& l, const Quaternion& r ) 234 | { 235 | return l.w()*r.w() + l.x()*r.x() + l.y()*r.y() + l.z()*r.z(); 236 | } 237 | 238 | 239 | inline Matrix4x4 Quaternion::rotationMatrix() const 240 | { 241 | Matrix4x4 m; 242 | 243 | const float qw = q[0]; 244 | const float qx = q[1]; 245 | const float qy = q[2]; 246 | const float qz = q[3]; 247 | 248 | m[0*4+0] = 1.0f - 2.0f*qy*qy - 2.0f*qz*qz; 249 | m[0*4+1] = 2.0f*qx*qy - 2.0f*qz*qw; 250 | m[0*4+2] = 2.0f*qx*qz + 2.0f*qy*qw; 251 | m[0*4+3] = 0.0f; 252 | 253 | m[1*4+0] = 2.0f*qx*qy + 2.0f*qz*qw; 254 | m[1*4+1] = 1.0f - 2.0f*qx*qx - 2.0f*qz*qz; 255 | m[1*4+2] = 2.0f*qy*qz - 2.0f*qx*qw; 256 | m[1*4+3] = 0.0f; 257 | 258 | m[2*4+0] = 2.0f*qx*qz - 2.0f*qy*qw; 259 | m[2*4+1] = 2.0f*qy*qz + 2.0f*qx*qw; 260 | m[2*4+2] = 1.0f - 2.0f*qx*qx - 2.0f*qy*qy; 261 | m[2*4+3] = 0.0f; 262 | 263 | m[3*4+0] = 0.0f; 264 | m[3*4+1] = 0.0f; 265 | m[3*4+2] = 0.0f; 266 | m[3*4+3] = 1.0f; 267 | 268 | return m; 269 | } 270 | 271 | } // end namespace sutil 272 | -------------------------------------------------------------------------------- /fredholm/include/fredholm/shared.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include "fredholm/arhosek.h" 6 | #include "sutil/vec_math.h" 7 | 8 | namespace fredholm 9 | { 10 | 11 | struct Matrix3x4 { 12 | // column major 13 | float4 m[3]; 14 | }; 15 | 16 | // TODO: rename c(column) to r(row) 17 | __forceinline__ __host__ __device__ Matrix3x4 make_mat3x4(const float4& c0, 18 | const float4& c1, 19 | const float4& c2) 20 | { 21 | Matrix3x4 m; 22 | m.m[0] = c0; 23 | m.m[1] = c1; 24 | m.m[2] = c2; 25 | return m; 26 | } 27 | 28 | __forceinline__ __host__ __device__ float3 29 | transform_position(const Matrix3x4& m, const float3& p) 30 | { 31 | const float4 v = make_float4(p.x, p.y, p.z, 1.0f); 32 | return make_float3(dot(m.m[0], v), dot(m.m[1], v), dot(m.m[2], v)); 33 | } 34 | 35 | __forceinline__ __host__ __device__ float3 36 | transform_direction(const Matrix3x4& m, const float3& v) 37 | { 38 | const float4 t = make_float4(v.x, v.y, v.z, 0.0f); 39 | return make_float3(dot(m.m[0], t), dot(m.m[1], t), dot(m.m[2], t)); 40 | } 41 | 42 | __forceinline__ __host__ __device__ float3 transform_normal(const Matrix3x4& m, 43 | const float3& n) 44 | { 45 | const float4 c0 = make_float4(m.m[0].x, m.m[1].x, m.m[2].x, 0.0f); 46 | const float4 c1 = make_float4(m.m[0].y, m.m[1].y, m.m[2].y, 0.0f); 47 | const float4 c2 = make_float4(m.m[0].z, m.m[1].z, m.m[2].z, 0.0f); 48 | const float4 t = make_float4(n.x, n.y, n.z, 0.0f); 49 | return make_float3(dot(c0, t), dot(c1, t), dot(c2, t)); 50 | } 51 | 52 | enum class RayType : unsigned int { 53 | RAY_TYPE_RADIANCE = 0, 54 | RAY_TYPE_SHADOW = 1, 55 | RAY_TYPE_LIGHT = 2, 56 | RAY_TYPE_COUNT 57 | }; 58 | 59 | struct CameraParams { 60 | Matrix3x4 transform; 61 | float fov; 62 | float F; // F number 63 | float focus; // focus distance 64 | }; 65 | 66 | struct PCGState { 67 | unsigned long long state = 0; 68 | unsigned long long inc = 1; 69 | }; 70 | 71 | struct SobolState { 72 | unsigned long long index = 0; 73 | unsigned int dimension = 0; 74 | unsigned int seed = 0; 75 | }; 76 | 77 | struct CMJState { 78 | unsigned long long n_spp = 0; 79 | unsigned int scramble = 0; 80 | unsigned int depth = 0; 81 | unsigned int image_idx = 0; 82 | }; 83 | 84 | struct BlueNoiseState { 85 | int pixel_i = 0; 86 | int pixel_j = 0; 87 | int index = 0; 88 | int dimension = 0; 89 | }; 90 | 91 | struct SamplerState { 92 | PCGState pcg_state; 93 | SobolState sobol_state; 94 | CMJState cmj_state; 95 | BlueNoiseState blue_noise_state; 96 | }; 97 | 98 | // similar to arnold standard surface 99 | // https://autodesk.github.io/standard-surface/ 100 | struct Material { 101 | float diffuse = 1.0f; 102 | float3 base_color = make_float3(1, 1, 1); 103 | int base_color_texture_id = -1; 104 | float diffuse_roughness = 0.0f; 105 | 106 | float specular = 1.0f; 107 | float3 specular_color = make_float3(1, 1, 1); 108 | int specular_color_texture_id = -1; 109 | float specular_roughness = 0.2f; 110 | int specular_roughness_texture_id = -1; 111 | 112 | float metalness = 0; 113 | int metalness_texture_id = -1; 114 | 115 | int metallic_roughness_texture_id = -1; 116 | 117 | float coat = 0; 118 | int coat_texture_id = -1; 119 | float3 coat_color = make_float3(1, 1, 1); 120 | float coat_roughness = 0.1; 121 | int coat_roughness_texture_id = -1; 122 | 123 | float transmission = 0; 124 | float3 transmission_color = make_float3(1, 1, 1); 125 | 126 | float sheen = 0.0f; 127 | float3 sheen_color = make_float3(1.0f, 1.0f, 1.0f); 128 | float sheen_roughness = 0.3f; 129 | 130 | float subsurface = 0; 131 | float3 subsurface_color = make_float3(1.0f, 1.0f, 1.0f); 132 | 133 | float thin_walled = 0.0f; 134 | 135 | float emission = 0; 136 | float3 emission_color = make_float3(0, 0, 0); 137 | int emission_texture_id = -1; 138 | 139 | int heightmap_texture_id = -1; 140 | int normalmap_texture_id = -1; 141 | int alpha_texture_id = -1; 142 | }; 143 | 144 | struct TextureHeader { 145 | uint2 size; 146 | cudaTextureObject_t texture_object; 147 | }; 148 | 149 | struct AreaLight { 150 | uint3 indices; 151 | uint material_id; 152 | uint instance_idx; // instance id 153 | }; 154 | 155 | struct DirectionalLight { 156 | float3 le; // emission 157 | float3 dir; // direction 158 | float angle = 0; // angle size 159 | }; 160 | 161 | struct SurfaceInfo { 162 | float t; // ray tmax 163 | float3 x; // shading position 164 | float3 n_g; // geometric normal in world space 165 | float3 n_s; // shading normal in world space 166 | float2 barycentric; // barycentric coordinate 167 | float2 texcoord; // texture coordinate 168 | float3 tangent; // tangent vector in world space 169 | float3 bitangent; // bitangent vector in world space 170 | bool is_entering; 171 | }; 172 | 173 | struct ShadingParams { 174 | float diffuse = 1.0f; 175 | float3 base_color = make_float3(0, 0, 0); 176 | float diffuse_roughness = 0.0f; 177 | 178 | float specular = 1.0f; 179 | float3 specular_color = make_float3(0, 0, 0); 180 | float specular_roughness = 0.2f; 181 | 182 | float metalness = 0.0f; 183 | 184 | float coat = 0.0f; 185 | float3 coat_color = make_float3(1, 1, 1); 186 | float coat_roughness = 0.1f; 187 | 188 | float transmission = 0; 189 | float3 transmission_color = make_float3(1, 1, 1); 190 | 191 | float sheen = 0.0f; 192 | float3 sheen_color = make_float3(1.0f, 1.0f, 1.0f); 193 | float sheen_roughness = 0.3f; 194 | 195 | float subsurface = 0; 196 | float3 subsurface_color = make_float3(1.0f, 1.0f, 1.0f); 197 | 198 | float thin_walled = 0.0f; 199 | }; 200 | 201 | struct RenderLayer { 202 | float4* beauty; 203 | float4* position; 204 | float* depth; 205 | float4* normal; 206 | float4* texcoord; 207 | float4* albedo; 208 | }; 209 | 210 | struct LaunchParams { 211 | RenderLayer render_layer; 212 | uint* sample_count; 213 | uint seed; 214 | 215 | uint width; 216 | uint height; 217 | uint n_samples; 218 | uint max_depth; 219 | 220 | CameraParams camera; 221 | 222 | Matrix3x4* object_to_world; 223 | Matrix3x4* world_to_object; 224 | 225 | float3* vertices; 226 | float3* normals; 227 | float2* texcoords; 228 | 229 | Material* materials; 230 | TextureHeader* textures; 231 | 232 | AreaLight* lights; 233 | uint n_lights; 234 | 235 | DirectionalLight* directional_light; 236 | 237 | float sky_intensity; 238 | float3 bg_color; 239 | cudaTextureObject_t ibl; 240 | float3 sun_direction; 241 | ArHosekSkyModelState* arhosek; 242 | 243 | OptixTraversableHandle ias_handle; 244 | }; 245 | 246 | struct RayGenSbtRecordData { 247 | }; 248 | 249 | struct MissSbtRecordData { 250 | }; 251 | 252 | struct HitGroupSbtRecordData { 253 | uint3* indices; 254 | uint* material_ids; 255 | }; 256 | 257 | template 258 | struct SbtRecord { 259 | __align__( 260 | OPTIX_SBT_RECORD_ALIGNMENT) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; 261 | T data; 262 | }; 263 | 264 | using RayGenSbtRecord = SbtRecord; 265 | using MissSbtRecord = SbtRecord; 266 | using HitGroupSbtRecord = SbtRecord; 267 | 268 | // *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org 269 | // Licensed under Apache License 2.0 (NO WARRANTY, etc. see website) 270 | static __forceinline__ __device__ __host__ uint pcg32_random_r(PCGState* rng) 271 | { 272 | unsigned long long oldstate = rng->state; 273 | // Advance internal state 274 | rng->state = oldstate * 6364136223846793005ULL + (rng->inc | 1); 275 | // Calculate output function (XSH RR), uses old state for max ILP 276 | uint xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; 277 | uint rot = oldstate >> 59u; 278 | return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); 279 | } 280 | 281 | // https://www.shadertoy.com/view/XlGcRh 282 | static __forceinline__ __device__ __host__ uint xxhash32(uint p) 283 | { 284 | const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U; 285 | const uint PRIME32_4 = 668265263U, PRIME32_5 = 374761393U; 286 | uint h32 = p + PRIME32_5; 287 | h32 = PRIME32_4 * ((h32 << 17) | (h32 >> (32 - 17))); 288 | h32 = PRIME32_2 * (h32 ^ (h32 >> 15)); 289 | h32 = PRIME32_3 * (h32 ^ (h32 >> 13)); 290 | return h32 ^ (h32 >> 16); 291 | } 292 | 293 | static __forceinline__ __device__ __host__ uint xxhash32(const uint3& p) 294 | { 295 | const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U; 296 | const uint PRIME32_4 = 668265263U, PRIME32_5 = 374761393U; 297 | uint h32 = p.z + PRIME32_5 + p.x * PRIME32_3; 298 | h32 = PRIME32_4 * ((h32 << 17) | (h32 >> (32 - 17))); 299 | h32 += p.y * PRIME32_3; 300 | h32 = PRIME32_4 * ((h32 << 17) | (h32 >> (32 - 17))); 301 | h32 = PRIME32_2 * (h32 ^ (h32 >> 15)); 302 | h32 = PRIME32_3 * (h32 ^ (h32 >> 13)); 303 | return h32 ^ (h32 >> 16); 304 | } 305 | 306 | static __forceinline__ __device__ __host__ uint xxhash32(const uint4& p) 307 | { 308 | const uint PRIME32_2 = 2246822519U, PRIME32_3 = 3266489917U; 309 | const uint PRIME32_4 = 668265263U, PRIME32_5 = 374761393U; 310 | uint h32 = p.w + PRIME32_5 + p.x * PRIME32_3; 311 | h32 = PRIME32_4 * ((h32 << 17) | (h32 >> (32 - 17))); 312 | h32 += p.y * PRIME32_3; 313 | h32 = PRIME32_4 * ((h32 << 17) | (h32 >> (32 - 17))); 314 | h32 += p.z * PRIME32_3; 315 | h32 = PRIME32_4 * ((h32 << 17) | (h32 >> (32 - 17))); 316 | h32 = PRIME32_2 * (h32 ^ (h32 >> 15)); 317 | h32 = PRIME32_3 * (h32 ^ (h32 >> 13)); 318 | return h32 ^ (h32 >> 16); 319 | } 320 | 321 | } // namespace fredholm -------------------------------------------------------------------------------- /externals/sutil/sutil/GLDisplay.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | #include 30 | #include 31 | 32 | #include 33 | 34 | namespace sutil 35 | { 36 | 37 | //----------------------------------------------------------------------------- 38 | // 39 | // Helper functions 40 | // 41 | //----------------------------------------------------------------------------- 42 | namespace 43 | { 44 | 45 | GLuint createGLShader( const std::string& source, GLuint shader_type ) 46 | { 47 | GLuint shader = glCreateShader( shader_type ); 48 | { 49 | const GLchar* source_data= reinterpret_cast( source.data() ); 50 | glShaderSource( shader, 1, &source_data, nullptr ); 51 | glCompileShader( shader ); 52 | 53 | GLint is_compiled = 0; 54 | glGetShaderiv( shader, GL_COMPILE_STATUS, &is_compiled ); 55 | if( is_compiled == GL_FALSE ) 56 | { 57 | GLint max_length = 0; 58 | glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &max_length ); 59 | 60 | std::string info_log( max_length, '\0' ); 61 | GLchar* info_log_data= reinterpret_cast( &info_log[0]); 62 | glGetShaderInfoLog( shader, max_length, nullptr, info_log_data ); 63 | 64 | glDeleteShader(shader); 65 | std::cerr << "Compilation of shader failed: " << info_log << std::endl; 66 | 67 | return 0; 68 | } 69 | } 70 | 71 | GL_CHECK_ERRORS(); 72 | 73 | return shader; 74 | } 75 | 76 | 77 | GLuint createGLProgram( 78 | const std::string& vert_source, 79 | const std::string& frag_source 80 | ) 81 | { 82 | GLuint vert_shader = createGLShader( vert_source, GL_VERTEX_SHADER ); 83 | if( vert_shader == 0 ) 84 | return 0; 85 | 86 | GLuint frag_shader = createGLShader( frag_source, GL_FRAGMENT_SHADER ); 87 | if( frag_shader == 0 ) 88 | { 89 | glDeleteShader( vert_shader ); 90 | return 0; 91 | } 92 | 93 | GLuint program = glCreateProgram(); 94 | glAttachShader( program, vert_shader ); 95 | glAttachShader( program, frag_shader ); 96 | glLinkProgram( program ); 97 | 98 | GLint is_linked = 0; 99 | glGetProgramiv( program, GL_LINK_STATUS, &is_linked ); 100 | if (is_linked == GL_FALSE) 101 | { 102 | GLint max_length = 0; 103 | glGetProgramiv( program, GL_INFO_LOG_LENGTH, &max_length ); 104 | 105 | std::string info_log( max_length, '\0' ); 106 | GLchar* info_log_data= reinterpret_cast( &info_log[0]); 107 | glGetProgramInfoLog( program, max_length, nullptr, info_log_data ); 108 | std::cerr << "Linking of program failed: " << info_log << std::endl; 109 | 110 | glDeleteProgram( program ); 111 | glDeleteShader( vert_shader ); 112 | glDeleteShader( frag_shader ); 113 | 114 | return 0; 115 | } 116 | 117 | glDetachShader( program, vert_shader ); 118 | glDetachShader( program, frag_shader ); 119 | 120 | GL_CHECK_ERRORS(); 121 | 122 | return program; 123 | } 124 | 125 | 126 | GLint getGLUniformLocation( GLuint program, const std::string& name ) 127 | { 128 | GLint loc = glGetUniformLocation( program, name.c_str() ); 129 | SUTIL_ASSERT_MSG( loc != -1, "Failed to get uniform loc for '" + name + "'" ); 130 | return loc; 131 | } 132 | 133 | } // anonymous namespace 134 | 135 | 136 | //----------------------------------------------------------------------------- 137 | // 138 | // GLDisplay implementation 139 | // 140 | //----------------------------------------------------------------------------- 141 | 142 | const std::string GLDisplay::s_vert_source = R"( 143 | #version 330 core 144 | 145 | layout(location = 0) in vec3 vertexPosition_modelspace; 146 | out vec2 UV; 147 | 148 | void main() 149 | { 150 | gl_Position = vec4(vertexPosition_modelspace,1); 151 | UV = (vec2( vertexPosition_modelspace.x, vertexPosition_modelspace.y )+vec2(1,1))/2.0; 152 | } 153 | )"; 154 | 155 | const std::string GLDisplay::s_frag_source = R"( 156 | #version 330 core 157 | 158 | in vec2 UV; 159 | out vec3 color; 160 | 161 | uniform sampler2D render_tex; 162 | uniform bool correct_gamma; 163 | 164 | void main() 165 | { 166 | color = texture( render_tex, UV ).xyz; 167 | } 168 | )"; 169 | 170 | 171 | 172 | GLDisplay::GLDisplay( BufferImageFormat image_format ) 173 | : m_image_format( image_format ) 174 | { 175 | GLuint m_vertex_array; 176 | GL_CHECK( glGenVertexArrays(1, &m_vertex_array ) ); 177 | GL_CHECK( glBindVertexArray( m_vertex_array ) ); 178 | 179 | m_program = createGLProgram( s_vert_source, s_frag_source ); 180 | m_render_tex_uniform_loc = getGLUniformLocation( m_program, "render_tex"); 181 | 182 | GL_CHECK( glGenTextures( 1, &m_render_tex ) ); 183 | GL_CHECK( glBindTexture( GL_TEXTURE_2D, m_render_tex ) ); 184 | 185 | GL_CHECK( glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ) ); 186 | GL_CHECK( glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ) ); 187 | GL_CHECK( glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ) ); 188 | GL_CHECK( glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ) ); 189 | 190 | static const GLfloat g_quad_vertex_buffer_data[] = { 191 | -1.0f, -1.0f, 0.0f, 192 | 1.0f, -1.0f, 0.0f, 193 | -1.0f, 1.0f, 0.0f, 194 | 195 | -1.0f, 1.0f, 0.0f, 196 | 1.0f, -1.0f, 0.0f, 197 | 1.0f, 1.0f, 0.0f, 198 | }; 199 | 200 | GL_CHECK( glGenBuffers( 1, &m_quad_vertex_buffer ) ); 201 | GL_CHECK( glBindBuffer( GL_ARRAY_BUFFER, m_quad_vertex_buffer ) ); 202 | GL_CHECK( glBufferData( GL_ARRAY_BUFFER, 203 | sizeof( g_quad_vertex_buffer_data), 204 | g_quad_vertex_buffer_data, 205 | GL_STATIC_DRAW 206 | ) 207 | ); 208 | 209 | GL_CHECK_ERRORS(); 210 | } 211 | 212 | 213 | void GLDisplay::display( 214 | const int32_t screen_res_x, 215 | const int32_t screen_res_y, 216 | const int32_t framebuf_res_x, 217 | const int32_t framebuf_res_y, 218 | const uint32_t pbo 219 | ) const 220 | { 221 | GL_CHECK( glBindFramebuffer( GL_FRAMEBUFFER, 0 ) ); 222 | GL_CHECK( glViewport( 0, 0, framebuf_res_x, framebuf_res_y ) ); 223 | 224 | GL_CHECK( glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ); 225 | 226 | GL_CHECK( glUseProgram( m_program ) ); 227 | 228 | // Bind our texture in Texture Unit 0 229 | GL_CHECK( glActiveTexture( GL_TEXTURE0 ) ); 230 | GL_CHECK( glBindTexture( GL_TEXTURE_2D, m_render_tex ) ); 231 | GL_CHECK( glBindBuffer( GL_PIXEL_UNPACK_BUFFER, pbo ) ); 232 | 233 | GL_CHECK( glPixelStorei(GL_UNPACK_ALIGNMENT, 4) ); // TODO!!!!!! 234 | 235 | size_t elmt_size = pixelFormatSize( m_image_format ); 236 | if ( elmt_size % 8 == 0) glPixelStorei(GL_UNPACK_ALIGNMENT, 8); 237 | else if ( elmt_size % 4 == 0) glPixelStorei(GL_UNPACK_ALIGNMENT, 4); 238 | else if ( elmt_size % 2 == 0) glPixelStorei(GL_UNPACK_ALIGNMENT, 2); 239 | else glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 240 | 241 | bool convertToSrgb = true; 242 | 243 | if( m_image_format == BufferImageFormat::UNSIGNED_BYTE4 ) 244 | { 245 | // input is assumed to be in srgb since it is only 1 byte per channel in size 246 | glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, screen_res_x, screen_res_y, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr ); 247 | convertToSrgb = false; 248 | } 249 | else if( m_image_format == BufferImageFormat::FLOAT3 ) 250 | glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB32F, screen_res_x, screen_res_y, 0, GL_RGB, GL_FLOAT, nullptr ); 251 | 252 | else if( m_image_format == BufferImageFormat::FLOAT4 ) 253 | glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA32F, screen_res_x, screen_res_y, 0, GL_RGBA, GL_FLOAT, nullptr ); 254 | 255 | else 256 | throw Exception( "Unknown buffer format" ); 257 | 258 | GL_CHECK( glBindBuffer( GL_PIXEL_UNPACK_BUFFER, 0 ) ); 259 | GL_CHECK( glUniform1i( m_render_tex_uniform_loc , 0 ) ); 260 | 261 | // 1st attribute buffer : vertices 262 | GL_CHECK( glEnableVertexAttribArray( 0 ) ); 263 | GL_CHECK( glBindBuffer(GL_ARRAY_BUFFER, m_quad_vertex_buffer ) ); 264 | GL_CHECK( glVertexAttribPointer( 265 | 0, // attribute 0. No particular reason for 0, but must match the layout in the shader. 266 | 3, // size 267 | GL_FLOAT, // type 268 | GL_FALSE, // normalized? 269 | 0, // stride 270 | (void*)0 // array buffer offset 271 | ) 272 | ); 273 | 274 | if( convertToSrgb ) 275 | GL_CHECK( glEnable( GL_FRAMEBUFFER_SRGB ) ); 276 | else 277 | GL_CHECK( glDisable( GL_FRAMEBUFFER_SRGB ) ); 278 | 279 | // Draw the triangles ! 280 | GL_CHECK( glDrawArrays(GL_TRIANGLES, 0, 6) ); // 2*3 indices starting at 0 -> 2 triangles 281 | 282 | GL_CHECK( glDisableVertexAttribArray(0) ); 283 | 284 | GL_CHECK( glDisable( GL_FRAMEBUFFER_SRGB ) ); 285 | 286 | GL_CHECK_ERRORS(); 287 | } 288 | 289 | } // namespace sutil 290 | -------------------------------------------------------------------------------- /externals/sutil/sutil/PPMLoader.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | //----------------------------------------------------------------------------- 42 | // 43 | // PPMLoader class definition 44 | // 45 | //----------------------------------------------------------------------------- 46 | 47 | 48 | PPMLoader::PPMLoader( const std::string& filename, const bool vflip ) 49 | : m_nx( 0u ) 50 | , m_ny( 0u ) 51 | , m_max_val( 0u ) 52 | , m_raster( 0 ) 53 | , m_is_ascii( false ) 54 | { 55 | if( filename.empty() ) 56 | return; 57 | 58 | size_t pos; 59 | std::string extension; 60 | if( ( pos = filename.find_last_of( '.' ) ) != std::string::npos ) 61 | extension = filename.substr( pos ); 62 | if( !( extension == ".ppm" || extension == ".PPM" ) ) 63 | { 64 | std::cerr << "PPMLoader( '" << filename << "' ) non-ppm file extension given '" << extension << "'" << std::endl; 65 | return; 66 | } 67 | 68 | // Open file 69 | try 70 | { 71 | std::ifstream file_in( filename.c_str(), std::ifstream::in | std::ifstream::binary ); 72 | if( !file_in ) 73 | { 74 | std::cerr << "PPMLoader( '" << filename << "' ) failed to open file." << std::endl; 75 | return; 76 | } 77 | 78 | // Check magic number to make sure we have an ascii or binary PPM 79 | std::string line, magic_number; 80 | getLine( file_in, line ); 81 | std::istringstream iss1( line ); 82 | iss1 >> magic_number; 83 | if( magic_number != "P6" && magic_number != "P3" ) 84 | { 85 | std::cerr << "PPMLoader( '" << filename << "' ) unknown magic number: " << magic_number 86 | << ". Only P3 and P6 supported." << std::endl; 87 | return; 88 | } 89 | if( magic_number == "P3" ) 90 | { 91 | m_is_ascii = true; 92 | } 93 | 94 | // width, height 95 | getLine( file_in, line ); 96 | std::istringstream iss2( line ); 97 | iss2 >> m_nx >> m_ny; 98 | 99 | // max channel value 100 | getLine( file_in, line ); 101 | std::istringstream iss3( line ); 102 | iss3 >> m_max_val; 103 | 104 | m_raster = new( std::nothrow ) unsigned char[m_nx * m_ny * 3]; 105 | if( m_is_ascii ) 106 | { 107 | unsigned int num_elements = m_nx * m_ny * 3; 108 | unsigned int count = 0; 109 | 110 | while( count < num_elements ) 111 | { 112 | getLine( file_in, line ); 113 | std::istringstream iss( line ); 114 | 115 | while( iss.good() ) 116 | { 117 | unsigned int c; 118 | iss >> c; 119 | m_raster[count++] = static_cast( c ); 120 | } 121 | } 122 | } 123 | else 124 | { 125 | file_in.read( reinterpret_cast( m_raster ), m_nx * m_ny * 3 ); 126 | } 127 | 128 | if( vflip ) 129 | { 130 | for( unsigned int y2 = m_ny - 1, y = 0; y < y2; y2--, y++ ) 131 | { 132 | for( unsigned int x = 0; x < m_nx * 3; x++ ) 133 | { 134 | unsigned char temp = m_raster[y * m_nx * 3 + x]; 135 | m_raster[y * m_nx * 3 + x] = m_raster[y2 * m_nx * 3 + x]; 136 | m_raster[y2 * m_nx * 3 + x] = temp; 137 | } 138 | } 139 | } 140 | } 141 | catch( ... ) 142 | { 143 | std::cerr << "PPMLoader( '" << filename << "' ) failed to load" << std::endl; 144 | m_raster = 0; 145 | } 146 | } 147 | 148 | 149 | PPMLoader::~PPMLoader() 150 | { 151 | if( m_raster ) 152 | delete[] m_raster; 153 | } 154 | 155 | 156 | bool PPMLoader::failed() const 157 | { 158 | return m_raster == 0; 159 | } 160 | 161 | 162 | unsigned int PPMLoader::width() const 163 | { 164 | return m_nx; 165 | } 166 | 167 | 168 | unsigned int PPMLoader::height() const 169 | { 170 | return m_ny; 171 | } 172 | 173 | 174 | unsigned char* PPMLoader::raster() const 175 | { 176 | return m_raster; 177 | } 178 | 179 | 180 | void PPMLoader::getLine( std::ifstream& file_in, std::string& s ) 181 | { 182 | for( ;; ) 183 | { 184 | if( !std::getline( file_in, s ) ) 185 | return; 186 | std::string::size_type index = s.find_first_not_of( "\n\r\t " ); 187 | if( index != std::string::npos && s[index] != '#' ) 188 | break; 189 | } 190 | } 191 | 192 | 193 | //----------------------------------------------------------------------------- 194 | // 195 | // Utility functions 196 | // 197 | //----------------------------------------------------------------------------- 198 | float clamp( float f, float a, float b ) 199 | { 200 | return std::max( a, std::min( f, b ) ); 201 | } 202 | 203 | sutil::Texture PPMLoader::loadTexture( const float3& default_color, cudaTextureDesc* tex_desc ) 204 | { 205 | std::vector buffer; 206 | const unsigned int nx = width(); 207 | const unsigned int ny = height(); 208 | if( failed() ) 209 | { 210 | buffer.resize( 4 ); 211 | 212 | // Create buffer with single texel set to default_color 213 | constexpr float gamma = 2.2f; 214 | // multiplying by 255.5 and rounding down is a good trade-off when compressing a float to [0,255]. 215 | buffer[0] = static_cast( (int)( powf( clamp( default_color.x, 0.0f, 1.0f ), 1.0f / gamma ) * 255.5f ) ); 216 | buffer[1] = static_cast( (int)( powf( clamp( default_color.y, 0.0f, 1.0f ), 1.0f / gamma ) * 255.5f ) ); 217 | buffer[2] = static_cast( (int)( powf( clamp( default_color.z, 0.0f, 1.0f ), 1.0f / gamma ) * 255.5f ) ); 218 | buffer[3] = 255; 219 | } 220 | else 221 | { 222 | buffer.resize( 4 * nx * ny ); 223 | 224 | for( unsigned int i = 0; i < nx; ++i ) 225 | { 226 | for( unsigned int j = 0; j < ny; ++j ) 227 | { 228 | 229 | unsigned int ppm_index = ( ( ny - j - 1 ) * nx + i ) * 3; 230 | unsigned int buf_index = ( (j)*nx + i ) * 4; 231 | 232 | buffer[buf_index + 0] = raster()[ppm_index + 0]; 233 | buffer[buf_index + 1] = raster()[ppm_index + 1]; 234 | buffer[buf_index + 2] = raster()[ppm_index + 2]; 235 | buffer[buf_index + 3] = 255; 236 | } 237 | } 238 | } 239 | 240 | // Allocate CUDA array in device memory 241 | int32_t pitch = nx * 4 * sizeof( unsigned char ); 242 | cudaChannelFormatDesc channel_desc = cudaCreateChannelDesc(); 243 | 244 | cudaArray_t cuda_array = nullptr; 245 | CUDA_CHECK( cudaMallocArray( &cuda_array, &channel_desc, nx, ny ) ); 246 | CUDA_CHECK( cudaMemcpy2DToArray( cuda_array, 0, 0, buffer.data(), pitch, pitch, ny, cudaMemcpyHostToDevice ) ); 247 | 248 | // Create texture object 249 | cudaResourceDesc res_desc = {}; 250 | res_desc.resType = cudaResourceTypeArray; 251 | res_desc.res.array.array = cuda_array; 252 | 253 | cudaTextureDesc default_tex_desc = {}; 254 | if( tex_desc == nullptr ) 255 | { 256 | default_tex_desc.addressMode[0] = cudaAddressModeWrap; 257 | default_tex_desc.addressMode[1] = cudaAddressModeWrap; 258 | default_tex_desc.filterMode = cudaFilterModeLinear; 259 | default_tex_desc.readMode = cudaReadModeNormalizedFloat; 260 | default_tex_desc.normalizedCoords = 1; 261 | default_tex_desc.maxAnisotropy = 1; 262 | default_tex_desc.maxMipmapLevelClamp = 99; 263 | default_tex_desc.minMipmapLevelClamp = 0; 264 | default_tex_desc.mipmapFilterMode = cudaFilterModePoint; 265 | default_tex_desc.borderColor[0] = 1.0f; 266 | default_tex_desc.sRGB = 1; // ppm files are in sRGB space according to specification 267 | 268 | tex_desc = &default_tex_desc; 269 | } 270 | 271 | // Create texture object 272 | cudaTextureObject_t cuda_tex = 0; 273 | CUDA_CHECK( cudaCreateTextureObject( &cuda_tex, &res_desc, tex_desc, nullptr ) ); 274 | 275 | sutil::Texture ppm_texture = {cuda_array, cuda_tex}; 276 | return ppm_texture; 277 | } 278 | 279 | 280 | //----------------------------------------------------------------------------- 281 | // 282 | // Utility functions 283 | // 284 | //----------------------------------------------------------------------------- 285 | 286 | sutil::Texture loadPPMTexture( const std::string& filename, const float3& default_color, cudaTextureDesc* tex_desc ) 287 | { 288 | PPMLoader ppm( filename ); 289 | return ppm.loadTexture( default_color, tex_desc ); 290 | } 291 | 292 | -------------------------------------------------------------------------------- /app/rtcamp8.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "cwl/buffer.h" 9 | #include "cwl/util.h" 10 | #include "fredholm/denoiser.h" 11 | #include "fredholm/renderer.h" 12 | #include "kernels/post-process.h" 13 | #include "optwl/optwl.h" 14 | #include "spdlog/spdlog.h" 15 | #include "stb_image_write.h" 16 | 17 | inline float deg2rad(float deg) { return deg / 180.0f * M_PI; } 18 | 19 | class Timer 20 | { 21 | public: 22 | Timer() {} 23 | 24 | void start() { m_start = std::chrono::steady_clock::now(); } 25 | 26 | void end() { m_end = std::chrono::steady_clock::now(); } 27 | 28 | template 29 | int elapsed() const 30 | { 31 | return std::chrono::duration_cast(std::chrono::steady_clock::now() - 32 | m_start) 33 | .count(); 34 | } 35 | 36 | template 37 | int duration() const 38 | { 39 | return std::chrono::duration_cast(m_end - m_start).count(); 40 | } 41 | 42 | private: 43 | std::chrono::steady_clock::time_point m_start; 44 | std::chrono::steady_clock::time_point m_end; 45 | }; 46 | 47 | int main() 48 | { 49 | const int width = 1920; 50 | const int height = 1080; 51 | const bool upscale = false; 52 | const int n_spp = 16; 53 | const std::string scene_filepath = 54 | "../resources/camera_animation_test/camera_animation_test.gltf"; 55 | 56 | const int max_depth = 5; 57 | const float ISO = 80.0f; 58 | const float chromatic_aberration = 1.0f; 59 | const float bloom_threshold = 2.0f; 60 | const float bloom_sigma = 5.0f; 61 | const float max_time = 9.5f; 62 | const float fps = 24.0f; 63 | const float time_step = 1.0f / fps; 64 | const int kill_time = 590; 65 | 66 | const int width_denoised = upscale ? 2 * width : width; 67 | const int height_denoised = upscale ? 2 * height : height; 68 | 69 | // if global timer elapsed greater than kill time, program will exit 70 | // immediately 71 | Timer global_timer; 72 | global_timer.start(); 73 | 74 | // init CUDA 75 | CUDA_CHECK(cudaFree(0)); 76 | optwl::Context context; 77 | 78 | // init renderer 79 | fredholm::Renderer renderer(context.m_context); 80 | renderer.create_module("./fredholm/CMakeFiles/modules.dir/modules/pt.ptx"); 81 | renderer.create_program_group(); 82 | renderer.create_pipeline(); 83 | renderer.set_resolution(width, height); 84 | 85 | // init render layers 86 | cwl::CUDABuffer layer_beauty = 87 | cwl::CUDABuffer(width * height); 88 | cwl::CUDABuffer layer_position = 89 | cwl::CUDABuffer(width * height); 90 | cwl::CUDABuffer layer_normal = 91 | cwl::CUDABuffer(width * height); 92 | cwl::CUDABuffer layer_depth = cwl::CUDABuffer(width * height); 93 | cwl::CUDABuffer layer_texcoord = 94 | cwl::CUDABuffer(width * height); 95 | cwl::CUDABuffer layer_albedo = 96 | cwl::CUDABuffer(width * height); 97 | cwl::CUDABuffer layer_denoised = 98 | cwl::CUDABuffer(width_denoised * height_denoised); 99 | 100 | cwl::CUDABuffer layer_beauty_pp = 101 | cwl::CUDABuffer(width * height); 102 | cwl::CUDABuffer layer_denoised_pp = 103 | cwl::CUDABuffer(width_denoised * height_denoised); 104 | 105 | cwl::CUDABuffer beauty_high_luminance = 106 | cwl::CUDABuffer(width * height); 107 | cwl::CUDABuffer denoised_high_luminance = 108 | cwl::CUDABuffer(width_denoised * height_denoised); 109 | cwl::CUDABuffer beauty_temp = cwl::CUDABuffer(width * height); 110 | cwl::CUDABuffer denoised_temp = 111 | cwl::CUDABuffer(width_denoised * height_denoised); 112 | 113 | // init denoiser 114 | fredholm::Denoiser denoiser = fredholm::Denoiser( 115 | context.m_context, width, height, layer_beauty.get_device_ptr(), 116 | layer_normal.get_device_ptr(), layer_albedo.get_device_ptr(), 117 | layer_denoised.get_device_ptr(), upscale); 118 | 119 | // load scene 120 | renderer.load_scene("../resources/rtcamp8/rtcamp8.obj"); 121 | renderer.load_scene("../resources/rtcamp8/rtcamp8_camera.gltf", false); 122 | renderer.build_gas(); 123 | renderer.build_ias(); 124 | renderer.create_sbt(); 125 | 126 | // init camera 127 | fredholm::Camera camera; 128 | camera.m_fov = deg2rad(60.0f); 129 | camera.m_F = 100.0f; 130 | camera.m_focus = 8.0f; 131 | 132 | // init render layer 133 | fredholm::RenderLayer render_layer; 134 | render_layer.beauty = layer_beauty.get_device_ptr(); 135 | render_layer.position = layer_position.get_device_ptr(); 136 | render_layer.normal = layer_normal.get_device_ptr(); 137 | render_layer.depth = layer_depth.get_device_ptr(); 138 | render_layer.texcoord = layer_texcoord.get_device_ptr(); 139 | render_layer.albedo = layer_albedo.get_device_ptr(); 140 | 141 | // set directional light 142 | renderer.set_directional_light(make_float3(20, 20, 20), 143 | make_float3(-0.1f, 1, 0.1f), 1.0f); 144 | 145 | // set arhosek sky 146 | renderer.load_arhosek_sky(3.0f, 0.3f); 147 | 148 | Timer render_timer; 149 | Timer denoiser_timer; 150 | Timer pp_timer; 151 | Timer transfer_timer; 152 | Timer convert_timer; 153 | Timer save_timer; 154 | 155 | std::queue>> queue; 156 | std::mutex queue_mutex; 157 | bool render_finished = false; 158 | 159 | std::thread render_thread([&] { 160 | int frame_idx = 0; 161 | float time = 0.0f; 162 | 163 | while (true) { 164 | spdlog::info("[Render] rendering frame: {}", frame_idx); 165 | 166 | if (time > max_time || 167 | global_timer.elapsed() > kill_time) { 168 | render_finished = true; 169 | break; 170 | } 171 | 172 | // clear render layers 173 | layer_beauty.clear(); 174 | layer_position.clear(); 175 | layer_normal.clear(); 176 | layer_depth.clear(); 177 | layer_texcoord.clear(); 178 | layer_albedo.clear(); 179 | 180 | // clear render states 181 | renderer.init_render_states(); 182 | 183 | // render 184 | render_timer.start(); 185 | renderer.set_time(time); 186 | renderer.render(camera, make_float3(0, 0, 0), render_layer, n_spp, 187 | max_depth); 188 | CUDA_SYNC_CHECK(); 189 | render_timer.end(); 190 | 191 | spdlog::info("[Render] rendering time: {}", 192 | render_timer.duration()); 193 | 194 | // denoise 195 | denoiser_timer.start(); 196 | denoiser.denoise(); 197 | CUDA_SYNC_CHECK(); 198 | denoiser_timer.end(); 199 | 200 | spdlog::info("[Render] denoising time: {}", 201 | denoiser_timer.duration()); 202 | 203 | // post process 204 | PostProcessParams params; 205 | params.use_bloom = true; 206 | params.bloom_threshold = bloom_threshold; 207 | params.bloom_sigma = bloom_sigma; 208 | params.chromatic_aberration = chromatic_aberration; 209 | params.ISO = ISO; 210 | 211 | pp_timer.start(); 212 | post_process_kernel_launch(layer_beauty.get_device_ptr(), 213 | beauty_high_luminance.get_device_ptr(), 214 | beauty_temp.get_device_ptr(), width, height, 215 | params, layer_beauty_pp.get_device_ptr()); 216 | post_process_kernel_launch(layer_denoised.get_device_ptr(), 217 | denoised_high_luminance.get_device_ptr(), 218 | denoised_temp.get_device_ptr(), width_denoised, 219 | height_denoised, params, 220 | layer_denoised_pp.get_device_ptr()); 221 | CUDA_SYNC_CHECK(); 222 | pp_timer.end(); 223 | 224 | spdlog::info("[Render] post process time: {}", 225 | pp_timer.duration()); 226 | 227 | // copy image from device to host 228 | std::vector image_f4; 229 | transfer_timer.start(); 230 | layer_denoised_pp.copy_from_device_to_host(image_f4); 231 | transfer_timer.end(); 232 | 233 | spdlog::info("[Render] transfer time: {}", 234 | transfer_timer.duration()); 235 | 236 | // add image to queue 237 | { 238 | std::lock_guard lock(queue_mutex); 239 | queue.push({frame_idx, image_f4}); 240 | } 241 | 242 | // go to next frame 243 | frame_idx++; 244 | time += time_step; 245 | } 246 | }); 247 | 248 | std::thread save_thread([&] { 249 | while (true) { 250 | if (global_timer.elapsed() > kill_time) { break; } 251 | if (render_finished && queue.empty()) { break; } 252 | 253 | if (queue.empty()) continue; 254 | 255 | // get image from queue 256 | int frame_idx; 257 | std::vector image_f4; 258 | { 259 | std::lock_guard lock(queue_mutex); 260 | frame_idx = queue.front().first; 261 | image_f4 = queue.front().second; 262 | queue.pop(); 263 | } 264 | 265 | // convert float image to uchar image 266 | convert_timer.start(); 267 | std::vector image_c4(width_denoised * height_denoised); 268 | for (int j = 0; j < height_denoised; ++j) { 269 | for (int i = 0; i < width_denoised; ++i) { 270 | const int idx = i + width_denoised * j; 271 | const float4& v = image_f4[idx]; 272 | image_c4[idx].x = static_cast( 273 | std::clamp(255.0f * v.x, 0.0f, 255.0f)); 274 | image_c4[idx].y = static_cast( 275 | std::clamp(255.0f * v.y, 0.0f, 255.0f)); 276 | image_c4[idx].z = static_cast( 277 | std::clamp(255.0f * v.z, 0.0f, 255.0f)); 278 | image_c4[idx].w = 255; 279 | } 280 | } 281 | convert_timer.end(); 282 | 283 | spdlog::info("[Image Write] convert time: {}", 284 | convert_timer.duration()); 285 | 286 | save_timer.start(); 287 | const std::string filename = 288 | "output/" + std::to_string(frame_idx) + ".png"; 289 | stbi_write_png(filename.c_str(), width_denoised, height_denoised, 4, 290 | image_c4.data(), sizeof(uchar4) * width_denoised); 291 | save_timer.end(); 292 | 293 | spdlog::info("[Image Write] {} saved", filename); 294 | spdlog::info("[Image Write] image save time: {}", 295 | save_timer.duration()); 296 | } 297 | }); 298 | 299 | render_thread.join(); 300 | save_thread.join(); 301 | 302 | return 0; 303 | } -------------------------------------------------------------------------------- /app/controller.cpp: -------------------------------------------------------------------------------- 1 | #include "controller.h" 2 | 3 | #include "cwl/buffer.h" 4 | #include "cwl/util.h" 5 | #include "kernels/post-process.h" 6 | #include "stb_image_write.h" 7 | 8 | Controller::Controller() 9 | { 10 | m_camera = std::make_unique(); 11 | 12 | // init CUDA 13 | CUDA_CHECK(cudaFree(0)); 14 | 15 | m_context = std::make_unique(); 16 | m_renderer = std::make_unique(m_context->m_context); 17 | } 18 | 19 | void Controller::init_camera() 20 | { 21 | const float3 origin = 22 | make_float3(m_imgui_origin[0], m_imgui_origin[1], m_imgui_origin[2]); 23 | m_camera = std::make_unique(origin, deg2rad(m_imgui_fov)); 24 | m_camera->m_fov = deg2rad(m_imgui_fov); 25 | m_camera->m_F = m_imgui_F; 26 | m_camera->m_focus = m_imgui_focus; 27 | m_camera->m_movement_speed = m_imgui_movement_speed; 28 | m_camera->m_look_around_speed = m_imgui_rotation_speed; 29 | } 30 | 31 | void Controller::update_camera() 32 | { 33 | m_camera->set_origin( 34 | make_float3(m_imgui_origin[0], m_imgui_origin[1], m_imgui_origin[2])); 35 | m_camera->m_fov = deg2rad(m_imgui_fov); 36 | m_camera->m_F = m_imgui_F; 37 | m_camera->m_focus = m_imgui_focus; 38 | m_camera->m_movement_speed = m_imgui_movement_speed; 39 | m_camera->m_look_around_speed = m_imgui_rotation_speed; 40 | } 41 | 42 | void Controller::move_camera(const fredholm::CameraMovement &direction, 43 | float dt) 44 | { 45 | m_camera->move(direction, dt); 46 | const float3 origin = m_camera->get_origin(); 47 | m_imgui_origin[0] = origin.x; 48 | m_imgui_origin[1] = origin.y; 49 | m_imgui_origin[2] = origin.z; 50 | } 51 | 52 | void Controller::rotate_camera(float dphi, float dtheta) 53 | { 54 | m_camera->lookAround(dphi, dtheta); 55 | // m_imgui_forward[0] = m_camera->m_forward.x; 56 | // m_imgui_forward[1] = m_camera->m_forward.y; 57 | // m_imgui_forward[2] = m_camera->m_forward.z; 58 | } 59 | 60 | void Controller::init_renderer() 61 | 62 | { 63 | m_renderer->create_module(std::filesystem::path(MODULES_SOURCE_DIR) / 64 | "pt.ptx"); 65 | m_renderer->create_program_group(); 66 | m_renderer->create_pipeline(); 67 | m_renderer->set_resolution(m_imgui_resolution[0], m_imgui_resolution[1]); 68 | } 69 | 70 | void Controller::init_denoiser() 71 | { 72 | m_layer_denoised = std::make_unique>( 73 | m_imgui_resolution[0] * m_imgui_resolution[1]); 74 | m_denoiser = std::make_unique( 75 | m_context->m_context, m_imgui_resolution[0], m_imgui_resolution[1], 76 | m_layer_beauty->get_device_ptr(), m_layer_normal->get_device_ptr(), 77 | m_layer_albedo->get_device_ptr(), m_layer_denoised->get_device_ptr()); 78 | } 79 | 80 | void Controller::init_render_layers() 81 | { 82 | m_layer_beauty = std::make_unique>( 83 | m_imgui_resolution[0] * m_imgui_resolution[1]); 84 | m_layer_position = std::make_unique>( 85 | m_imgui_resolution[0] * m_imgui_resolution[1]); 86 | m_layer_normal = std::make_unique>( 87 | m_imgui_resolution[0] * m_imgui_resolution[1]); 88 | m_layer_depth = std::make_unique>( 89 | m_imgui_resolution[0] * m_imgui_resolution[1]); 90 | m_layer_texcoord = std::make_unique>( 91 | m_imgui_resolution[0] * m_imgui_resolution[1]); 92 | m_layer_albedo = std::make_unique>( 93 | m_imgui_resolution[0] * m_imgui_resolution[1]); 94 | 95 | m_beauty_high_luminance = std::make_unique>( 96 | m_imgui_resolution[0] * m_imgui_resolution[1]); 97 | m_denoised_high_luminance = std::make_unique>( 98 | m_imgui_resolution[0] * m_imgui_resolution[1]); 99 | m_beauty_temp = std::make_unique>( 100 | m_imgui_resolution[0] * m_imgui_resolution[1]); 101 | m_denoised_temp = std::make_unique>( 102 | m_imgui_resolution[0] * m_imgui_resolution[1]); 103 | m_layer_beauty_pp = std::make_unique>( 104 | m_imgui_resolution[0] * m_imgui_resolution[1]); 105 | m_layer_denoised_pp = std::make_unique>( 106 | m_imgui_resolution[0] * m_imgui_resolution[1]); 107 | } 108 | 109 | void Controller::clear_render_layers() 110 | { 111 | m_layer_beauty->clear(); 112 | m_layer_position->clear(); 113 | m_layer_normal->clear(); 114 | m_layer_depth->clear(); 115 | m_layer_texcoord->clear(); 116 | m_layer_albedo->clear(); 117 | 118 | m_beauty_high_luminance->clear(); 119 | m_denoised_high_luminance->clear(); 120 | m_beauty_temp->clear(); 121 | m_denoised_temp->clear(); 122 | m_layer_beauty_pp->clear(); 123 | m_layer_denoised_pp->clear(); 124 | } 125 | 126 | void Controller::load_scene() 127 | { 128 | m_renderer->load_scene(scene_filepaths[m_imgui_scene_id]); 129 | // m_renderer->load_scene("../resources/rtcamp8/rtcamp8.obj"); 130 | // m_renderer->load_scene("../resources/rtcamp8/rtcamp8_camera.gltf", false); 131 | m_renderer->build_gas(); 132 | m_renderer->build_ias(); 133 | m_renderer->create_sbt(); 134 | } 135 | 136 | void Controller::update_directional_light() 137 | { 138 | m_renderer->set_directional_light( 139 | make_float3(m_imgui_directional_light_le[0], 140 | m_imgui_directional_light_le[1], 141 | m_imgui_directional_light_le[2]), 142 | make_float3(m_imgui_directional_light_dir[0], 143 | m_imgui_directional_light_dir[1], 144 | m_imgui_directional_light_dir[2]), 145 | m_imgui_directional_light_angle); 146 | } 147 | 148 | void Controller::update_sky_type() 149 | { 150 | switch (m_imgui_sky_type) { 151 | case SkyType::CONSTANT: { 152 | m_renderer->clear_ibl(); 153 | m_renderer->clear_arhosek_sky(); 154 | } break; 155 | case SkyType::IBL: { 156 | m_renderer->clear_arhosek_sky(); 157 | load_ibl(); 158 | } break; 159 | case SkyType::ARHOSEK: { 160 | m_renderer->clear_ibl(); 161 | load_arhosek(); 162 | } break; 163 | } 164 | } 165 | 166 | void Controller::set_sky_intensity() 167 | { 168 | m_renderer->set_sky_intensity(m_imgui_sky_intensity); 169 | } 170 | 171 | void Controller::load_ibl() 172 | { 173 | m_renderer->load_ibl(ibl_filepaths[m_imgui_ibl_id]); 174 | } 175 | 176 | void Controller::load_arhosek() 177 | { 178 | m_renderer->load_arhosek_sky(m_imgui_arhosek_turbidity, 179 | m_imgui_arhosek_albedo); 180 | } 181 | 182 | void Controller::set_time() { m_renderer->set_time(m_imgui_time); } 183 | 184 | void Controller::advance_time() 185 | { 186 | m_imgui_time += m_imgui_timestep; 187 | m_renderer->set_time(m_imgui_time); 188 | } 189 | 190 | void Controller::update_resolution() 191 | { 192 | init_render_layers(); 193 | m_renderer->set_resolution(m_imgui_resolution[0], m_imgui_resolution[1]); 194 | 195 | init_denoiser(); 196 | } 197 | 198 | void Controller::clear_render() 199 | { 200 | m_imgui_n_samples = 0; 201 | clear_render_layers(); 202 | m_renderer->init_render_states(); 203 | } 204 | 205 | void Controller::render() 206 | { 207 | if (m_imgui_play_animation) { 208 | advance_time(); 209 | clear_render(); 210 | } 211 | 212 | if (m_imgui_n_samples < m_imgui_max_samples) { 213 | fredholm::RenderLayer render_layers; 214 | render_layers.beauty = m_layer_beauty->get_device_ptr(); 215 | render_layers.position = m_layer_position->get_device_ptr(); 216 | render_layers.normal = m_layer_normal->get_device_ptr(); 217 | render_layers.depth = m_layer_depth->get_device_ptr(); 218 | render_layers.texcoord = m_layer_texcoord->get_device_ptr(); 219 | render_layers.albedo = m_layer_albedo->get_device_ptr(); 220 | 221 | m_renderer->render(*m_camera, 222 | make_float3(m_imgui_bg_color[0], m_imgui_bg_color[1], 223 | m_imgui_bg_color[2]), 224 | render_layers, 1, m_imgui_max_depth); 225 | // TODO: Is is safe to remove this? 226 | m_renderer->wait_for_completion(); 227 | 228 | m_imgui_n_samples++; 229 | } 230 | } 231 | 232 | void Controller::denoise() 233 | { 234 | m_denoiser->denoise(); 235 | m_denoiser->wait_for_completion(); 236 | } 237 | 238 | void Controller::post_process() 239 | { 240 | PostProcessParams params; 241 | params.use_bloom = m_imgui_use_bloom; 242 | params.bloom_threshold = m_imgui_bloom_threshold; 243 | params.bloom_sigma = m_imgui_bloom_sigma; 244 | params.chromatic_aberration = m_imgui_chromatic_aberration; 245 | params.ISO = m_imgui_iso; 246 | 247 | // launch post process kernel 248 | post_process_kernel_launch(m_layer_beauty->get_device_ptr(), 249 | m_beauty_high_luminance->get_device_ptr(), 250 | m_beauty_temp->get_device_ptr(), 251 | m_imgui_resolution[0], m_imgui_resolution[1], 252 | params, m_layer_beauty_pp->get_device_ptr()); 253 | 254 | post_process_kernel_launch(m_layer_denoised->get_device_ptr(), 255 | m_denoised_high_luminance->get_device_ptr(), 256 | m_denoised_temp->get_device_ptr(), 257 | m_imgui_resolution[0], m_imgui_resolution[1], 258 | params, m_layer_denoised_pp->get_device_ptr()); 259 | 260 | CUDA_SYNC_CHECK(); 261 | } 262 | 263 | void Controller::save_image() const 264 | { 265 | // copy image from device to host 266 | std::vector image_f4; 267 | switch (m_imgui_aov_type) { 268 | case AOVType::BEAUTY: { 269 | m_layer_beauty_pp->copy_from_device_to_host(image_f4); 270 | } break; 271 | case AOVType::DENOISED: { 272 | m_layer_denoised_pp->copy_from_device_to_host(image_f4); 273 | } break; 274 | case AOVType::POSITION: { 275 | m_layer_position->copy_from_device_to_host(image_f4); 276 | } break; 277 | case AOVType::NORMAL: { 278 | m_layer_normal->copy_from_device_to_host(image_f4); 279 | } break; 280 | // TODO: handle depth case 281 | case AOVType::DEPTH: { 282 | } break; 283 | case AOVType::TEXCOORD: { 284 | m_layer_texcoord->copy_from_device_to_host(image_f4); 285 | } break; 286 | case AOVType::ALBEDO: { 287 | m_layer_albedo->copy_from_device_to_host(image_f4); 288 | } break; 289 | } 290 | 291 | // convert float4 to uchar4 292 | std::vector image_c4(image_f4.size()); 293 | for (int j = 0; j < m_imgui_resolution[1]; ++j) { 294 | for (int i = 0; i < m_imgui_resolution[0]; ++i) { 295 | const int idx = i + m_imgui_resolution[0] * j; 296 | const float4 v = image_f4[idx]; 297 | image_c4[idx].x = 298 | static_cast(std::clamp(255.0f * v.x, 0.0f, 255.0f)); 299 | image_c4[idx].y = 300 | static_cast(std::clamp(255.0f * v.y, 0.0f, 255.0f)); 301 | image_c4[idx].z = 302 | static_cast(std::clamp(255.0f * v.z, 0.0f, 255.0f)); 303 | image_c4[idx].w = 255; 304 | } 305 | } 306 | 307 | // save image 308 | stbi_write_png(m_imgui_filename, m_imgui_resolution[0], m_imgui_resolution[1], 309 | 4, image_c4.data(), sizeof(uchar4) * m_imgui_resolution[0]); 310 | 311 | spdlog::info("[GUI] image saved as {}", m_imgui_filename); 312 | } --------------------------------------------------------------------------------