├── .gitignore ├── .gitmodules ├── .travis.yml ├── CMakeLists.txt ├── Changelog.md ├── LICENSE ├── README.md ├── external ├── stb_image.h └── stb_image_write.h ├── header.png ├── header2.png ├── include ├── BVH │ └── bvh.h ├── CL │ ├── cl_help.h │ ├── cl_kernel.h │ └── cl_program.h ├── Camera │ └── camera.h ├── GL │ ├── cl_gl_interop.h │ └── user_interaction.h ├── Math │ ├── MathHelp.h │ ├── linear_algebra.h │ └── random.h ├── Model │ └── model_loader.h ├── Scene │ ├── geometry.h │ └── scene.h ├── Texture │ └── texture.h ├── Types │ ├── material.h │ └── media.h ├── align.h ├── string_helper_functions.h └── utils.h ├── kernels ├── bxdf │ ├── Fresnel.cl │ ├── Materials │ │ ├── Coat.cl │ │ ├── Conductor.cl │ │ ├── Dielectric.cl │ │ ├── Lambert.cl │ │ ├── RoughConductor.cl │ │ └── RoughDielectric.cl │ ├── bxdf.cl │ ├── microfacet.cl │ └── old │ │ ├── blinn.cl │ │ └── burley_diffuse.cl ├── camera.cl ├── geometry │ ├── aabb.cl │ ├── box.cl │ ├── bvh.cl │ ├── geometry.cl │ ├── quad.cl │ ├── sdf.cl │ ├── sphere.cl │ └── triangle.cl ├── header.cl ├── integrators │ ├── base.cl │ ├── bidirectional.cl │ └── pathtracing.cl ├── intersect.cl ├── main.cl ├── media.cl ├── media │ ├── exponential.cl │ └── homogeneous.cl ├── noise │ └── value_noise.cl ├── phasefunctions │ ├── HenyeyGreenstein.cl │ ├── Isotropic.cl │ └── Rayleigh.cl ├── prng │ └── prng.cl ├── texture.cl └── utils.cl ├── resources ├── models │ ├── buddha.obj │ ├── dragon.obj │ ├── suzanne.obj │ ├── suzanne2.obj │ └── teapot.obj └── textures │ ├── rgb_noise1024.png │ └── rgba_noise1024.png ├── scenes ├── cornell.json ├── cornell_media.json └── test.json ├── shaders ├── tonemapper.glsl └── vert.glsl ├── src ├── BVH │ └── bvh.cpp ├── Camera │ └── camera.cpp ├── Math │ └── MathHelp.cpp ├── Models │ └── model_loader.cpp └── main.cpp ├── vcpkg-configuration.json └── vcpkg.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Precompiled Headers 7 | *.gch 8 | *.pch 9 | 10 | # Compiled Dynamic libraries 11 | *.so 12 | *.dylib 13 | *.dll 14 | 15 | # Fortran module files 16 | *.mod 17 | *.smod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | /build/ 31 | *.log 32 | *.mtl 33 | kernels/bxdf/disney.cl 34 | *.hdr 35 | include/BVH/bvh_morton_code.h 36 | 37 | .vscode 38 | *.old 39 | 40 | external/AMD APP SDK/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/bvh"] 2 | path = external/bvh 3 | url = https://github.com/madmann91/bvh 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | os: linux 3 | dist: bionic 4 | 5 | compiler: 6 | - clang 7 | - gcc 8 | 9 | sudo: required 10 | 11 | addons: 12 | apt: 13 | sources: 14 | - ubuntu-toolchain-r-test 15 | packages: 16 | - g++-7 17 | - gcc-7 18 | - cmake 19 | - make 20 | - libglu1-mesa-dev 21 | - freeglut3-dev 22 | - mesa-common-dev 23 | - build-essential 24 | - libglew-dev 25 | - nvidia-opencl-dev 26 | - opencl-headers 27 | - libfreeimage-dev 28 | - libxrandr-dev 29 | - libxinerama-dev 30 | - libxcursor-dev 31 | - libxi-dev 32 | - libassimp-dev 33 | - libglfw3-dev 34 | 35 | # Build steps 36 | script: 37 | - mkdir build 38 | - cd build 39 | - cmake .. 40 | - make VERBOSE=1 -j 41 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.30) 2 | 3 | # Set up CMake variables 4 | 5 | # set VCPKG_ROOT per platform 6 | if(WIN32) 7 | set(VCPKG_ROOT "C:/dev/vcpkg/") 8 | elseif(UNIX) 9 | set(VCPKG_ROOT "/home/user/vcpkg/") 10 | endif() 11 | 12 | set(CMAKE_TOOLCHAIN_FILE "${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake") 13 | set(vcpkg_DIR "${VCPKG_ROOT}") 14 | set(CMAKE_PREFIX_PATH "${VCPKG_ROOT}") 15 | 16 | SET(PROJECT_NAME "OpenCL_Pathtracer") 17 | SET(TRACER_TARGET "OpenCL_Pathtracer") 18 | 19 | PROJECT(${TRACER_TARGET}) 20 | 21 | # First for the generic no-config case (e.g. with mingw) 22 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) 23 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) 24 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) 25 | # Second, for multi-config builds (e.g. msvc) 26 | foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) 27 | string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) 28 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin ) 29 | set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/lib ) 30 | set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/lib ) 31 | endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) 32 | 33 | function(assign_source_group) 34 | foreach(_source IN ITEMS ${ARGN}) 35 | if (IS_ABSOLUTE "${_source}") 36 | file(RELATIVE_PATH _source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${_source}") 37 | else() 38 | set(_source_rel "${_source}") 39 | endif() 40 | get_filename_component(_source_path "${_source_rel}" PATH) 41 | string(REPLACE "/" "\\" _source_path_msvc "${_source_path}") 42 | source_group("${_source_path_msvc}" FILES "${_source}") 43 | endforeach() 44 | endfunction(assign_source_group) 45 | 46 | # Enable VCPKG support 47 | include(${CMAKE_TOOLCHAIN_FILE}) 48 | 49 | FILE( GLOB_RECURSE SRCS "${CMAKE_SOURCE_DIR}/src/*.cpp" ) 50 | FILE( GLOB_RECURSE INC "${CMAKE_SOURCE_DIR}/include/*.h") 51 | FILE( GLOB_RECURSE CL_SRCS "${CMAKE_SOURCE_DIR}/kernels/*.cl" ) 52 | FILE( GLOB_RECURSE SHADERS "${CMAKE_SOURCE_DIR}/shaders/*.glsl" ) 53 | FILE( GLOB_RECURSE SCENES "${CMAKE_SOURCE_DIR}/scenes/*.json" ) 54 | 55 | if(WIN32) 56 | assign_source_group(${SRCS}) 57 | assign_source_group(${INC}) 58 | assign_source_group(${CL_SRCS}) 59 | assign_source_group(${SHADERS}) 60 | assign_source_group(${SCENES}) 61 | ENDIF(WIN32) 62 | 63 | add_executable(${TRACER_TARGET} ${SRCS} ${INC} ${CL_SRCS} ${SHADERS} ${SCENES}) 64 | 65 | SET_TARGET_PROPERTIES(${TRACER_TARGET} PROPERTIES 66 | CXX_STANDARD 17 67 | CXX_STANDARD_REQUIRED ON) 68 | 69 | # add the include directories 70 | TARGET_INCLUDE_DIRECTORIES(${TRACER_TARGET} PUBLIC "${CMAKE_SOURCE_DIR}/include" "${CMAKE_SOURCE_DIR}/external") 71 | 72 | IF(UNIX) 73 | IF(APPLE) 74 | TARGET_COMPILE_DEFINITIONS(${TRACER_TARGET} PRIVATE -DOS_MAC) 75 | ELSE(APPLE) 76 | TARGET_COMPILE_DEFINITIONS(${TRACER_TARGET} PRIVATE -DOS_LNX) 77 | ENDIF(APPLE) 78 | ELSE(UNIX) 79 | TARGET_COMPILE_DEFINITIONS(${TRACER_TARGET} PRIVATE -DOS_WIN) 80 | ENDIF(UNIX) 81 | 82 | ################################ 83 | # Compile Flags 84 | ################################ 85 | 86 | SET_TARGET_PROPERTIES(${TRACER_TARGET} PROPERTIES 87 | CXX_STANDARD 20 88 | CXX_STANDARD_REQUIRED ON) 89 | 90 | SET(RAYTRACER_COMPILE_FLAGS) 91 | # set C++ standard 92 | LIST(APPEND RAYTRACER_COMPILE_FLAGS "-std=c++20") 93 | # -fexceptions: enables exceptions 94 | LIST(APPEND RAYTRACER_COMPILE_FLAGS "-fexceptions") 95 | # -frtti: enables runtime type check (required for virtual functions, etc.) 96 | LIST(APPEND RAYTRACER_COMPILE_FLAGS "-frtti") 97 | # -Wall: displays all warnings 98 | LIST(APPEND RAYTRACER_COMPILE_FLAGS "-Wall") 99 | 100 | TARGET_COMPILE_OPTIONS(${TRACER_TARGET} PUBLIC "${RAYTRACER_COMPILE_FLAGS}") 101 | 102 | ################################ 103 | # Dependencies 104 | ################################ 105 | 106 | # OpenGL 107 | find_package(OpenGL REQUIRED) 108 | TARGET_INCLUDE_DIRECTORIES(${TRACER_TARGET} PRIVATE ${OPENGL_INCLUDE_DIR}) 109 | TARGET_LINK_LIBRARIES(${TRACER_TARGET} PRIVATE ${OPENGL_LIBRARIES}) 110 | 111 | # BVH 112 | add_subdirectory("external/bvh") 113 | target_link_libraries(${TRACER_TARGET} PRIVATE "bvh") 114 | target_include_directories(${TRACER_TARGET} PRIVATE "external/bvh/src") 115 | 116 | # Ensure bvh uses C++20 117 | set_target_properties(bvh PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON) 118 | 119 | find_package(GLEW REQUIRED) 120 | include_directories(${GLEW_INCLUDE_DIRS}) 121 | target_link_libraries(${TRACER_TARGET} PRIVATE GLEW::GLEW) 122 | 123 | find_package(glfw3 CONFIG REQUIRED) 124 | target_link_libraries(${TRACER_TARGET} PRIVATE glfw) 125 | 126 | find_package(Eigen3 CONFIG REQUIRED) 127 | target_link_libraries(${TRACER_TARGET} PRIVATE Eigen3::Eigen) 128 | 129 | find_package(OpenCL CONFIG REQUIRED) 130 | 131 | # Khronos OpenCL ICD Loader 132 | target_link_libraries(${TRACER_TARGET} PRIVATE OpenCL::OpenCL) 133 | 134 | # Khronos OpenCL Headers and C++ bindings 135 | target_link_libraries(${TRACER_TARGET} PRIVATE OpenCL::Headers) 136 | target_link_libraries(${TRACER_TARGET} PRIVATE OpenCL::HeadersCpp) 137 | 138 | # OpenCL Utility Library and C++ bindings 139 | target_link_libraries(${TRACER_TARGET} PRIVATE OpenCL::Utils) 140 | target_link_libraries(${TRACER_TARGET} PRIVATE OpenCL::UtilsCpp) 141 | 142 | find_package(assimp CONFIG REQUIRED) 143 | target_link_libraries(${TRACER_TARGET} PRIVATE assimp::assimp) 144 | 145 | find_package(RapidJSON CONFIG REQUIRED) 146 | target_link_libraries(${TRACER_TARGET} PRIVATE rapidjson) 147 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | ## # Version **0.1** 3 | - Add support for more 3D file formats using Assimp 4 | - Fix compilation errors on Linux 5 | - New BVH accelation structure 6 | - Stack based BVH traversal on GPU 7 | ## # Version **0.0** 8 | - SAH BVH 9 | - Volumetric pathtracing (homogeneous, exponential medium) 10 | - Multiple Importance Sampling (MIS) 11 | - SDF Raymarching 12 | - Thin lens camera 13 | - Image-based lighting 14 | - Alpha blending 15 | - Media 16 | - Homogeneous 17 | - Exponential 18 | - Phase functions 19 | - Isotropic 20 | - Henyey-Greenstein 21 | - Rayleigh 22 | - Materials 23 | - Lambertian BRDF 24 | - Burley BRDF 25 | - Rough Conductor 26 | - Rough Dielectric + Absorption 27 | - Microfacet 28 | - GGX 29 | - Beckmann 30 | - Phong 31 | - Specular Subsurface Scattering 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Alex Mourtziapis 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![header](header2.png) 2 | 3 | [![Build Status](https://travis-ci.org/Mourtz/Photorealistic-Rendering-using-OpenCL.svg?branch=bleeding-edge)](https://travis-ci.org/Mourtz/Photorealistic-Rendering-using-OpenCL) 4 | 5 | ## Controls 6 | __Escape__ - Exit\ 7 | __Space__ - Reset\ 8 | __WASDFR__ - Translate Camera\ 9 | __G__ - Increase Aperture Diameter\ 10 | __H__ - Decrease Aperture Diameter\ 11 | __T__ - Increase Focal Distance\ 12 | __Y__ - Decrease Focal Distance\ 13 | __Arrows__ - Yaw/Pitch\ 14 | __Prtsc__ - Export 15 | ``` 16 | -width "{integer}: window's width" 17 | -height "{integer}: window's height" 18 | -scene "{string}: filepath of the scene you want to render" 19 | -hdr "{string}: filepath of the hdr you want to use" 20 | -alpha "{void}: add this flag if you want to enable alpha blending" 21 | -encoder "{integer}: { 0: ".png", 1: ".hdr" }" 22 | ``` 23 | > [**hdrihaven**](https://hdrihaven.com/hdris/) is a great site for downloading free hi-res HDR images. 24 | 25 | ## Features 26 | - SAH BVH 27 | - Volumetric pathtracing (homogeneous, exponential medium) 28 | - Multiple Importance Sampling (MIS) 29 | - SDF Raymarching 30 | - Thin lens camera 31 | - Image-based lighting 32 | - Alpha blending 33 | - Media 34 | - Homogeneous 35 | - Exponential 36 | - Phase functions 37 | - Isotropic 38 | - Henyey-Greenstein 39 | - Rayleigh 40 | - Materials 41 | - Lambertian BRDF 42 | - Burley BRDF 43 | - Rough Conductor 44 | - Rough Dielectric + Absorption 45 | - Microfacet 46 | - GGX 47 | - Beckmann 48 | - Phong 49 | - Smooth/Flat shading 50 | 51 | ## Possible Future work 52 | - Quasi Monte Carlo 53 | - Disney's principled, layered BRDF 54 | - Volumetric pathtracing (heterogeneous medium) 55 | - Volumetric pathtracing (SDF density map) 56 | - Photon Mapping 57 | - Bi-Directional PT 58 | - MLT 59 | - Sheen BRDF 60 | - Blinn Phong Microfacet BRDF 61 | - Oren-Nayar BRDF 62 | - Denoiser 63 | - LBVH using spatial Morton codes 64 | - Phong Tessellation 65 | 66 | ## How To Build 67 | 68 | ### Windows 69 | ```bash 70 | git clone https://github.com/microsoft/vcpkg.git 71 | move vcpkg C:/dev 72 | cd C:/dev/vcpkg && bootstrap-vcpkg.bat 73 | ``` 74 | 75 | ### Linux 76 | ```bash 77 | git clone https://github.com/microsoft/vcpkg.git 78 | mv vcpkg /home/user 79 | cd /home/user/vcpkg && ./bootstrap-vcpkg.sh 80 | ``` 81 | 82 | ## Credits 83 | [tunabrain](https://twitter.com/tunabrain) - Benedikt Bitterli\ 84 | [sebadorn](https://sebadorn.de/) - Sebastian Dorn\ 85 | [mmp](http://pharr.org/matt/) - Matt Pharr 86 | -------------------------------------------------------------------------------- /header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mourtz/Photorealistic-Rendering-using-OpenCL/71f5b7d62b030ad9cabc0ee757c673a1969193bf/header.png -------------------------------------------------------------------------------- /header2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mourtz/Photorealistic-Rendering-using-OpenCL/71f5b7d62b030ad9cabc0ee757c673a1969193bf/header2.png -------------------------------------------------------------------------------- /include/BVH/bvh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using Scalar = float; 18 | using Vec3 = bvh::v2::Vec; 19 | using BBox = bvh::v2::BBox; 20 | using Tri = bvh::v2::Tri; 21 | using Node = bvh::v2::Node; 22 | using Bvh = bvh::v2::Bvh; 23 | using Ray = bvh::v2::Ray; 24 | 25 | using PrecomputedTri = bvh::v2::PrecomputedTri; 26 | 27 | //-------------------- Logic --------------------- 28 | namespace CL_RAYTRACER 29 | { 30 | struct cl_Mesh; 31 | struct cl_BVHnode 32 | { 33 | float bounds[6]; 34 | unsigned int first_child_or_primitive; 35 | unsigned int primitive_count; 36 | bool is_leaf; 37 | }; 38 | 39 | namespace IO 40 | { 41 | class ModelLoader; 42 | } 43 | } // namespace CL_RAYTRACER 44 | 45 | namespace CL_RAYTRACER 46 | { 47 | class BVH 48 | { 49 | private: 50 | std::vector triangles; 51 | std::unique_ptr bvh; 52 | const std::shared_ptr model_loader; 53 | 54 | public: 55 | BVH(const std::shared_ptr &ml); 56 | ~BVH(); 57 | 58 | void buildTree(const std::shared_ptr &ml); 59 | 60 | std::unique_ptr> GetPrimitiveIndices() const; 61 | 62 | std::unique_ptr> PrepareData() const; 63 | }; 64 | } // namespace CL_RAYTRACER -------------------------------------------------------------------------------- /include/CL/cl_help.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | extern cl::Context context; 11 | 12 | namespace cl_help 13 | { 14 | 15 | namespace err 16 | { 17 | inline void expectedError(const char *errorMsg) 18 | { 19 | std::cout << "Expected Error: " << errorMsg << std::endl; 20 | } 21 | 22 | template 23 | inline const char *getOpenCLErrorCodeStr(T input) 24 | { 25 | int errorCode = (int)input; 26 | switch (errorCode) 27 | { 28 | case CL_DEVICE_NOT_FOUND: 29 | return "CL_DEVICE_NOT_FOUND"; 30 | case CL_DEVICE_NOT_AVAILABLE: 31 | return "CL_DEVICE_NOT_AVAILABLE"; 32 | case CL_COMPILER_NOT_AVAILABLE: 33 | return "CL_COMPILER_NOT_AVAILABLE"; 34 | case CL_MEM_OBJECT_ALLOCATION_FAILURE: 35 | return "CL_MEM_OBJECT_ALLOCATION_FAILURE"; 36 | case CL_OUT_OF_RESOURCES: 37 | return "CL_OUT_OF_RESOURCES"; 38 | case CL_OUT_OF_HOST_MEMORY: 39 | return "CL_OUT_OF_HOST_MEMORY"; 40 | case CL_PROFILING_INFO_NOT_AVAILABLE: 41 | return "CL_PROFILING_INFO_NOT_AVAILABLE"; 42 | case CL_MEM_COPY_OVERLAP: 43 | return "CL_MEM_COPY_OVERLAP"; 44 | case CL_IMAGE_FORMAT_MISMATCH: 45 | return "CL_IMAGE_FORMAT_MISMATCH"; 46 | case CL_IMAGE_FORMAT_NOT_SUPPORTED: 47 | return "CL_IMAGE_FORMAT_NOT_SUPPORTED"; 48 | case CL_BUILD_PROGRAM_FAILURE: 49 | return "CL_BUILD_PROGRAM_FAILURE"; 50 | case CL_MAP_FAILURE: 51 | return "CL_MAP_FAILURE"; 52 | case CL_MISALIGNED_SUB_BUFFER_OFFSET: 53 | return "CL_MISALIGNED_SUB_BUFFER_OFFSET"; 54 | case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST: 55 | return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST"; 56 | case CL_INVALID_VALUE: 57 | return "CL_INVALID_VALUE"; 58 | case CL_INVALID_DEVICE_TYPE: 59 | return "CL_INVALID_DEVICE_TYPE"; 60 | case CL_INVALID_PLATFORM: 61 | return "CL_INVALID_PLATFORM"; 62 | case CL_INVALID_DEVICE: 63 | return "CL_INVALID_DEVICE"; 64 | case CL_INVALID_CONTEXT: 65 | return "CL_INVALID_CONTEXT"; 66 | case CL_INVALID_QUEUE_PROPERTIES: 67 | return "CL_INVALID_QUEUE_PROPERTIES"; 68 | case CL_INVALID_COMMAND_QUEUE: 69 | return "CL_INVALID_COMMAND_QUEUE"; 70 | case CL_INVALID_HOST_PTR: 71 | return "CL_INVALID_HOST_PTR"; 72 | case CL_INVALID_MEM_OBJECT: 73 | return "CL_INVALID_MEM_OBJECT"; 74 | case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR: 75 | return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR"; 76 | case CL_INVALID_IMAGE_SIZE: 77 | return "CL_INVALID_IMAGE_SIZE"; 78 | case CL_INVALID_SAMPLER: 79 | return "CL_INVALID_SAMPLER"; 80 | case CL_INVALID_BINARY: 81 | return "CL_INVALID_BINARY"; 82 | case CL_INVALID_BUILD_OPTIONS: 83 | return "CL_INVALID_BUILD_OPTIONS"; 84 | case CL_INVALID_PROGRAM: 85 | return "CL_INVALID_PROGRAM"; 86 | case CL_INVALID_PROGRAM_EXECUTABLE: 87 | return "CL_INVALID_PROGRAM_EXECUTABLE"; 88 | case CL_INVALID_KERNEL_NAME: 89 | return "CL_INVALID_KERNEL_NAME"; 90 | case CL_INVALID_KERNEL_DEFINITION: 91 | return "CL_INVALID_KERNEL_DEFINITION"; 92 | case CL_INVALID_KERNEL: 93 | return "CL_INVALID_KERNEL"; 94 | case CL_INVALID_ARG_INDEX: 95 | return "CL_INVALID_ARG_INDEX"; 96 | case CL_INVALID_ARG_VALUE: 97 | return "CL_INVALID_ARG_VALUE"; 98 | case CL_INVALID_ARG_SIZE: 99 | return "CL_INVALID_ARG_SIZE"; 100 | case CL_INVALID_KERNEL_ARGS: 101 | return "CL_INVALID_KERNEL_ARGS"; 102 | case CL_INVALID_WORK_DIMENSION: 103 | return "CL_INVALID_WORK_DIMENSION"; 104 | case CL_INVALID_WORK_GROUP_SIZE: 105 | return "CL_INVALID_WORK_GROUP_SIZE"; 106 | case CL_INVALID_WORK_ITEM_SIZE: 107 | return "CL_INVALID_WORK_ITEM_SIZE"; 108 | case CL_INVALID_GLOBAL_OFFSET: 109 | return "CL_INVALID_GLOBAL_OFFSET"; 110 | case CL_INVALID_EVENT_WAIT_LIST: 111 | return "CL_INVALID_EVENT_WAIT_LIST"; 112 | case CL_INVALID_EVENT: 113 | return "CL_INVALID_EVENT"; 114 | case CL_INVALID_OPERATION: 115 | return "CL_INVALID_OPERATION"; 116 | case CL_INVALID_GL_OBJECT: 117 | return "CL_INVALID_GL_OBJECT"; 118 | case CL_INVALID_BUFFER_SIZE: 119 | return "CL_INVALID_BUFFER_SIZE"; 120 | case CL_INVALID_MIP_LEVEL: 121 | return "CL_INVALID_MIP_LEVEL"; 122 | case CL_INVALID_GLOBAL_WORK_SIZE: 123 | return "CL_INVALID_GLOBAL_WORK_SIZE"; 124 | case CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR: 125 | return "CL_INVALID_GL_SHAREGROUP_REFERENCE_KHR"; 126 | case CL_PLATFORM_NOT_FOUND_KHR: 127 | return "CL_PLATFORM_NOT_FOUND_KHR"; 128 | //case CL_INVALID_PROPERTY_EXT: 129 | // return "CL_INVALID_PROPERTY_EXT"; 130 | case CL_DEVICE_PARTITION_FAILED_EXT: 131 | return "CL_DEVICE_PARTITION_FAILED_EXT"; 132 | case CL_INVALID_PARTITION_COUNT_EXT: 133 | return "CL_INVALID_PARTITION_COUNT_EXT"; 134 | //case CL_INVALID_DEVICE_QUEUE: 135 | // return "CL_INVALID_DEVICE_QUEUE"; 136 | //case CL_INVALID_PIPE_SIZE: 137 | // return "CL_INVALID_PIPE_SIZE"; 138 | 139 | default: 140 | return "unknown error code"; 141 | } 142 | } 143 | 144 | inline void error(std::string errorMsg) 145 | { 146 | std::cout << "Error: " << errorMsg << std::endl; 147 | } 148 | 149 | template 150 | inline bool checkVal( 151 | T input, 152 | T reference, 153 | std::string message, bool isAPIerror = true) 154 | { 155 | if (input == reference) 156 | { 157 | return false; 158 | } 159 | else 160 | { 161 | if (isAPIerror) 162 | { 163 | std::cout << "Error: " << message << " Error code : "; 164 | std::cout << getOpenCLErrorCodeStr(input) << std::endl; 165 | } 166 | else 167 | { 168 | error(message); 169 | } 170 | return true; 171 | } 172 | } 173 | 174 | inline void printErrorLog(const cl::Program &program, const cl::Device &device) 175 | { 176 | 177 | // Get the error log and print to console 178 | std::string buildlog = program.getBuildInfo(device); 179 | std::cerr << "Build log:" << std::endl 180 | << buildlog << std::endl; 181 | 182 | // Print the error log to a file 183 | FILE *log = fopen("errorlog.txt", "w"); 184 | fprintf(log, "%s\n", buildlog.c_str()); 185 | fclose(log); 186 | 187 | std::cout << "Error log saved in 'errorlog.txt'" << std::endl; 188 | std::cin.get(); 189 | exit(1); 190 | } 191 | } // namespace err 192 | 193 | namespace buffer 194 | { 195 | template 196 | inline cl::Buffer create( 197 | std::vector& data, 198 | std::size_t size, 199 | cl_mem_flags flags = (CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR)) 200 | { 201 | return cl::Buffer(context, flags, size, &data[0]); 202 | } 203 | } // namespace buffer 204 | 205 | //--------------------------------------------------------------------------------------- 206 | 207 | namespace platform 208 | { 209 | inline void select(cl::Platform &platform, const std::vector &platforms) 210 | { 211 | 212 | if (platforms.size() == 1) 213 | platform = platforms[0]; 214 | else 215 | { 216 | int input = 0; 217 | std::cout << "\nChoose an OpenCL platform: "; 218 | std::cin >> input; 219 | 220 | // handle incorrect user input 221 | while (input < 1 || input > platforms.size()) 222 | { 223 | std::cin.clear(); //clear errors/bad flags on std::cin 224 | std::cin.ignore(std::cin.rdbuf()->in_avail(), '\n'); // ignores exact number of chars in std::cin buffer 225 | std::cout << "No such option. Choose an OpenCL platform: "; 226 | std::cin >> input; 227 | } 228 | platform = platforms[input - 1]; 229 | } 230 | } 231 | }; // namespace platform 232 | 233 | //--------------------------------------------------------------------------------------- 234 | 235 | namespace device 236 | { 237 | inline void select(cl::Device &device, const std::vector &devices) 238 | { 239 | 240 | if (devices.size() == 1) 241 | device = devices[0]; 242 | else 243 | { 244 | int input = 0; 245 | std::cout << "\nChoose an OpenCL device: "; 246 | std::cin >> input; 247 | 248 | // handle incorrect user input 249 | while (input < 1 || input > devices.size()) 250 | { 251 | std::cin.clear(); //clear errors/bad flags on std::cin 252 | std::cin.ignore(std::cin.rdbuf()->in_avail(), '\n'); // ignores exact number of chars in std::cin buffer 253 | std::cout << "No such option. Choose an OpenCL device: "; 254 | std::cin >> input; 255 | } 256 | device = devices[input - 1]; 257 | } 258 | } 259 | } // namespace device 260 | } // namespace cl_help 261 | 262 | #define OPENCL_EXPECTED_ERROR(msg) \ 263 | { \ 264 | cl_help::err::expectedError(msg); \ 265 | return EXIT_FAILURE; \ 266 | } 267 | 268 | #define CHECK_OPENCL_ERROR(actual, msg) \ 269 | if (cl_help::err::checkVal(actual, CL_SUCCESS, msg)) \ 270 | { \ 271 | std::cout << "Location : " << __FILE__ << ":" << __LINE__ << std::endl; \ 272 | return EXIT_FAILURE; \ 273 | } 274 | -------------------------------------------------------------------------------- /include/CL/cl_kernel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | extern bool ALPHA_TESTING; 7 | 8 | namespace cl_help 9 | { 10 | namespace kernel 11 | { 12 | // definetely not optimized 13 | inline std::string parse(std::string filepath, host_scene *scene) 14 | { 15 | using std::string; 16 | 17 | std::string source; 18 | 19 | std::cout << "----------------------------------------------------------" << std::endl; 20 | 21 | std::ifstream file(filepath); 22 | if (!file) 23 | { 24 | std::cout << "\nCouldn't find OpenCL file (" + filepath + ')' << std::endl 25 | << "Exiting..." << std::endl; 26 | std::cin.get(); 27 | exit(1); 28 | } 29 | 30 | std::string line; 31 | while (std::getline(file, line)) 32 | { 33 | if (line.substr(0, 6) == "#FILE:") 34 | { 35 | 36 | std::string filepath = "../../kernels/" + line.substr(6); 37 | std::cout << "Appending (" << filepath << ")\n"; 38 | source += parse(filepath, scene); 39 | continue; 40 | } 41 | 42 | string temp_name; 43 | std::size_t temp; 44 | 45 | //--------------------------------- RENDER SETTINGS --------------------------------- 46 | 47 | temp_name = "#GLOBAL_MEDIUM#"; 48 | temp = line.find(temp_name); 49 | if (temp != string::npos) 50 | { 51 | line.replace(temp, temp_name.length(), (scene->HAS_GLOBAL_MEDIUM ? "#define GLOBAL_MEDIUM" : "")); 52 | source += line + "\n"; 53 | continue; 54 | } 55 | 56 | temp_name = "#ALPHA_TESTING#"; 57 | temp = line.find(temp_name); 58 | if (temp != string::npos) 59 | { 60 | line.replace(temp, temp_name.length(), (ALPHA_TESTING ? "#define ALPHA_TESTING" : "")); 61 | source += line + "\n"; 62 | continue; 63 | } 64 | 65 | //--------------------------------- GLOBAL MEDIUM --------------------------------------------- 66 | if (scene->HAS_GLOBAL_MEDIUM) 67 | { 68 | temp_name = "#GLOBAL_FOG_DENSITY#"; 69 | temp = line.find(temp_name); 70 | if (temp != string::npos) 71 | { 72 | line.replace(temp, temp_name.length(), std::to_string(scene->GLOBAL_MEDIUM.density) + "f"); 73 | source += line + "\n"; 74 | continue; 75 | } 76 | 77 | temp_name = "#GLOBAL_FOG_SIGMA_A#"; 78 | temp = line.find(temp_name); 79 | if (temp != string::npos) 80 | { 81 | line.replace(temp, temp_name.length(), std::to_string(scene->GLOBAL_MEDIUM.sigmaA) + "f"); 82 | source += line + "\n"; 83 | continue; 84 | } 85 | 86 | temp_name = "#GLOBAL_FOG_SIGMA_S#"; 87 | temp = line.find(temp_name); 88 | if (temp != string::npos) 89 | { 90 | line.replace(temp, temp_name.length(), std::to_string(scene->GLOBAL_MEDIUM.sigmaS) + "f"); 91 | source += line + "\n"; 92 | continue; 93 | } 94 | 95 | temp_name = "#GLOBAL_FOG_SIGMA_T#"; 96 | temp = line.find(temp_name); 97 | if (temp != string::npos) 98 | { 99 | line.replace(temp, temp_name.length(), std::to_string(scene->GLOBAL_MEDIUM.sigmaT) + "f"); 100 | source += line + "\n"; 101 | continue; 102 | } 103 | 104 | temp_name = "#GLOBAL_FOG_ABS_ONLY#"; 105 | temp = line.find(temp_name); 106 | if (temp != string::npos) 107 | { 108 | line.replace(temp, temp_name.length(), std::to_string(scene->GLOBAL_MEDIUM.absorptionOnly)); 109 | source += line + "\n"; 110 | continue; 111 | } 112 | } 113 | //------------------------------------------------------------------------------------------------ 114 | 115 | temp_name = "#MAX_BOUNCES#"; 116 | temp = line.find(temp_name); 117 | if (temp != string::npos) 118 | { 119 | line.replace(temp, temp_name.length(), std::to_string(scene->MAX_BOUNCES)); 120 | source += line + "\n"; 121 | continue; 122 | } 123 | 124 | temp_name = "#MAX_DIFF_BOUNCES#"; 125 | temp = line.find(temp_name); 126 | if (temp != string::npos) 127 | { 128 | line.replace(temp, temp_name.length(), std::to_string(scene->MAX_DIFF_BOUNCES)); 129 | source += line + "\n"; 130 | continue; 131 | } 132 | 133 | temp_name = "#MAX_SPEC_BOUNCES#"; 134 | temp = line.find(temp_name); 135 | if (temp != string::npos) 136 | { 137 | line.replace(temp, temp_name.length(), std::to_string(scene->MAX_SPEC_BOUNCES)); 138 | source += line + "\n"; 139 | continue; 140 | } 141 | 142 | temp_name = "#MAX_TRANS_BOUNCES#"; 143 | temp = line.find(temp_name); 144 | if (temp != string::npos) 145 | { 146 | line.replace(temp, temp_name.length(), std::to_string(scene->MAX_TRANS_BOUNCES)); 147 | source += line + "\n"; 148 | continue; 149 | } 150 | 151 | temp_name = "#MAX_SCATTERING_EVENTS#"; 152 | temp = line.find(temp_name); 153 | if (temp != string::npos) 154 | { 155 | line.replace(temp, temp_name.length(), std::to_string(scene->MAX_SCATTERING_EVENTS)); 156 | source += line + "\n"; 157 | continue; 158 | } 159 | 160 | temp_name = "#MARCHING_STEPS#"; 161 | temp = line.find(temp_name); 162 | if (temp != string::npos) 163 | { 164 | line.replace(temp, temp_name.length(), std::to_string(scene->MARCHING_STEPS)); 165 | source += line + "\n"; 166 | continue; 167 | } 168 | 169 | temp_name = "#SHADOW_MARCHING_STEPS#"; 170 | temp = line.find(temp_name); 171 | if (temp != string::npos) 172 | { 173 | line.replace(temp, temp_name.length(), std::to_string(scene->SHADOW_MARCHING_STEPS)); 174 | source += line + "\n"; 175 | continue; 176 | } 177 | 178 | //--------------------------------- MESH TYPES --------------------------------- 179 | 180 | temp_name = "#SPHERE#"; 181 | temp = line.find(temp_name); 182 | if (temp != string::npos) 183 | { 184 | if (scene->H_SPHERE) { 185 | line.replace(temp, temp_name.length(), std::to_string(SPHERE)); 186 | source += line + "\n"; 187 | } 188 | continue; 189 | } 190 | 191 | temp_name = "#BOX#"; 192 | temp = line.find(temp_name); 193 | if (temp != string::npos) 194 | { 195 | if (scene->H_BOX) { 196 | line.replace(temp, temp_name.length(), std::to_string(BOX)); 197 | source += line + "\n"; 198 | } 199 | continue; 200 | } 201 | 202 | temp_name = "#SDF#"; 203 | temp = line.find(temp_name); 204 | if (temp != string::npos) 205 | { 206 | if (scene->H_SDF) { 207 | line.replace(temp, temp_name.length(), std::to_string(SDF)); 208 | source += line + "\n"; 209 | } 210 | continue; 211 | } 212 | 213 | temp_name = "#QUAD#"; 214 | temp = line.find(temp_name); 215 | if (temp != string::npos) 216 | { 217 | if (scene->H_QUAD) { 218 | line.replace(temp, temp_name.length(), std::to_string(QUAD)); 219 | source += line + "\n"; 220 | } 221 | continue; 222 | } 223 | 224 | //--------------------------------- MATERIAL TYPES --------------------------------- 225 | 226 | temp_name = "#LIGHT#"; 227 | temp = line.find(temp_name); 228 | if (temp != string::npos) 229 | { 230 | if (scene->ACTIVE_MATS & LIGHT) 231 | { 232 | line.replace(temp, temp_name.length(), std::to_string(LIGHT)); 233 | source += line + "\n"; 234 | } 235 | continue; 236 | } 237 | 238 | temp_name = "#DIFF#"; 239 | temp = line.find(temp_name); 240 | if (temp != string::npos) 241 | { 242 | if (scene->ACTIVE_MATS & DIFF) 243 | { 244 | line.replace(temp, temp_name.length(), std::to_string(DIFF)); 245 | source += line + "\n"; 246 | } 247 | 248 | continue; 249 | } 250 | 251 | temp_name = "#COND#"; 252 | temp = line.find(temp_name); 253 | if (temp != string::npos) 254 | { 255 | if (scene->ACTIVE_MATS & COND) 256 | { 257 | line.replace(temp, temp_name.length(), std::to_string(COND)); 258 | source += line + "\n"; 259 | } 260 | continue; 261 | } 262 | 263 | temp_name = "#ROUGH_COND#"; 264 | temp = line.find(temp_name); 265 | if (temp != string::npos) 266 | { 267 | if (scene->ACTIVE_MATS & ROUGH_COND) 268 | { 269 | line.replace(temp, temp_name.length(), std::to_string(ROUGH_COND)); 270 | source += line + "\n"; 271 | } 272 | continue; 273 | } 274 | 275 | temp_name = "#DIEL#"; 276 | temp = line.find(temp_name); 277 | if (temp != string::npos) 278 | { 279 | if (scene->ACTIVE_MATS & DIEL) 280 | { 281 | line.replace(temp, temp_name.length(), std::to_string(DIEL)); 282 | source += line + "\n"; 283 | } 284 | continue; 285 | } 286 | 287 | temp_name = "#ROUGH_DIEL#"; 288 | temp = line.find(temp_name); 289 | if (temp != string::npos) 290 | { 291 | if (scene->ACTIVE_MATS & ROUGH_DIEL) 292 | { 293 | line.replace(temp, temp_name.length(), std::to_string(ROUGH_DIEL)); 294 | source += line + "\n"; 295 | } 296 | continue; 297 | } 298 | 299 | temp_name = "#COAT#"; 300 | temp = line.find(temp_name); 301 | if (temp != string::npos) 302 | { 303 | if (scene->ACTIVE_MATS & COAT) 304 | { 305 | line.replace(temp, temp_name.length(), std::to_string(COAT)); 306 | source += line + "\n"; 307 | } 308 | continue; 309 | } 310 | 311 | temp_name = "#VOL#"; 312 | temp = line.find(temp_name); 313 | if (temp != string::npos) 314 | { 315 | if (scene->ACTIVE_MATS & VOL) 316 | { 317 | line.replace(temp, temp_name.length(), std::to_string(VOL)); 318 | source += line + "\n"; 319 | } 320 | continue; 321 | } 322 | 323 | temp_name = "#TRANS#"; 324 | temp = line.find(temp_name); 325 | if (temp != string::npos) 326 | { 327 | if (scene->ACTIVE_MATS & TRANS) 328 | { 329 | line.replace(temp, temp_name.length(), std::to_string(TRANS)); 330 | source += line + "\n"; 331 | } 332 | continue; 333 | } 334 | 335 | temp_name = "#SPECSUB#"; 336 | temp = line.find(temp_name); 337 | if (temp != string::npos) 338 | { 339 | if (scene->ACTIVE_MATS & SPECSUB) 340 | { 341 | line.replace(temp, temp_name.length(), std::to_string(SPECSUB)); 342 | source += line + "\n"; 343 | } 344 | continue; 345 | } 346 | 347 | temp_name = "#ABS_REFR#"; 348 | temp = line.find(temp_name); 349 | if (temp != string::npos) 350 | { 351 | line.replace(temp, temp_name.length(), std::to_string(ABS_REFR)); 352 | source += line + "\n"; 353 | continue; 354 | } 355 | 356 | temp_name = "#ABS_REFR2#"; 357 | temp = line.find(temp_name); 358 | if (temp != string::npos) 359 | { 360 | line.replace(temp, temp_name.length(), std::to_string(ABS_REFR2)); 361 | source += line + "\n"; 362 | continue; 363 | } 364 | 365 | //--------------------------------- LIGHT --------------------------------- 366 | 367 | if (scene->LIGHT_COUNT) 368 | { 369 | 370 | temp_name = "#LIGHT_COUNT#"; 371 | temp = line.find(temp_name); 372 | if (temp != string::npos) 373 | { 374 | line.replace(temp, temp_name.length(), std::to_string(scene->LIGHT_COUNT)); 375 | source += line + "\n"; 376 | continue; 377 | } 378 | 379 | temp_name = "#INV_LIGHT_COUNT#"; 380 | temp = line.find(temp_name); 381 | if (temp != string::npos) 382 | { 383 | line.replace(temp, temp_name.length(), std::to_string(1.0f / scene->LIGHT_COUNT) + "f"); 384 | source += line + "\n"; 385 | continue; 386 | } 387 | 388 | temp_name = "#LIGHT_INDICES#"; 389 | temp = line.find(temp_name); 390 | if (temp != string::npos) 391 | { 392 | string res = ""; 393 | for (cl_uint i = 0; i < scene->LIGHT_COUNT; ++i) 394 | res += std::to_string(scene->LIGHT_INDICES[i]) + ((i != (scene->LIGHT_COUNT - 1)) ? "," : ""); 395 | 396 | line.replace(temp, temp_name.length(), res); 397 | source += line + "\n"; 398 | continue; 399 | } 400 | } 401 | 402 | //--------------------------------- SDF TYPES --------------------------------- 403 | 404 | temp_name = "#SDF_SPHERE#"; 405 | temp = line.find(temp_name); 406 | if (temp != string::npos) 407 | { 408 | line.replace(temp, temp_name.length(), std::to_string(SDF_SPHERE)); 409 | source += line + "\n"; 410 | continue; 411 | } 412 | 413 | temp_name = "#SDF_BOX#"; 414 | temp = line.find(temp_name); 415 | if (temp != string::npos) 416 | { 417 | line.replace(temp, temp_name.length(), std::to_string(SDF_BOX)); 418 | source += line + "\n"; 419 | continue; 420 | } 421 | 422 | temp_name = "#SDF_ROUND_BOX#"; 423 | temp = line.find(temp_name); 424 | if (temp != string::npos) 425 | { 426 | line.replace(temp, temp_name.length(), std::to_string(SDF_ROUND_BOX)); 427 | source += line + "\n"; 428 | continue; 429 | } 430 | 431 | temp_name = "#SDF_PLANE#"; 432 | temp = line.find(temp_name); 433 | if (temp != string::npos) 434 | { 435 | line.replace(temp, temp_name.length(), std::to_string(SDF_PLANE)); 436 | source += line + "\n"; 437 | continue; 438 | } 439 | 440 | //----------------------------------------------------------------------------- 441 | 442 | source += line + "\n"; 443 | } 444 | 445 | return source; 446 | } 447 | } // namespace kernel 448 | } // namespace cl_help 449 | -------------------------------------------------------------------------------- /include/CL/cl_program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | extern cl::Context context; 8 | 9 | namespace cl_help 10 | { 11 | namespace program 12 | { 13 | inline cl::Program LoadProgram(std::string filepath, std::string opts, std::vector devices) 14 | { 15 | cl::Program program = cl::Program(context, utils::ReadFile(filepath).c_str()); 16 | 17 | //"-D OBJECTS_SIZE=23" 18 | // Build the program for the selected device 19 | cl_int result = program.build(devices, opts.c_str()); // "-cl-fast-relaxed-math" 20 | if (result) 21 | std::cout << "Error during compilation OpenCL code!!!\n (" << result << ")" << std::endl; 22 | if (result == CL_BUILD_PROGRAM_FAILURE) 23 | std::cerr << "couldn't load the program '" << filepath << "'\n"; 24 | 25 | return program; 26 | } 27 | } // namespace program 28 | } // namespace cl_help 29 | -------------------------------------------------------------------------------- /include/Camera/camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // Camera struct, used to store interactive camera data, copied to the GPU and used by OpenCL for each frame 7 | struct Camera { 8 | ALIGN(16)vec3 position; 9 | ALIGN(16)vec3 view; 10 | ALIGN(16)vec3 up; 11 | ALIGN(8)vec2 resolution; 12 | ALIGN(8)vec2 fov; 13 | float apertureRadius; 14 | float focalDistance; 15 | }; 16 | 17 | // class for interactive camera object, updated on the CPU for each frame and copied into Camera struct 18 | class InteractiveCamera 19 | { 20 | private: 21 | 22 | vec3 centerPosition; 23 | vec3 viewDirection; 24 | float yaw; 25 | float pitch; 26 | float radius; 27 | float apertureRadius; 28 | float focalDistance; 29 | 30 | void fixYaw(); 31 | void fixPitch(); 32 | void fixRadius(); 33 | void fixApertureRadius(); 34 | void fixFocalDistance(); 35 | 36 | public: 37 | InteractiveCamera(); 38 | virtual ~InteractiveCamera(); 39 | 40 | void changeYaw(float m); 41 | void changePitch(float m); 42 | void changeRadius(float m); 43 | void changeAltitude(float m); 44 | void changeFocalDistance(float m); 45 | void strafe(float m); 46 | void goForward(float m); 47 | void rotateRight(float m); 48 | void changeApertureDiameter(float m); 49 | void setResolution(float x, float y); 50 | void setFOVX(float fovx); 51 | 52 | void buildRenderCamera(Camera* renderCamera); 53 | 54 | vec2 resolution; 55 | vec2 fov; 56 | }; 57 | -------------------------------------------------------------------------------- /include/GL/cl_gl_interop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // OpenGL window 13 | GLFWwindow* window; 14 | 15 | // quad vertices 16 | const GLfloat quad_vertices[] = { -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0 }; 17 | 18 | // display texture 19 | GLuint tex0, tex1/*, tex2*/; 20 | 21 | // OpenGL vertex buffer object 22 | GLuint vbo; 23 | 24 | const std::string vert_filepath = "../../shaders/vert.glsl"; 25 | const std::string tonemapper_filepath = "../../shaders/tonemapper.glsl"; 26 | 27 | extern std::string env_map_filepath; 28 | extern unsigned char encoder; 29 | 30 | bool initGL(){ 31 | 32 | if(glfwInit()) std::cout << "GLFW initialized!" << std::endl; 33 | else return false; 34 | 35 | glfwWindowHint(GLFW_VISIBLE, GL_FALSE); 36 | glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); 37 | 38 | window = glfwCreateWindow(window_width, window_height, "OpenCL-Pathtracer", NULL, NULL); 39 | glfwMakeContextCurrent(window); 40 | 41 | glfwSetKeyCallback(window, key_callback); 42 | glfwSetMouseButtonCallback(window, mouse_button_callback); 43 | glfwSetCursorPosCallback(window, cursor_pos_callback); 44 | glfwSetScrollCallback(window, scroll_callback); 45 | //glfwSetWindowSizeCallback(window, window_size_callback); 46 | 47 | // initialise OpenGL extensions 48 | if(glewInit() == GLEW_OK) std::cout << "GLEW initialized \n"; 49 | else return false; 50 | 51 | // initialise OpenGL 52 | glEnable(GL_BLEND); 53 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 54 | glMatrixMode(GL_PROJECTION); 55 | glOrtho(0.0f, window_width, window_height, 0.0f, 0.0f, 1.0f); 56 | // create vbo 57 | glGenBuffers(1, &vbo); 58 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 59 | glBufferData(GL_ARRAY_BUFFER, sizeof(quad_vertices), quad_vertices, GL_STATIC_DRAW); 60 | 61 | // radiance 62 | glGenTextures(1, &tex0); 63 | glActiveTexture(GL_TEXTURE0); 64 | glBindTexture(GL_TEXTURE_2D, tex0); 65 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, window_width, window_height, 0, GL_RGBA, GL_FLOAT, NULL); 66 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 67 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 68 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 69 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 70 | 71 | // enviroment map 72 | glGenTextures(1, &tex1); 73 | glActiveTexture(GL_TEXTURE1); 74 | glBindTexture(GL_TEXTURE_2D, tex1); 75 | if (!env_map_filepath.empty()) { 76 | Texture* cubemap = loadHDR(env_map_filepath.c_str()); 77 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, cubemap->width, cubemap->height, 0, GL_RGB, GL_FLOAT, &cubemap->data[0]); 78 | stbi_image_free(cubemap->data); 79 | delete cubemap; 80 | } else { 81 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1, 1, 0, GL_RGB, GL_FLOAT, NULL); 82 | } 83 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 84 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 85 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 86 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 87 | 88 | // noise texture 89 | // glGenTextures(1, &tex2); 90 | // glActiveTexture(GL_TEXTURE2); 91 | // glBindTexture(GL_TEXTURE_2D, tex2); 92 | 93 | // Texture* noise_tex = loadPNG("../resources/textures/rgb_noise1024.png"); 94 | // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, noise_tex->width, noise_tex->height, 0, GL_RGB, GL_UNSIGNED_BYTE, &noise_tex->data[0]); 95 | // stbi_image_free(noise_tex->data); 96 | // delete noise_tex; 97 | 98 | // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 99 | // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 100 | // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 101 | // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 102 | 103 | // glActiveTexture(GL_TEXTURE0); 104 | // glBindTexture(GL_TEXTURE_2D, tex0); 105 | 106 | // Create and compile the vertex shader 107 | std::string vertStr = utils::ReadFile(vert_filepath); 108 | const char* vertSrc = vertStr.c_str(); 109 | 110 | GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); 111 | glShaderSource(vertexShader, 1, &vertSrc, NULL); 112 | glCompileShader(vertexShader); 113 | 114 | // Create and compile the fragment shader 115 | std::string fragmentStr = utils::ReadFile(tonemapper_filepath); 116 | const char* fragmentSrc = fragmentStr.c_str(); 117 | 118 | GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 119 | glShaderSource(fragmentShader, 1, &fragmentSrc, NULL); 120 | glCompileShader(fragmentShader); 121 | 122 | // Link the vertex and fragment shader into a shader program 123 | GLuint shaderProgram = glCreateProgram(); 124 | glAttachShader(shaderProgram, vertexShader); 125 | glAttachShader(shaderProgram, fragmentShader); 126 | glLinkProgram(shaderProgram); 127 | glUseProgram(shaderProgram); 128 | 129 | glUniform1i(glGetUniformLocation(shaderProgram, "u_tex"), 0); 130 | glUniform2f(glGetUniformLocation(shaderProgram, "u_resolution"), window_width, window_height); 131 | 132 | // load vbo 133 | GLint posAttrib = glGetAttribLocation(shaderProgram, "position"); 134 | glEnableVertexAttribArray(posAttrib); 135 | glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0); 136 | 137 | std::cout << "OpenGL initialized \n"; 138 | 139 | stbi_flip_vertically_on_write(true); 140 | 141 | return true; 142 | } 143 | 144 | void saveImage() { 145 | double tStart = glfwGetTime(); 146 | 147 | if (encoder == 0) { 148 | GLubyte* pixels = new GLubyte[4 * window_width * window_height]; 149 | glReadPixels(0, 0, window_width, window_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 150 | stbi_write_png("render.png", window_width, window_height, 4, pixels, 0); 151 | delete pixels; 152 | } else if (encoder == 1) { 153 | float* pixels = new float[3 * window_width * window_height]; 154 | glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_FLOAT, pixels); 155 | stbi_write_hdr("render.hdr", window_width, window_height, 3, pixels); 156 | delete pixels; 157 | } 158 | 159 | std::cout << std::endl << "succesfully saved in ( " << glfwGetTime() - tStart << "s )" << std::endl; 160 | } 161 | 162 | void createVBO(GLuint* vbo){ 163 | 164 | //create vertex buffer object 165 | glGenBuffers(1, vbo); 166 | glBindBuffer(GL_ARRAY_BUFFER, *vbo); 167 | 168 | //initialise VBO 169 | unsigned int size = window_width * window_height * sizeof(cl_float4); 170 | glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW); 171 | glBindBuffer(GL_ARRAY_BUFFER, 0); 172 | } 173 | 174 | void drawGL(){ 175 | glClear(GL_COLOR_BUFFER_BIT); 176 | glDrawArrays(GL_TRIANGLES, 0, 6); 177 | } 178 | -------------------------------------------------------------------------------- /include/GL/user_interaction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | bool buffer_reset(true); 7 | bool render_to_file(false); 8 | 9 | void initCamera(); 10 | 11 | extern InteractiveCamera *interactiveCamera; 12 | extern int window_width; 13 | extern int window_height; 14 | 15 | // keyboard interaction 16 | inline void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) 17 | { 18 | switch (key) { 19 | case GLFW_KEY_ESCAPE: glfwDestroyWindow(window); glfwTerminate(); exit(0); 20 | case GLFW_KEY_SPACE: initCamera(); buffer_reset = true; break; 21 | case GLFW_KEY_A : interactiveCamera->strafe(-0.05f); buffer_reset = true; break; 22 | case GLFW_KEY_D: interactiveCamera->strafe(0.05f); buffer_reset = true; break; 23 | case GLFW_KEY_R: interactiveCamera->changeAltitude(0.05f); buffer_reset = true; break; 24 | case GLFW_KEY_F: interactiveCamera->changeAltitude(-0.05f); buffer_reset = true; break; 25 | case GLFW_KEY_W: interactiveCamera->goForward(0.05f); buffer_reset = true; break; 26 | case GLFW_KEY_S: interactiveCamera->goForward(-0.05f); buffer_reset = true; break; 27 | case GLFW_KEY_G: interactiveCamera->changeApertureDiameter(0.1); buffer_reset = true; break; 28 | case GLFW_KEY_H: interactiveCamera->changeApertureDiameter(-0.1); buffer_reset = true; break; 29 | case GLFW_KEY_T: interactiveCamera->changeFocalDistance(0.1); buffer_reset = true; break; 30 | case GLFW_KEY_Y: interactiveCamera->changeFocalDistance(-0.1); buffer_reset = true; break; 31 | case GLFW_KEY_LEFT: interactiveCamera->changeYaw(0.02f); buffer_reset = true; break; 32 | case GLFW_KEY_RIGHT: interactiveCamera->changeYaw(-0.02f); buffer_reset = true; break; 33 | case GLFW_KEY_UP: interactiveCamera->changePitch(0.02f); buffer_reset = true; break; 34 | case GLFW_KEY_DOWN: interactiveCamera->changePitch(-0.02f); buffer_reset = true; break; 35 | case GLFW_KEY_PRINT_SCREEN: render_to_file = true; break; 36 | } 37 | } 38 | 39 | // mouse event handlers 40 | double lastX = 0, lastY = 0; 41 | bool updateCamera = false; 42 | int theButtonState = 0; 43 | 44 | // camera mouse controls in X and Y direction 45 | inline void cursor_pos_callback(GLFWwindow* window, double x, double y) 46 | { 47 | if (!updateCamera) return; 48 | 49 | double deltaX = lastX - x; 50 | double deltaY = lastY - y; 51 | 52 | if (deltaX != 0 || deltaY != 0) { 53 | 54 | if (theButtonState == GLFW_MOUSE_BUTTON_LEFT) // Rotate 55 | { 56 | interactiveCamera->changeYaw(deltaX * 0.01); 57 | interactiveCamera->changePitch(-deltaY * 0.01); 58 | } 59 | else if (theButtonState == GLFW_MOUSE_BUTTON_MIDDLE) // Zoom 60 | { 61 | interactiveCamera->changeAltitude(-deltaY * 0.01); 62 | // interactiveCamera->strafe(-deltaX * 0.01); 63 | } 64 | 65 | if (theButtonState == GLFW_MOUSE_BUTTON_RIGHT) // camera move 66 | { 67 | interactiveCamera->changeRadius(-deltaY * 0.01); 68 | } 69 | 70 | lastX = x; 71 | lastY = y; 72 | buffer_reset = true; 73 | } 74 | } 75 | 76 | inline void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) 77 | { 78 | updateCamera = (action == GLFW_PRESS); 79 | 80 | if (updateCamera) { 81 | theButtonState = button; 82 | glfwGetCursorPos(window, &lastX, &lastY); 83 | } 84 | } 85 | 86 | inline void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) 87 | { 88 | interactiveCamera->changeRadius(-yoffset * 0.01); 89 | buffer_reset = true; 90 | } 91 | -------------------------------------------------------------------------------- /include/Math/MathHelp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef FLT_MAX 4 | #define FLT_MAX 3.402823466e+38F 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | struct Tri { 12 | cl_uint4 face; 13 | vec3 bbMin; 14 | vec3 bbMax; 15 | }; 16 | 17 | class MathHelp { 18 | public: 19 | static cl_float degToRad(cl_float deg); 20 | static void getAABB( 21 | const std::vector& vertices, vec3& bbMin, vec3& bbMax 22 | ); 23 | static void getAABB( 24 | const std::vector& vertices, vec3& bbMin, vec3& bbMax 25 | ); 26 | static void getAABB( 27 | const std::vector& bbMins, const std::vector& bbMaxs, 28 | vec3* bbMin, vec3* bbMax 29 | ); 30 | static cl_float getOverlapSA(vec3 bbA, vec3 bbB); 31 | static cl_float getSurfaceArea(vec3 bbMin, vec3 bbMax); 32 | static void getTriangleAABB( 33 | cl_float4 v0, cl_float4 v1, cl_float4 v2, vec3* bbMin, vec3* bbMax 34 | ); 35 | static vec3 getTriangleCenter( 36 | cl_float4 v0, cl_float4 v1, cl_float4 v2 37 | ); 38 | static vec3 getTriangleCentroid( 39 | cl_float4 v0, cl_float4 v1, cl_float4 v2 40 | ); 41 | static vec3 intersectLinePlane( 42 | vec3 p, vec3 q, vec3 x, vec3 nl, bool* isParallel 43 | ); 44 | static short longestAxis(vec3 bbMin, vec3 bbMax); 45 | static vec3 phongTessellate( 46 | const vec3 p1, const vec3 p2, const vec3 p3, 47 | const vec3 n1, const vec3 n2, const vec3 n3, 48 | const float alpha, const float u, const float v 49 | ); 50 | static vec3 projectOnPlane(vec3 q, vec3 p, vec3 n); 51 | static cl_float radToDeg(cl_float rad); 52 | static void triCalcAABB(Tri* tri, const std::vector* vertices, const std::vector* normals); 53 | static void triThicknessAndSidedrop( 54 | const vec3 p1, const vec3 p2, const vec3 p3, 55 | const vec3 n1, const vec3 n2, const vec3 n3, 56 | float* thickness, vec3* sidedropMin, vec3* sidedropMax 57 | ); 58 | }; 59 | -------------------------------------------------------------------------------- /include/Math/linear_algebra.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #ifndef M_PI 7 | #define M_PI 3.14156265 8 | #endif 9 | 10 | #ifndef PI_OVER_TWO 11 | #define PI_OVER_TWO 1.5707963267948966192313216916397514420985 12 | #endif 13 | 14 | struct vec2 15 | { 16 | union { 17 | struct { float x, y; }; 18 | float _v[2]; 19 | }; 20 | 21 | vec2(float _x = 0.0f, float _y = 0.0f) : x(_x), y(_y) {} 22 | vec2(const vec2& v) : x(v.x), y(v.y) {} 23 | inline vec2 operator*(float a) const { return vec2(x*a, y*a); } 24 | inline vec2 operator/(float a) const { return vec2(x / a, y / a); } 25 | inline vec2 operator*(const vec2& v) const { return vec2(x * v.x, y * v.y); } 26 | inline vec2 operator+(const vec2& v) const { return vec2(x + v.x, y + v.y); } 27 | inline vec2 operator-(const vec2& v) const { return vec2(x - v.x, y - v.y); } 28 | }; 29 | 30 | //------------------------------------------------------------------------------------------------- 31 | 32 | template 33 | struct Vector 34 | { 35 | union { 36 | struct { Scalar x, y, z, w; }; 37 | Scalar _v[4]; 38 | }; 39 | 40 | // constructors 41 | Vector() : x(0), y(0), z(0), w(0) {} 42 | Vector(Scalar val) : x(val), y(val), z(val), w(val) {} 43 | Vector(Scalar _x, Scalar _y) : x(_x), y(_y), z(0), w(0) {} 44 | Vector(Scalar _x, Scalar _y, Scalar _z) : x(_x), y(_y), z(_z), w(0) {} 45 | Vector(Scalar _x, Scalar _y, Scalar _z, Scalar _w) : x(_x), y(_y), z(_z), w(_w) {} 46 | Vector(const Vector& v) : x(v.x), y(v.y), z(v.z), w(v.w) {} 47 | 48 | // operators 49 | 50 | inline Scalar& operator[](const int i) { if (i == 0) return x; if (i == 1) return y; if (i == 2) return z; return w; } 51 | inline Scalar operator[](const int i) const { if (i == 0) return x; if (i == 1) return y; if (i == 2) return z; return w; } 52 | 53 | inline Vector operator+(Scalar a) const { return Vector(x + a, y + a, z + a, w + a); } 54 | inline Vector operator-(Scalar a) const { return Vector(x - a, y - a, z - a, w - a); } 55 | inline Vector operator*(Scalar a) const { return Vector(x * a, y * a, z * a, w * a); } 56 | inline Vector operator/(Scalar a) const { return Vector(x / a, y / a, z / a, w / a); } 57 | 58 | inline Vector operator+(const Vector& v) const { return Vector(x + v.x, y + v.y, z + v.z, w + v.w); } 59 | inline Vector operator-(const Vector& v) const { return Vector(x - v.x, y - v.y, z - v.z, w - v.w); } 60 | inline Vector operator*(const Vector& v) const { return Vector(x * v.x, y * v.y, z * v.z, w * v.w); } 61 | inline Vector operator/(const Vector& v) const { return Vector(x / v.x, y / v.y, z / v.z, w / v.w); } 62 | 63 | inline Vector& operator+=(const Scalar& a) { return *this=(*this + a); } 64 | inline Vector& operator+=(const Vector& v) { return *this=(*this + v); } 65 | 66 | inline Vector& operator-=(const Scalar& a) { return *this=(*this - a); } 67 | inline Vector& operator-=(const Vector& v) { return *this=(*this - v); } 68 | 69 | inline Vector& operator*=(const Scalar& a) { return *this=(*this * a); } 70 | inline Vector& operator*=(const Vector& v) { return *this=(*this * v); } 71 | 72 | inline Vector& operator/=(const Scalar& a) { return *this=(*this / a); } 73 | inline Vector& operator/=(const Vector& v) { return *this=(*this / v); } 74 | 75 | inline bool operator!=(const Vector& v) { return x != v.x || y != v.y || z != v.z; } 76 | 77 | //------------------------------------------------------------------------------------------------- 78 | 79 | float lengthsq3(){return sqrtf(x * x + y * y + z * z);}; 80 | float lengthsq4(){return sqrtf(x * x + y * y + z * z + w * w);}; 81 | void normalize(){ float norm = sqrtf(x * x + y * y + z * z); *this = *this / norm; }; 82 | }; 83 | 84 | using vec4 = Vector; 85 | 86 | inline vec4 operator+(const float& f, const vec4& v) { return v + f; } 87 | inline vec4 operator-(const float& f, const vec4& v) { return vec4(f) - v; } 88 | inline vec4 operator*(const float& f, const vec4& v) { return v * f; } 89 | inline vec4 operator/(const float& f, const vec4& v) { return vec4(f) / v; } 90 | 91 | inline vec4 min4(const vec4& v1, const vec4& v2){ return vec4(fmin(v1.x, v2.x), fmin(v1.y, v2.y), fmin(v1.z, v2.z), fmin(v1.w, v2.w)); } 92 | inline vec4 max4(const vec4& v1, const vec4& v2){ return vec4(fmax(v1.x, v2.x), fmax(v1.y, v2.y), fmax(v1.z, v2.z), fmax(v1.w, v2.w)); } 93 | 94 | inline float v_min4(const float& v1, const float& v2, const float& v3, const float& v4) { return fmin(fmin(fmin(v1, v2), v3), v4); } 95 | inline float v_min4(const vec4& v) { return fmin(fmin(fmin(v.x, v.y), v.z), v.w); } 96 | 97 | inline float v_max4(const float& v1, const float& v2, const float& v3, const float& v4) { return fmax(fmax(fmax(v1, v2), v3), v4); } 98 | inline float v_max4(const vec4& v) { return fmax(fmax(fmax(v.x, v.y), v.z), v.w); } 99 | 100 | //------------------------------------------------------------------------------------------------- 101 | 102 | // OpenCL handles vec3 exactly the same as vec4 103 | using vec3 = vec4; 104 | 105 | inline vec3 cross(const vec3& v1, const vec3& v2) { return vec3(v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x); } 106 | inline float dot(const vec3& v1, const vec3& v2) { return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; } 107 | inline float distancesq(const vec3& v1, const vec3& v2) { return (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) + (v1.z - v2.z)*(v1.z - v2.z); } 108 | inline float distance(const vec3& v1, const vec3& v2) { return sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) + (v1.z - v2.z)*(v1.z - v2.z)); } 109 | inline vec3 normalize(const vec3& v) { float norm = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z); return v / norm; } 110 | 111 | inline vec3 min3(const vec3& v1, const vec3& v2) { return vec3(fmin(v1.x, v2.x), fmin(v1.y, v2.y), fmin(v1.z, v2.z)); } 112 | inline vec3 max3(const vec3& v1, const vec3& v2) { return vec3(fmax(v1.x, v2.x), fmax(v1.y, v2.y), fmax(v1.z, v2.z)); } 113 | 114 | inline float v_min3(const float& v1, const float& v2, const float& v3) { return fmin(fmin(v1, v2), v3); } 115 | inline float v_min3(const vec3& v) { return fmin(fmin(v.x, v.z), v.w); } 116 | 117 | inline float v_max3(const float& v1, const float& v2, const float& v3) { return fmax(fmax(v1, v2), v3); } 118 | inline float v_max3(const vec3& v) { return fmax(fmax(v.x, v.y), v.w); } 119 | 120 | //------------------------------------------------------------------------------------------------- 121 | 122 | inline float fract(float x) { return (x - floor(x)); } -------------------------------------------------------------------------------- /include/Math/random.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace PRNG 6 | { 7 | // single iteration of Bob Jenkins' One-At-A-Time hashing algorithm: 8 | // http://www.burtleburtle.net/bob/hash/doobs.html 9 | // suggestes by Spatial on stackoverflow: 10 | // http://stackoverflow.com/questions/4200224/random-noise-functions-for-glsl 11 | inline uint32_t BJXorShift(uint32_t x) 12 | { 13 | x += x << 10u; 14 | x ^= x >> 6u; 15 | x += x << 3u; 16 | x ^= x >> 11u; 17 | x += x << 15u; 18 | 19 | return x; 20 | } 21 | 22 | // xor-shift algorithm by George Marsaglia 23 | // https://www.thecodingforums.com/threads/re-rngs-a-super-kiss.704080/ 24 | // suggestes by Nathan Reed: 25 | // http://www.reedbeta.com/blog/quick-and-easy-gpu-random-numbers-in-d3d11/ 26 | inline uint32_t GMXorShift(uint32_t x) 27 | { 28 | x ^= x << 13u; 29 | x ^= x >> 17u; 30 | x ^= x << 5u; 31 | 32 | return x; 33 | } 34 | 35 | // hashing algorithm by Thomas Wang 36 | // http://www.burtleburtle.net/bob/hash/integer.html 37 | // suggestes by Nathan Reed: 38 | // http://www.reedbeta.com/blog/quick-and-easy-gpu-random-numbers-in-d3d11/ 39 | inline uint32_t WangHash(uint32_t x) 40 | { 41 | x = (x ^ 61u) ^ (x >> 16u); 42 | x *= 9u; 43 | x ^= x >> 4u; 44 | x *= 0x27d4eb2du; 45 | x ^= x >> 15u; 46 | 47 | return x; 48 | } 49 | 50 | // classic sin hash function 51 | inline float sinHash(float seed) 52 | { 53 | return fract(sin(seed) * 43758.5453123); 54 | } 55 | 56 | inline vec2 sinHash2(float seed) 57 | { 58 | return vec2(sin(seed) * 43758.5453123, sin(seed) * 22578.1459123); 59 | } 60 | 61 | inline vec3 sinHash3(float seed) 62 | { 63 | return vec3(sin(seed) * 43758.5453123, sin(seed) * 22578.1459123, sin(seed) * 19642.3490423); 64 | } 65 | 66 | } // namespace PRNG 67 | -------------------------------------------------------------------------------- /include/Model/model_loader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include // C++ importer interface 14 | 15 | struct aiScene; 16 | struct aiMesh; 17 | struct aiNode; 18 | 19 | namespace CL_RAYTRACER 20 | { 21 | namespace IO 22 | { 23 | struct Vertex 24 | { 25 | cl_float3 pos; 26 | cl_float3 nor; 27 | 28 | /* 29 | cl_float3 tangent; 30 | cl_float2 uv; 31 | cl_uint id; 32 | */ 33 | Vertex() {} 34 | }; 35 | 36 | struct Face 37 | { 38 | std::array points; 39 | 40 | Face() {} 41 | Face(Vertex v0, Vertex v1, Vertex v2) 42 | { 43 | points[0] = v0; 44 | points[1] = v1; 45 | points[2] = v2; 46 | } 47 | }; 48 | 49 | struct Mesh 50 | { 51 | std::vector faces; 52 | 53 | Mesh() {} 54 | Mesh(std::vector &_faces) : faces(_faces) {} 55 | }; 56 | 57 | struct Scene 58 | { 59 | std::vector meshes; 60 | 61 | Scene() {} 62 | Scene(std::vector &_meshes) : meshes(_meshes) {} 63 | }; 64 | 65 | // Raw Data 66 | typedef std::pair, std::vector> MeshData; 67 | typedef std::vector SceneData; 68 | 69 | class ModelLoader 70 | { 71 | 72 | public: 73 | ModelLoader() {} 74 | ~ModelLoader() {} 75 | 76 | bool ImportFromFile(const std::string &filepath); 77 | const std::shared_ptr getData() const 78 | { 79 | return sceneData; 80 | } 81 | const std::unique_ptr getFaces(); 82 | 83 | std::vector getIndices() const; 84 | std::vector getIndices4() const; 85 | std::vector getIndicesAt(unsigned index) const; 86 | 87 | std::vector getPositions() const; 88 | std::vector getPositions4() const; 89 | std::vector getPositionsAt(unsigned index) const; 90 | 91 | std::vector getNormals() const; 92 | std::vector getNormals4() const; 93 | std::vector getNormalsAt(unsigned index) const; 94 | 95 | std::vector getTextureCoords() const; 96 | std::vector getTextureCoords4() const; 97 | // std::vector getTextureCoordsAt(unsigned index) const; 98 | 99 | std::vector getTangents() const; 100 | std::vector getTangents4() const; 101 | // std::vector getTangentsAt(unsigned index) const; 102 | 103 | private: 104 | void updateSceneData(aiNode *node, const aiScene *scene); 105 | const MeshData assimpGetMeshData(const aiMesh *mesh); 106 | 107 | // raw data 108 | std::shared_ptr sceneData; 109 | 110 | // Create an instance of the Importer class 111 | Assimp::Importer importer; 112 | 113 | // get pointers to data 114 | const void *getPositionsPtr(const MeshData &data); 115 | const void *getNormalsPtr(const MeshData &data); 116 | const void *getTextureCoordsPtr(const MeshData &data); 117 | const void *getTangentsPtr(const MeshData &data); 118 | 119 | std::vector getIndices(const MeshData &data) const; 120 | std::vector getIndices4(const MeshData &data) const; 121 | 122 | std::vector getPositions(const MeshData &data) const; 123 | std::vector getPositions4(const MeshData &data) const; 124 | 125 | std::vector getNormals(const MeshData &data) const; 126 | std::vector getNormals4(const MeshData &data) const; 127 | 128 | std::vector getTextureCoords(const MeshData &data) const; 129 | std::vector getTextureCoords4(const MeshData &data) const; 130 | 131 | std::vector getTangents(const MeshData &data) const; 132 | std::vector getTangents4(const MeshData &data) const; 133 | }; 134 | } // namespace IO 135 | } // namespace CL_RAYTRACER -------------------------------------------------------------------------------- /include/Scene/geometry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | constexpr cl_uchar TOTAL_GEOM_TYPES = 4; 10 | constexpr cl_uchar SPHERE = 1 << 0; 11 | constexpr cl_uchar BOX = 1 << 1; 12 | constexpr cl_uchar SDF = 1 << 2; 13 | constexpr cl_uchar QUAD = 1 << 3; 14 | 15 | constexpr cl_uchar TOTAL_SDF_TYPES = 4; 16 | constexpr cl_uchar SDF_SPHERE = 1 << 4; 17 | constexpr cl_uchar SDF_BOX = 1 << 5; 18 | constexpr cl_uchar SDF_ROUND_BOX = 1 << 6; 19 | constexpr cl_uchar SDF_PLANE = 1 << 7; 20 | 21 | struct Mesh { 22 | Material mat; 23 | ALIGN(16)vec3 position; 24 | ALIGN(64)cl_float16 joker; 25 | cl_uchar t; 26 | 27 | Mesh() : t(SPHERE) {} 28 | }; 29 | -------------------------------------------------------------------------------- /include/Texture/texture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define STB_IMAGE_IMPLEMENTATION 6 | #include 7 | #define STB_IMAGE_WRITE_IMPLEMENTATION 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | template 15 | struct Texture 16 | { 17 | int width, height, nrComponents; 18 | T* data; 19 | }; 20 | 21 | inline Texture* loadPNG(const char* filepath) { 22 | Texture* res = new Texture(); 23 | 24 | //stbi_set_flip_vertically_on_load(true); 25 | res->data = stbi_load(filepath, &res->width, &res->height, &res->nrComponents, 0); 26 | std::cout << "Successfully loaded the given PNG image(" << res->width << "x" << res->height << "x" << res->nrComponents << ")" << std::endl; 27 | 28 | return res; 29 | } 30 | 31 | inline Texture* loadHDR(const char* filepath) { 32 | Texture* res = new Texture(); 33 | 34 | //stbi_set_flip_vertically_on_load(true); 35 | res->data = stbi_loadf(filepath, &res->width, &res->height, &res->nrComponents, 0); 36 | std::cout << "Successfully loaded the given HDR image(" << res->width << "x" << res->height << "x" << res->nrComponents << ")" << std::endl; 37 | 38 | return res; 39 | } 40 | -------------------------------------------------------------------------------- /include/Types/material.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mourtz/Photorealistic-Rendering-using-OpenCL/71f5b7d62b030ad9cabc0ee757c673a1969193bf/include/Types/material.h -------------------------------------------------------------------------------- /include/Types/media.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct cl_medium { 6 | cl_float density; 7 | cl_float sigmaA; 8 | cl_float sigmaS; 9 | cl_float sigmaT; 10 | bool absorptionOnly; 11 | }; 12 | -------------------------------------------------------------------------------- /include/align.h: -------------------------------------------------------------------------------- 1 | #ifndef __ALIGN_H___ 2 | #define __ALIGN_H___ 3 | 4 | #if defined(_MSC_VER) 5 | #define ALIGN(x) __declspec(align(x)) 6 | #elif defined(__GNUC__) || defined(__MINGW32__) 7 | #define ALIGN(x) __attribute__((aligned(x))) 8 | #elif defined(__OPENCL_C_VERSION__) 9 | #define ALIGN(x) __attribute__((aligned(x))) 10 | #else 11 | #error Alignment macro not set. 12 | #endif 13 | 14 | #endif // __ALIGN_H___ 15 | -------------------------------------------------------------------------------- /include/string_helper_functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // trim from start (in place) 10 | inline void ltrim(std::string &s) { 11 | s.erase(s.begin(), find_if(s.begin(), s.end(), [](int ch) { 12 | return !isspace(ch); 13 | })); 14 | } 15 | 16 | // trim from end (in place) 17 | inline void rtrim(std::string &s) { 18 | s.erase(find_if(s.rbegin(), s.rend(), [](int ch) { 19 | return !isspace(ch); 20 | }).base(), s.end()); 21 | } 22 | 23 | // trim from both ends (in place) 24 | inline void trim(std::string &s) { 25 | ltrim(s); 26 | rtrim(s); 27 | } 28 | 29 | std::vector split(const std::string& str, const std::string& delim) 30 | { 31 | using std::string; 32 | 33 | std::vector tokens; 34 | unsigned int prev = 0, pos = 0; 35 | do 36 | { 37 | pos = str.find(delim, prev); 38 | if (pos == string::npos) pos = str.length(); 39 | string token = str.substr(prev, pos-prev); 40 | trim(token); 41 | if (!token.empty()) tokens.push_back(token); 42 | prev = pos + delim.length(); 43 | } 44 | while (pos < str.length() && prev < str.length()); 45 | return tokens; 46 | } 47 | -------------------------------------------------------------------------------- /include/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include // std::string 3 | #include // std::cout 4 | #include 5 | #include // std::stringstream 6 | 7 | namespace utils { 8 | 9 | inline std::string ReadFile(std::string filepath) 10 | { 11 | std::ifstream t(filepath); 12 | std::stringstream buffer; 13 | buffer << t.rdbuf(); 14 | return buffer.str(); 15 | } 16 | 17 | /** 18 | * Format a value of bytes into more readable units. 19 | * @param {size_t} bytes 20 | * @param {float*} bytesFloat 21 | * @param {string*} unit 22 | */ 23 | inline void formatBytes(std::size_t bytes, float* bytesFloat, std::string* unit) { 24 | *unit = std::string("bytes"); 25 | *bytesFloat = (float)bytes; 26 | 27 | if (*bytesFloat >= 1024.0f) { 28 | *bytesFloat /= 1024.0f; 29 | *unit = std::string("KB"); 30 | } 31 | if (*bytesFloat >= 1024.0f) { 32 | *bytesFloat /= 1024.0f; 33 | *unit = std::string("MB"); 34 | } 35 | if (*bytesFloat >= 1024.0f) { 36 | *bytesFloat /= 1024.0f; 37 | *unit = std::string("GB"); 38 | } 39 | } 40 | 41 | /** 42 | * Read the contents of a file as string. 43 | * @param {const char*} filename Path to and name of the file. 44 | * @return {std::string} File content as string. 45 | */ 46 | inline std::string loadFileAsString(const char* filename) { 47 | std::ifstream fileIn(filename); 48 | std::string content; 49 | 50 | while (fileIn.good()) { 51 | std::string line; 52 | std::getline(fileIn, line); 53 | content.append(line + "\n"); 54 | } 55 | fileIn.close(); 56 | 57 | return content; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /kernels/bxdf/Fresnel.cl: -------------------------------------------------------------------------------- 1 | #ifndef __FRESNEL__ 2 | #define __FRESNEL__ 3 | 4 | // From "PHYSICALLY BASED LIGHTING CALCULATIONS FOR COMPUTER GRAPHICS" by Peter Shirley 5 | // http://www.cs.virginia.edu/~jdl/bib/globillum/shirley_thesis.pdf 6 | inline float conductorReflectance(float eta, float k, float cosThetaI) { 7 | float cosThetaISq = cosThetaI * cosThetaI; 8 | float sinThetaISq = fmax(1.0f - cosThetaISq, 0.0f); 9 | float sinThetaIQu = sinThetaISq * sinThetaISq; 10 | 11 | float innerTerm = eta * eta - k * k - sinThetaISq; 12 | float aSqPlusBSq = sqrt(fmax(innerTerm * innerTerm + 4.0f * eta * eta * k * k, 0.0f)); 13 | float a = sqrt(fmax((aSqPlusBSq + innerTerm) * 0.5f, 0.0f)); 14 | 15 | float Rs = ((aSqPlusBSq + cosThetaISq) - (2.0f * a * cosThetaI)) / 16 | ((aSqPlusBSq + cosThetaISq) + (2.0f * a * cosThetaI)); 17 | float Rp = ((cosThetaISq * aSqPlusBSq + sinThetaIQu) - (2.0f * a * cosThetaI * sinThetaISq)) / 18 | ((cosThetaISq * aSqPlusBSq + sinThetaIQu) + (2.0f * a * cosThetaI * sinThetaISq)); 19 | 20 | return 0.5f * (Rs + Rs * Rp); 21 | } 22 | 23 | inline float conductorReflectanceApprox(float eta, float k, float cosThetaI) { 24 | float cosThetaISq = cosThetaI * cosThetaI; 25 | float ekSq = eta * eta * +k * k; 26 | float cosThetaEta2 = cosThetaI * 2.0f * eta; 27 | 28 | float Rp = (ekSq * cosThetaISq - cosThetaEta2 + 1.0f) / (ekSq * cosThetaISq + cosThetaEta2 + 1.0f); 29 | float Rs = (ekSq - cosThetaEta2 + cosThetaISq) / (ekSq + cosThetaEta2 + cosThetaISq); 30 | return (Rs + Rp) * 0.5f; 31 | } 32 | 33 | inline float3 conductorReflectance3(float3 eta, float3 k, float cosThetaI) { 34 | return (float3)( 35 | conductorReflectance(eta.x, k.x, cosThetaI), 36 | conductorReflectance(eta.y, k.y, cosThetaI), 37 | conductorReflectance(eta.z, k.z, cosThetaI) 38 | ); 39 | } 40 | 41 | inline float dielectricReflectance(float eta, float cosThetaI, float* cosThetaT) { 42 | if (cosThetaI < 0.0f) { 43 | eta = 1.0f / eta; 44 | cosThetaI = -cosThetaI; 45 | } 46 | float sinThetaTSq = eta * eta * (1.0f - cosThetaI * cosThetaI); 47 | if (sinThetaTSq > 1.0f) { 48 | *cosThetaT = 0.0f; 49 | return 1.0f; 50 | } 51 | *cosThetaT = sqrt(fmax(1.0f - sinThetaTSq, 0.0f)); 52 | 53 | float Rs = (eta * ( cosThetaI) - (*cosThetaT)) / (eta * ( cosThetaI) + (*cosThetaT)); 54 | float Rp = (eta * (*cosThetaT) - ( cosThetaI)) / (eta * (*cosThetaT) + ( cosThetaI)); 55 | 56 | return (Rs * Rs + Rp * Rp) * 0.5f; 57 | } 58 | 59 | inline float3 dielectricReflectance3(float3 eta, float cosThetaI, 60 | float* cosThetaT_r, float* cosThetaT_g, float* cosThetaT_b 61 | ) { 62 | return (float3)( 63 | dielectricReflectance(eta.x, cosThetaI, cosThetaT_r), 64 | dielectricReflectance(eta.y, cosThetaI, cosThetaT_g), 65 | dielectricReflectance(eta.z, cosThetaI, cosThetaT_b) 66 | ); 67 | } 68 | 69 | #endif 70 | 71 | #if 0 72 | /* Schlick's approximation of Fresnel equation */ 73 | float schlick(const float3 dir, const float3 n, const float nc, const float nt) { 74 | float R0 = pow((nc - nt) / (nc + nt), 2.0f); 75 | return R0 + (1.0f - R0) * pow(1.0f + dot(n, dir), 5.0f); 76 | } 77 | 78 | /* Full Fresnel equation */ 79 | float fresnel(const float3 dir, const float3 n, const float nc, const float nt, const float3 refr) { 80 | float cosI = dot(dir, n); 81 | float costT = dot(n, refr); 82 | 83 | float Rs = pow((nc * cosI - nt * costT) / (nc * cosI + nt * costT), 2.0f); 84 | float Rp = pow((nc * costT - nt * cosI) / (nc * costT + nt * cosI), 2.0f); 85 | return (Rs + Rp) * 0.5f; 86 | } 87 | 88 | float3 refract(const float3 dir, const float3 nl, const float eta) { 89 | float k = 1.0f - eta * eta * (1.0f - dot(nl, dir) * dot(nl, dir)); 90 | 91 | if (k < 0.0f) 92 | return (float3)(0.0f); 93 | else 94 | return eta * dir - (eta * dot(nl, dir) + sqrt(k)) * nl; 95 | } 96 | #endif -------------------------------------------------------------------------------- /kernels/bxdf/Materials/Coat.cl: -------------------------------------------------------------------------------- 1 | #if defined(COAT) && !defined(__COAT__) 2 | #define __COAT__ 3 | 4 | #define _ior 1.3f 5 | #define _thickness 1.0f 6 | #define _sigmaA 0.0f 7 | #define _scaledSigmaA _thickness*_sigmaA 8 | #define _avgTransmittance native_exp(-2.0f*_scaledSigmaA) 9 | 10 | bool CoatBSDF( 11 | const Ray* ray, SurfaceScatterEvent* event, 12 | const Material* mat, 13 | RNG_SEED_PARAM 14 | ){ 15 | if (event->wi.z <= 0.0f) 16 | return false; 17 | 18 | const float eta = 1.0f / _ior; 19 | 20 | float cosThetaTi; 21 | float Fi = dielectricReflectance(eta, event->wi.z, &cosThetaTi); 22 | 23 | float specularProbability = Fi / (Fi + _avgTransmittance * (1.0f - Fi)); 24 | 25 | if (nextBoolean(specularProbability, RNG_SEED_VALUE)) { 26 | event->wo = (float3)(-event->wi.x, -event->wi.y, event->wi.z); 27 | event->pdf = specularProbability; 28 | event->weight = (float3)(Fi / specularProbability); 29 | event->sampledLobe = SpecularReflectionLobe; 30 | } 31 | else { 32 | float3 originalWi = event->wi; 33 | float3 wiSubstrate = (float3)(originalWi.x * eta, originalWi.y * eta, cosThetaTi); 34 | event->wi = wiSubstrate; 35 | if (!RoughConductorBSDF(ray, event, mat, RNG_SEED_VALUE)) 36 | return false; 37 | 38 | event->wi = originalWi; 39 | 40 | float cosThetaTo; 41 | float Fo = dielectricReflectance(_ior, event->wo.z, &cosThetaTo); 42 | if (Fo == 1.0f) 43 | return false; 44 | float cosThetaSubstrate = event->wo.z; 45 | event->wo = (float3)(event->wo.x * _ior, event->wo.y * _ior, cosThetaTo); 46 | event->weight *= (1.0f - Fi) * (1.0f - Fo); 47 | if (_scaledSigmaA > 0.0f) 48 | event->weight *= native_exp(_scaledSigmaA * (-1.0f / cosThetaSubstrate - 1.0f / cosThetaTi)); 49 | 50 | event->weight /= 1.0f - specularProbability; 51 | event->pdf *= 1.0f - specularProbability; 52 | event->pdf *= eta * eta * cosThetaTo / cosThetaSubstrate; 53 | } 54 | 55 | return true; 56 | } 57 | 58 | float3 CoatBSDF_eval(const SurfaceScatterEvent* event, const Material* mat) { 59 | if (event->wi.z <= 0.0f || event->wo.z <= 0.0f) 60 | return (float3)(0.0f); 61 | 62 | const float eta = 1.0f / _ior; 63 | 64 | float cosThetaTi; 65 | float Fi = dielectricReflectance(eta, event->wi.z, &cosThetaTi); 66 | 67 | if (checkReflectionConstraint(&event->wi, &event->wo)) { 68 | return (float3)(Fi); 69 | } 70 | else { 71 | float cosThetaTo; 72 | float Fo = dielectricReflectance(eta, event->wo.z, &cosThetaTo); 73 | 74 | SurfaceScatterEvent nE = *event; 75 | nE.wi = (float3)(event->wi.x * eta, event->wi.y * eta, copysign(cosThetaTi, event->wi.z)); 76 | nE.wo = (float3)(event->wo.x * eta, event->wo.y * eta, copysign(cosThetaTo, event->wo.z)); 77 | float3 substrateF = RoughConductorBSDF_eval(&nE, mat); 78 | 79 | if (_scaledSigmaA > 0.0f) 80 | substrateF *= native_exp(_scaledSigmaA * (-1.0f / cosThetaTo - 1.0f / cosThetaTi)); 81 | 82 | float laplacian = eta * eta * event->wo.z / cosThetaTo; 83 | 84 | return laplacian * (1.0f - Fi) * (1.0f - Fo) * substrateF; 85 | } 86 | } 87 | 88 | float CoatBSDF_pdf(const SurfaceScatterEvent* event, const Material* mat) { 89 | if (event->wi.z <= 0.0f || event->wo.z <= 0.0f) 90 | return 0.0f; 91 | 92 | const float eta = 1.0f / _ior; 93 | 94 | float cosThetaTi; 95 | float Fi = dielectricReflectance(eta, event->wi.z, &cosThetaTi); 96 | 97 | float specularProbability = Fi / (Fi + _avgTransmittance * (1.0f - Fi)); 98 | 99 | if (checkReflectionConstraint(&event->wi, &event->wo)) 100 | return specularProbability; 101 | else { 102 | float cosThetaTo; 103 | dielectricReflectance(eta, event->wo.z, &cosThetaTo); 104 | 105 | SurfaceScatterEvent nE = *event; 106 | nE.wi = (float3)(event->wi.x * eta, event->wi.y * eta, copysign(cosThetaTi, event->wi.z)); 107 | nE.wo = (float3)(event->wo.x * eta, event->wo.y * eta, copysign(cosThetaTo, event->wo.z)); 108 | 109 | return RoughConductorBSDF_pdf(&nE, mat) 110 | * (1.0f - specularProbability) * eta * eta * fabs(event->wo.z / cosThetaTo); 111 | } 112 | } 113 | 114 | #undef _ior 115 | #undef _thickness 116 | #undef _sigmaA 117 | #undef _scaledSigmaA 118 | #undef _avgTransmittance 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /kernels/bxdf/Materials/Conductor.cl: -------------------------------------------------------------------------------- 1 | #if defined(COND) && !defined(__CONDUCTOR__) 2 | #define __CONDUCTOR__ 3 | 4 | bool ConductorBSDF( 5 | Ray* ray, SurfaceScatterEvent* event, 6 | const Material* mat, 7 | RNG_SEED_PARAM 8 | ) { 9 | float3 F = conductorReflectance3(mat->eta, mat->k, event->wi.z); 10 | 11 | event->wo = (float3)(-event->wi.x, -event->wi.y, event->wi.z); 12 | event->pdf = 1.0f; 13 | event->weight = mat->albedo * F; 14 | event->sampledLobe = SpecularReflectionLobe; 15 | return true; 16 | } 17 | 18 | float3 ConductorBSDF_eval(const SurfaceScatterEvent* event, const Material* mat) { 19 | float3 F = conductorReflectance3(mat->eta, mat->k, event->wi.z); 20 | 21 | if (checkReflectionConstraint(&event->wi, &event->wo)) 22 | return mat->color * F; 23 | else 24 | return (float3)(0.0f); 25 | } 26 | 27 | float ConductorBSDF_pdf(const SurfaceScatterEvent* event) { 28 | return (float)(checkReflectionConstraint(&event->wi, &event->wo)); 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /kernels/bxdf/Materials/Dielectric.cl: -------------------------------------------------------------------------------- 1 | #if defined(DIEL) && !defined(__DIELECTRIC__) 2 | #define __DIELECTRIC__ 3 | 4 | bool DielectricBSDF( 5 | const Ray* ray, SurfaceScatterEvent* event, 6 | const Material* mat, 7 | RNG_SEED_PARAM 8 | ) { 9 | const float eta = event->wi.z < 0.0f ? mat->eta_t.x : 1.0f / mat->eta_t.x; 10 | 11 | float cosThetaT = 0.0f; 12 | float F = dielectricReflectance(eta, fabs(event->wi.z), &cosThetaT); 13 | 14 | if (next1D(RNG_SEED_VALUE) < F) { 15 | event->wo = (float3)(-event->wi.x, -event->wi.y, event->wi.z); 16 | event->pdf = F; 17 | event->sampledLobe = SpecularReflectionLobe; 18 | event->weight = (float3)(F); 19 | } 20 | else { 21 | if (F == 1.0f) 22 | return false; 23 | 24 | event->wo = (float3)(-event->wi.x * eta, -event->wi.y * eta, -copysign(cosThetaT, event->wi.z)); 25 | event->pdf = 1.0f - F; 26 | event->sampledLobe = SpecularTransmissionLobe; 27 | event->weight = (float3)(1.0f - F); 28 | } 29 | 30 | const bool ABS1 = mat->t & ABS_REFR, ABS2 = mat->t & ABS_REFR2; 31 | if (ABS1 | ABS2) { 32 | event->weight *= ABS2 ? mat->color : 1.0f; 33 | event->weight *= ray->backside ? exp(-ray->t * ((ABS1) ? mat->color : 1.0f) * 10.0f) : 1.0f; 34 | } 35 | else { 36 | event->weight *= mat->color; 37 | } 38 | 39 | return true; 40 | } 41 | 42 | float3 DielectricBSDF_eval(const SurfaceScatterEvent* event, const Material* mat){ 43 | const float eta = event->wi.z < 0.0f ? mat->eta_t.x : 1.0f / mat->eta_t.x; 44 | 45 | float cosThetaT = 0.0f; 46 | float F = dielectricReflectance(eta, fabs(event->wi.z), &cosThetaT); 47 | 48 | if (event->wi.z * event->wo.z >= 0.0f) { 49 | if (checkReflectionConstraint(&event->wi, &event->wo)) 50 | return F * mat->albedo; 51 | else 52 | return (float3)(0.0f); 53 | } 54 | else { 55 | if (checkRefractionConstraint(&event->wi, &event->wo, eta, cosThetaT)) 56 | return (1.0f - F) * mat->albedo; 57 | else 58 | return (float3)(0.0f); 59 | } 60 | } 61 | 62 | float DielectricBSDF_pdf(const SurfaceScatterEvent* event, const Material* mat){ 63 | const float eta = event->wi.z < 0.0f ? mat->eta_t.x : 1.0f / mat->eta_t.x; 64 | 65 | float cosThetaT = 0.0f; 66 | float F = dielectricReflectance(eta, fabs(event->wi.z), &cosThetaT); 67 | 68 | if (event->wi.z * event->wo.z >= 0.0f) { 69 | if (checkReflectionConstraint(&event->wi, &event->wo)) 70 | return F; 71 | else 72 | return 0.0f; 73 | } 74 | else { 75 | if (checkRefractionConstraint(&event->wi, &event->wo, eta, cosThetaT)) 76 | return 1.0f - F; 77 | else 78 | return 0.0f; 79 | } 80 | } 81 | 82 | inline float DielectricBSDF_eta(const SurfaceScatterEvent* event, const Material* mat){ 83 | if (event->wi.z * event->wo.z >= 0.0f) 84 | return 1.0f; 85 | else 86 | return event->wi.z < 0.0f ? mat->eta_t.x : 1.0f / mat->eta_t.x; 87 | } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /kernels/bxdf/Materials/Lambert.cl: -------------------------------------------------------------------------------- 1 | #if defined(DIFF) && !defined(__LAMBERT__) 2 | #define __LAMBERT__ 3 | 4 | bool LambertBSDF( 5 | const Ray* ray, SurfaceScatterEvent* event, 6 | const Material* mat, 7 | RNG_SEED_PARAM 8 | ) { 9 | if (event->wi.z <= 0.0f) 10 | return false; 11 | 12 | event->wo = cosineHemisphere(next2D(RNG_SEED_VALUE)); 13 | event->pdf = cosineHemispherePdf(event->wo); 14 | event->weight = mat->albedo; 15 | event->sampledLobe = DiffuseReflectionLobe; 16 | return true; 17 | } 18 | 19 | float3 LambertBSDF_eval(const SurfaceScatterEvent* event, const Material* mat) { 20 | if (event->wi.z <= 0.0f || event->wo.z <= 0.0f) 21 | return (float3)(0.0f); 22 | 23 | return mat->albedo * INV_PI * event->wo.z; 24 | } 25 | 26 | float LambertBSDF_pdf(const SurfaceScatterEvent* event) { 27 | if (event->wi.z <= 0.0f || event->wo.z <= 0.0f) 28 | return 0.0f; 29 | 30 | cosineHemispherePdf(event->wo); 31 | } 32 | 33 | #endif -------------------------------------------------------------------------------- /kernels/bxdf/Materials/RoughConductor.cl: -------------------------------------------------------------------------------- 1 | #if (defined(ROUGH_COND) || defined(COAT)) && !defined(__ROUGH_CONDUCTOR__) 2 | #define __ROUGH_CONDUCTOR__ 3 | 4 | bool RoughConductorBSDF( 5 | Ray* ray, SurfaceScatterEvent* event, 6 | const Material* mat, 7 | RNG_SEED_PARAM 8 | ) { 9 | if (event->wi.z <= 0.0f) 10 | return false; 11 | 12 | float alpha = roughnessToAlpha(mat->dist, mat->roughness); 13 | 14 | float3 m = Microfacet_sample(mat->dist, alpha, next2D(RNG_SEED_VALUE)); 15 | float wiDotM = dot(event->wi, m); 16 | event->wo = 2.0f * wiDotM * m - event->wi; 17 | if (wiDotM <= 0.0f || event->wo.z <= 0.0f) 18 | return false; 19 | 20 | 21 | float G = Microfacet_G(mat->dist, alpha, event->wi, event->wo, m); 22 | float D = Microfacet_D(mat->dist, alpha, m); 23 | float mPdf = Microfacet_pdf(mat->dist, alpha, m); 24 | float pdf = mPdf * 0.25f / wiDotM; 25 | float weight = wiDotM * G * D / (event->wi.z * mPdf); 26 | 27 | float3 F = conductorReflectance3(mat->eta, mat->k, wiDotM); 28 | 29 | event->pdf = pdf; 30 | event->weight = mat->color * F * weight; 31 | event->sampledLobe = GlossyReflectionLobe; 32 | 33 | return true; 34 | } 35 | 36 | float3 RoughConductorBSDF_eval(const SurfaceScatterEvent* event, const Material* mat){ 37 | if (event->wi.z <= 0.0f || event->wo.z <= 0.0f) 38 | return (float3)(0.0f); 39 | 40 | float alpha = roughnessToAlpha(mat->dist, mat->roughness); 41 | 42 | float3 hr = normalize(event->wi + event->wo); 43 | float cosThetaM = dot(event->wi, hr); 44 | 45 | float3 F = conductorReflectance3(mat->eta, mat->k, cosThetaM); 46 | 47 | float G = Microfacet_G(mat->dist, alpha, event->wi, event->wo, hr); 48 | float D = Microfacet_D(mat->dist, alpha, hr); 49 | float fr = (G * D * 0.25f) / event->wi.z; 50 | 51 | return mat->albedo * (F * fr); 52 | } 53 | 54 | float RoughConductorBSDF_pdf(const SurfaceScatterEvent* event, const Material* mat){ 55 | if (event->wi.z <= 0.0f || event->wo.z <= 0.0f) 56 | return 0.0f; 57 | 58 | float sampleAlpha = roughnessToAlpha(mat->dist, mat->roughness); 59 | 60 | float3 hr = normalize(event->wi + event->wo); 61 | return Microfacet_pdf(mat->dist, sampleAlpha, hr) * 0.25f / dot(event->wi, hr); 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /kernels/bxdf/Materials/RoughDielectric.cl: -------------------------------------------------------------------------------- 1 | #if !defined(__ROUGH_DIELECTRIC__) 2 | #define __ROUGH_DIELECTRIC__ 3 | 4 | bool RoughDielectricBSDF( 5 | const Ray* ray, SurfaceScatterEvent* event, 6 | const Material* mat, 7 | RNG_SEED_PARAM 8 | ) { 9 | const float wiDotN = event->wi.z; 10 | 11 | const float eta = event->wi.z < 0.0f ? mat->eta_t.x : 1.0f / mat->eta_t.x; 12 | 13 | float sampleRoughness = (1.2f - 0.2f * sqrt(fabs(wiDotN))) * mat->roughness; 14 | float alpha = roughnessToAlpha(mat->dist, mat->roughness); 15 | float sampleAlpha = roughnessToAlpha(mat->dist, sampleRoughness); 16 | 17 | float3 m = Microfacet_sample(mat->dist, sampleAlpha, next2D(RNG_SEED_VALUE)); 18 | float pm = Microfacet_pdf(mat->dist, sampleAlpha, m); 19 | 20 | if (pm < 1e-10f) 21 | return false; 22 | 23 | float wiDotM = dot(event->wi, m); 24 | float cosThetaT = 0.0f; 25 | float F = dielectricReflectance(1.0f / mat->eta_t.x, wiDotM, &cosThetaT); 26 | float etaM = wiDotM < 0.0f ? mat->eta_t.x : 1.0f / mat->eta_t.x; 27 | 28 | bool reflect = next1D(RNG_SEED_VALUE) < F; 29 | 30 | if (reflect) 31 | event->wo = 2.0f * wiDotM * m - event->wi; 32 | else 33 | event->wo = (etaM * wiDotM - sgnE(wiDotM) * cosThetaT) * m - etaM * event->wi; 34 | 35 | float woDotN = event->wo.z; 36 | 37 | bool reflected = wiDotN * woDotN > 0.0f; 38 | if (reflected != reflect) 39 | return false; 40 | 41 | float woDotM = dot(event->wo, m); 42 | float G = Microfacet_G(mat->dist, alpha, event->wi, event->wo, m); 43 | float D = Microfacet_D(mat->dist, alpha, m); 44 | event->weight = (float3)(fabs(wiDotM) * G * D / (fabs(wiDotN) * pm)); 45 | 46 | if (reflect) { 47 | event->pdf = F * pm * 0.25f / fabs(wiDotM); 48 | event->sampledLobe = GlossyReflectionLobe; 49 | } 50 | else { 51 | event->pdf = (1.0f - F) * pm * fabs(woDotM) / pow(eta * wiDotM + woDotM, 2.0f); 52 | event->sampledLobe = GlossyTransmissionLobe; 53 | } 54 | 55 | const bool ABS1 = mat->t & ABS_REFR, ABS2 = mat->t & ABS_REFR2; 56 | if (ABS1 | ABS2) { 57 | event->weight *= ABS2 ? mat->color : 1.0f; 58 | event->weight *= ray->backside ? exp(-ray->t * ((ABS1) ? mat->color : 1.0f) * 10.0f) : 1.0f; 59 | } 60 | else { 61 | event->weight *= mat->albedo; 62 | } 63 | 64 | return true; 65 | } 66 | 67 | float3 RoughDielectricBSDF_eval(const SurfaceScatterEvent* event, const Material* mat) { 68 | float wiDotN = event->wi.z; 69 | float woDotN = event->wo.z; 70 | 71 | bool reflect = wiDotN * woDotN >= 0.0f; 72 | 73 | float alpha = roughnessToAlpha(mat->dist, mat->roughness); 74 | 75 | const float eta = wiDotN < 0.0f ? mat->eta_t.x : 1.0f / mat->eta_t.x; 76 | float3 m; 77 | if (reflect) 78 | m = sgnE(wiDotN) * normalize(event->wi + event->wo); 79 | else 80 | m = -normalize(event->wi * eta + event->wo); 81 | 82 | float wiDotM = dot(event->wi, m); 83 | float woDotM = dot(event->wo, m); 84 | 85 | float cosThetaT = 0.0f; 86 | float F = dielectricReflectance(1.0f / mat->eta_t.x, wiDotM, &cosThetaT); 87 | float G = Microfacet_G(mat->dist, alpha, event->wi, event->wo, m); 88 | float D = Microfacet_D(mat->dist, alpha, m); 89 | 90 | float fx; 91 | if (reflect) { 92 | fx = (F * G * D * 0.25f) / fabs(wiDotN); 93 | } 94 | else { 95 | fx = fabs(wiDotM * woDotM) * (1.0f - F) * G * D / (pow(eta * wiDotM + woDotM, 2.0f) * fabs(wiDotN)); 96 | } 97 | 98 | return mat->albedo*fx; 99 | } 100 | 101 | float RoughDielectricBSDF_pdf(const SurfaceScatterEvent* event, const Material* mat) { 102 | float wiDotN = event->wi.z; 103 | float woDotN = event->wo.z; 104 | 105 | bool reflect = wiDotN * woDotN >= 0.0f; 106 | 107 | float sampleRoughness = (1.2f - 0.2f * sqrt(fabs(wiDotN))) * mat->roughness; 108 | float sampleAlpha = roughnessToAlpha(mat->dist, sampleRoughness); 109 | 110 | float eta = wiDotN < 0.0f ? mat->eta_t.x : 1.0f / mat->eta_t.x; 111 | float3 m; 112 | if (reflect) 113 | m = sgnE(wiDotN) * normalize(event->wi + event->wo); 114 | else 115 | m = -normalize(event->wi * eta + event->wo); 116 | 117 | float wiDotM = dot(event->wi, m); 118 | float woDotM = dot(event->wo, m); 119 | float cosThetaT = 0.0f; 120 | float F = dielectricReflectance(1.0f / mat->eta_t.x, wiDotM, &cosThetaT); 121 | float pm = Microfacet_pdf(mat->dist, sampleAlpha, m); 122 | 123 | float pdf; 124 | if (reflect) 125 | pdf = F * pm * 0.25f / fabs(wiDotM); 126 | else 127 | pdf = (1.0f - F) * pm * fabs(woDotM) / pow(eta * wiDotM + woDotM, 2.0f); 128 | 129 | return pdf; 130 | } 131 | 132 | inline float RoughDielectricBSDF_eta(const SurfaceScatterEvent* event, const Material* mat){ 133 | if (event->wi.z * event->wo.z >= 0.0f) 134 | return 1.0f; 135 | else 136 | return event->wi.z < 0.0f ? mat->eta_t.x : 1.0f/mat->eta_t.x; 137 | } 138 | 139 | #endif 140 | -------------------------------------------------------------------------------- /kernels/bxdf/bxdf.cl: -------------------------------------------------------------------------------- 1 | #ifndef __BXDF__ 2 | #define __BXDF__ 3 | 4 | #FILE:bxdf/microfacet.cl 5 | #FILE:bxdf/Fresnel.cl 6 | 7 | /*-------------- LAMBERTIAN ---------------*/ 8 | #FILE:bxdf/materials/Lambert.cl 9 | 10 | /*----------------- FIBER -----------------*/ 11 | 12 | float lambertianCylinder(const float3* wo){ 13 | float cosThetaO = trigInverse(wo->y); 14 | float phi = atan2(wo->x, wo->z); 15 | if (phi < 0.0f) 16 | phi += TWO_PI; 17 | 18 | return cosThetaO*fabs(((PI - phi)*native_cos(phi) + native_sin(phi))*INV_FOUR_PI); 19 | } 20 | 21 | void LambertianFiberBCSDF( 22 | Ray* ray, SurfaceScatterEvent* res, 23 | const Material* mat, 24 | RNG_SEED_PARAM 25 | ){ 26 | float h = next1D(RNG_SEED_VALUE)*2.0f - 1.0f; 27 | float nx = h; 28 | float nz = trigInverse(nx); 29 | 30 | float3 d = cosineHemisphere(next2D(RNG_SEED_VALUE)); 31 | 32 | ray->dir = (float3)(d.z*nx + d.x*nz, d.y, d.z*nz - d.x*nx); 33 | 34 | res->pdf = lambertianCylinder(&ray->dir); 35 | res->weight = mat->color; 36 | 37 | ray->origin = ray->pos + ray->normal * EPS; 38 | ray->dir = toGlobal(&res->frame, ray->dir); 39 | } 40 | 41 | #define LambertianFiberBCSDF_pdf(ray) lambertianCylinder(&ray->dir) 42 | 43 | /*---------- DIELECTRIC ----------*/ 44 | #FILE:bxdf/materials/Dielectric.cl 45 | #FILE:bxdf/materials/RoughDielectric.cl 46 | 47 | /*---------- CONDUCTOR ----------*/ 48 | #FILE:bxdf/materials/Conductor.cl 49 | #FILE:bxdf/materials/RoughConductor.cl 50 | 51 | /*---------- COAT ----------*/ 52 | #FILE:bxdf/materials/Coat.cl 53 | 54 | 55 | //------------------------------------------------------------------ 56 | 57 | bool BSDF( 58 | SurfaceScatterEvent* event, 59 | const Ray* ray, 60 | const Scene* scene, 61 | const Material* mat, 62 | RNG_SEED_PARAM 63 | ) { 64 | 65 | #ifdef DIFF 66 | if (mat->t & DIFF) 67 | #else 68 | if (false) 69 | #endif 70 | { 71 | return LambertBSDF(ray, event, mat, RNG_SEED_VALUE); 72 | } 73 | #ifdef COND 74 | else if (mat->t & COND) 75 | { 76 | return ConductorBSDF(ray, event, mat, RNG_SEED_VALUE); 77 | } 78 | #endif 79 | #ifdef ROUGH_COND 80 | else if (mat->t & ROUGH_COND) 81 | { 82 | return RoughConductorBSDF(ray, event, mat, RNG_SEED_VALUE); 83 | } 84 | #endif 85 | #ifdef DIEL 86 | else if (mat->t & DIEL) 87 | { 88 | return DielectricBSDF(ray, event, mat, RNG_SEED_VALUE); 89 | } 90 | #endif 91 | #ifdef ROUGH_DIEL 92 | else if (mat->t & ROUGH_DIEL) { 93 | return RoughDielectricBSDF(ray, event, mat, RNG_SEED_VALUE); 94 | } 95 | #endif 96 | #ifdef COAT 97 | else if (mat->t & COAT) { 98 | return CoatBSDF(ray, event, mat, RNG_SEED_VALUE); 99 | } 100 | #endif 101 | 102 | return false; 103 | } 104 | 105 | bool BSDF2( 106 | SurfaceScatterEvent* event, 107 | const Ray* ray, 108 | const Scene* scene, 109 | const Material* mat, 110 | RNG_SEED_PARAM, 111 | bool adjoint 112 | ) { 113 | if (!BSDF(event, ray, scene, mat, RNG_SEED_VALUE)) 114 | return false; 115 | 116 | if (adjoint) { 117 | event->weight *= fabs( 118 | (dot(toGlobal(&event->frame, event->wo), event->frame.normal) * event->wi.z) / 119 | (dot(toGlobal(&event->frame, event->wi), event->frame.normal) * event->wo.z)); // TODO: Optimize 120 | } 121 | #if defined(DIEL) || defined(ROUGH_DIEL) 122 | else { 123 | float eta = 1.0f; 124 | #ifdef DIEL 125 | if (mat->t & DIEL) 126 | #else 127 | if (false) 128 | #endif 129 | { 130 | eta = DielectricBSDF_eta(event, mat); 131 | } 132 | #ifdef ROUGH_DIEL 133 | else if (mat->t & ROUGH_DIEL) { 134 | eta = RoughDielectricBSDF_eta(event, mat); 135 | } 136 | #endif 137 | 138 | event->weight *= pow(eta, 2.0f); 139 | } 140 | #endif 141 | 142 | return true; 143 | } 144 | 145 | //------------------------------------------------------------------ 146 | 147 | float3 BSDF_eval( 148 | const SurfaceScatterEvent* event, 149 | const Material* mat 150 | ) { 151 | 152 | #ifdef DIFF 153 | if (mat->t & DIFF) 154 | #else 155 | if (false) 156 | #endif 157 | { 158 | return LambertBSDF_eval(event, mat); 159 | } 160 | #ifdef COND 161 | else if (mat->t & COND) 162 | { 163 | return ConductorBSDF_eval(event, mat); 164 | } 165 | #endif 166 | #ifdef ROUGH_COND 167 | else if (mat->t & ROUGH_COND) 168 | { 169 | return RoughConductorBSDF_eval(event, mat); 170 | } 171 | #endif 172 | #ifdef DIEL 173 | else if (mat->t & DIEL) 174 | { 175 | return DielectricBSDF_eval(event, mat); 176 | } 177 | #endif 178 | #ifdef ROUGH_DIEL 179 | else if (mat->t & ROUGH_DIEL) { 180 | return RoughDielectricBSDF_eval(event, mat); 181 | } 182 | #endif 183 | #ifdef COAT 184 | else if (mat->t & COAT) { 185 | return CoatBSDF_eval(event, mat); 186 | } 187 | #endif 188 | 189 | return (float3)(0.0f); 190 | } 191 | 192 | float3 BSDF_eval2( 193 | const SurfaceScatterEvent* event, 194 | const Material* mat, 195 | bool adjoint 196 | ) { 197 | float3 f = BSDF_eval(event, mat); 198 | 199 | if (adjoint) { 200 | f *= fabs( 201 | (dot(toGlobal(&event->frame, event->wo), event->frame.normal) * event->wi.z) / 202 | (dot(toGlobal(&event->frame, event->wi), event->frame.normal) * event->wo.z)); // TODO: Optimize 203 | } 204 | #if defined(DIEL) || defined(ROUGH_DIEL) 205 | else { 206 | float eta = 1.0f; 207 | #ifdef DIEL 208 | if (mat->t & DIEL) 209 | #else 210 | if(false) 211 | #endif 212 | { 213 | eta = DielectricBSDF_eta(event, mat); 214 | } 215 | #ifdef ROUGH_DIEL 216 | else if (mat->t & ROUGH_DIEL) { 217 | eta = RoughDielectricBSDF_eta(event, mat); 218 | } 219 | #endif 220 | 221 | f *= pow(eta, 2.0f); 222 | } 223 | #endif 224 | 225 | return f; 226 | } 227 | 228 | 229 | //------------------------------------------------------------------ 230 | 231 | float BSDF_pdf( 232 | const SurfaceScatterEvent* event, 233 | const Material* mat 234 | ) { 235 | #ifdef DIFF 236 | if (mat->t & DIFF) 237 | #else 238 | if (false) 239 | #endif 240 | { 241 | return LambertBSDF_pdf(event); 242 | } 243 | #ifdef COND 244 | else if (mat->t & COND) 245 | { 246 | return ConductorBSDF_pdf(event); 247 | } 248 | #endif 249 | #ifdef ROUGH_COND 250 | else if (mat->t & ROUGH_COND) 251 | { 252 | return RoughConductorBSDF_pdf(event, mat); 253 | } 254 | #endif 255 | #ifdef DIEL 256 | else if (mat->t & DIEL) 257 | { 258 | return DielectricBSDF_pdf(event, mat); 259 | } 260 | #endif 261 | #ifdef ROUGH_DIEL 262 | else if (mat->t & ROUGH_DIEL) { 263 | return RoughDielectricBSDF_pdf(event, mat); 264 | } 265 | #endif 266 | #ifdef COAT 267 | else if (mat->t & COAT) { 268 | return CoatBSDF_pdf(event, mat); 269 | } 270 | #endif 271 | 272 | return 0.0f; 273 | } 274 | 275 | /* 276 | #ifdef __BURLEY_DIFF__ 277 | float3 H = fast_normalize(ray->incomingRayDir + ray->dir); 278 | float NoV = clamp(dot(ray->normal, ray->incomingRayDir), EPS, 1.0f); 279 | float NoL = clamp(dot(ray->normal, ray->dir), EPS, 1.0f); 280 | float VoH = clamp(dot(ray->incomingRayDir, H), EPS, 1.0f); 281 | 282 | return DiffuseBurley(mat->color, fmax(mat->roughness, EPS2), NoV, NoL, VoH); 283 | #else 284 | */ 285 | 286 | #endif 287 | -------------------------------------------------------------------------------- /kernels/bxdf/microfacet.cl: -------------------------------------------------------------------------------- 1 | #ifndef __MICROFACET__ 2 | #define __MICROFACET__ 3 | 4 | /*Taken from https://github.com/tunabrain/tungsten/blob/master/src/core/bsdfs/Microfacet.hpp */ 5 | 6 | #define BECKMANN 1 << 0 7 | #define PHONG 1 << 1 8 | #define GGX 1 << 2 9 | #define BLINN 1 << 3 10 | 11 | float roughnessToAlpha(int dist, float roughness){ 12 | roughness = fmax(roughness, 1e-3f); 13 | 14 | if (dist & PHONG) 15 | return 2.0f / (roughness * roughness) - 2.0f; 16 | else 17 | return roughness; 18 | } 19 | 20 | float Microfacet_D(int dist, float alpha, const float3 m) 21 | { 22 | if (m.z <= 0.0f) 23 | return 0.0f; 24 | 25 | if (dist & BECKMANN) { 26 | float alphaSq = alpha * alpha; 27 | float cosThetaSq = m.z * m.z; 28 | float tanThetaSq = fmax(1.0f - cosThetaSq, 0.0f) / cosThetaSq; 29 | float cosThetaQu = cosThetaSq * cosThetaSq; 30 | return INV_PI * exp(-tanThetaSq / alphaSq) / (alphaSq * cosThetaQu); 31 | } 32 | else if (dist & PHONG) { 33 | return (alpha + 2.0f) * INV_TWO_PI * pow(m.z, alpha); 34 | } 35 | else if (dist & GGX) { 36 | float alphaSq = alpha * alpha; 37 | float cosThetaSq = m.z * m.z; 38 | float tanThetaSq = fmax(1.0f - cosThetaSq, 0.0f) / cosThetaSq; 39 | float cosThetaQu = cosThetaSq * cosThetaSq; 40 | return alphaSq * INV_PI / (cosThetaQu * pow(alphaSq + tanThetaSq, 2.0f)); 41 | } 42 | 43 | return 0.0f; 44 | } 45 | 46 | float Microfacet_G1(int dist, float alpha, const float3 v, const float3 m) 47 | { 48 | if (dot(v, m) * v.z <= 0.0f) 49 | return 0.0f; 50 | 51 | if (dist & BECKMANN) { 52 | float cosThetaSq = v.z * v.z; 53 | float tanTheta = fabs(sqrt(fmax(1.0f - cosThetaSq, 0.0f)) / v.z); 54 | float a = 1.0f / (alpha * tanTheta); 55 | if (a < 1.6f) 56 | return (3.535f * a + 2.181f * a * a) / (1.0f + 2.276f * a + 2.577f * a * a); 57 | else 58 | return 1.0f; 59 | } 60 | else if (dist & PHONG) { 61 | float cosThetaSq = v.z * v.z; 62 | float tanTheta = fabs(sqrt(fmax(1.0f - cosThetaSq, 0.0f)) / v.z); 63 | float a = sqrt(0.5f * alpha + 1.0f) / tanTheta; 64 | if (a < 1.6f) 65 | return (3.535f * a + 2.181f * a * a) / (1.0f + 2.276f * a + 2.577f * a * a); 66 | else 67 | return 1.0f; 68 | } 69 | else if (dist & GGX) { 70 | float alphaSq = alpha * alpha; 71 | float cosThetaSq = v.z * v.z; 72 | float tanThetaSq = fmax(1.0f - cosThetaSq, 0.0f) / cosThetaSq; 73 | return 2.0f / (1.0f + sqrt(1.0f + alphaSq * tanThetaSq)); 74 | } 75 | 76 | return 0.0f; 77 | } 78 | 79 | float Microfacet_G(int dist, float alpha, const float3 i, const float3 o, const float3 m) 80 | { 81 | return Microfacet_G1(dist, alpha, i, m) * Microfacet_G1(dist, alpha, o, m); 82 | } 83 | 84 | float Microfacet_pdf(int dist, float alpha, const float3 m) 85 | { 86 | return Microfacet_D(dist, alpha, m) * m.z; 87 | } 88 | 89 | float3 Microfacet_sample(int dist, float alpha, float2 xi) 90 | { 91 | float phi = xi.y * TWO_PI; 92 | float cosTheta = 0.0f; 93 | 94 | if (dist & BECKMANN) { 95 | float tanThetaSq = -alpha * alpha * log(1.0f - xi.x); 96 | cosTheta = 1.0f / sqrt(1.0f + tanThetaSq); 97 | } 98 | else if (dist & PHONG) { 99 | cosTheta = pow(xi.x, 1.0f / (alpha + 2.0f)); 100 | } 101 | else if (dist & GGX) { 102 | float tanThetaSq = alpha * alpha * xi.x / (1.0f - xi.x); 103 | cosTheta = 1.0f / sqrt(1.0f + tanThetaSq); 104 | } 105 | 106 | float r = sqrt(fmax(1.0f - cosTheta * cosTheta, 0.0f)); 107 | return (float3)(cos(phi) * r, sin(phi) * r, cosTheta); 108 | } 109 | 110 | #endif -------------------------------------------------------------------------------- /kernels/bxdf/old/blinn.cl: -------------------------------------------------------------------------------- 1 | #ifndef __BLINN__ 2 | #define __BLINN__ 3 | 4 | /*---------------------------------- BLINN ----------------------------------*/ 5 | float DistributionBlinn(float3 normal, float3 wh, float alpha) { 6 | return (alpha + 2.0f) * pow(max(0.0f, dot(normal, wh)), alpha) * INV_TWO_PI; 7 | } 8 | 9 | float3 SampleBlinn(float3 n, float alpha, RNG_SEED_PARAM) { 10 | float phi = TWO_PI * next1D(RNG_SEED_VALUE); 11 | float cosTheta = pow(next1D(RNG_SEED_VALUE), 1.0f / (alpha + 1.0f)); 12 | float sinTheta = sqrt(1.0f - cosTheta * cosTheta); 13 | 14 | float3 axis = fabs(n.x) > 0.001f ? (float3)(0.0f, 1.0f, 0.0f) : (float3)(1.0f, 0.0f, 0.0f); 15 | float3 t = normalize(cross(axis, n)); 16 | float3 s = cross(n, t); 17 | 18 | return normalize(s*cos(phi)*sinTheta + t * sin(phi)*sinTheta + n * cosTheta); 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /kernels/bxdf/old/burley_diffuse.cl: -------------------------------------------------------------------------------- 1 | #ifndef __BURLEY_DIFF__ 2 | #define __BURLEY_DIFF__ 3 | 4 | #FILE:bxdf/diffuse.cl 5 | 6 | float FSchlickDiffuse(float F90, float NoX){ 7 | return 1.0f + (F90 - 1.0f) * pow(1.0f - NoX, 5.0f); 8 | } 9 | 10 | float3 DiffuseBurley(float3 albedo, float roughness, float NoV, float NoL, float VoH){ 11 | float energyBias = mix(0.0f, 0.5f, roughness); 12 | float energyFactor = mix(1.0f, 1.0f / 1.51f, roughness); 13 | float FD90 = energyBias + 2.0f * VoH * VoH * roughness; 14 | float FdV = FSchlickDiffuse(FD90, NoV); 15 | float FdL = FSchlickDiffuse(FD90, NoL); 16 | return albedo * FdV * FdL * energyFactor * INV_PI; 17 | } 18 | 19 | #endif -------------------------------------------------------------------------------- /kernels/camera.cl: -------------------------------------------------------------------------------- 1 | #ifndef __CL_CAMERA__ 2 | #define __CL_CAMERA__ 3 | 4 | #FILE:header.cl 5 | #FILE:prng/prng.cl 6 | 7 | typedef struct { 8 | float3 position; 9 | float3 view; 10 | float3 up; 11 | float2 resolution; 12 | float2 fov; 13 | float apertureRadius; 14 | float focalDistance; 15 | } Camera; 16 | 17 | Ray createCamRay(const int2 coord, const int width, const int height, __constant Camera* cam, RNG_SEED_PARAM) { 18 | 19 | /* create a local coordinate frame for the camera */ 20 | float3 rendercamview = cam->view; rendercamview = normalize(rendercamview); 21 | float3 rendercamup = cam->up; rendercamup = normalize(rendercamup); 22 | float3 horizontalAxis = cross(rendercamview, rendercamup); horizontalAxis = normalize(horizontalAxis); 23 | float3 verticalAxis = cross(horizontalAxis, rendercamview); verticalAxis = normalize(verticalAxis); 24 | 25 | float3 middle = cam->position + rendercamview; 26 | float3 horizontal = horizontalAxis * tan(cam->fov.x * 0.5f * (PI / 180)); 27 | float3 vertical = verticalAxis * tan(cam->fov.y * -0.5f * (PI / 180)); 28 | 29 | int pixelx = coord.x; 30 | int pixely = height - coord.y - 1; 31 | 32 | float sx = (float)pixelx / (width - 1.0f); 33 | float sy = (float)pixely / (height - 1.0f); 34 | 35 | float3 pointOnPlaneOneUnitAwayFromEye = middle + (horizontal * ((2 * sx) - 1)) + (vertical * ((2 * sy) - 1)); 36 | float3 pointOnImagePlane = cam->position + ((pointOnPlaneOneUnitAwayFromEye - cam->position) * cam->focalDistance); /* cam->focalDistance */ 37 | 38 | float3 aperturePoint; 39 | 40 | /* if aperture is non-zero (aperture is zero for pinhole camera), pick a random point on the aperture/lens */ 41 | if (cam->apertureRadius > 0.00001f) { 42 | 43 | float random1 = next1D(RNG_SEED_VALUE); 44 | float random2 = next1D(RNG_SEED_VALUE); 45 | 46 | float angle = 2 * PI * random1; 47 | float distance = cam->apertureRadius * sqrt(random2); 48 | float apertureX = cos(angle) * distance; 49 | float apertureY = sin(angle) * distance; 50 | 51 | aperturePoint = cam->position + (horizontalAxis * apertureX) + (verticalAxis * apertureY); 52 | } 53 | else aperturePoint = cam->position; 54 | 55 | float3 apertureToImagePlane = normalize(pointOnImagePlane - aperturePoint); 56 | 57 | 58 | /* create camera ray*/ 59 | Ray ray; 60 | ray.backside = false; 61 | ray.origin = aperturePoint; 62 | ray.dir = apertureToImagePlane; 63 | ray.time = next1D(RNG_SEED_VALUE); 64 | 65 | return ray; 66 | } 67 | 68 | #endif -------------------------------------------------------------------------------- /kernels/geometry/aabb.cl: -------------------------------------------------------------------------------- 1 | /* AABB intersection */ 2 | const bool intersectBox( 3 | const Ray* ray, const float3* invDir, 4 | const float4 bbMin, const float4 bbMax, 5 | float* tNear, float* tFar 6 | ) { 7 | const float3 t1 = (bbMin.xyz - ray->origin) * (*invDir); 8 | float3 tMax = (bbMax.xyz - ray->origin) * (*invDir); 9 | const float3 tMin = fmin(t1, tMax); 10 | tMax = fmax(t1, tMax); 11 | 12 | *tNear = fmax(fmax(tMin.x, tMin.y), tMin.z); 13 | *tFar = fmin(fmin(tMax.x, tMax.y), fmin(tMax.z, *tFar)); 14 | 15 | return (*tNear <= *tFar); 16 | } 17 | -------------------------------------------------------------------------------- /kernels/geometry/box.cl: -------------------------------------------------------------------------------- 1 | #if defined(BOX) && !defined(__BOX__) 2 | #define __BOX__ 3 | 4 | /* box intesection */ 5 | bool intersect_box(const Mesh* box, Ray* ray) { 6 | const float3 invDir = native_recip(ray->dir); 7 | 8 | const float3 tmin = (box->pos + box->joker.s012 - ray->origin) * invDir; 9 | const float3 tmax = (box->pos - box->joker.s012 - ray->origin) * invDir; 10 | 11 | const float3 real_min = fmin(tmin, tmax); 12 | const float3 real_max = fmax(tmin, tmax); 13 | 14 | const float minmax = fmin(fmin(real_max.x, real_max.y), real_max.z); 15 | const float maxmin = fmax(fmax(real_min.x, real_min.y), real_min.z); 16 | 17 | if (minmax <= maxmin) 18 | return false; 19 | 20 | if (maxmin > 0.0f) // outside the box 21 | { 22 | if(maxmin < ray->t){ 23 | ray->normal = -sign(ray->dir) * step(real_min.yzx, real_min) * step(real_min.zxy, real_min); 24 | ray->t = maxmin; 25 | ray->backside = false; 26 | return true; 27 | } 28 | } 29 | else if (minmax > 0.0f) // inside the box 30 | { 31 | if (minmax < ray->t) { 32 | ray->normal = -sign(ray->dir) * step(real_max, real_max.yzx) * step(real_max, real_max.zxy); 33 | ray->t = minmax; 34 | ray->backside = true; 35 | return true; 36 | } 37 | } 38 | 39 | return false; 40 | } 41 | 42 | #endif -------------------------------------------------------------------------------- /kernels/geometry/bvh.cl: -------------------------------------------------------------------------------- 1 | #ifndef __BVH__ 2 | #define __BVH__ 3 | 4 | float intersectAxis(int axis, const float p, const Ray* ray){ 5 | const float3 invDir = native_recip(ray->dir); 6 | const float3 scaled_origin = -ray->origin*invDir; 7 | 8 | return fma(p, ((float*)(&invDir))[axis], ((float*)(&scaled_origin))[axis]); 9 | } 10 | 11 | float2 intersectNode(__constant new_bvhNode* node, const Ray* ray){ 12 | int3 octant = (int3)(ray->dir.x < 0.0f, ray->dir.y < 0.0f, ray->dir.z < 0.0f); 13 | 14 | float entry0 = intersectAxis(0, node->bounds[0 * 2 + octant.x], ray); 15 | float entry1 = intersectAxis(1, node->bounds[1 * 2 + octant.y], ray); 16 | float entry2 = intersectAxis(2, node->bounds[2 * 2 + octant.z], ray); 17 | 18 | float exit0 = intersectAxis(0, node->bounds[0 * 2 + 1 - octant.x], ray); 19 | float exit1 = intersectAxis(1, node->bounds[1 * 2 + 1 - octant.y], ray); 20 | float exit2 = intersectAxis(2, node->bounds[2 * 2 + 1 - octant.z], ray); 21 | 22 | return (float2)( 23 | fmax(entry0, fmax(entry1, fmax(entry2, EPS))), 24 | fmin(exit0, fmin(exit1, fmin(exit2, ray->t))) 25 | ); 26 | } 27 | 28 | bool intersectLeafShadows(const Scene* scene, 29 | __constant new_bvhNode* node, 30 | Ray* ray){ 31 | 32 | uint begin = node->first_child_or_primitive; 33 | uint end = begin + node->primitive_count; 34 | 35 | for(uint i = begin; i < end; ++i){ 36 | if(intersectTriangle(scene, ray, i)) 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | #define STACK_SIZE 8 43 | bool traverseShadows(const Scene* scene, Ray* ray) { 44 | __constant new_bvhNode* stack[STACK_SIZE]; 45 | uchar stackSize = 0; 46 | 47 | __constant new_bvhNode* node = &scene->new_nodes[0]; 48 | 49 | if(node->isLeaf){ 50 | LOGWARNING("[Warning]: root is a leaf!\n"); 51 | return intersectLeafShadows(scene, node, ray); 52 | } 53 | 54 | while(true){ 55 | uint first_child = node->first_child_or_primitive; 56 | __constant new_bvhNode* left_child = 57 | &scene->new_nodes[first_child + 0]; 58 | __constant new_bvhNode* right_child = 59 | &scene->new_nodes[first_child + 1]; 60 | float2 dist_left = intersectNode(left_child, ray); 61 | float2 dist_right = intersectNode(right_child, ray); 62 | 63 | // left child 64 | bool l_child = true; 65 | if(dist_left.x <= dist_left.y){ 66 | if(left_child->isLeaf){ 67 | if(intersectLeafShadows(scene, left_child, ray)){ 68 | return true; 69 | } 70 | l_child = false; 71 | } 72 | } else { 73 | l_child = false; 74 | } 75 | 76 | // right child 77 | bool r_child = true; 78 | if(dist_right.x <= dist_right.y){ 79 | if(right_child->isLeaf){ 80 | if(intersectLeafShadows(scene, right_child, ray)){ 81 | return true; 82 | } 83 | r_child = false; 84 | } 85 | } else { 86 | r_child = false; 87 | } 88 | 89 | if(l_child ^ r_child){ 90 | node = l_child ? left_child : right_child; 91 | } else if(l_child & r_child){ 92 | if(dist_left.x > dist_right.x){ 93 | __constant new_bvhNode* temp = left_child; 94 | left_child = right_child; 95 | right_child = temp; 96 | } 97 | stack[stackSize++] = right_child; 98 | node = left_child; 99 | } else { 100 | if(stackSize == 0) 101 | break; 102 | node = stack[--stackSize]; 103 | } 104 | } 105 | #if DEBUG 106 | #if VIEW_OPTION == VIEW_STACK_INDEX 107 | ray->bvh_stackSize = stackSize; 108 | #endif 109 | if(stackSize >= STACK_SIZE) 110 | LOGWARNING("[WARNING]: exceeded max stack size!\n"); 111 | #endif 112 | 113 | return false; 114 | } 115 | #undef STACK_SIZE 116 | 117 | bool intersectLeaf(const Scene* scene, 118 | __constant new_bvhNode* node, 119 | Ray* ray){ 120 | 121 | uint begin = node->first_child_or_primitive; 122 | uint end = begin + node->primitive_count; 123 | 124 | bool res = false; 125 | for(uint i = begin; i < end; ++i){ 126 | res |= intersectTriangle(scene, ray, i); 127 | } 128 | return res; 129 | } 130 | 131 | #define STACK_SIZE 64 132 | bool traverse(const Scene* scene, Ray* ray) { 133 | __constant new_bvhNode* stack[STACK_SIZE]; 134 | uchar stackSize = 0; 135 | 136 | __constant new_bvhNode* node = &scene->new_nodes[0]; 137 | 138 | if(node->isLeaf){ 139 | LOGWARNING("[Warning]: root is a leaf!\n"); 140 | return intersectLeaf(scene, node, ray); 141 | } 142 | 143 | 144 | while(true){ 145 | uint first_child = node->first_child_or_primitive; 146 | __constant new_bvhNode* left_child = 147 | &scene->new_nodes[first_child + 0]; 148 | __constant new_bvhNode* right_child = 149 | &scene->new_nodes[first_child + 1]; 150 | float2 dist_left = intersectNode(left_child, ray); 151 | float2 dist_right = intersectNode(right_child, ray); 152 | 153 | // left child 154 | bool l_child = true; 155 | if(dist_left.x <= dist_left.y){ 156 | if(left_child->isLeaf){ 157 | if(intersectLeaf(scene, left_child, ray)){ 158 | if(ray->t <= EPS) 159 | return true; 160 | } 161 | l_child = false; 162 | } 163 | } else { 164 | l_child = false; 165 | } 166 | 167 | // right child 168 | bool r_child = true; 169 | if(dist_right.x <= dist_right.y){ 170 | if(right_child->isLeaf){ 171 | if(intersectLeaf(scene, right_child, ray)){ 172 | if(ray->t <= EPS) 173 | return true; 174 | } 175 | r_child = false; 176 | } 177 | } else { 178 | r_child = false; 179 | } 180 | 181 | if(l_child ^ r_child){ 182 | node = l_child ? left_child : right_child; 183 | } else if(l_child & r_child){ 184 | if(dist_left.x > dist_right.x){ 185 | __constant new_bvhNode* temp = left_child; 186 | left_child = right_child; 187 | right_child = temp; 188 | } 189 | stack[stackSize++] = right_child; 190 | node = left_child; 191 | } else { 192 | if(stackSize == 0) 193 | break; 194 | node = stack[--stackSize]; 195 | } 196 | } 197 | #if DEBUG 198 | #if VIEW_OPTION == VIEW_STACK_INDEX 199 | ray->bvh_stackSize = stackSize; 200 | #endif 201 | if(stackSize >= STACK_SIZE) 202 | LOGWARNING("[WARNING]: exceeded max stack size!\n"); 203 | #endif 204 | 205 | return false; 206 | } 207 | #undef STACK_SIZE 208 | 209 | #endif -------------------------------------------------------------------------------- /kernels/geometry/geometry.cl: -------------------------------------------------------------------------------- 1 | #ifndef __GEOMETRY__ 2 | #define __GEOMETRY__ 3 | 4 | #FILE:geometry/sdf.cl 5 | #FILE:geometry/sphere.cl 6 | #FILE:geometry/quad.cl 7 | #FILE:geometry/aabb.cl 8 | #FILE:geometry/triangle.cl 9 | #FILE:geometry/bvh.cl 10 | 11 | bool sampleDirect( 12 | const Mesh* mesh, 13 | const float3* p, 14 | LightSample* lightSample, 15 | RNG_SEED_PARAM 16 | ) { 17 | #ifdef __SPHERE__ 18 | if (mesh->t & SPHERE) 19 | #else 20 | if (false) 21 | #endif 22 | { 23 | return sphere_sampleDirect(mesh, p, lightSample, RNG_SEED_VALUE); 24 | } 25 | #ifdef __QUAD__ 26 | else if (mesh->t & QUAD) { 27 | return quad_sampleDirect(mesh, p, lightSample, RNG_SEED_VALUE); 28 | } 29 | #endif 30 | 31 | return false; 32 | } 33 | 34 | float directPdf(const Mesh* mesh, const float3* dir, const float3* p) { 35 | float dPdf = 0.0f; 36 | 37 | #ifdef __SPHERE__ 38 | if (mesh->t & SPHERE) 39 | #else 40 | if (false) 41 | #endif 42 | { 43 | dPdf = sphere_directPdf(mesh, p); 44 | } 45 | #ifdef __QUAD__ 46 | else if (mesh->t & QUAD) { 47 | dPdf = quad_directPdf(dir, mesh, p); 48 | } 49 | #endif 50 | 51 | return dPdf; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /kernels/geometry/quad.cl: -------------------------------------------------------------------------------- 1 | #if defined(QUAD) && !defined(__QUAD__) 2 | #define __QUAD__ 3 | 4 | #define _base plane->joker.s012 5 | #define _edge0 plane->joker.s345 6 | #define _edge1 plane->joker.s678 7 | #define _normal plane->joker.s9ab 8 | #define _area plane->joker.sC 9 | 10 | /* Quad intesection */ 11 | bool intersect_quad(const Mesh* plane, Ray* ray) { 12 | float nDotW = dot(_normal, ray->dir); 13 | 14 | // parallel or backside 15 | if (nDotW < 1e-5) return false; 16 | 17 | float3 anchor = _base - (_edge0 + _edge1) * 0.5f; 18 | 19 | float rt = dot(_normal, anchor - ray->origin) / nDotW; 20 | if (rt <= EPS || rt >= ray->t) 21 | return false; 22 | 23 | // ray-quad intersection point 24 | float3 q = ray->origin + rt * ray->dir; 25 | 26 | float3 v = q - anchor; 27 | float l0 = dot(v, _edge0) / dot(_edge0, _edge0); 28 | float l1 = dot(v, _edge1) / dot(_edge1, _edge1); 29 | 30 | if (l0 < 0.0f || l0 > 1.0f || l1 < 0.0f || l1 > 1.0f) 31 | return false; 32 | 33 | ray->backside = false; 34 | ray->normal = _normal; 35 | ray->pos = q; 36 | ray->t = rt; 37 | return true; 38 | } 39 | 40 | bool quad_sampleDirect(const Mesh* plane, const float3* p, LightSample* sample, RNG_SEED_PARAM) { 41 | if (dot(_normal, *p - _base) <= 0.0f) 42 | return false; 43 | 44 | float2 xi = next2D(RNG_SEED_VALUE); 45 | float3 q = _base + xi.x * _edge0 + xi.y * _edge1; 46 | sample->d = q - *p; 47 | float rSq = dot(sample->d, sample->d); 48 | sample->dist = sqrt(rSq); 49 | sample->d /= sample->dist; 50 | float cosTheta = -dot(_normal, sample->d); 51 | sample->pdf = rSq / (cosTheta * _area); 52 | 53 | return true; 54 | } 55 | 56 | 57 | float quad_directPdf(const float3* dir, const Mesh* plane, const float3* p) { 58 | float cosTheta = fabs(dot(_normal, *dir)); 59 | float t = dot(_normal, _base - *p) / dot(_normal, *dir); 60 | 61 | return t * t / (cosTheta * _area); 62 | } 63 | 64 | 65 | #undef _base 66 | #undef _edge0 67 | #undef _edge1 68 | #undef _normal 69 | #undef _area 70 | 71 | #endif -------------------------------------------------------------------------------- /kernels/geometry/sdf.cl: -------------------------------------------------------------------------------- 1 | #if defined(SDF) && !defined(__SDF__) 2 | #define __SDF__ 3 | 4 | /*----------------------------------- PRIMITIVES -----------------------------------*/ 5 | float sdSphere(const float3 p, const float s) { 6 | return fast_length(p) - s; 7 | } 8 | 9 | float sdBox(const float3 p, const float3 b) { 10 | float3 d = fabs(p) - b; 11 | return fmin(fmax(d.x, fmax(d.y, d.z)), 0.0f) + fast_length(fmax(d, 0.0f)); 12 | } 13 | 14 | float udBox(const float3 p, const float3 b) { 15 | return fast_length(fmax(fabs(p) - b, 0.0f)); 16 | } 17 | 18 | float udRoundBox(const float3 p, const float3 b, const float r){ 19 | return fast_length(fmax(fabs(p) - b, 0.0f)) - r; 20 | } 21 | 22 | float sdPlane(float3 p, float4 n){ 23 | return dot(p, n.xyz) + n.w; 24 | } 25 | 26 | float sdCylinder(const float3 p, const float r, const float height) { 27 | float d = fast_length(p.xz) - r; 28 | d = fmax(d, fabs(p.y) - height); 29 | return d; 30 | } 31 | 32 | float sdTorus( const float3 p, float2 t ){ 33 | float2 q = (float2)(fast_length(p.xz)-t.x,p.y); 34 | return fast_length(q)-t.y; 35 | } 36 | 37 | /*----------------------------------- Map -----------------------------------*/ 38 | 39 | float s_map(const Mesh* sdf, const float3 pos) { 40 | const float3 sdf_center = pos - sdf->pos; 41 | 42 | if (sdf->t & SDF_SPHERE) { 43 | return sdSphere(sdf_center, sdf->joker.s0); 44 | } 45 | else if (sdf->t & SDF_BOX) { 46 | return sdBox(sdf_center, sdf->joker.s012); 47 | } 48 | else if (sdf->t & SDF_ROUND_BOX) { 49 | return udRoundBox(sdf_center, sdf->joker.s012, sdf->joker.s3); 50 | } 51 | else if (sdf->t & SDF_PLANE) { 52 | return sdPlane(sdf_center, sdf->joker.s0123); 53 | } 54 | 55 | return INF; 56 | } 57 | 58 | float map(__constant Mesh* meshes, const float tmin, const float3 pos, int* mesh_id, const uint* mesh_count) { 59 | 60 | float dist = tmin; 61 | 62 | const uint fl = mesh_count[0] + mesh_count[1]; 63 | 64 | for (uint i = mesh_count[0]; i < fl; ++i) { 65 | Mesh sdf = meshes[i]; /* local copy */ 66 | float temp_dist = s_map(&sdf, pos); 67 | 68 | if (temp_dist < dist) { 69 | dist = temp_dist; 70 | *mesh_id = i; 71 | } 72 | } 73 | 74 | return dist; 75 | } 76 | 77 | float3 calcNormal(const Mesh* mesh, const float3 pos) { 78 | const float3 eps = (float3)(EPS*2.0f, 0.0f, 0.0f); 79 | 80 | return normalize((float3)( 81 | s_map(mesh, pos + eps.xyy) - s_map(mesh, pos - eps.xyy), 82 | s_map(mesh, pos + eps.yxy) - s_map(mesh, pos - eps.yxy), 83 | s_map(mesh, pos + eps.yyx) - s_map(mesh, pos - eps.yyx)) 84 | ); 85 | } 86 | 87 | /*----------------------------------- Raymarching -----------------------------------*/ 88 | 89 | bool shadow_sdf(__constant Mesh* meshes, Ray* ray, const uint* mesh_count) { 90 | float t = EPS * 100.0f; 91 | int id; 92 | 93 | for (int i = 0; i < SHADOW_MARCHING_STEPS; ++i) { 94 | float h = fabs(map(meshes, ray->t, (ray->origin + ray->dir * t), &id, mesh_count)); 95 | t += h; 96 | if (h < EPS || t > ray->t) break; 97 | } 98 | 99 | return (t <= ray->t); 100 | } 101 | 102 | /* sdf intersection */ 103 | bool intesect_sdf(__constant Mesh* meshes, Ray* ray, int* mesh_id, const uint* mesh_count) { 104 | float t = EPS*10.0f; 105 | int id; 106 | 107 | for (int i = 0; i < MARCHING_STEPS; ++i) { 108 | float h = fabs(map(meshes, ray->t, (ray->origin + ray->dir * t), &id, mesh_count)); 109 | if (h < EPS || t > ray->t) break; 110 | t += h; 111 | } 112 | 113 | if (t > ray->t) return false; 114 | 115 | ray->t = t; 116 | *mesh_id = id; 117 | return true; 118 | } 119 | 120 | #endif -------------------------------------------------------------------------------- /kernels/geometry/sphere.cl: -------------------------------------------------------------------------------- 1 | #if defined(SPHERE) && !defined(__SPHERE__) 2 | #define __SPHERE__ 3 | 4 | /* sphere intesection */ 5 | bool intersect_sphere(Ray* ray, const Mesh* sphere) { 6 | 7 | #if 1 // faster by 2ms! :P 8 | float3 p = ray->origin - sphere->pos; 9 | float B = dot(p, ray->dir); 10 | float C = dot(p, p) - sphere->radius * sphere->radius ; 11 | float detSq = B*B - C; 12 | if (detSq >= 0.0f) { 13 | float det = sqrt(detSq); 14 | float t = -B - det; 15 | if (t < ray->t && t > EPS) { 16 | ray->t = t; 17 | return true; 18 | } 19 | t = -B + det; 20 | if (t < ray->t && t > EPS) { 21 | ray->t = t; 22 | return true; 23 | } 24 | } 25 | 26 | #else 27 | float3 rayToCenter = sphere->pos - ray->origin; 28 | float b = dot(rayToCenter, ray->dir); 29 | float det = b * b - dot(rayToCenter, rayToCenter) + sphere->radius * sphere->radius; 30 | 31 | if (det < 0.0f) return false; 32 | det = sqrt(det); 33 | 34 | *dist = b - det; 35 | if (*dist > EPS && *dist < ray->t) return true; 36 | *dist = b + det; 37 | if (*dist > EPS && *dist < ray->t) return true; 38 | #endif 39 | 40 | return false; 41 | } 42 | 43 | float sphere_solidAngle(const Mesh* sphere, const float3* p) { 44 | float3 L = sphere->pos - *p; 45 | float d = fast_length(L); 46 | float cosTheta = sqrt(fmax(d * d - sphere->radius * sphere->radius, 0.0f)) / d; 47 | 48 | return TWO_PI * (1.0f - cosTheta); 49 | } 50 | 51 | float sphere_approximateRadiance(const Mesh* sphere, const float3* p){ 52 | return sphere_solidAngle(sphere, p) * fmax3(sphere->mat.color); 53 | } 54 | 55 | float sphere_area(const Mesh* sphere){ 56 | return FOUR_PI * sphere->radius * sphere->radius; 57 | } 58 | 59 | float sphere_directPdf(const Mesh* sphere, const float3* p) { 60 | float dist = length(sphere->pos - *p); 61 | float cosTheta = sqrt(fmax(dist * dist - sphere->radius * sphere->radius, 0.0f)) / dist; 62 | return uniformSphericalCapPdf(cosTheta); 63 | } 64 | 65 | bool sphere_sampleDirect(const Mesh* sphere, const float3* p, LightSample* sample, RNG_SEED_PARAM) { 66 | float3 L = sphere->pos - *p; 67 | float d = length(L); 68 | float C = d * d - sphere->radius * sphere->radius; 69 | 70 | if (C <= 0.0f) 71 | return false; 72 | 73 | L = normalize(L); 74 | float cosTheta = sqrt(C) / d; 75 | 76 | sample->d = uniformSphericalCap(next2D(RNG_SEED_VALUE), cosTheta); 77 | 78 | float B = d * sample->d.z; 79 | float det = sqrt(fmax(B * B - C, 0.0f)); 80 | sample->dist = B - det; 81 | 82 | 83 | TangentFrame frame = createTangentFrame(&L); 84 | sample->d = toGlobal(&frame, cosTheta); 85 | sample->pdf = uniformSphericalCapPdf(cosTheta); 86 | 87 | return true; 88 | } 89 | 90 | #endif -------------------------------------------------------------------------------- /kernels/geometry/triangle.cl: -------------------------------------------------------------------------------- 1 | #ifndef __TRIANGLE__ 2 | #define __TRIANGLE__ 3 | 4 | bool intersectTriangle( 5 | const Scene* scene, Ray* ray, const uint fIndex 6 | ) { 7 | const uint fv = scene->indices[fIndex]*3; 8 | const float3 p0 = scene->vertices[fv+0].xyz; 9 | const float3 p1 = scene->vertices[fv+1].xyz; 10 | const float3 p2 = scene->vertices[fv+2].xyz; 11 | 12 | const float3 e1 = p0 - p1; 13 | const float3 e2 = p2 - p0; 14 | 15 | const float3 n = cross(e1, e2); 16 | 17 | float3 c = p0 - ray->origin; 18 | float3 r = cross(ray->dir, c); 19 | float inv_det = native_recip(dot(n, ray->dir)); 20 | 21 | float u = dot(r, e2) * inv_det; 22 | float v = dot(r, e1) * inv_det; 23 | float w = 1.0f - u - v; 24 | 25 | if(u >= 0 && v >= 0 && w >= 0){ 26 | float t = dot(n, c) * inv_det; 27 | if(t > EPS && t < ray->t){ 28 | ray->t = t; 29 | #if 1 // smooth shading 30 | const float3 n0 = scene->normals[fv+0].xyz; 31 | const float3 n1 = scene->normals[fv+1].xyz; 32 | const float3 n2 = scene->normals[fv+2].xyz; 33 | 34 | ray->normal = w * n0 + u * n1 + v * n2; 35 | #else 36 | ray->normal = n; 37 | #endif 38 | return true; 39 | } 40 | } 41 | 42 | return false; 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /kernels/header.cl: -------------------------------------------------------------------------------- 1 | #ifndef __HEADER__ 2 | #define __HEADER__ 3 | 4 | #define EPS 1e-5f 5 | #define INF 2e1f 6 | 7 | #define PI 3.1415926535897932384626433832795f 8 | #define PI_HALF 1.5707963267948966192313216916398f 9 | #define TWO_PI 6.283185307179586476925286766559f 10 | #define FOUR_PI 12.566370614359172953850573533118f 11 | #define INV_PI 0.3183098861837906715377675267450f 12 | #define INV_TWO_PI 0.1591549430918953357688837633725f 13 | #define INV_FOUR_PI 0.0795774715459476678844418816863f 14 | #define SQRT_PI 1.7724538509055160272981674833411f 15 | #define ONE_OVER_SQRT_PI 0.5641895835477562869480794515608f 16 | 17 | #define F3_EPS (float3)(EPS) 18 | #define F3_ZERO (float3)(0.0f) 19 | #define F3_ONE (float3)(1.0f) 20 | 21 | #define F3_UP (float3)(0.0f, 1.0f, 0.0f) 22 | #define F3_DOWN (float3)(0.0f, -1.0f, 0.0f) 23 | #define F3_RIGHT (float3)(1.0f, 0.0f, 0.0f) 24 | #define F3_LEFT (float3)(-1.0f, 0.0f, 0.0f) 25 | #define F3_FRONT (float3)(0.0f, 0.0f, 1.0f) 26 | #define F3_BACK (float3)(0.0f, 0.0f, -1.0f) 27 | 28 | #define RAD 0.01745329251994329576923690768489f 29 | #define E 2.71828182845904523536028747135266f 30 | 31 | #define BIT(N) ( 0b1<z); 183 | float a = -1.0f / (sn + normal->z); 184 | float b = normal->x * normal->y * a; 185 | 186 | res.normal = *normal; 187 | res.tangent = (float3)(1.0f + sn * normal->x * normal->x * a, sn * b, -sn * normal->x); 188 | res.bitangent = (float3)(b, sn + normal->y * normal->y * a, -normal->y); 189 | return res; 190 | } 191 | 192 | float3 toLocal(const TangentFrame* tf, const float3 p) { 193 | return (float3)( 194 | dot(tf->tangent, p), 195 | dot(tf->bitangent, p), 196 | dot(tf->normal, p) 197 | ); 198 | } 199 | 200 | float3 toGlobal(const TangentFrame* tf, const float3 p) { 201 | return tf->tangent * p.x + 202 | tf->bitangent * p.y + 203 | tf->normal * p.z; 204 | } 205 | 206 | //------------- Surface Scatter Event ------------- 207 | 208 | typedef struct { 209 | float3 wi, wo; 210 | float3 weight; 211 | float pdf; 212 | uchar requestedLobe; 213 | uchar sampledLobe; 214 | TangentFrame frame; 215 | } SurfaceScatterEvent; 216 | 217 | //------------- Material ------------- 218 | 219 | typedef struct { 220 | union { 221 | float3 color; 222 | float3 emission; 223 | float3 albedo; 224 | }; 225 | union { 226 | float3 eta; 227 | float3 eta_t; 228 | }; 229 | float3 k; 230 | float roughness; // surface roughness 231 | ushort t; // mesh type 232 | uchar lobes; // asigned lobe/s 233 | uchar dist; // distribution 234 | } Material; 235 | 236 | //------------- MESH ------------- 237 | 238 | typedef struct { 239 | Material mat; // assigned material 240 | float3 pos; // position 241 | union { // generic data 242 | float16 joker; 243 | float* value; 244 | float radius; 245 | }; 246 | uchar t; // type 247 | } Mesh; 248 | 249 | //------------- BVH ------------- 250 | 251 | typedef struct { 252 | float4 bbMin; 253 | float4 bbMax; 254 | } bvhNode; 255 | 256 | typedef struct { 257 | float bounds[6]; 258 | uint first_child_or_primitive; 259 | uint primitive_count; 260 | bool isLeaf; 261 | } new_bvhNode; 262 | 263 | //------------- Light Sampler ------------- 264 | typedef struct { 265 | float3 d; 266 | float dist; 267 | float pdf; 268 | //const Medium* medium; 269 | } LightSample; 270 | 271 | #if 0 272 | typedef struct { 273 | float4 pos; 274 | float4 rgb; 275 | float4 data; 276 | } light_t; 277 | #endif 278 | 279 | typedef struct { 280 | __constant Mesh* meshes; 281 | __constant ulong* indices; 282 | __constant new_bvhNode* new_nodes; 283 | const uint* mesh_count; 284 | __constant float4* vertices; 285 | __constant float4* normals; 286 | __constant Material* mat; 287 | } Scene; 288 | 289 | #endif 290 | -------------------------------------------------------------------------------- /kernels/integrators/base.cl: -------------------------------------------------------------------------------- 1 | #ifndef __T_BASE__ 2 | #define __T_BASE__ 3 | 4 | __constant bool enableLightSampling = true; 5 | __constant bool enableVolumeLightSampling = true; 6 | __constant bool lowOrderScattering = true; 7 | 8 | #define CONSISTENCY_CHECKS 0 9 | #define PICK_RANDOM_LIGHT 0 10 | 11 | SurfaceScatterEvent makeLocalScatterEvent(Ray* ray, const Scene* scene) { 12 | TangentFrame frame = createTangentFrame(&ray->normal); 13 | return (SurfaceScatterEvent){ toLocal(&frame, -ray->dir) , (float3)(0.0), (float3)(1.0), 1.0, NullLobe, NullLobe, frame }; 14 | } 15 | 16 | SurfaceScatterEvent makeForwardEvent(const SurfaceScatterEvent* event){ 17 | SurfaceScatterEvent copy = *event; 18 | copy.wo = -copy.wi; 19 | copy.requestedLobe = ForwardLobe; 20 | return copy; 21 | } 22 | 23 | inline float powerHeuristic(float pdf0, float pdf1){ 24 | return (pdf0 * pdf0) / (pdf0 * pdf0 + pdf1 * pdf1); 25 | } 26 | 27 | /*--------------------------- LIGHT ---------------------------*/ 28 | 29 | #ifdef LIGHT 30 | 31 | float3 bsdfSample( 32 | SurfaceScatterEvent* event, 33 | Ray* ray, 34 | const Medium* medium, 35 | const Scene* scene, 36 | RNG_SEED_PARAM, 37 | const Material* mat, 38 | bool* terminate 39 | ) { 40 | if (!BSDF2(event, ray, scene, mat, RNG_SEED_VALUE, false)) { 41 | *terminate = true; 42 | return (float3)(0.0f); 43 | } 44 | 45 | float3 wo = toGlobal(&event->frame, event->wo); 46 | 47 | #if CONSISTENCY_CHECKS 48 | bool geometricBackside = (dot(wo, ray->normal) < 0.0f); 49 | bool shadingBackside = (event->wo.z < 0.0f) ^ ray->backside; 50 | 51 | if (geometricBackside == shadingBackside) 52 | #endif 53 | { 54 | ray->origin = ray->pos; 55 | ray->dir = wo; 56 | 57 | int mesh_id; 58 | if (intersect_scene(ray, &mesh_id, scene)) { 59 | const Mesh light = scene->meshes[mesh_id]; 60 | 61 | if (light.mat.t & LIGHT) { 62 | //*terminate = true; 63 | float3 contribution = light.mat.color * event->weight * 64 | powerHeuristic(event->pdf, directPdf(&light, &ray->dir, &ray->pos)); 65 | 66 | #ifdef GLOBAL_MEDIUM 67 | if (medium != NULL) 68 | contribution *= native_exp(-medium->sigmaT * ray->t); 69 | #endif 70 | 71 | return contribution; 72 | } 73 | } 74 | } 75 | 76 | return (float3)(0.0f); 77 | } 78 | 79 | float3 lightSample( 80 | SurfaceScatterEvent* event, 81 | const Ray* ray, 82 | const Medium* medium, 83 | const Scene* scene, 84 | RNG_SEED_PARAM, 85 | const Material* mat 86 | ) { 87 | 88 | #if PICK_RANDOM_LIGHT 89 | // pick a random light source 90 | const Mesh light = scene->meshes[LIGHT_INDICES[(int)(next1D(RNG_SEED_VALUE) * (float)(LIGHT_COUNT + 1))]]; 91 | #else 92 | const Mesh light = scene->meshes[LIGHT_INDICES[0]]; 93 | #endif 94 | 95 | LightSample rec; 96 | 97 | if (!sampleDirect(&light, &ray->pos, &rec, RNG_SEED_VALUE)) 98 | return (float3)(0.0f); 99 | 100 | event->wo = toLocal(&event->frame, rec.d); 101 | 102 | #if CONSISTENCY_CHECKS 103 | bool geometricBackside = (dot(rec.d, ray->normal) < 0.0f); 104 | bool shadingBackside = (event->wo.z < 0.0f) ^ ray->backside; 105 | 106 | if (geometricBackside == shadingBackside) 107 | #endif 108 | { 109 | float3 fr = BSDF_eval2(event, mat, false); 110 | 111 | if (dot(fr, fr) == 0.0) 112 | return (float3)(0.0f); 113 | 114 | Ray shadowRay; 115 | shadowRay.origin = ray->pos; 116 | shadowRay.dir = rec.d; 117 | shadowRay.t = rec.dist; 118 | 119 | if (shadow(&shadowRay, scene)) { 120 | float3 contribution = light.mat.color * fr; 121 | 122 | #ifdef GLOBAL_MEDIUM 123 | if (medium != NULL) 124 | contribution *= native_exp(-medium->sigmaT * shadowRay.t); 125 | #endif 126 | 127 | contribution *= powerHeuristic(rec.pdf, BSDF_pdf(event, mat)); 128 | return contribution/rec.pdf; 129 | } 130 | } 131 | 132 | 133 | return (float3)(0.0f); 134 | } 135 | 136 | #endif 137 | 138 | bool handleSurface( 139 | SurfaceScatterEvent* event, 140 | Ray* ray, 141 | const Medium* medium, 142 | const Scene* scene, 143 | RNG_SEED_PARAM, 144 | Material* mat, 145 | __global RLH* rlh, 146 | float3* emmision 147 | ) { 148 | bool terminate = false; 149 | 150 | #if 0 // Dispersion Test 151 | #if defined(DIEL) && defined(ROUGH_DIEL) 152 | if (mat->t & (DIEL | ROUGH_DIEL)) 153 | #elif defined(DIEL) 154 | if (mat->t & DIEL) 155 | #elif defined(ROUGH_DIEL) 156 | if (mat->t & ROUGH_DIEL) 157 | #else 158 | if (false) 159 | #endif 160 | { 161 | return false; 162 | float _min = fmin3(mat->eta_t); 163 | float _max = fmax3(mat->eta_t); 164 | mat->eta_t.x = dot(rlh->mask, mat->eta_t) / dot(rlh->mask, 1.0f); 165 | } 166 | #endif // End of Dispersion Test 167 | 168 | #ifdef LIGHT 169 | if (enableLightSampling && mat->lobes & ~(SpecularLobe|ForwardLobe)) { 170 | *emmision += (bsdfSample(event, ray, medium, scene, RNG_SEED_VALUE, mat, &terminate)+ 171 | lightSample(event, ray, medium, scene, RNG_SEED_VALUE, mat)) * rlh->mask; 172 | } 173 | else 174 | #endif 175 | { 176 | if (!BSDF2(event, ray, scene, mat, RNG_SEED_VALUE, false)) { 177 | return true; 178 | } 179 | 180 | ray->origin = ray->pos; 181 | ray->dir = toGlobal(&event->frame, event->wo); 182 | } 183 | 184 | rlh->bounce.wasSpecular = event->sampledLobe & SpecularLobe; 185 | 186 | rlh->mask *= event->weight; 187 | rlh->bounce.diff += (event->sampledLobe & (DiffuseReflectionLobe| GlossyReflectionLobe)) != 0; 188 | rlh->bounce.spec += (event->sampledLobe & SpecularReflectionLobe) != 0; 189 | rlh->bounce.trans += (event->sampledLobe & TransmissiveLobe) != 0; 190 | 191 | return terminate; 192 | } 193 | 194 | float3 volumeLightSample( 195 | MediumSample* mediumSample, 196 | const Medium* medium, 197 | const Ray* ray, 198 | const Scene* scene, 199 | RNG_SEED_PARAM, 200 | const Material* mat 201 | ){ 202 | #if PICK_RANDOM_LIGHT 203 | // pick a random light source 204 | const Mesh light = scene->meshes[LIGHT_INDICES[(int)(next1D(RNG_SEED_VALUE) * (float)(LIGHT_COUNT + 1))]]; 205 | #else 206 | const Mesh light = scene->meshes[LIGHT_INDICES[0]]; 207 | #endif 208 | 209 | LightSample rec; 210 | 211 | if(!sampleDirect(&light, &ray->pos, &rec, RNG_SEED_VALUE)) 212 | return (float3)(0.0f); 213 | 214 | float3 f = phase_eval(ray->dir, rec.d); 215 | if (dot(f, f) == 0.0f) 216 | return (float3)(0.0f); 217 | 218 | Ray sRay; 219 | sRay.origin = mediumSample->p; 220 | sRay.dir = rec.d; 221 | sRay.t = rec.dist; 222 | 223 | if (shadow(&sRay, scene)) { 224 | float3 contribution = native_exp(-medium->sigmaT * sRay.t) * light.mat.color * f * 225 | powerHeuristic(rec.pdf, phase_pdf(ray->dir, rec.d)); 226 | return contribution / rec.pdf; 227 | } 228 | 229 | return (float3)(0.0f); 230 | } 231 | 232 | float3 volumePhaseSample( 233 | MediumSample* mediumSample, 234 | PhaseSample* phaseSample, 235 | const Medium* medium, 236 | const Ray* ray, 237 | const Scene* scene, 238 | RNG_SEED_PARAM, 239 | const Material* mat 240 | ){ 241 | if (!phase_sample(ray->dir, phaseSample, RNG_SEED_VALUE)) { 242 | return (float3)(0.0f); 243 | } 244 | 245 | Ray sRay; 246 | sRay.origin = mediumSample->p; 247 | sRay.dir = phaseSample->w; 248 | 249 | int mesh_id; 250 | if (intersect_scene(&sRay, &mesh_id, scene)) { 251 | const Mesh light = scene->meshes[mesh_id]; 252 | 253 | if (light.mat.t & LIGHT) { 254 | return native_exp(-medium->sigmaT * sRay.t) * light.mat.color * phaseSample->weight * 255 | powerHeuristic(phaseSample->pdf, directPdf(&light, &sRay.dir, &mediumSample->p)); 256 | } 257 | } 258 | 259 | return (float3)(0.0f); 260 | } 261 | 262 | #endif 263 | -------------------------------------------------------------------------------- /kernels/integrators/bidirectional.cl: -------------------------------------------------------------------------------- 1 | #ifndef __INTEGRATOR__ 2 | #define __INTEGRATOR__ 3 | 4 | 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /kernels/integrators/pathtracing.cl: -------------------------------------------------------------------------------- 1 | #ifndef __INTEGRATOR__ 2 | #define __INTEGRATOR__ 3 | 4 | float4 radiance( 5 | const Scene* scene, 6 | __read_only image2d_t env_map, 7 | Ray* ray, 8 | __global RLH* rlh, 9 | RNG_SEED_PARAM 10 | ){ 11 | #ifdef GLOBAL_MEDIUM 12 | const Medium _medium = (Medium){ 13 | (float3)(GLOBAL_FOG_DENSITY), 14 | (float3)(GLOBAL_FOG_SIGMA_A), 15 | (float3)(GLOBAL_FOG_SIGMA_S), 16 | (float3)(GLOBAL_FOG_SIGMA_T), 17 | GLOBAL_FOG_ABS_ONLY 18 | }; 19 | const Medium* medium = &_medium; 20 | #else 21 | const Medium* medium = NULL; 22 | #endif 23 | 24 | float alpha = 1.0f; 25 | float3 emission = (float3)(0.0f); 26 | #define acc (float4)(emission, alpha) 27 | 28 | int mesh_id; 29 | bool didHit = intersect_scene(ray, &mesh_id, scene); 30 | 31 | const Mesh mesh = scene->meshes[mesh_id]; 32 | Material mat = (mesh_id + 1) ? mesh.mat : *scene->mat; 33 | 34 | /*------------------- GLOBAL MEDIUM -------------------*/ 35 | #ifdef GLOBAL_MEDIUM 36 | MediumSample mediumSample; 37 | mediumSample.continuedWeight = rlh->mask; 38 | 39 | HomogeneousMedium_sampleDistance(&mediumSample, medium, ray, RNG_SEED_VALUE); 40 | 41 | rlh->mask *= mediumSample.weight; 42 | 43 | // scatter 44 | if (!mediumSample.exited && rlh->bounce.scatters < MAX_SCATTERING_EVENTS){ 45 | ++rlh->bounce.scatters; 46 | 47 | PhaseSample phaseSample; 48 | 49 | rlh->bounce.wasSpecular = !(enableVolumeLightSampling && (lowOrderScattering || rlh->bounce.scatters > 1)); 50 | 51 | if (!rlh->bounce.wasSpecular) { 52 | emission += ( 53 | volumeLightSample(&mediumSample, medium, ray, scene, RNG_SEED_VALUE, &mat) + 54 | volumePhaseSample(&mediumSample, &phaseSample, medium, ray, scene, RNG_SEED_VALUE, &mat) 55 | ) * rlh->mask; 56 | } 57 | 58 | ray->origin = mediumSample.p; 59 | ray->dir = phaseSample.w; 60 | 61 | rlh->mask *= phaseSample.weight; 62 | } else 63 | #endif 64 | //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- 65 | { 66 | if (!didHit) { 67 | rlh->reset = true; 68 | 69 | #ifdef ALPHA_TESTING 70 | return (float4)(0.0f); 71 | #else 72 | return (float4)(rlh->mask * read_imagef(env_map, samplerA, envMapEquirect(ray->dir)).xyz, 1.0f); 73 | #endif 74 | } 75 | 76 | #ifdef LIGHT 77 | if (mat.t & LIGHT) { 78 | if (!enableLightSampling || rlh->bounce.wasSpecular) 79 | emission += mat.emission * rlh->mask; 80 | 81 | rlh->reset = true; 82 | return acc; 83 | } 84 | #endif 85 | 86 | SurfaceScatterEvent surfaceEvent = makeLocalScatterEvent(ray, scene); 87 | 88 | if (handleSurface(&surfaceEvent, ray, medium, scene, RNG_SEED_VALUE, &mat, rlh, &emission)) { 89 | rlh->reset = true; 90 | return acc; 91 | } 92 | 93 | rlh->bounce.scatters = 0; 94 | ++rlh->bounce.total; 95 | } 96 | 97 | //russian roulette 98 | const float roulettePdf = fmax3(rlh->mask); 99 | if (rlh->bounce.total > 2 && roulettePdf < 0.1f) { 100 | if (next1D(RNG_SEED_VALUE) < roulettePdf){ 101 | rlh->mask /= roulettePdf; 102 | } else { 103 | rlh->reset = true; 104 | return acc; 105 | } 106 | } 107 | 108 | /* terminate if necessary */ 109 | if (rlh->bounce.total >= MAX_BOUNCES || 110 | rlh->bounce.diff >= MAX_DIFF_BOUNCES || 111 | rlh->bounce.spec >= MAX_SPEC_BOUNCES || 112 | rlh->bounce.trans >= MAX_TRANS_BOUNCES 113 | ) { 114 | rlh->reset = true; 115 | } 116 | 117 | return acc; 118 | 119 | #undef acc 120 | } 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /kernels/intersect.cl: -------------------------------------------------------------------------------- 1 | #ifndef __INTERSECT__ 2 | #define __INTERSECT__ 3 | 4 | /* Find the closest distance to a specific object */ 5 | bool get_dist(float* dist, const Ray* sray, const Mesh* mesh, const Scene* scene, const bool isOBJ){ 6 | Ray temp_ray = *sray; 7 | temp_ray.t = INF; 8 | 9 | if(isOBJ) { 10 | traverse(scene, &temp_ray); 11 | } 12 | #ifdef __SPHERE__ 13 | else if(mesh->t & SPHERE){ 14 | intersect_sphere(&temp_ray, mesh); 15 | } 16 | #endif 17 | #ifdef __SDF__ 18 | else if(mesh->t & SDF){ 19 | temp_ray.t = fmin(s_map(mesh, temp_ray.origin), temp_ray.t); 20 | } 21 | #endif 22 | #ifdef __BOX__ 23 | else if(mesh->t & BOX){ 24 | intersect_box(mesh, &temp_ray); 25 | } 26 | #endif 27 | #ifdef __QUAD__ 28 | else if (mesh->t & QUAD) { 29 | intersect_quad(mesh, &temp_ray); 30 | } 31 | #endif 32 | 33 | *dist = temp_ray.t; 34 | return temp_ray.t < INF; 35 | } 36 | 37 | //-------------# LIGHTS 38 | #ifdef LIGHT 39 | 40 | /* Hit a specific object and pass the intesection info to the ray */ 41 | bool intersect_mesh(Ray* sray, const Mesh* mesh, const Scene* scene, const bool isOBJ) { 42 | const Ray temp_ray = *sray; 43 | 44 | sray->t = INF; 45 | 46 | if (isOBJ) { 47 | traverse(scene, sray); 48 | sray->pos = sray->origin + sray->dir * sray->t; 49 | 50 | sray->backside = dot(sray->normal, sray->dir) >= 0.0f; 51 | sray->normal = sray->backside ? -sray->normal : sray->normal; 52 | } 53 | #ifdef __SPHERE__ 54 | else if (mesh->t & SPHERE) { 55 | if (intersect_sphere(sray, mesh)) { 56 | sray->pos = sray->origin + sray->dir * sray->t; 57 | sray->normal = fast_normalize(sray->pos - mesh->pos); 58 | 59 | //sray->backside = dot(sray->normal, sray->dir) >= 0.0f; 60 | sray->normal = sray->backside ? -sray->normal : sray->normal; 61 | } 62 | } 63 | #endif 64 | #ifdef __SDF__ 65 | else if (mesh->t & SDF) { 66 | sray->t = fmin(s_map(mesh, sray->origin), sray->t); 67 | sray->pos = sray->origin + sray->dir * sray->t; 68 | sray->normal = calcNormal(mesh, sray->pos); 69 | 70 | sray->backside = dot(sray->normal, sray->dir) >= 0.0f; 71 | sray->normal = sray->backside ? -sray->normal : sray->normal; 72 | } 73 | #endif 74 | #ifdef __BOX__ 75 | else if (mesh->t & BOX) { 76 | intersect_box(mesh, sray); 77 | sray->pos = sray->origin + sray->dir * sray->t; 78 | } 79 | #endif 80 | #ifdef __QUAD__ 81 | else if (mesh->t & QUAD) { 82 | intersect_quad(mesh, sray); 83 | } 84 | #endif 85 | 86 | if (sray->t >= INF) { 87 | *sray = temp_ray; 88 | return false; 89 | } 90 | return true; 91 | } 92 | 93 | /* shadow casting */ 94 | bool shadow( 95 | Ray* ray, 96 | const Scene* scene 97 | ){ 98 | const float maxDist = ray->t; 99 | 100 | #ifdef __BVH__ 101 | Ray temp_ray = *ray; 102 | if(traverseShadows(scene, ray)){ 103 | *ray = temp_ray; 104 | return false; 105 | } 106 | #endif 107 | 108 | #ifdef __SPHERE__ 109 | for (uint i = 0; i < scene->mesh_count[0]; ++i) { 110 | 111 | Mesh sphere = scene->meshes[i]; /* local copy */ 112 | 113 | if (intersect_sphere(ray, &sphere)) { 114 | if (ray->t < maxDist) return false; 115 | } 116 | } 117 | #endif 118 | 119 | #ifdef __SDF__ 120 | /* if there are any sdfs in the scene raymarch them */ 121 | if (scene->mesh_count[1]) { 122 | if (shadow_sdf(scene->meshes, ray, scene->mesh_count)) { 123 | return false; 124 | } 125 | } 126 | #endif 127 | 128 | uint fl = scene->mesh_count[0] + scene->mesh_count[1]; 129 | #ifdef __BOX__ 130 | for (uint i = 0; i < scene->mesh_count[2]; ++i) { 131 | 132 | Mesh box = scene->meshes[fl++]; /* local copy */ 133 | 134 | if (intersect_box(&box, ray)) { 135 | if (ray->t < maxDist) return false; 136 | } 137 | } 138 | #endif 139 | 140 | #ifdef __QUAD__ 141 | for (uint i = 0; i < scene->mesh_count[3]; ++i) { 142 | 143 | Mesh tquad = scene->meshes[fl++]; /* local copy */ 144 | 145 | if (intersect_quad(&tquad, ray)) { 146 | if (ray->t < maxDist) return false; 147 | } 148 | } 149 | #endif 150 | 151 | return true; 152 | } 153 | 154 | #endif 155 | //-------------# LIGHTS 156 | 157 | /* find the closest intersection in the scene */ 158 | bool intersect_scene( 159 | Ray* ray, 160 | int* mesh_id, 161 | const Scene* scene 162 | ) { 163 | ray->t = INF; 164 | *mesh_id = -1; 165 | 166 | #ifdef __BVH__ 167 | traverse(scene, ray); 168 | ray->normal = normalize(ray->normal); 169 | ray->pos = ray->origin + ray->dir * ray->t; 170 | #endif 171 | 172 | #ifdef __SPHERE__ 173 | for (uint i = 0; i < scene->mesh_count[0]; ++i) { 174 | 175 | Mesh sphere = scene->meshes[i]; /* local copy */ 176 | 177 | if (intersect_sphere(ray, &sphere)) { 178 | ray->pos = ray->origin + ray->dir * ray->t; 179 | ray->normal = fast_normalize(ray->pos - sphere.pos); 180 | *mesh_id = i; 181 | } 182 | } 183 | #endif 184 | 185 | #ifdef __SDF__ 186 | /* if there are any sdfs in the scene raymarch them */ 187 | if (scene->mesh_count[1]) { 188 | if (intesect_sdf(scene->meshes, ray, mesh_id, scene->mesh_count)) { 189 | ray->pos = ray->origin + ray->dir * ray->t; 190 | Mesh sdf = scene->meshes[*mesh_id]; /* local copy */ 191 | ray->normal = calcNormal(&sdf, ray->pos); 192 | } 193 | } 194 | #endif 195 | 196 | uint fl = scene->mesh_count[0] + scene->mesh_count[1]; 197 | #ifdef __BOX__ 198 | for (uint i = 0; i < scene->mesh_count[2]; ++i) { 199 | 200 | Mesh box = scene->meshes[fl]; /* local copy */ 201 | 202 | if (intersect_box(&box, ray)) { 203 | ray->pos = ray->origin + ray->dir * ray->t; 204 | *mesh_id = fl; 205 | } 206 | ++fl; 207 | } 208 | #endif 209 | 210 | #ifdef __QUAD__ 211 | for (uint i = 0; i < scene->mesh_count[3]; ++i) { 212 | 213 | Mesh tquad = scene->meshes[fl]; /* local copy */ 214 | 215 | if(intersect_quad(&tquad, ray)){ 216 | *mesh_id = fl; 217 | } 218 | ++fl; 219 | } 220 | #endif 221 | 222 | #if defined DIEL && defined ROUGH_DIEL 223 | const bool nTrans = scene->meshes[*mesh_id].mat.t & ~(DIEL | ROUGH_DIEL); 224 | #elif defined DIEL 225 | const bool nTrans = scene->meshes[*mesh_id].mat.t & ~DIEL; 226 | #elif defined ROUGH_DIEL 227 | const bool nTrans = scene->meshes[*mesh_id].mat.t & ~ROUGH_DIEL; 228 | #else 229 | const bool nTrans = true; 230 | #endif 231 | 232 | ray->backside = dot(ray->normal, ray->dir) > 0.0f; 233 | ray->normal = nTrans && ray->backside ? -ray->normal : ray->normal; 234 | 235 | return ray->t < INF; 236 | } 237 | 238 | #endif 239 | -------------------------------------------------------------------------------- /kernels/main.cl: -------------------------------------------------------------------------------- 1 | #ifndef __OPENCL_RAYTRACER__ 2 | #define __OPENCL_RAYTRACER__ 3 | 4 | #define DEBUG 1 5 | 6 | #define VIEW_RESULTS (0) 7 | #define VIEW_NORMAL (1<<0) 8 | #define VIEW_STACK_INDEX (1<<1) 9 | #define VIEW_ALBEDO (1<<2) 10 | #define VIEW_SPECULAR (1<<3) 11 | #define VIEW_BVH_HIT (1<<4) 12 | 13 | #define VIEW_OPTION (~(0xFF<<(DEBUG*8)) & VIEW_RESULTS) 14 | 15 | #if DEBUG 16 | #define LOGWARNING(x) printf(x); 17 | #define LOGERROR(x) printf(x); 18 | #else 19 | #define LOGERROR(x) 20 | #define LOGWARNING(x) 21 | #endif 22 | 23 | #pragma OPENCL EXTENSION cl_khr_fp16 : enable 24 | 25 | __constant sampler_t samplerA = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP | CLK_FILTER_LINEAR; 26 | 27 | #define tempToRay(tray) (Ray){ tray.origin, tray.dir, (float3)(0.0f), (float3)(0.0f), {tray.dist}, false, tray.time } 28 | #define rayToTemp(ray) (TempRay){ ray.origin, ray.dir, ray.t, ray.time } 29 | 30 | typedef struct { 31 | // throughput 32 | float3 mask; 33 | // accumulation buffer 34 | float4 acc; 35 | 36 | struct { 37 | // total bounces 38 | uint total; 39 | // explicit light controls 40 | ushort diff, spec, trans, scatters; 41 | bool wasSpecular; 42 | } bounce; 43 | 44 | bool reset; 45 | uint samples; 46 | //int mesh_id; 47 | } RLH; 48 | 49 | #FILE:header.cl 50 | #FILE:utils.cl 51 | #FILE:noise/value_noise.cl 52 | #FILE:camera.cl 53 | #FILE:geometry/geometry.cl 54 | #FILE:intersect.cl 55 | #FILE:bxdf/bxdf.cl 56 | #FILE:media.cl 57 | 58 | typedef struct { 59 | TempRay ray; 60 | RLH data; 61 | } RTD; 62 | 63 | #FILE:integrators/base.cl 64 | #FILE:integrators/pathtracing.cl 65 | 66 | __kernel void render_kernel( 67 | /* scene's Meshes */ 68 | __constant Mesh* meshes, 69 | 70 | /* window size */ 71 | const int width, const int height, 72 | 73 | /* total meshes in the scene @ToRemove */ 74 | const uint8 mesh_count, 75 | 76 | /* current frame */ 77 | const uint framenumber, 78 | 79 | /* camera */ 80 | __constant Camera* cam, 81 | 82 | /* seeds */ 83 | const int random0, const int random1, 84 | 85 | /* new frame */ 86 | __write_only image2d_t output_tex, 87 | 88 | /* BVH */ 89 | __constant uint* primitive_indices, 90 | __constant float4* vertices, 91 | __constant float4* normals, 92 | __constant Material* mat, 93 | 94 | /* enviroment map */ 95 | __read_only image2d_t env_map, 96 | 97 | __global RTD* r_flat, 98 | 99 | __constant new_bvhNode* new_bvh_node 100 | ) { 101 | const int work_item_id = get_global_id(0); /* the unique global id of the work item for the current pixel */ 102 | 103 | /* xy-coordinate of the pixel */ 104 | const int2 i_coord = (int2)(work_item_id % width, work_item_id / width); 105 | 106 | #if RNG_TYPE == 0 107 | /* seeds for random number generator */ 108 | uint seed0 = i_coord.x * framenumber % 1000 + (random0 * 100); 109 | uint seed1 = i_coord.y * framenumber % 1000 + (random1 * 100); 110 | #elif RNG_TYPE == 1 111 | ulong state = 0xBA5EBA11; 112 | #elif RNG_TYPE == 2 113 | const float2 f_coord = (float2)((float)(i_coord.x) / width, (float)(i_coord.y) / height); 114 | double seed = dot(f_coord, (float2)(framenumber % 1000 + random0 * 100, framenumber % 333 + random1 * 33)); 115 | #endif 116 | 117 | __global RLH* rlh = &r_flat[work_item_id].data; 118 | 119 | Ray ray = tempToRay(r_flat[work_item_id].ray); 120 | 121 | // firstBounce or reset 122 | if (rlh->reset || rlh->samples == 0) { 123 | ++rlh->samples; 124 | rlh->bounce.total = 0; 125 | rlh->bounce.diff = 0; 126 | rlh->bounce.spec = 0; 127 | rlh->bounce.trans = 0; 128 | rlh->bounce.scatters = 0; 129 | rlh->bounce.wasSpecular = true; 130 | rlh->reset = false; 131 | 132 | rlh->mask = (float3)(1.0f); 133 | 134 | // @ToDo generate cam ray on CPU 135 | ray = createCamRay(i_coord, width, height, cam, RNG_SEED_VALUE_P); 136 | } 137 | 138 | const Scene scene = { meshes, primitive_indices, new_bvh_node, &mesh_count, vertices, normals, mat }; 139 | 140 | #if VIEW_OPTION == VIEW_RESULTS 141 | /* add pixel colour to accumulation buffer (accumulates all samples) */ 142 | rlh->acc += radiance(&scene, env_map, &ray, rlh, RNG_SEED_VALUE_P); 143 | #elif VIEW_OPTION == VIEW_NORMAL 144 | radiance(&scene, env_map, &ray, rlh, RNG_SEED_VALUE_P); 145 | rlh->acc = (float4)(ray.normal, 1.0f); 146 | #elif VIEW_OPTION == VIEW_STACK_INDEX 147 | radiance(&scene, env_map, &ray, rlh, RNG_SEED_VALUE_P); 148 | // rlh->acc = (float4)((float3)((float)(64-ray.bvh_stackIndex)/64.0f), 1.0f); 149 | rlh->acc = (float4)((float3)(fmin(1.0f, (float)(ray.bvh_stackIndex))), 1.0f); 150 | #elif VIEW_OPTION == VIEW_BVH_HIT 151 | radiance(&scene, env_map, &ray, rlh, RNG_SEED_VALUE_P); 152 | rlh->acc = (float4)(ray.normal, 1.0f); 153 | #endif 154 | 155 | r_flat[work_item_id].ray = rayToTemp(ray); 156 | 157 | /* update the output GLTexture */ 158 | #if VIEW_OPTION == VIEW_RESULTS 159 | write_imagef(output_tex, i_coord, rlh->acc / (float)(rlh->samples)); 160 | #else 161 | write_imagef(output_tex, i_coord, rlh->acc); 162 | #endif 163 | } 164 | 165 | #endif -------------------------------------------------------------------------------- /kernels/media.cl: -------------------------------------------------------------------------------- 1 | #ifndef __MEDIA__ 2 | #define __MEDIA__ 3 | 4 | typedef struct { 5 | float3 w; 6 | float3 weight; 7 | float pdf; 8 | } PhaseSample; 9 | 10 | typedef struct { 11 | int phase; 12 | float3 p; 13 | float continuedT; 14 | float3 continuedWeight; 15 | float t; 16 | float3 weight; 17 | float pdf; 18 | bool exited; 19 | } MediumSample; 20 | 21 | typedef struct { 22 | float3 density; 23 | float3 sigmaA; 24 | float3 sigmaS; 25 | float3 sigmaT; 26 | bool absorptionOnly; 27 | } Medium; 28 | 29 | //---------------------------------------------------- 30 | 31 | #ifdef LIGHT 32 | 33 | /* only for point and sphere lights */ 34 | void sampleEquiAngular( 35 | const Ray* ray, 36 | const float Xi, 37 | const float3 lightPos, 38 | float* dist, 39 | float* pdf 40 | ){ 41 | // get coord of closest point to light along (infinite) ray 42 | float delta = dot(lightPos - ray->origin, ray->dir); 43 | 44 | // get distance this point is from light 45 | float D = length(ray->origin + delta * ray->dir - lightPos); 46 | 47 | // get angle of endpoints 48 | float thetaA = atan2(0.0f - delta, D); 49 | float thetaB = atan2(ray->t - delta, D); 50 | 51 | // take sample 52 | float t = D * tan(mix(thetaA, thetaB, Xi)); 53 | *dist = delta + t; 54 | *pdf = D / ((thetaB - thetaA)*(D*D + t*t)); 55 | } 56 | 57 | #endif 58 | 59 | //---------------------------------------------------- 60 | 61 | #FILE:phasefunctions/Isotropic.cl 62 | #FILE:media/homogeneous.cl 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /kernels/media/exponential.cl: -------------------------------------------------------------------------------- 1 | #ifndef __EXPONENTIAL_MEDIUM__ 2 | #define __EXPONENTIAL_MEDIUM__ 3 | 4 | #define _falloffScale 1.0f 5 | #define _falloffDirection F3_UP 6 | #define _unitPoint 0.0f 7 | 8 | #define density(x, dx, t) exp(-(x + dx * t)) 9 | #define density2(p) exp(-_falloffScale * dot(p - _unitPoint, _falloffDirection)) 10 | 11 | float densityIntegral(float x, float dx, float tMax){ 12 | if (tMax == INF) 13 | return exp(-x) / dx; 14 | else if (dx == 0.0f) 15 | return exp(-x)*tMax; 16 | else 17 | return (exp(-x) - exp(-dx * tMax - x)) / dx; 18 | } 19 | 20 | 21 | float inverseOpticalDepth(float x, float dx, float sigmaT, float logXi){ 22 | if (dx == 0.0f) { 23 | float effectiveSigmaTc = sigmaT * exp(-x); 24 | return -logXi / effectiveSigmaTc; 25 | } 26 | else { 27 | float denom = sigmaT + dx*exp(x)*logXi; 28 | return denom <= 0.0f ? INF : log(sigmaT / denom) / dx; 29 | } 30 | } 31 | 32 | void sampleDistance( 33 | const Ray* ray, MediumSample* m_sample, 34 | const Medium* medium, 35 | RNG_SEED_PARAM 36 | ) { 37 | float x = _falloffScale * dot(ray->origin - _unitPoint, _falloffDirection); 38 | float dx = _falloffScale * dot(ray->dir, _falloffDirection); 39 | 40 | const float maxT = ray->t; 41 | if (medium->absorptionOnly) { 42 | m_sample->t = maxT; 43 | m_sample->weight = exp(-medium->sigmaT * densityIntegral(x, dx, ray->t)); 44 | m_sample->pdf = 1.0f; 45 | m_sample->exited = true; 46 | } else { 47 | const float* sigmaT = &medium->sigmaT; 48 | float sigmaTc = sigmaT[(int)(round(next1D(RNG_SEED_VALUE)*3.0f))]; 49 | 50 | float xi = 1.0f - next1D(RNG_SEED_VALUE); 51 | float logXi = log(xi); 52 | 53 | float t = inverseOpticalDepth(x, dx, sigmaTc, logXi); 54 | m_sample->t = fmin(t, maxT); 55 | m_sample->weight = exp(-medium->sigmaT * densityIntegral(x, dx, m_sample->t)); 56 | m_sample->exited = (t >= maxT); 57 | if (m_sample->exited) { 58 | m_sample->pdf = avg3(m_sample->weight); 59 | } 60 | else { 61 | float rho = density(x, dx, m_sample->t); 62 | m_sample->pdf = avg3(rho*medium->sigmaT*m_sample->weight); 63 | m_sample->weight *= rho * medium->sigmaT; 64 | } 65 | m_sample->weight /= m_sample->pdf; 66 | } 67 | 68 | m_sample->p = ray->origin + m_sample->t*ray->dir; 69 | } 70 | 71 | #endif -------------------------------------------------------------------------------- /kernels/media/homogeneous.cl: -------------------------------------------------------------------------------- 1 | #ifndef __HOMOGENEOUS_MEDIUM__ 2 | #define __HOMOGENEOUS_MEDIUM__ 3 | 4 | #define _sigmaA medium->sigmaA 5 | #define _sigmaS medium->sigmaS 6 | #define _sigmaT medium->sigmaT 7 | #define _absorptionOnly medium->absorptionOnly 8 | 9 | //------------------------- Homogeneous Medium ------------------------- 10 | 11 | void HomogeneousMedium_sampleDistance( 12 | MediumSample* mediumSample, 13 | const Medium* medium, 14 | const Ray* ray, 15 | RNG_SEED_PARAM 16 | ) { 17 | const float maxT = ray->t; 18 | 19 | if (_absorptionOnly) { 20 | mediumSample->t = maxT; 21 | mediumSample->weight = native_exp(-mediumSample->t*_sigmaT); 22 | mediumSample->pdf = 1.0f; 23 | mediumSample->exited = true; 24 | } 25 | else { 26 | float sigmaTc = ((float*)(&_sigmaT))[(int)(round(next1D(RNG_SEED_VALUE)*3.0f))]; 27 | 28 | float t = -native_log(1.0f - next1D(RNG_SEED_VALUE)) / sigmaTc; 29 | mediumSample->t = fmin(t, maxT); 30 | mediumSample->continuedT = t; 31 | mediumSample->exited = (t >= maxT); 32 | 33 | float3 tau = mediumSample->t * _sigmaT; 34 | float3 continuedTau = mediumSample->continuedT * _sigmaT; 35 | 36 | mediumSample->weight = native_exp(-tau); 37 | mediumSample->continuedWeight = native_exp(-continuedTau); 38 | 39 | if (mediumSample->exited) { 40 | mediumSample->pdf = avg3(native_exp(-tau)); 41 | } 42 | else { 43 | mediumSample->pdf = avg3(_sigmaT*native_exp(-tau)); 44 | mediumSample->weight *= _sigmaS; 45 | } 46 | mediumSample->weight /= mediumSample->pdf; 47 | mediumSample->continuedWeight = _sigmaS * mediumSample->continuedWeight / avg3(_sigmaT*native_exp(-continuedTau)); 48 | } 49 | 50 | mediumSample->p = ray->origin + ray->dir*mediumSample->t; 51 | } 52 | 53 | #undef _sigmaA 54 | #undef _sigmaS 55 | #undef _sigmaT 56 | #undef _absorptionOnly 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /kernels/noise/value_noise.cl: -------------------------------------------------------------------------------- 1 | #ifndef __VALUE_NOISE__ 2 | #define __VALUE_NOISE__ 3 | 4 | float value_hash(float seed) { 5 | float fl; 6 | #if 1 7 | return fract(sin(seed) * 43758.5453123f, &fl); 8 | #else 9 | float res = fract(seed * 43758.5453123f, &fl); 10 | return fract(dot(res, res * (fl * 213.321f)), &fl); 11 | #endif 12 | } 13 | 14 | float value_noise(const float3 x){ 15 | const float3 step = (float3)(110.0f, 241.0f, 171.0f); 16 | 17 | float3 i; 18 | float3 f = fract(x,&i); 19 | 20 | // For performance, compute the base input to a 1D value_hash from the integer part of the argument and the 21 | // incremental change to the 1D based on the 3D -> 1D wrapping 22 | float n = dot(i, step); 23 | 24 | float3 u = f * f * (3.0f - 2.0f * f); 25 | return mix(mix(mix(value_hash(n + dot(step, F3_ZERO)), value_hash(n + dot(step, F3_RIGHT)), u.x), 26 | mix(value_hash(n + dot(step, F3_UP)), value_hash(n + dot(step, (float3)(1.0f, 1.0f, 0.0f))), u.x), u.y), 27 | mix(mix(value_hash(n + dot(step, F3_FRONT)), value_hash(n + dot(step, (float3)(1.0f, 0.0f, 1.0f))), u.x), 28 | mix(value_hash(n + dot(step, (float3)(0, 1, 1))), value_hash(n + dot(step, F3_ONE)), u.x), u.y), u.z); 29 | } 30 | 31 | float value_fbm( 32 | float3 x, const int octaves 33 | ){ 34 | float v = 0.0f; // value 35 | float a = 0.5f; // amplitude 36 | const float g = 0.5f; // gain 37 | const float l = 2.0f; // lacunarity 38 | 39 | // remove tiling artifacts 40 | const float3 shift = (float3)(100.0f); 41 | 42 | for (int i = 0; i < octaves; ++i) { 43 | v += a * value_noise(x); 44 | x = x * l + shift; 45 | a *= g; 46 | } 47 | return v; 48 | } 49 | 50 | #endif -------------------------------------------------------------------------------- /kernels/phasefunctions/HenyeyGreenstein.cl: -------------------------------------------------------------------------------- 1 | #ifndef __HG__ 2 | #define __HG__ 3 | 4 | #define _g 0.6f 5 | 6 | //--------------------- HenyeyGreensteinPhaseFunction ----------------------- 7 | 8 | float hg(const float cosTheta) { 9 | float term = 1.0f + _g*_g - 2.0f*_g*cosTheta; 10 | return INV_FOUR_PI*(1.0f - _g*_g)/(term*native_sqrt(term)); 11 | } 12 | 13 | float3 phase_eval(const float3 wi, const float3 wo) { 14 | return (float3)(hg(dot(wi, wo))); 15 | } 16 | 17 | float phase_pdf(const float3 wi, const float3 wo) { 18 | return hg(dot(wi, wo)); 19 | } 20 | 21 | bool phase_sample( 22 | const float3 wi, PhaseSample* phaseSample, 23 | RNG_SEED_PARAM 24 | ) { 25 | 26 | float2 xi = next2D(RNG_SEED_VALUE); 27 | if (_g == 0.0f) { 28 | phaseSample->w = uniformSphere(xi); 29 | phaseSample->pdf = uniformSpherePdf(); 30 | } 31 | else { 32 | float phi = xi.x*TWO_PI; 33 | float cosTheta = (1.0f + _g * _g - pow((1.0f - _g * _g) / (1.0f + _g * (xi.y*2.0f - 1.0f)), 2.0f)) / (2.0f*_g); 34 | float sinTheta = native_sqrt(fmax(1.0f - cosTheta * cosTheta, 0.0f)); 35 | 36 | TangentFrame tf = createTangentFrame(&wi); 37 | phaseSample->w = toGlobal(&tf, (float3)( 38 | native_cos(phi)*sinTheta, 39 | native_sin(phi)*sinTheta, 40 | cosTheta 41 | )); 42 | 43 | phaseSample->pdf = hg(cosTheta); 44 | } 45 | phaseSample->weight = (float3)(1.0f); 46 | 47 | return true; 48 | } 49 | 50 | #undef _g 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /kernels/phasefunctions/Isotropic.cl: -------------------------------------------------------------------------------- 1 | #ifndef __ISOTROPIC_PHASE__ 2 | #define __ISOTROPIC_PHASE__ 3 | 4 | //--------------------- IsotropicPhaseFunction ----------------------- 5 | 6 | inline float3 phase_eval(const float3 wi, const float3 wo) { 7 | return (float3)(INV_FOUR_PI); 8 | } 9 | 10 | inline float phase_pdf(const float3 wi, const float3 wo) { 11 | return INV_FOUR_PI; 12 | } 13 | 14 | bool phase_sample( 15 | const float3 wi, PhaseSample* phaseSample, 16 | RNG_SEED_PARAM 17 | ) { 18 | 19 | phaseSample->w = uniformSphere(next2D(RNG_SEED_VALUE)); 20 | phaseSample->weight = (float3)(1.0f); 21 | phaseSample->pdf = INV_FOUR_PI; 22 | 23 | return true; 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /kernels/phasefunctions/Rayleigh.cl: -------------------------------------------------------------------------------- 1 | #ifndef __RAYLEIGH__ 2 | #define __RAYLEIGH__ 3 | 4 | inline float rayleigh(float cosTheta) { 5 | return (3.0f / (16.0f*PI))*(1.0f + cosTheta * cosTheta); 6 | } 7 | 8 | float3 phase_eval(const float3 wi, const float3 wo) { 9 | return (float3)(rayleigh(dot(wi,wo))); 10 | } 11 | 12 | float phase_pdf(const float3 wi, const float3 wo) { 13 | return rayleigh(dot(wi, wo)); 14 | } 15 | 16 | bool phase_sample( 17 | const float3 wi, PhaseSample* phaseSample, 18 | RNG_SEED_PARAM 19 | ) { 20 | float2 xi = next2D(RNG_SEED_VALUE); 21 | float phi = xi.x*TWO_PI; 22 | float z = xi.y*4.0f - 2.0f; 23 | float invZ = sqrt(z*z + 1.0f); 24 | float u = cbrt(z + invZ); 25 | 26 | float cosTheta = u - 1.0f / u; 27 | float sinTheta = sqrt(fmax(1.0f - cosTheta * cosTheta, 0.0f)); 28 | 29 | TangentFrame tf = createTangentFrame(&wi); 30 | phaseSample->w = toGlobal(&tf, (float3)( 31 | native_cos(phi) * sinTheta, 32 | native_sin(phi) * sinTheta, 33 | cosTheta 34 | )); 35 | 36 | phaseSample->weight = (float3)(1.0f); 37 | phaseSample->pdf = rayleigh(cosTheta); 38 | return true; 39 | } 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /kernels/prng/prng.cl: -------------------------------------------------------------------------------- 1 | #ifndef __PRNG__ 2 | #define __PRNG__ 3 | 4 | #if RNG_TYPE == 0 5 | inline float next1D(RNG_SEED_PARAM) { 6 | /* hash the seeds */ 7 | *seed0 = 36969 * ((*seed0) & 65535) + ((*seed0) >> 16); 8 | *seed1 = 18000 * ((*seed1) & 65535) + ((*seed1) >> 16); 9 | 10 | uint ires = ((*seed0) << 16) + (*seed1); 11 | 12 | union_32 res; 13 | 14 | res.ui = (ires & 0x007fffff) | 0x40000000; 15 | return (res.f - 2.0f) * 0.5f; 16 | } 17 | #elif RNG_TYPE == 1 18 | inline float next1D(RNG_SEED_PARAM) { 19 | ulong oldState = *state; 20 | *state = oldState * 6364136223846793005UL + 1; 21 | uint xorShifted = (uint)(((oldState >> 18u) ^ oldState) >> 27u); 22 | uint rot = oldState >> 59u; 23 | return normalizedUint((xorShifted >> rot) | (xorShifted << ((uint)(-(int)(rot)) & 31))); 24 | } 25 | #elif RNG_TYPE == 2 26 | inline float next1D(RNG_SEED_PARAM) { 27 | float fl; 28 | return fract(sin(*seed += 0.2f) * 43758.5453123f, &fl); 29 | } 30 | #endif 31 | 32 | #define nextBoolean(c, RNG_SEED_VALUE) (next1D(RNG_SEED_VALUE) < c) 33 | #define next2D(RNG_SEED_VALUE) (float2)(next1D(RNG_SEED_VALUE), next1D(RNG_SEED_VALUE)) 34 | 35 | #if 0 36 | 37 | //---------------------------------- SIN HASH ---------------------------------- 38 | 39 | // 1f32 -> 1f32 40 | float hash_1f32_1f32(float seed) { 41 | float fl; 42 | #if 1 43 | return fract(sin(seed)*43758.5453123f, &fl); 44 | #else 45 | float res = fract(seed*43758.5453123f, &fl); 46 | return fract(dot(res, res*(fl*213.321f)), &fl); 47 | #endif 48 | } 49 | // 1f32 -> 2f32 50 | float2 hash_1f32_2f32(float seed) { 51 | #if 1 52 | float2 fl; 53 | return fract(sin(seed)*(float2)(43758.5453123f,22578.1459123f), &fl); 54 | #else 55 | float n = hash_1f32_1f32(seed); 56 | return (float2)(n, hash_1f32_1f32(n+seed)); 57 | #endif 58 | } 59 | // 1f32 -> 3f32 60 | float3 hash_1f32_3f32(float seed){ 61 | #if 1 62 | float3 fl; 63 | return fract(sin(seed)*(float3)(43758.5453123f,22578.1459123f,19642.3490423f), &fl); 64 | #else 65 | float n0 = hash_1f32_1f32(seed); 66 | float n1 = hash_1f32_1f32(seed+n0); 67 | return (float3)(n0, n1, hash_1f32_1f32(seed+n0+n1)); 68 | #endif 69 | } 70 | 71 | //---------------------------- HAMMERSLEY ---------------------------- 72 | 73 | float VanDerCorpus(uint n, uint base){ 74 | float invBase = 1.0f / (float)(base); 75 | float denom = 1.0f; 76 | float result = 0.0f; 77 | 78 | for(uint i = 0; i < 32; ++i){ 79 | if(n > 0){ 80 | denom = fmod((float)(n), 2.0f); 81 | result += denom * invBase; 82 | invBase = invBase * 0.5f; 83 | n = (uint)((float)(n) * 0.5f); 84 | } 85 | } 86 | 87 | return result; 88 | } 89 | /* https://learnopengl.com/PBR/IBL/Specular-IBL */ 90 | float RadicalInverse_VdC(uint bits){ 91 | bits = (bits << 16u) | (bits >> 16u); 92 | bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); 93 | bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); 94 | bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); 95 | bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); 96 | return (float)(bits) * 2.3283064365386963e-10f; // / 0x100000000 97 | } 98 | float2 Hammersley(uint i, uint N){ 99 | return (float2)((float)(i) / (float)(N), RadicalInverse_VdC(i)); 100 | } 101 | 102 | //-------------------------------------------------------------------- 103 | 104 | uint BJXorShift(uint x){ 105 | x += x << 10u; 106 | x ^= x >> 6u; 107 | x += x << 3u; 108 | x ^= x >> 11u; 109 | x += x << 15u; 110 | 111 | return x; 112 | } 113 | 114 | uint GMXorShift(uint x){ 115 | x ^= x << 13u; 116 | x ^= x >> 17u; 117 | x ^= x << 5u; 118 | 119 | return x; 120 | } 121 | 122 | uint WangHash(uint x){ 123 | x = (x ^ 61u) ^ (x >> 16u); 124 | x *= 9u; 125 | x ^= x >> 4u; 126 | x *= 0x27d4eb2du; 127 | x ^= x >> 15u; 128 | 129 | return x; 130 | } 131 | #endif 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /kernels/texture.cl: -------------------------------------------------------------------------------- 1 | #ifndef __TEXTURE__ 2 | #define __TEXTURE__ 3 | 4 | __constant sampler_t TEX_SAMPLER = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP | CLK_FILTER_LINEAR; 5 | 6 | float4 SampleTextureTrilinear(__read_only image2d_array_t texture_atlas, __global const texture_t *texture, 7 | const float2 uvs, float lod) { 8 | const float2 tex_atlas_size = (float2)(get_image_width(texture_atlas), get_image_height(texture_atlas)); 9 | 10 | const float2 uvs1 = TransformUVs(uvs, tex_atlas_size, texture, floor(lod)); 11 | const float2 uvs2 = TransformUVs(uvs, tex_atlas_size, texture, ceil(lod)); 12 | int page1 = (int)min(floor(lod), (float)MAX_MIP_LEVEL); 13 | int page2 = (int)min(ceil(lod), (float)MAX_MIP_LEVEL); 14 | float4 coord1 = (float4)(uvs1, (float)texture->page[page1], 0); 15 | float4 coord2 = (float4)(uvs2, (float)texture->page[page2], 0); 16 | float4 tex_col1 = read_imagef(texture_atlas, TEX_SAMPLER, coord1); 17 | float4 tex_col2 = read_imagef(texture_atlas, TEX_SAMPLER, coord2); 18 | return mix(tex_col1, tex_col2, lod - floor(lod)); 19 | } 20 | 21 | float4 SampleTextureAnisotropic(__read_only image2d_array_t texture_atlas, __global const texture_t *texture, 22 | const float2 uvs, const float2 duv_dx, const float2 duv_dy) { 23 | float l1 = fast_length(duv_dx * (float2)(texture->size[0], texture->size[1])); 24 | float l2 = fast_length(duv_dy * (float2)(texture->size[0], texture->size[1])); 25 | float lod; 26 | float k; 27 | float2 step; 28 | if (l1 <= l2) { 29 | lod = native_log2(l1); 30 | k = l1 / l2; 31 | step = duv_dx / (float2)(texture->size[0], texture->size[1]); 32 | } 33 | else { 34 | lod = native_log2(l2); 35 | k = l2 / l1; 36 | step = duv_dy / (float2)(texture->size[0], texture->size[1]); 37 | } 38 | lod = clamp(lod, 0.0f, (float)MAX_MIP_LEVEL); 39 | float2 _uvs = uvs - step * 0.5f; 40 | int num = clamp((int)(1.0f / k), 1, 32); 41 | step = step / num; 42 | float4 res = 0; 43 | 44 | for (int i = 0; i < num; i++) { 45 | res += SampleTextureTrilinear(texture_atlas, texture, _uvs, lod); 46 | _uvs += step; 47 | } 48 | return res / num; 49 | } 50 | 51 | __kernel void TextureDebugPage(__read_only image2d_array_t texture_atlas, int page, __write_only image2d_t frame_buf) { 52 | int i = get_global_id(0), 53 | j = get_global_id(1); 54 | float x = 1.0f * ((float)i) / get_global_size(0); 55 | float y = 1.0f * ((float)j) / get_global_size(1); 56 | float4 coord = (float4)(x, y, (float)page, 0); 57 | float4 col = read_imagef(texture_atlas, TEX_SAMPLER, coord); 58 | write_imagef(frame_buf, (int2)(i, j), col); 59 | } 60 | 61 | #endif -------------------------------------------------------------------------------- /kernels/utils.cl: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS__ 2 | #define __UTILS__ 3 | 4 | typedef union { half f; ushort ui; short i; } union_16; 5 | typedef union { float f; uint ui; int i; } union_32; 6 | typedef union { double f; ulong ui; long i; } union_64; 7 | 8 | inline float uintBitsToFloat(uint i){ 9 | union_32 unionHack; 10 | unionHack.ui = i; 11 | return unionHack.f; 12 | } 13 | 14 | inline uint floatBitsToUint(float f){ 15 | union_32 unionHack; 16 | unionHack.f = f; 17 | return unionHack.ui; 18 | } 19 | 20 | // 2x-5x faster than i/float(UINT_MAX) 21 | inline float normalizedUint(uint i){ 22 | return uintBitsToFloat((i >> 9u) | 0x3F800000u) - 1.0f; 23 | } 24 | 25 | #FILE:prng/prng.cl 26 | 27 | /* max component */ 28 | #define fmax2(v) fmax(v.x, v.y) 29 | #define fmax3(v) fmax(fmax(v.x, v.y), v.z) 30 | #define fmax4(v) fmax(fmax(fmax(v.x, v.y), v.z),v.w) 31 | /* min component */ 32 | #define fmin2(v) fmin(v.x, v.y) 33 | #define fmin3(v) fmin(fmin(v.x, v.y), v.z) 34 | #define fmin4(v) fmin(fmin(fmin(v.x, v.y), v.z),v.w) 35 | /* average */ 36 | #define avg2(v) (dot(v, 1.0f)*0.5f) 37 | #define avg3(v) (dot(v, 1.0f)*0.3333333333333333333333333333333333333333333333f) 38 | #define avg4(v) (dot(v, 1.0f)*0.25f) 39 | /* linear interpolation */ 40 | #define lerp(a, b, w) (a + w * (b - a)) 41 | 42 | /* Signum that exludes 0 */ 43 | #define sgnE(T) (T < 0.0f ? -1.0f : 1.0f) 44 | 45 | /* equirectangular mapping */ 46 | #define envMapEquirect(dir) (float2)((atan2(dir.z, dir.x) * INV_TWO_PI) + 0.5f, acos(dir.y) * INV_PI) 47 | 48 | #define DiracAcceptanceThreshold 1e-3f 49 | 50 | inline bool checkReflectionConstraint(const float3* wi, const float3* wo){ 51 | return fabs(wi->z * wo->z - wi->x * wo->x - wi->y * wo->y - 1.0f) < DiracAcceptanceThreshold; 52 | } 53 | 54 | inline bool checkRefractionConstraint(const float3* wi, const float3* wo, float eta, float cosThetaT) 55 | { 56 | float dotP = -wi->x * wo->x * eta - wi->y * wo->y * eta - copysign(cosThetaT, wi->z) * wo->z; 57 | return fabs(dotP - 1.0f) < DiracAcceptanceThreshold; 58 | } 59 | 60 | inline float invertPhi(float3 w, float mu){ 61 | float result = (w.x == 0.0f && w.y == 0.0f) ? mu*INV_TWO_PI : atan2(w.y, w.x)*INV_TWO_PI; 62 | result += (result < 0.0f); 63 | return result; 64 | } 65 | 66 | /// Translate cartesian coordinates to spherical system 67 | void CartesianToSpherical( 68 | float3 cart, 69 | float* r, float* phi, float* theta 70 | ){ 71 | float temp = atan2(cart.x, cart.z); 72 | *r = sqrt(cart.x*cart.x + cart.y*cart.y + cart.z*cart.z); 73 | /* Account for discontinuity */ 74 | *phi = (float)((temp >= 0) ? temp : (temp + 2 * PI)); 75 | *theta = acos(cart.y / *r); 76 | } 77 | 78 | /// Translate polar coordinates to cartesian 79 | inline float3 polar_to_cartesian( 80 | const float sinTheta, const float cosTheta, 81 | const float sinPhi, const float cosPhi 82 | ){ 83 | return (float3)(sinTheta * cosPhi, 84 | sinTheta * sinPhi, 85 | cosTheta); 86 | } 87 | 88 | #define trigInverse(x) fmin(sqrt(fmax(1.0f - x*x, 0.0f)), 1.0f) 89 | 90 | //-------------------------------------------------------------------- 91 | 92 | inline float3 uniformSphere(const float2 xi){ 93 | float phi = xi.x*TWO_PI; 94 | float z = xi.y*2.0f - 1.0f; 95 | float r = sqrt(fmax(1.0f - z * z, 0.0f)); 96 | 97 | return (float3)( 98 | cos(phi)*r, 99 | sin(phi)*r, 100 | z 101 | ); 102 | } 103 | 104 | #define uniformSpherePdf() INV_FOUR_PI 105 | #define invertUniformSphere(w, mu) (float2)(invertPhi(w, mu), (w.z + 1.0f)*0.5f) 106 | 107 | //-------------------------------------------------------------------- 108 | 109 | inline float3 uniformHemisphere(const float2* xi){ 110 | float phi = TWO_PI*xi->x; 111 | float r = sqrt(fmax(1.0f - xi->y*xi->y, 0.0f)); 112 | return (float3)(cos(phi)*r, sin(phi)*r, xi->y); 113 | } 114 | 115 | #define uniformHemispherePdf() INV_TWO_PI 116 | #define invertUniformHemisphere(w, mu) (float2)(invertPhi(w, mu), w.z) 117 | 118 | //-------------------------------------------------------------------- 119 | 120 | inline float3 uniformSphericalCap(const float2 xi, const float cosThetaMax){ 121 | float phi = xi.x*TWO_PI; 122 | float z = xi.y*(1.0f - cosThetaMax) + cosThetaMax; 123 | float r = sqrt(fmax(1.0f - z * z, 0.0f)); 124 | return (float3)( 125 | cos(phi)*r, 126 | sin(phi)*r, 127 | z 128 | ); 129 | } 130 | 131 | #define uniformSphericalCapPdf(cosThetaMax) INV_TWO_PI/(1.0f - cosThetaMax) 132 | inline bool invertUniformSphericalCap(float3 w, float cosThetaMax, float2* xi, float mu) 133 | { 134 | float xiY = (w.z - cosThetaMax)/(1.0f - cosThetaMax); 135 | if (xiY >= 1.0f || xiY < 0.0f) 136 | return false; 137 | 138 | *xi = (float2)(invertPhi(w, mu), xiY); 139 | return true; 140 | } 141 | 142 | //-------------------------------------------------------------------- 143 | 144 | inline float3 cosineHemisphere(const float2 xi){ 145 | float phi = xi.x*TWO_PI; 146 | float r = sqrt(xi.y); 147 | return (float3)( 148 | cos(phi)*r, 149 | sin(phi)*r, 150 | sqrt(fmax(1.0f - xi.y, 0.0f)) 151 | ); 152 | } 153 | 154 | inline float cosineHemispherePdf(float3 p) { return fabs(p.z) * INV_PI; } 155 | inline float2 invertCosineHemisphere(float3 w, float mu) { 156 | return (float2)(invertPhi(w, mu), fmax(1.0f - w.z * w.z, 0.0f)); 157 | } 158 | 159 | //-------------------------------------------------------------------- 160 | 161 | inline float3 phongHemisphere(const float2* xi, float n){ 162 | float phi = xi->x*TWO_PI; 163 | float cosTheta = pow(xi->y, 1.0f/(n + 1.0f)); 164 | float r = sqrt(fmax(1.0f - cosTheta*cosTheta, 0.0f)); 165 | return (float3)(cos(phi)*r, sin(phi)*r, cosTheta); 166 | } 167 | 168 | #define phongHemispherePdf(v, n) INV_TWO_PI*(n + 1.0f)*pow(v->z, n) 169 | #define invertPhongHemisphere(w, n, mu) (float2)(invertPhi(w, mu), pow(w.z, n + 1.0f)) 170 | 171 | //-------------------------------------------------------------------- 172 | 173 | #endif 174 | -------------------------------------------------------------------------------- /resources/textures/rgb_noise1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mourtz/Photorealistic-Rendering-using-OpenCL/71f5b7d62b030ad9cabc0ee757c673a1969193bf/resources/textures/rgb_noise1024.png -------------------------------------------------------------------------------- /resources/textures/rgba_noise1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mourtz/Photorealistic-Rendering-using-OpenCL/71f5b7d62b030ad9cabc0ee757c673a1969193bf/resources/textures/rgba_noise1024.png -------------------------------------------------------------------------------- /scenes/cornell.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "MAX_BOUNCES": 32, 4 | "MAX_DIFF_BOUNCES": 8, 5 | "MAX_SPEC_BOUNCES": 32, 6 | "MAX_TRANS_BOUNCES": 64, 7 | "MAX_SCATTERING_EVENTS": 128, 8 | 9 | "MARCHING_STEPS": 128, 10 | "SHADOW_MARCHING_STEPS": 64 11 | }, 12 | "scene": { 13 | "obj": { 14 | "path": "teapot.obj", 15 | "material": { 16 | "color": [ 1.0, 1.0, 1.0 ], 17 | "type": 4, 18 | "roughness": 0.1 19 | } 20 | }, 21 | "spheres": [ 22 | { 23 | "pos": [ 0.0, 3.0, 0.0 ], 24 | "radius": 0.5, 25 | "material": { 26 | "color": [ 5.0, 5.0, 5.0 ], 27 | "type": 0 28 | } 29 | } 30 | ], 31 | "quads": [ 32 | { 33 | "vertices": [ 34 | 0.0, 0.0, 0.0, 35 | 4.0, 0.0, 0.0, 36 | 0.0, 0.0, 4.0 37 | ], 38 | "material": { 39 | "color": [ 1.0, 1.0, 1.0 ] 40 | } 41 | }, 42 | { 43 | "vertices": [ 44 | 0.0, 4.0, 0.0, 45 | -4.0, 0.0, 0.0, 46 | 0.0, 0.0, 4.0 47 | ], 48 | "material": { 49 | "color": [ 1.0, 1.0, 1.0 ] 50 | } 51 | }, 52 | { 53 | "vertices": [ 54 | 0.0, 2.0, 2.0, 55 | 4.0, 0.0, 0.0, 56 | 0.0, 4.0, 0.0 57 | ], 58 | "material": { 59 | "color": [ 1.0, 1.0, 1.0 ] 60 | } 61 | }, 62 | { 63 | "vertices": [ 64 | 0.0, 2.0, -2.0, 65 | -4.0, 0.0, 0.0, 66 | 0.0, 4.0, 0.0 67 | ], 68 | "material": { 69 | "color": [ 1.0, 1.0, 1.0 ] 70 | } 71 | }, 72 | { 73 | "vertices": [ 74 | 2.0, 2.0, 0.0, 75 | 0.0, 4.0, 0.0, 76 | 0.0, 0.0, 4.0 77 | ], 78 | "material": { 79 | "color": [ 0.8, 0.1, 0.1 ] 80 | } 81 | }, 82 | { 83 | "vertices": [ 84 | -2.0, 2.0, 0.0, 85 | 0.0, -4.0, 0.0, 86 | 0.0, 0.0, 4.0 87 | ], 88 | "material": { 89 | "color": [ 0.1, 0.8, 0.1 ] 90 | } 91 | } 92 | ] 93 | } 94 | } -------------------------------------------------------------------------------- /scenes/cornell_media.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mourtz/Photorealistic-Rendering-using-OpenCL/71f5b7d62b030ad9cabc0ee757c673a1969193bf/scenes/cornell_media.json -------------------------------------------------------------------------------- /scenes/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "settings": { 3 | "MAX_BOUNCES": 128, 4 | "MAX_DIFF_BOUNCES": 32, 5 | "MAX_SPEC_BOUNCES": 64, 6 | "MAX_TRANS_BOUNCES": 64, 7 | "MAX_SCATTERING_EVENTS": 128, 8 | 9 | "MARCHING_STEPS": 128, 10 | "SHADOW_MARCHING_STEPS": 64 11 | }, 12 | "scene": { 13 | "obj": { 14 | "path": "suzanne.obj", 15 | "material": { 16 | "color": [ 1.0, 1.0, 1.0 ], 17 | "type": 11, 18 | "roughness": 0.05 19 | } 20 | }, 21 | "spheres": [ 22 | { 23 | "pos": [ 0.0, 3.0, 0.0 ], 24 | "radius": 0.5, 25 | "material": { 26 | "color": [ 30.0, 30.0, 30.0 ], 27 | "type": 0 28 | } 29 | } 30 | ], 31 | "quads": [ 32 | { 33 | "vertices": [ 34 | 0.0, 35 | 0.0, 36 | 0.0, 37 | 4.0, 38 | 0.0, 39 | 0.0, 40 | 0.0, 41 | 0.0, 42 | 4.0 43 | ], 44 | "material": { 45 | "color": [ 1.0, 1.0, 1.0 ] 46 | } 47 | } 48 | ] 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /shaders/tonemapper.glsl: -------------------------------------------------------------------------------- 1 | #version 150 core 2 | 3 | out vec4 FragColor; 4 | 5 | uniform sampler2D u_tex; 6 | uniform vec2 u_resolution; 7 | 8 | // linear white point 9 | const float W = 1.2; 10 | const float T2 = 7.5; 11 | 12 | float filmic_reinhard_curve(float x) { 13 | float q = (T2 * T2 + 1.0) * x * x; 14 | return q / (q + x + T2 * T2); 15 | } 16 | 17 | vec3 filmic_reinhard(vec3 x) { 18 | float w = filmic_reinhard_curve(W); 19 | return vec3( 20 | filmic_reinhard_curve(x.r), 21 | filmic_reinhard_curve(x.g), 22 | filmic_reinhard_curve(x.b)) / w; 23 | } 24 | 25 | const int N = 8; 26 | vec3 ca(sampler2D t, vec2 UV, vec4 sampl) { 27 | vec2 uv = 1.0 - 2.0 * UV; 28 | vec3 c = vec3(0); 29 | float rf = 1.0; 30 | float gf = 1.0; 31 | float bf = 1.0; 32 | float f = 1.0 / float(N); 33 | for (int i = 0; i < N; ++i) { 34 | c.r += f * texture(t, 0.5 - 0.5 * (uv * rf)).r; 35 | c.g += f * texture(t, 0.5 - 0.5 * (uv * gf)).g; 36 | c.b += f * texture(t, 0.5 - 0.5 * (uv * bf)).b; 37 | rf *= 0.9972; 38 | gf *= 0.998; 39 | bf /= 0.9988; 40 | c = clamp(c, 0.0, 1.0); 41 | } 42 | return c; 43 | } 44 | 45 | #define col tex.rgb 46 | 47 | void main() 48 | { 49 | const float brightness = 1.0; 50 | vec2 pp = gl_FragCoord.xy / u_resolution.xy; 51 | vec2 p = 1. - 2. * gl_FragCoord.xy / u_resolution.xy; 52 | 53 | vec3 color = texture(u_tex, pp).rgb; 54 | 55 | float vignette = 1.25 / (1.1 + 1.1 * dot(p, p)); 56 | vignette *= vignette; 57 | vignette = mix(1.0, smoothstep(0.1, 1.1, vignette), 0.25); 58 | color = color * vignette; 59 | color = filmic_reinhard(brightness * color); 60 | 61 | color = smoothstep(-0.025, 1.0, color); 62 | 63 | color = pow(color, vec3(1.0 / 2.2)); 64 | FragColor = vec4(color, 1.0); 65 | } -------------------------------------------------------------------------------- /shaders/vert.glsl: -------------------------------------------------------------------------------- 1 | #version 150 core 2 | 3 | in vec2 position; 4 | 5 | void main() 6 | { 7 | gl_Position = vec4(position, 0.0, 1.0); 8 | } -------------------------------------------------------------------------------- /src/BVH/bvh.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #define GLFW_INCLUDE_NONE 19 | #include 20 | 21 | using Scalar = float; 22 | using Vec3 = bvh::v2::Vec; 23 | using BBox = bvh::v2::BBox; 24 | using Tri = bvh::v2::Tri; 25 | using Node = bvh::v2::Node; 26 | using Bvh = bvh::v2::Bvh; 27 | using Ray = bvh::v2::Ray; 28 | 29 | using PrecomputedTri = bvh::v2::PrecomputedTri; 30 | 31 | namespace CL_RAYTRACER 32 | { 33 | struct cl_Mesh 34 | { 35 | std::vector position; 36 | std::vector normal; 37 | std::vector uv; 38 | std::vector color; 39 | }; 40 | 41 | BVH::BVH(const std::shared_ptr &ml) : bvh(std::make_unique()), 42 | model_loader(ml) 43 | { 44 | buildTree(ml); 45 | } 46 | 47 | BVH::~BVH() 48 | { 49 | bvh.reset(); 50 | triangles.clear(); 51 | } 52 | 53 | void BVH::buildTree(const std::shared_ptr &ml) 54 | { 55 | std::cout << "[BVH] Building tree..." << std::endl; 56 | double t0 = glfwGetTime(); 57 | 58 | auto &scene = ml->getFaces(); 59 | for (const auto &mesh : scene->meshes) 60 | { 61 | for (const auto &face : mesh.faces) 62 | { 63 | triangles.emplace_back( 64 | Vec3(face.points[0].pos.x, face.points[0].pos.y, face.points[0].pos.z), Vec3(face.points[1].pos.x, face.points[1].pos.y, face.points[1].pos.z), Vec3(face.points[2].pos.x, face.points[2].pos.y, face.points[2].pos.z)); 65 | } 66 | } 67 | 68 | bvh::v2::ThreadPool thread_pool; 69 | bvh::v2::ParallelExecutor executor(thread_pool); 70 | 71 | // Get triangle centers and bounding boxes (required for BVH builder) 72 | std::vector bboxes(triangles.size()); 73 | std::vector centers(triangles.size()); 74 | executor.for_each(0, triangles.size(), [&] (size_t begin, size_t end) { 75 | for (size_t i = begin; i < end; ++i) { 76 | bboxes[i] = triangles[i].get_bbox(); 77 | centers[i] = triangles[i].get_center(); 78 | } 79 | }); 80 | 81 | typename bvh::v2::DefaultBuilder::Config config; 82 | config.quality = bvh::v2::DefaultBuilder::Quality::High; 83 | bvh = std::make_unique(bvh::v2::DefaultBuilder::build(thread_pool, bboxes, centers, config)); 84 | 85 | double t1 = glfwGetTime(); 86 | std::cout << "[BVH] Tree built in " << t1 - t0 << " seconds" << std::endl; 87 | } 88 | 89 | std::unique_ptr> BVH::GetPrimitiveIndices() const { 90 | std::unique_ptr> res = std::make_unique>(); 91 | for(size_t i = 0; i < triangles.size(); ++i){ 92 | res->emplace_back(bvh->prim_ids[i]); 93 | } 94 | return res; 95 | } 96 | 97 | std::unique_ptr> BVH::PrepareData() const 98 | { 99 | std::unique_ptr> res = std::make_unique>(); 100 | for (int i = 0; i < bvh->nodes.size(); ++i) 101 | { 102 | const Node &node = bvh->nodes[i]; 103 | 104 | cl_BVHnode bb; 105 | bb.bounds[0] = node.bounds[0]; 106 | bb.bounds[1] = node.bounds[1]; 107 | bb.bounds[2] = node.bounds[2]; 108 | bb.bounds[3] = node.bounds[3]; 109 | bb.bounds[4] = node.bounds[4]; 110 | bb.bounds[5] = node.bounds[5]; 111 | bb.is_leaf = node.is_leaf(); 112 | bb.first_child_or_primitive = node.index.first_id(); 113 | bb.primitive_count = node.index.prim_count(); 114 | res->push_back(bb); 115 | } 116 | return res; 117 | } 118 | 119 | } // namespace CL_RAYTRACER -------------------------------------------------------------------------------- /src/Camera/camera.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // constructor and default values 4 | InteractiveCamera::InteractiveCamera() 5 | { 6 | centerPosition = vec3(); 7 | yaw = 0; 8 | pitch = 0.3; 9 | radius = 4; 10 | apertureRadius = 0.01; 11 | focalDistance = 4.0f; 12 | } 13 | 14 | InteractiveCamera::~InteractiveCamera() {} 15 | 16 | void InteractiveCamera::changeYaw(float m){ 17 | yaw += m; 18 | fixYaw(); 19 | } 20 | 21 | void InteractiveCamera::changePitch(float m){ 22 | pitch += m; 23 | fixPitch(); 24 | } 25 | 26 | void InteractiveCamera::changeRadius(float m){ 27 | radius += radius * m; // Change proportional to current radius. Assuming radius isn't allowed to go to zero. 28 | fixRadius(); 29 | } 30 | 31 | void InteractiveCamera::changeAltitude(float m){ 32 | centerPosition.y += m; 33 | } 34 | 35 | void InteractiveCamera::goForward(float m){ 36 | centerPosition += viewDirection * m; 37 | } 38 | 39 | void InteractiveCamera::strafe(float m){ 40 | vec3 strafeAxis = cross(viewDirection, vec3(0, 1, 0)); 41 | strafeAxis.normalize(); 42 | centerPosition += strafeAxis * m; 43 | } 44 | 45 | void InteractiveCamera::rotateRight(float m){ 46 | float yaw2 = yaw; 47 | yaw2 += m; 48 | float pitch2 = pitch; 49 | float xDirection = sin(yaw2) * cos(pitch2); 50 | float yDirection = sin(pitch2); 51 | float zDirection = cos(yaw2) * cos(pitch2); 52 | vec3 directionToCamera = vec3(xDirection, yDirection, zDirection); 53 | viewDirection = directionToCamera * (-1.0); 54 | } 55 | 56 | void InteractiveCamera::changeApertureDiameter(float m){ 57 | apertureRadius += (apertureRadius + 0.01) * m; // Change proportional to current apertureRadius. 58 | fixApertureRadius(); 59 | } 60 | 61 | 62 | void InteractiveCamera::changeFocalDistance(float m){ 63 | focalDistance += m; 64 | fixFocalDistance(); 65 | } 66 | 67 | 68 | void InteractiveCamera::setResolution(float x, float y){ 69 | resolution = vec2(x, y); 70 | } 71 | 72 | float radiansToDegrees(float radians) { 73 | float degrees = radians * 180.0 / M_PI; 74 | return degrees; 75 | } 76 | 77 | float degreesToRadians(float degrees) { 78 | float radians = degrees / 180.0 * M_PI; 79 | return radians; 80 | } 81 | 82 | void InteractiveCamera::setFOVX(float fovx){ 83 | fov.x = fovx; 84 | fov.y = radiansToDegrees(atan(tan(degreesToRadians(fovx) * 0.5) * (resolution.y / resolution.x)) * 2.0); 85 | // resolution float division 86 | } 87 | 88 | void InteractiveCamera::buildRenderCamera(Camera* renderCamera){ 89 | float xDirection = sin(yaw) * cos(pitch); 90 | float yDirection = sin(pitch); 91 | float zDirection = cos(yaw) * cos(pitch); 92 | vec3 directionToCamera = vec3(xDirection, yDirection, zDirection); 93 | viewDirection = directionToCamera * (-1.0); 94 | vec3 eyePosition = centerPosition + directionToCamera * radius; 95 | //vec3 eyePosition = centerPosition; // rotate camera from stationary viewpoint 96 | 97 | renderCamera->position = eyePosition; 98 | renderCamera->view = viewDirection; 99 | renderCamera->up = vec3(0, 1, 0); 100 | renderCamera->resolution = vec2(resolution.x, resolution.y); 101 | renderCamera->fov = vec2(fov.x, fov.y); 102 | renderCamera->apertureRadius = apertureRadius; 103 | renderCamera->focalDistance = focalDistance; 104 | } 105 | 106 | float mod(float x, float y) { // Does this account for -y ??? 107 | return x - y * floorf(x / y); 108 | } 109 | 110 | void InteractiveCamera::fixYaw() { 111 | yaw = mod(yaw, 2 * M_PI); // Normalize the yaw. 112 | } 113 | 114 | float clamp2(float n, float low, float high) { 115 | n = fminf(n, high); 116 | n = fmaxf(n, low); 117 | return n; 118 | } 119 | 120 | void InteractiveCamera::fixPitch() { 121 | float padding = 0.05; 122 | pitch = clamp2(pitch, -PI_OVER_TWO + padding, PI_OVER_TWO - padding); // Limit the pitch. 123 | } 124 | 125 | void InteractiveCamera::fixRadius() { 126 | float minRadius = 0.2; 127 | float maxRadius = 100.0; 128 | radius = clamp2(radius, minRadius, maxRadius); 129 | } 130 | 131 | void InteractiveCamera::fixApertureRadius() { 132 | float minApertureRadius = 0.0; 133 | float maxApertureRadius = 25.0; 134 | apertureRadius = clamp2(apertureRadius, minApertureRadius, maxApertureRadius); 135 | } 136 | 137 | void InteractiveCamera::fixFocalDistance() { 138 | float minFocalDist = 0.2; 139 | float maxFocalDist = 100.0; 140 | focalDistance = clamp2(focalDistance, minFocalDist, maxFocalDist); 141 | } 142 | -------------------------------------------------------------------------------- /src/Math/MathHelp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using std::vector; 4 | 5 | const cl_float RENDER_PHONGTESS = 0; 6 | 7 | cl_float MathHelp::degToRad(cl_float deg) { 8 | return (deg * M_PI / 180.0f); 9 | } 10 | 11 | void MathHelp::getAABB(const vector& vertices, vec3& bbMin, vec3& bbMax) { 12 | bbMin = vec3(vertices[0].x, vertices[0].y, vertices[0].z); 13 | bbMax = vec3(vertices[0].x, vertices[0].y, vertices[0].z); 14 | 15 | for (cl_uint i = 1; i < vertices.size(); i++) { 16 | cl_float4 v = vertices[i]; 17 | 18 | (bbMin)[0] = ((bbMin)[0] < v.x) ? (bbMin)[0] : v.x; 19 | (bbMin)[1] = ((bbMin)[1] < v.y) ? (bbMin)[1] : v.y; 20 | (bbMin)[2] = ((bbMin)[2] < v.z) ? (bbMin)[2] : v.z; 21 | 22 | (bbMax)[0] = ((bbMax)[0] > v.x) ? (bbMax)[0] : v.x; 23 | (bbMax)[1] = ((bbMax)[1] > v.y) ? (bbMax)[1] : v.y; 24 | (bbMax)[2] = ((bbMax)[2] > v.z) ? (bbMax)[2] : v.z; 25 | } 26 | } 27 | 28 | void MathHelp::getAABB(const vector& vertices, vec3& bbMin, vec3& bbMax) { 29 | bbMin = vec3(vertices[0].x, vertices[0].y, vertices[0].z); 30 | bbMax = vec3(vertices[0].x, vertices[0].y, vertices[0].z); 31 | 32 | for (cl_uint i = 1; i < vertices.size(); i++) { 33 | vec3 v = vertices[i]; 34 | 35 | (bbMin)[0] = ((bbMin)[0] < v.x) ? (bbMin)[0] : v.x; 36 | (bbMin)[1] = ((bbMin)[1] < v.y) ? (bbMin)[1] : v.y; 37 | (bbMin)[2] = ((bbMin)[2] < v.z) ? (bbMin)[2] : v.z; 38 | 39 | (bbMax)[0] = ((bbMax)[0] > v.x) ? (bbMax)[0] : v.x; 40 | (bbMax)[1] = ((bbMax)[1] > v.y) ? (bbMax)[1] : v.y; 41 | (bbMax)[2] = ((bbMax)[2] > v.z) ? (bbMax)[2] : v.z; 42 | } 43 | } 44 | 45 | void MathHelp::getAABB( 46 | const vector& bbMins, const vector& bbMaxs, vec3* bbMin, vec3* bbMax 47 | ) { 48 | (*bbMin)[0] = bbMins[0][0]; 49 | (*bbMin)[1] = bbMins[0][1]; 50 | (*bbMin)[2] = bbMins[0][2]; 51 | 52 | (*bbMax)[0] = bbMaxs[0][0]; 53 | (*bbMax)[1] = bbMaxs[0][1]; 54 | (*bbMax)[2] = bbMaxs[0][2]; 55 | 56 | for (cl_uint i = 1; i < bbMins.size(); i++) { 57 | (*bbMin)[0] = fmin(bbMins[i][0], (*bbMin)[0]); 58 | (*bbMin)[1] = fmin(bbMins[i][1], (*bbMin)[1]); 59 | (*bbMin)[2] = fmin(bbMins[i][2], (*bbMin)[2]); 60 | 61 | (*bbMax)[0] = fmax(bbMaxs[i][0], (*bbMax)[0]); 62 | (*bbMax)[1] = fmax(bbMaxs[i][1], (*bbMax)[1]); 63 | (*bbMax)[2] = fmax(bbMaxs[i][2], (*bbMax)[2]); 64 | } 65 | } 66 | 67 | cl_float MathHelp::getOverlapSA(vec3 bbA, vec3 bbB) { 68 | cl_float overlapSA = 0.0f; 69 | 70 | cl_float sideX = bbA.x - bbB.x; 71 | cl_float sideY = bbA.y - bbB.y; 72 | cl_float sideZ = bbA.z - bbB.z; 73 | 74 | if (fmin(sideX, fmin(sideY, sideZ)) > 0.0f) { 75 | overlapSA = 2.0f * (sideX * sideY + sideX * sideZ + sideY * sideZ); 76 | } 77 | 78 | return overlapSA; 79 | }; 80 | 81 | cl_float MathHelp::getSurfaceArea(vec3 bbMin, vec3 bbMax) { 82 | cl_float xy = fabs(bbMax[0] - bbMin[0]) * fabs(bbMax[1] - bbMin[1]); 83 | cl_float zy = fabs(bbMax[2] - bbMin[2]) * fabs(bbMax[1] - bbMin[1]); 84 | cl_float xz = fabs(bbMax[0] - bbMin[0]) * fabs(bbMax[2] - bbMin[2]); 85 | 86 | return 2.0f * (xy + zy + xz); 87 | } 88 | 89 | void MathHelp::getTriangleAABB(cl_float4 v0, cl_float4 v1, cl_float4 v2, vec3* bbMin, vec3* bbMax) { 90 | vector vertices; 91 | 92 | vertices.push_back(v0); 93 | vertices.push_back(v1); 94 | vertices.push_back(v2); 95 | 96 | MathHelp::getAABB(vertices, *bbMin, *bbMax); 97 | } 98 | 99 | vec3 MathHelp::getTriangleCenter(cl_float4 v0, cl_float4 v1, cl_float4 v2) { 100 | vec3 bbMin; 101 | vec3 bbMax; 102 | MathHelp::getTriangleAABB(v0, v1, v2, &bbMin, &bbMax); 103 | 104 | return (bbMax - bbMin) / 2.0f; 105 | } 106 | 107 | vec3 MathHelp::getTriangleCentroid(cl_float4 v0, cl_float4 v1, cl_float4 v2) { 108 | vec3 a(v0.x, v0.y, v0.z); 109 | vec3 b(v1.x, v1.y, v1.z); 110 | vec3 c(v2.x, v2.y, v2.z); 111 | 112 | return (a + b + c) / 3.0f; 113 | } 114 | 115 | vec3 MathHelp::intersectLinePlane(vec3 p, vec3 q, vec3 x, vec3 nl, bool* isParallel) { 116 | vec3 hit; 117 | vec3 u = q - p; 118 | vec3 w = p - x; 119 | cl_float d = dot(nl, u); 120 | 121 | if (fabs(d) < 0.000001f) { 122 | *isParallel = true; 123 | } 124 | else { 125 | cl_float t = -dot(nl, w) / d; 126 | hit = p + u * t; 127 | *isParallel = false; 128 | } 129 | 130 | return hit; 131 | } 132 | 133 | short MathHelp::longestAxis(vec3 bbMin, vec3 bbMax) { 134 | vec3 sides = bbMax - bbMin; 135 | 136 | if (sides[0] > sides[1]) { 137 | return (sides[0] > sides[2]) ? 0 : 2; 138 | } 139 | else { // sides[1] > sides[0] 140 | return (sides[1] > sides[2]) ? 1 : 2; 141 | } 142 | } 143 | 144 | vec3 MathHelp::projectOnPlane(vec3 q, vec3 p, vec3 n) { 145 | return q - dot(q - p, n) * n; 146 | } 147 | 148 | vec3 MathHelp::phongTessellate( 149 | const vec3 p1, const vec3 p2, const vec3 p3, 150 | const vec3 n1, const vec3 n2, const vec3 n3, 151 | const float alpha, const float u, const float v 152 | ) { 153 | float w = 1.0f - u - v; 154 | vec3 pBary = p1 * u + p2 * v + p3 * w; 155 | vec3 pTessellated = 156 | u * MathHelp::projectOnPlane(pBary, p1, n1) + 157 | v * MathHelp::projectOnPlane(pBary, p2, n2) + 158 | w * MathHelp::projectOnPlane(pBary, p3, n3); 159 | 160 | return (1.0f - alpha) * pBary + alpha * pTessellated; 161 | } 162 | 163 | cl_float MathHelp::radToDeg(cl_float rad) { 164 | return (rad * 180.0f / M_PI); 165 | } 166 | 167 | void MathHelp::triThicknessAndSidedrop( 168 | const vec3 p1, const vec3 p2, const vec3 p3, 169 | const vec3 n1, const vec3 n2, const vec3 n3, 170 | float* thickness, vec3* sidedropMin, vec3* sidedropMax 171 | ) { 172 | float alpha = RENDER_PHONGTESS; 173 | 174 | vec3 e12 = p2 - p1; 175 | vec3 e13 = p3 - p1; 176 | vec3 e23 = p3 - p2; 177 | vec3 e31 = p1 - p3; 178 | vec3 c12 = alpha * (dot(n2, e12) * n2 - dot(n1, e12) * n1); 179 | vec3 c23 = alpha * (dot(n3, e23) * n3 - dot(n2, e23) * n2); 180 | vec3 c31 = alpha * (dot(n1, e31) * n1 - dot(n3, e31) * n3); 181 | vec3 ng = normalize(cross(e12, e13)); 182 | 183 | float k_tmp = dot(ng, c12 - c23 - c31); 184 | float k = 1.0f / (4.0f * dot(ng, c23) * dot(ng, c31) - k_tmp * k_tmp); 185 | 186 | float u = k * ( 187 | 2.0f * dot(ng, c23) * dot(ng, c31 + e31) + 188 | dot(ng, c23 - e23) * dot(ng, c12 - c23 - c31) 189 | ); 190 | float v = k * ( 191 | 2.0f * dot(ng, c31) * dot(ng, c23 - e23) + 192 | dot(ng, c31 + e31) * dot(ng, c12 - c23 - c31) 193 | ); 194 | 195 | u = (u < 0.0f || u > 1.0f) ? 0.0f : u; 196 | v = (v < 0.0f || v > 1.0f) ? 0.0f : v; 197 | 198 | vec3 pt = MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, u, v); 199 | *thickness = dot(ng, pt - p1); 200 | 201 | vec3 ptsd[9] = { 202 | MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, 0.0f, 0.5f), 203 | MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, 0.5f, 0.0f), 204 | MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, 0.5f, 0.5f), 205 | MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, 0.25f, 0.75f), 206 | MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, 0.75f, 0.25f), 207 | MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, 0.25f, 0.0f), 208 | MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, 0.75f, 0.0f), 209 | MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, 0.0f, 0.25f), 210 | MathHelp::phongTessellate(p1, p2, p3, n1, n2, n3, alpha, 0.0f, 0.75f) 211 | }; 212 | 213 | *sidedropMin = ptsd[0]; 214 | *sidedropMax = ptsd[0]; 215 | 216 | for (cl_uint i = 1; i < 9; i++) { 217 | *sidedropMin = min3(*sidedropMin, ptsd[i]); 218 | *sidedropMax = max3(*sidedropMax, ptsd[i]); 219 | } 220 | } 221 | 222 | void MathHelp::triCalcAABB( 223 | Tri* tri, const vector* vertices, const vector* normals 224 | ) { 225 | vector v; 226 | v.push_back((*vertices)[tri->face.x]); 227 | v.push_back((*vertices)[tri->face.y]); 228 | v.push_back((*vertices)[tri->face.z]); 229 | 230 | vec3 bbMin, bbMax; 231 | MathHelp::getAABB(v, bbMin, bbMax); 232 | tri->bbMin = bbMin; 233 | tri->bbMax = bbMax; 234 | 235 | // ALPHA <= 0.0, no Phong Tessellation 236 | if (RENDER_PHONGTESS <= 0.0f) { 237 | return; 238 | } 239 | 240 | vec3 p1 = vec3(v[0].x, v[0].y, v[0].z); 241 | vec3 p2 = vec3(v[1].x, v[1].y, v[1].z); 242 | vec3 p3 = vec3(v[2].x, v[2].y, v[2].z); 243 | 244 | cl_float4 fn1 = (*normals)[tri->face.x]; 245 | cl_float4 fn2 = (*normals)[tri->face.y]; 246 | cl_float4 fn3 = (*normals)[tri->face.z]; 247 | 248 | vec3 n1 = vec3(fn1.x, fn1.y, fn1.z); 249 | vec3 n2 = vec3(fn2.x, fn2.y, fn2.z); 250 | vec3 n3 = vec3(fn3.x, fn3.y, fn3.z); 251 | 252 | // Normals are the same, which means no Phong Tessellation possible 253 | vec3 test = (n1 - n2) + (n2 - n3); 254 | if ( 255 | fabs(test.x) <= 0.000001f && 256 | fabs(test.y) <= 0.000001f && 257 | fabs(test.z) <= 0.000001f 258 | ) { 259 | return; 260 | } 261 | 262 | 263 | float thickness; 264 | vec3 sidedropMin, sidedropMax; 265 | MathHelp::triThicknessAndSidedrop(p1, p2, p3, n1, n2, n3, &thickness, &sidedropMin, &sidedropMax); 266 | 267 | // Grow bigger according to thickness and sidedrop 268 | vec3 e12 = p2 - p1; 269 | vec3 e13 = p3 - p1; 270 | vec3 e23 = p3 - p2; 271 | vec3 e31 = p1 - p3; 272 | vec3 ng = normalize(cross(e12, e13)); 273 | 274 | vec3 p1thick = p1 + thickness * ng; 275 | vec3 p2thick = p2 + thickness * ng; 276 | vec3 p3thick = p3 + thickness * ng; 277 | 278 | tri->bbMin = min3(min3(tri->bbMin, p1thick), min3(p2thick, p3thick)); 279 | tri->bbMax = max3(max3(tri->bbMax, p1thick), max3(p2thick, p3thick)); 280 | tri->bbMin = min3(tri->bbMin, sidedropMin); 281 | tri->bbMax = max3(tri->bbMax, sidedropMax); 282 | } -------------------------------------------------------------------------------- /src/Models/model_loader.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include // Output data structure 5 | #include // Post processing flags 6 | 7 | #ifdef PROFILING 8 | #include // std::setprecision 9 | #include // glfwGetTime 10 | #endif 11 | 12 | namespace CL_RAYTRACER 13 | { 14 | namespace IO 15 | { 16 | bool ModelLoader::ImportFromFile(const std::string &filepath) 17 | { 18 | // free cached scene 19 | sceneData.reset(); 20 | 21 | #ifdef PROFILING 22 | std::cout << "Loading " << filepath << " ..." << std::endl; 23 | double start = glfwGetTime(); 24 | #endif 25 | //check if file exists 26 | std::ifstream fin(filepath.c_str()); 27 | if (!fin.fail()) 28 | { 29 | fin.close(); 30 | } 31 | else 32 | { 33 | printf("Couldn't open file: %s\n", filepath.c_str()); 34 | printf("%s\n", importer.GetErrorString()); 35 | return false; 36 | } 37 | 38 | const aiScene *scene = importer.ReadFile(filepath, aiProcessPreset_TargetRealtime_Quality); 39 | 40 | // If the import failed, report it 41 | if (!scene) 42 | { 43 | printf("%s\n", importer.GetErrorString()); 44 | return false; 45 | } 46 | 47 | sceneData.reset(new SceneData); 48 | updateSceneData(scene->mRootNode, scene); 49 | 50 | #ifdef PROFILING 51 | std::cout << std::setprecision(4) << "Loaded " << filepath << " at " 52 | << (glfwGetTime() - start) << "s ..." << std::endl; 53 | #endif 54 | return true; 55 | } 56 | 57 | // from https://github.com/JoeyDeVries/LearnOpenGL/blob/0a8d6e582c99d90ad68181befe44c4589063ab20/includes/learnopengl/model.h 58 | void ModelLoader::updateSceneData(aiNode *node, const aiScene *scene) 59 | { 60 | // process each mesh located at the current node 61 | for(unsigned int i = 0; i < node->mNumMeshes; i++) 62 | { 63 | // the node object only contains indices to index the actual objects in the scene. 64 | // the scene contains all the data, node is just to keep stuff organized (like relations between nodes). 65 | aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; 66 | sceneData->push_back(assimpGetMeshData(mesh)); 67 | std::cout << "::::::::PROCESSING =>" << mesh->mName.C_Str() << " , Faces: " << mesh->mNumFaces << std::endl; 68 | } 69 | 70 | // after we've processed all of the meshes (if any) we then recursively process each of the children nodes 71 | for(unsigned int i = 0; i < node->mNumChildren; i++) 72 | { 73 | updateSceneData(node->mChildren[i], scene); 74 | } 75 | } 76 | 77 | const MeshData ModelLoader::assimpGetMeshData(const aiMesh *mesh) 78 | { 79 | MeshData res; 80 | 81 | // total faces 82 | res.first.push_back(mesh->mNumFaces); 83 | // total vertices 84 | res.first.push_back(mesh->mNumVertices); 85 | 86 | for (unsigned int f = 0; f < mesh->mNumFaces; f++) 87 | { 88 | aiFace *face = &mesh->mFaces[f]; 89 | for (unsigned int i = 0; i < face->mNumIndices; ++i) 90 | { 91 | if (i > 2) 92 | { 93 | std::cerr << "there's only support for triangles at the moment!" << std::endl; 94 | break; 95 | } 96 | res.first.emplace_back(face->mIndices[i]); 97 | } 98 | } 99 | 100 | for (unsigned int v = 0; v < mesh->mNumVertices; ++v) 101 | { 102 | res.second.push_back(mesh->mVertices[v].x); 103 | res.second.push_back(mesh->mVertices[v].y); 104 | res.second.push_back(mesh->mVertices[v].z); 105 | } 106 | 107 | for (unsigned int v = 0; v < mesh->mNumVertices; ++v) 108 | { 109 | res.second.push_back(mesh->mNormals[v].x); 110 | res.second.push_back(mesh->mNormals[v].y); 111 | res.second.push_back(mesh->mNormals[v].z); 112 | } 113 | 114 | for (unsigned int v = 0; v < mesh->mNumVertices; ++v) 115 | { 116 | if (mesh->HasTextureCoords(0)) 117 | { 118 | res.second.push_back(mesh->mTextureCoords[0][v].x); 119 | res.second.push_back(mesh->mTextureCoords[0][v].y); 120 | } 121 | else 122 | { 123 | res.second.push_back(0); 124 | res.second.push_back(0); 125 | } 126 | } 127 | 128 | if (mesh->HasTangentsAndBitangents()) 129 | { 130 | for (unsigned int v = 0; v < mesh->mNumVertices; ++v) 131 | { 132 | res.second.push_back(mesh->mTangents[v].x); 133 | res.second.push_back(mesh->mTangents[v].y); 134 | res.second.push_back(mesh->mTangents[v].z); 135 | } 136 | } 137 | else 138 | { 139 | for (unsigned int v = 0; v < mesh->mNumVertices; ++v) 140 | { 141 | res.second.push_back(0); 142 | res.second.push_back(0); 143 | res.second.push_back(0); 144 | } 145 | } 146 | 147 | return res; 148 | } 149 | 150 | const std::unique_ptr ModelLoader::getFaces() 151 | { 152 | std::unique_ptr scene = std::make_unique(); 153 | 154 | for (std::size_t m = 0; m < sceneData->size(); ++m) 155 | { 156 | const MeshData &meshData = (*sceneData)[m]; 157 | const auto &vertices = getPositions4(meshData); 158 | const auto &normals = getNormals4(meshData); 159 | 160 | Mesh mesh; 161 | for (const auto &f : getIndices4(meshData)) 162 | { 163 | std::array verts; 164 | for (std::size_t i = 0; i < 3; ++i) 165 | { 166 | const std::size_t index = f.s[i]; 167 | verts[i].pos = vertices[index]; 168 | verts[i].nor = normals[index]; 169 | } 170 | mesh.faces.emplace_back(verts[0], verts[1], verts[2]); 171 | } 172 | scene->meshes.push_back(mesh); 173 | } 174 | 175 | return scene; 176 | } 177 | 178 | const void *ModelLoader::getPositionsPtr(const MeshData &data) 179 | { 180 | return &data.second[0]; 181 | } 182 | 183 | const void *ModelLoader::getNormalsPtr(const MeshData &data) 184 | { 185 | return &data.second[3 * data.first[1]]; 186 | } 187 | 188 | const void *ModelLoader::getTextureCoordsPtr(const MeshData &data) 189 | { 190 | return &data.second[6 * data.first[1]]; 191 | } 192 | 193 | const void *ModelLoader::getTangentsPtr(const MeshData &data) 194 | { 195 | return &data.second[8 * data.first[1]]; 196 | } 197 | 198 | std::vector ModelLoader::getIndices(const MeshData &data) const 199 | { 200 | return std::vector(data.first.begin() + 2, data.first.end()); 201 | } 202 | 203 | std::vector ModelLoader::getIndices4(const MeshData &data) const 204 | { 205 | std::vector res; 206 | 207 | const auto &indices = getIndices(data); 208 | 209 | if(indices.size()%3 != 0){ 210 | std::cerr << "[Error]: indices%3 != 0 !!!!!!!!!!" << std::endl; 211 | } 212 | 213 | for (unsigned int i = 0; i < indices.size();) 214 | { 215 | res.push_back({indices[i++], indices[i++], indices[i++], 0U}); 216 | } 217 | return res; 218 | } 219 | 220 | std::vector ModelLoader::getIndices() const 221 | { 222 | std::vector res; 223 | 224 | for (const auto &meshData : *sceneData) 225 | { 226 | const std::vector &faces = getIndices(meshData); 227 | res.insert(res.end(), faces.begin(), faces.end()); 228 | } 229 | 230 | return res; 231 | } 232 | 233 | std::vector ModelLoader::getIndices4() const 234 | { 235 | std::vector res; 236 | 237 | for (const auto &meshData : *sceneData) 238 | { 239 | const auto &faces = getIndices4(meshData); 240 | res.insert(res.end(), faces.begin(), faces.end()); 241 | } 242 | 243 | return res; 244 | } 245 | 246 | std::vector ModelLoader::getIndicesAt(unsigned index) const 247 | { 248 | return getIndices(sceneData->at(index)); 249 | } 250 | 251 | std::vector ModelLoader::getPositions(const MeshData &data) const 252 | { 253 | return std::vector(data.second.begin(), data.second.begin() + data.first[1] * 3); 254 | } 255 | 256 | std::vector ModelLoader::getPositions4(const MeshData &data) const 257 | { 258 | std::vector res; 259 | 260 | const auto &positions = getPositions(data); 261 | for (int i = 0; i < positions.size();) 262 | { 263 | res.push_back({positions[i++], positions[i++], positions[i++], 0.0f}); 264 | } 265 | return res; 266 | } 267 | 268 | std::vector ModelLoader::getPositions() const 269 | { 270 | std::vector res; 271 | 272 | for (const auto &mesh : *sceneData) 273 | { 274 | const std::vector &pos = getPositions(mesh); 275 | res.insert(res.end(), pos.begin(), pos.end()); 276 | } 277 | 278 | return res; 279 | } 280 | 281 | std::vector ModelLoader::getPositions4() const 282 | { 283 | std::vector res; 284 | 285 | for (const auto &mesh : *sceneData) 286 | { 287 | const auto &pos = getPositions4(mesh); 288 | res.insert(res.end(), pos.begin(), pos.end()); 289 | } 290 | 291 | return res; 292 | } 293 | 294 | std::vector ModelLoader::getPositionsAt(unsigned index) const 295 | { 296 | return getPositions(sceneData->at(index)); 297 | } 298 | 299 | std::vector ModelLoader::getNormals(const MeshData &data) const 300 | { 301 | return std::vector(data.second.begin() + data.first[1] * 3, data.second.begin() + data.first[1] * 6); 302 | } 303 | 304 | std::vector ModelLoader::getNormals4(const MeshData &data) const 305 | { 306 | std::vector res; 307 | 308 | const auto &normals = getNormals(data); 309 | for (int i = 0; i < normals.size();) 310 | { 311 | res.push_back({normals[i++], normals[i++], normals[i++], 0.0f}); 312 | } 313 | return res; 314 | } 315 | 316 | std::vector ModelLoader::getNormals() const 317 | { 318 | std::vector res; 319 | 320 | for (const auto &mesh : *sceneData) 321 | { 322 | const std::vector &nor = getNormals(mesh); 323 | res.insert(res.end(), nor.begin(), nor.end()); 324 | } 325 | 326 | return res; 327 | } 328 | 329 | std::vector ModelLoader::getNormals4() const 330 | { 331 | std::vector res; 332 | 333 | for (const auto &mesh : *sceneData) 334 | { 335 | const auto &nor = getNormals4(mesh); 336 | res.insert(res.end(), nor.begin(), nor.end()); 337 | } 338 | 339 | return res; 340 | } 341 | 342 | std::vector ModelLoader::getNormalsAt(unsigned index) const 343 | { 344 | return getNormals(sceneData->at(index)); 345 | } 346 | 347 | std::vector ModelLoader::getTextureCoords(const MeshData &data) const 348 | { 349 | return std::vector(data.second.begin() + data.first[1] * 6, data.second.begin() + data.first[1] * 8); 350 | } 351 | 352 | std::vector ModelLoader::getTextureCoords4(const MeshData &data) const 353 | { 354 | std::vector res; 355 | 356 | const auto &tex_coord = getTextureCoords(data); 357 | for (int i = 0; i < tex_coord.size();) 358 | { 359 | res.push_back({tex_coord[i++], tex_coord[i++], tex_coord[i++], 0.0f}); 360 | } 361 | return res; 362 | } 363 | 364 | std::vector ModelLoader::getTextureCoords() const 365 | { 366 | std::vector res; 367 | 368 | for (const auto &mesh : *sceneData) 369 | { 370 | const std::vector &uv = getTextureCoords(mesh); 371 | res.insert(res.end(), uv.begin(), uv.end()); 372 | } 373 | 374 | return res; 375 | } 376 | 377 | std::vector ModelLoader::getTextureCoords4() const 378 | { 379 | std::vector res; 380 | 381 | for (const auto &mesh : *sceneData) 382 | { 383 | const auto &uv = getTextureCoords4(mesh); 384 | res.insert(res.end(), uv.begin(), uv.end()); 385 | } 386 | 387 | return res; 388 | } 389 | 390 | std::vector ModelLoader::getTangents(const MeshData &data) const 391 | { 392 | return std::vector(data.second.begin() + data.first[1] * 8, data.second.begin() + data.first[1] * 11); 393 | } 394 | 395 | std::vector ModelLoader::getTangents4(const MeshData &data) const 396 | { 397 | std::vector res; 398 | 399 | const auto &tg = getTangents(data); 400 | for (int i = 0; i < tg.size();) 401 | { 402 | res.push_back({tg[i++], tg[i++], tg[i++], 0.0f}); 403 | } 404 | return res; 405 | } 406 | 407 | std::vector ModelLoader::getTangents() const 408 | { 409 | std::vector res; 410 | 411 | for (const auto &mesh : *sceneData) 412 | { 413 | const std::vector &tangent = getTangents(mesh); 414 | res.insert(res.end(), tangent.begin(), tangent.end()); 415 | } 416 | 417 | return res; 418 | } 419 | 420 | std::vector ModelLoader::getTangents4() const 421 | { 422 | std::vector res; 423 | 424 | for (const auto &mesh : *sceneData) 425 | { 426 | const auto &tangent = getTangents4(mesh); 427 | res.insert(res.end(), tangent.begin(), tangent.end()); 428 | } 429 | 430 | return res; 431 | } 432 | } // namespace IO 433 | } // namespace CL_RAYTRACER 434 | -------------------------------------------------------------------------------- /vcpkg-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "default-registry": { 3 | "kind": "git", 4 | "baseline": "76d153790caf0592fce8fc4484aa6db18c7d00d4", 5 | "repository": "https://github.com/microsoft/vcpkg" 6 | }, 7 | "registries": [ 8 | { 9 | "kind": "artifact", 10 | "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", 11 | "name": "microsoft" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | "assimp", 4 | "eigen3", 5 | "glew", 6 | "glfw3", 7 | "opencl", 8 | "rapidjson", 9 | "opengl" 10 | ] 11 | } 12 | --------------------------------------------------------------------------------