├── .gitignore ├── .gitmodules ├── .python-version ├── CMakeLists.txt ├── LICENSE ├── README.md ├── app ├── CMakeLists.txt └── main.cpp ├── cmake ├── FindOptiX.cmake └── ptx2cpp.cmake ├── ext └── optix_sdk │ ├── cuda │ └── curve.h │ └── sutil │ ├── Preprocessor.h │ └── vec_math.h ├── include └── moana │ ├── core │ ├── bsdf_sample_record.hpp │ ├── camera.hpp │ ├── coordinates.hpp │ ├── frame.hpp │ ├── ray.hpp │ ├── texture.hpp │ ├── transform.hpp │ └── vec3.hpp │ ├── cuda │ ├── bsdf.hpp │ ├── environment_light.hpp │ ├── fresnel.hpp │ ├── snell.hpp │ ├── surface_sample.hpp │ ├── tangent_frame.hpp │ ├── triangle.hpp │ ├── trig.hpp │ └── world_frame.hpp │ ├── driver.hpp │ ├── io │ └── image.hpp │ ├── parsers │ ├── obj_parser.hpp │ └── string_util.hpp │ ├── render │ ├── pipeline.hpp │ └── renderer.hpp │ ├── scene.hpp │ ├── scene │ ├── as_arena.hpp │ └── types.hpp │ └── types.hpp ├── optix ├── CMakeLists.txt ├── bsdfs │ ├── lambertian.hpp │ └── water.hpp ├── kernel.cu ├── optix_sdk.hpp ├── random.hpp ├── ray_data.hpp ├── sample.hpp ├── shadow_ray_kernel.cu └── util.hpp ├── refs ├── beachCam.png ├── birdseyeCam.png ├── dunesACam.png ├── grassCam.png ├── palmsCam.png ├── rootsCam.png └── shotCam.png ├── scene └── .gitignore ├── scripts ├── .gitignore ├── code.py ├── curves.py ├── dupe_detector.py ├── files.py ├── hardcoded_data.py ├── materials.py ├── moana.py ├── obj.py ├── params.py ├── textures.py └── transforms.py ├── src ├── assert_macros.hpp ├── core │ ├── camera.cpp │ ├── ptex_texture.cpp │ ├── ptex_texture.hpp │ ├── texture.cpp │ └── transform.cpp ├── cuda │ └── environment_light.cu ├── driver.cpp ├── io │ └── image.cpp ├── parsers │ ├── curve_parser.cpp │ ├── curve_parser.hpp │ ├── obj_parser.cpp │ └── string_util.cpp ├── render │ ├── .gitignore │ ├── pipeline.cpp │ ├── pipeline_helper.cpp │ ├── pipeline_helper.hpp │ ├── renderer.cpp │ ├── timing.cpp │ └── timing.hpp ├── scene.cpp ├── scene │ ├── archive.cpp │ ├── archive.hpp │ ├── as_arena.cpp │ ├── bay_cedar_a1_element.cpp │ ├── bay_cedar_a1_element.hpp │ ├── beach_element.cpp │ ├── beach_element.hpp │ ├── coastline_element.cpp │ ├── coastline_element.hpp │ ├── container.cpp │ ├── container.hpp │ ├── coral_element.cpp │ ├── coral_element.hpp │ ├── data │ │ ├── texture_lookup_data.cpp │ │ └── texture_offsets_data.cpp │ ├── dunes_a_element.cpp │ ├── dunes_a_element.hpp │ ├── dunes_b_element.cpp │ ├── dunes_b_element.hpp │ ├── element.cpp │ ├── element.hpp │ ├── gardenia_a_element.cpp │ ├── gardenia_a_element.hpp │ ├── gas.cpp │ ├── gas.hpp │ ├── hibiscus_element.cpp │ ├── hibiscus_element.hpp │ ├── hibiscus_young_element.cpp │ ├── hibiscus_young_element.hpp │ ├── ias.cpp │ ├── ias.hpp │ ├── instances_bin.cpp │ ├── instances_bin.hpp │ ├── ironwood_a1_element.cpp │ ├── ironwood_a1_element.hpp │ ├── ironwood_b_element.cpp │ ├── ironwood_b_element.hpp │ ├── kava_element.cpp │ ├── kava_element.hpp │ ├── lava_rocks_element.cpp │ ├── lava_rocks_element.hpp │ ├── materials.cpp │ ├── materials.hpp │ ├── mountain_a_element.cpp │ ├── mountain_a_element.hpp │ ├── mountain_b_element.cpp │ ├── mountain_b_element.hpp │ ├── naupaka_a_element.cpp │ ├── naupaka_a_element.hpp │ ├── ocean_element.cpp │ ├── ocean_element.hpp │ ├── palm_dead_element.cpp │ ├── palm_dead_element.hpp │ ├── palm_rig_element.cpp │ ├── palm_rig_element.hpp │ ├── pandanus_a_element.cpp │ ├── pandanus_a_element.hpp │ ├── texture_lookup.cpp │ ├── texture_lookup.hpp │ ├── texture_offsets.cpp │ └── texture_offsets.hpp └── util │ ├── color_map.cpp │ ├── color_map.hpp │ └── enumerate.hpp └── test ├── CMakeLists.txt ├── test.cpp └── test_obj_parser.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/tinyexr"] 2 | path = ext/tinyexr 3 | url = https://github.com/syoyo/tinyexr.git 4 | [submodule "ext/ptex"] 5 | path = ext/ptex 6 | url = https://github.com/wdas/ptex.git 7 | [submodule "ext/Catch2"] 8 | path = ext/Catch2 9 | url = https://github.com/catchorg/Catch2.git 10 | -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.7.3 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | project(moana LANGUAGES CUDA CXX C) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | set(CMAKE_CXX_EXTENSIONS OFF) 7 | 8 | set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) 9 | 10 | find_package(CUDAToolkit REQUIRED) 11 | find_package(OptiX REQUIRED) 12 | find_package(OpenMP REQUIRED) 13 | 14 | # ptex 15 | SET(PTEX_BUILD_SHARED_LIBS OFF CACHE BOOL " " FORCE) 16 | ADD_SUBDIRECTORY(ext/ptex) 17 | 18 | add_library(moana 19 | src/driver.cpp 20 | src/scene.cpp 21 | 22 | src/core/camera.cpp 23 | src/core/ptex_texture.cpp 24 | src/core/texture.cpp 25 | src/core/transform.cpp 26 | 27 | src/cuda/environment_light.cu 28 | 29 | src/io/image.cpp 30 | 31 | src/parsers/curve_parser.cpp 32 | src/parsers/obj_parser.cpp 33 | src/parsers/string_util.cpp 34 | 35 | src/render/pipeline.cpp 36 | src/render/pipeline_helper.cpp 37 | src/render/renderer.cpp 38 | src/render/timing.cpp 39 | 40 | src/scene/archive.cpp 41 | src/scene/as_arena.cpp 42 | src/scene/bay_cedar_a1_element.cpp 43 | src/scene/beach_element.cpp 44 | src/scene/coastline_element.cpp 45 | src/scene/container.cpp 46 | src/scene/coral_element.cpp 47 | src/scene/dunes_a_element.cpp 48 | src/scene/dunes_b_element.cpp 49 | src/scene/element.cpp 50 | src/scene/gardenia_a_element.cpp 51 | src/scene/gas.cpp 52 | src/scene/hibiscus_element.cpp 53 | src/scene/hibiscus_young_element.cpp 54 | src/scene/ias.cpp 55 | src/scene/instances_bin.cpp 56 | src/scene/ironwood_a1_element.cpp 57 | src/scene/ironwood_b_element.cpp 58 | src/scene/kava_element.cpp 59 | src/scene/lava_rocks_element.cpp 60 | src/scene/materials.cpp 61 | src/scene/mountain_a_element.cpp 62 | src/scene/mountain_b_element.cpp 63 | src/scene/naupaka_a_element.cpp 64 | src/scene/ocean_element.cpp 65 | src/scene/palm_dead_element.cpp 66 | src/scene/palm_rig_element.cpp 67 | src/scene/pandanus_a_element.cpp 68 | src/scene/texture_lookup.cpp 69 | src/scene/texture_offsets.cpp 70 | 71 | src/util/color_map.cpp 72 | ) 73 | target_include_directories(moana PUBLIC include) 74 | target_include_directories(moana PUBLIC "${OptiX_INCLUDE}") 75 | target_include_directories(moana PRIVATE src) 76 | target_include_directories(moana PRIVATE ext/tinyexr) 77 | target_include_directories(moana PRIVATE ext/ptex/src/ptex) 78 | target_compile_definitions(moana PRIVATE MOANA_ROOT="${MOANA_ROOT}") 79 | target_link_libraries(moana CUDA::cudart Ptex_static dl OpenMP::OpenMP_CXX) 80 | add_subdirectory(optix) 81 | add_dependencies(moana ptx_headers shadow_ray_ptx_headers) 82 | 83 | add_subdirectory(app) 84 | add_subdirectory(test) 85 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Chris Hellmuth 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 | # GPU-Motunui 2 | 3 | GPU-Motunui is a unidirectional path tracer that renders Disney Animation's [Moana island scene](https://technology.disneyanimation.com/islandscene/). Using the OptiX 7 API and a custom out-of-core rendering solution, all ray tracing is done on the GPU. Read an introduction [here](https://www.render-blog.com/2020/10/03/gpu-motunui/). 4 | 5 | ## Renders 6 | **shotCam:** 7 | ![shotCam](refs/shotCam.png) 8 | 9 | **beachCam:** 10 | ![beachCam](refs/beachCam.png) 11 | 12 | **dunesACam:** 13 | ![dunesACam](refs/dunesACam.png) 14 | 15 | **palmsCam:** 16 | ![palmsCam](refs/palmsCam.png) 17 | 18 | **rootsCam:** 19 | ![rootsCam](refs/rootsCam.png) 20 | 21 | **grassCam:** 22 | ![grassCam](refs/grassCam.png) 23 | 24 | ## Build instructions 25 | ``` 26 | git clone --recursive https://github.com/chellmuth/gpu-motunui.git 27 | cd gpu-motunui 28 | 29 | # Pre-process the assets 30 | cd scripts 31 | export MOANA_ROOT=/path/to/moana/dataset 32 | python moana.py 33 | cd .. 34 | 35 | # Build and run the renderer 36 | mkdir build 37 | cd build 38 | export OPTIX_INSTALL_DIR=/path/to/optix 39 | cmake -DCMAKE_BUILD_TYPE=Release -DOptiX_INSTALL_DIR="${OPTIX_INSTALL_DIR}" -DMOANA_ROOT="${MOANA_ROOT}" .. 40 | make 41 | ./app/moana 42 | ``` 43 | -------------------------------------------------------------------------------- /app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(moana-app main.cpp) 2 | target_compile_definitions(moana-app PRIVATE MOANA_ROOT="${MOANA_ROOT}") 3 | target_link_libraries(moana-app moana) 4 | 5 | set_target_properties(moana-app PROPERTIES OUTPUT_NAME moana) 6 | -------------------------------------------------------------------------------- /app/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "moana/driver.hpp" 5 | #include "moana/scene.hpp" 6 | #include "moana/types.hpp" 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | using namespace moana; 11 | 12 | std::cout << "Moana!" << std::endl; 13 | 14 | Driver driver; 15 | driver.init(); 16 | 17 | RenderRequest request; 18 | request.spp = 1024; 19 | request.bounces = 5; 20 | request.width = 1024; 21 | request.height = 429; 22 | 23 | driver.launch(request, Cam::ShotCam, "shot.exr"); 24 | driver.launch(request, Cam::BeachCam, "beach.exr"); 25 | driver.launch(request, Cam::BirdseyeCam, "birdseye.exr"); 26 | driver.launch(request, Cam::DunesACam, "dunesA.exr"); 27 | driver.launch(request, Cam::GrassCam, "grass.exr"); 28 | driver.launch(request, Cam::PalmsCam, "palms.exr"); 29 | driver.launch(request, Cam::RootsCam, "roots.exr"); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /cmake/FindOptiX.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions 6 | # are met: 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # * Redistributions in binary form must reproduce the above copyright 10 | # notice, this list of conditions and the following disclaimer in the 11 | # documentation and/or other materials provided with the distribution. 12 | # * Neither the name of NVIDIA CORPORATION nor the names of its 13 | # contributors may be used to endorse or promote products derived 14 | # from this software without specific prior written permission. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | # 28 | 29 | # Locate the OptiX distribution. Search relative to the SDK first, then look in the system. 30 | 31 | # Our initial guess will be within the SDK. 32 | set(OptiX_INSTALL_DIR "${CMAKE_SOURCE_DIR}/../" CACHE PATH "Path to OptiX installed location.") 33 | 34 | # The distribution contains only 64 bit libraries. Error when we have been mis-configured. 35 | if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8) 36 | if(WIN32) 37 | message(SEND_ERROR "Make sure when selecting the generator, you select one with Win64 or x64.") 38 | endif() 39 | message(FATAL_ERROR "OptiX only supports builds configured for 64 bits.") 40 | endif() 41 | 42 | # search path based on the bit-ness of the build. (i.e. 64: bin64, lib64; 32: 43 | # bin, lib). Note that on Mac, the OptiX library is a universal binary, so we 44 | # only need to look in lib and not lib64 for 64 bit builds. 45 | if(NOT APPLE) 46 | set(bit_dest "64") 47 | else() 48 | set(bit_dest "") 49 | endif() 50 | 51 | # Include 52 | find_path(OptiX_INCLUDE 53 | NAMES optix.h 54 | PATHS "${OptiX_INSTALL_DIR}/include" 55 | NO_DEFAULT_PATH 56 | ) 57 | find_path(OptiX_INCLUDE 58 | NAMES optix.h 59 | ) 60 | 61 | # Check to make sure we found what we were looking for 62 | function(OptiX_report_error error_message required component ) 63 | if(DEFINED OptiX_FIND_REQUIRED_${component} AND NOT OptiX_FIND_REQUIRED_${component}) 64 | set(required FALSE) 65 | endif() 66 | if(OptiX_FIND_REQUIRED AND required) 67 | message(FATAL_ERROR "${error_message} Please locate before proceeding.") 68 | else() 69 | if(NOT OptiX_FIND_QUIETLY) 70 | message(STATUS "${error_message}") 71 | endif(NOT OptiX_FIND_QUIETLY) 72 | endif() 73 | endfunction() 74 | 75 | if(NOT OptiX_INCLUDE) 76 | OptiX_report_error("OptiX headers (optix.h and friends) not found." TRUE headers ) 77 | endif() 78 | 79 | -------------------------------------------------------------------------------- /cmake/ptx2cpp.cmake: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Copyright (c) 2008 - 2009 NVIDIA Corporation. All rights reserved. 4 | # 5 | # NVIDIA Corporation and its licensors retain all intellectual property and proprietary 6 | # rights in and to this software, related documentation and any modifications thereto. 7 | # Any use, reproduction, disclosure or distribution of this software and related 8 | # documentation without an express license agreement from NVIDIA Corporation is strictly 9 | # prohibited. 10 | # 11 | # TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* 12 | # AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, 13 | # INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 14 | # PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY 15 | # SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT 16 | # LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF 17 | # BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR 18 | # INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF 19 | # SUCH DAMAGES 20 | # 21 | 22 | # This script produces a string variable from the contents of a ptx 23 | # script. The variable is defined in the .cc file and the .h file. 24 | 25 | # This script excepts the following variable to be passed in like 26 | # -DVAR:TYPE=VALUE 27 | # 28 | # CPP_FILE 29 | # PTX_FILE 30 | # VARIABLE_NAME 31 | # NAMESPACE 32 | # CUDA_BIN2C_EXECUTABLE 33 | 34 | # message("PTX_FILE = ${PTX_FILE}") 35 | # message("CPP_FILE = ${CPP_FILE}") 36 | # message("VARIABLE_NAME = ${VARIABLE_NAME}") 37 | # message("NAMESPACE = ${NAMESPACE}") 38 | 39 | execute_process( COMMAND ${CUDA_BIN2C_EXECUTABLE} -p 0 -st -c -n ${VARIABLE_NAME}_static "${PTX_FILE}" 40 | OUTPUT_VARIABLE bindata 41 | RESULT_VARIABLE result 42 | ERROR_VARIABLE error 43 | ) 44 | if(result) 45 | message(FATAL_ERROR "bin2c error:\n" ${error}) 46 | endif() 47 | 48 | set(BODY 49 | "${bindata}\n" 50 | "namespace ${NAMESPACE} {\n\nstatic const char* const ${VARIABLE_NAME} = reinterpret_cast(&${VARIABLE_NAME}_static[0]);\n} // end namespace ${NAMESPACE}\n") 51 | file(WRITE ${CPP_FILE} "${BODY}") 52 | -------------------------------------------------------------------------------- /ext/optix_sdk/sutil/Preprocessor.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | 29 | 30 | #pragma once 31 | 32 | #if defined(__CUDACC__) || defined(__CUDABE__) 33 | # define SUTIL_HOSTDEVICE __host__ __device__ 34 | # define SUTIL_INLINE __forceinline__ 35 | # define CONST_STATIC_INIT( ... ) 36 | #else 37 | # define SUTIL_HOSTDEVICE 38 | # define SUTIL_INLINE inline 39 | # define CONST_STATIC_INIT( ... ) = __VA_ARGS__ 40 | #endif 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /include/moana/core/bsdf_sample_record.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/frame.hpp" 4 | #include "moana/core/vec3.hpp" 5 | 6 | namespace moana { 7 | 8 | struct BSDFSampleRecord { 9 | bool isValid = false; 10 | float3 point; 11 | Vec3 wiLocal; 12 | Vec3 normal; 13 | Frame frame; 14 | float weight; 15 | bool isDelta; 16 | }; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /include/moana/core/camera.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "moana/core/ray.hpp" 6 | #include "moana/core/transform.hpp" 7 | #include "moana/core/vec3.hpp" 8 | 9 | namespace moana { 10 | 11 | struct Resolution { 12 | int x; 13 | int y; 14 | }; 15 | 16 | class Camera { 17 | public: 18 | __device__ Camera() {} 19 | 20 | Camera( 21 | const Vec3 &origin, 22 | const Vec3 &target, 23 | const Vec3 &up, 24 | float verticalFOV, 25 | const Resolution &resolution, 26 | bool flipHandedness 27 | ); 28 | 29 | __device__ Ray generateRay(int row, int col, float2 samples) const { 30 | const float top = std::tan(m_verticalFOV / 2.f); 31 | const float height = top * 2.f; 32 | 33 | const float aspectRatio = 1.f * m_resolution.x / m_resolution.y; 34 | const float width = height * aspectRatio; 35 | const float right = width / 2.f; 36 | 37 | const float xCanonical = (col + samples.x) / m_resolution.x; 38 | const float yCanonical = (row + samples.y) / m_resolution.y; 39 | 40 | const float y = top - yCanonical * height; 41 | const float x = xCanonical * width - right; 42 | 43 | const Vec3 direction = normalized(Vec3(x, y, -1)); 44 | 45 | const Vec3 origin(0.f); 46 | const Ray transformedRay = m_cameraToWorld.apply(Ray(origin, direction)); 47 | return transformedRay; 48 | } 49 | 50 | private: 51 | Transform m_cameraToWorld; 52 | 53 | Vec3 m_origin; 54 | Vec3 m_target; 55 | Vec3 m_up; 56 | float m_verticalFOV; 57 | Resolution m_resolution; 58 | bool m_flipHandedness; 59 | }; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /include/moana/core/coordinates.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/vec3.hpp" 4 | 5 | namespace moana { namespace Coordinates { 6 | 7 | __forceinline__ __device__ float clamp(float value, float lowest, float highest) 8 | { 9 | return fminf(highest, fmaxf(value, lowest)); 10 | } 11 | 12 | __device__ inline void cartesianToSpherical(const Vec3 &cartesian, float *phi, float *theta) 13 | { 14 | *phi = atan2f(cartesian.z(), cartesian.x()); 15 | if (*phi < 0.f) { 16 | *phi += 2 * M_PI; 17 | } 18 | // if (*phi == M_TWO_PI) { 19 | // *phi = 0; 20 | // } 21 | 22 | *theta = acosf(clamp(cartesian.y(), -1.f, 1.f)); 23 | } 24 | 25 | __device__ inline Vec3 sphericalToCartesian(float phi, float cosTheta, float sinTheta) 26 | { 27 | const float y = cosTheta; 28 | const float x = sinTheta * cosf(phi); 29 | const float z = sinTheta * sinf(phi); 30 | 31 | return Vec3(x, y, z); 32 | } 33 | 34 | __device__ inline Vec3 sphericalToCartesian(float phi, float theta) { 35 | return sphericalToCartesian(phi, cosf(theta), sinf(theta)); 36 | } 37 | 38 | } } 39 | -------------------------------------------------------------------------------- /include/moana/core/frame.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/vec3.hpp" 4 | 5 | namespace moana { 6 | 7 | __device__ inline void coordinateSystem(const Vec3 &a, Vec3 &b, Vec3 &c) 8 | { 9 | if (fabsf(a.x()) > fabsf(a.y())) { 10 | float invLen = 1.0f / sqrtf(a.x() * a.x() + a.z() * a.z()); 11 | c = Vec3(a.z() * invLen, 0.0f, -a.x() * invLen); 12 | } else { 13 | float invLen = 1.0f / sqrtf(a.y() * a.y() + a.z() * a.z()); 14 | c = Vec3(0.0f, a.z() * invLen, -a.y() * invLen); 15 | } 16 | b = cross(c, a); 17 | } 18 | 19 | class Frame { 20 | public: 21 | __device__ Frame() {} 22 | 23 | __device__ Frame(const Vec3 &normal) : n(normal) 24 | { 25 | coordinateSystem(n, s, t); 26 | } 27 | 28 | __device__ Vec3 toWorld(const Vec3 &local) const 29 | { 30 | return Vec3( 31 | s.x() * local.x() + t.x() * local.y() + n.x() * local.z(), 32 | s.y() * local.x() + t.y() * local.y() + n.y() * local.z(), 33 | s.z() * local.x() + t.z() * local.y() + n.z() * local.z() 34 | ); 35 | } 36 | 37 | __device__ Vec3 toLocal(const Vec3 &world) const 38 | { 39 | return Vec3( 40 | s.x() * world.x() + s.y() * world.y() + s.z() * world.z(), 41 | t.x() * world.x() + t.y() * world.y() + t.z() * world.z(), 42 | n.x() * world.x() + n.y() * world.y() + n.z() * world.z() 43 | ); 44 | } 45 | 46 | __device__ float cosTheta(const Vec3 &wi) const 47 | { 48 | return wi.z(); 49 | } 50 | 51 | __device__ float absCosTheta(const Vec3 &wi) const 52 | { 53 | return fabsf(wi.z()); 54 | } 55 | 56 | Vec3 s; 57 | Vec3 t; 58 | Vec3 n; 59 | }; 60 | 61 | } 62 | -------------------------------------------------------------------------------- /include/moana/core/ray.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "moana/core/vec3.hpp" 6 | 7 | namespace moana { 8 | 9 | class Ray { 10 | public: 11 | __host__ __device__ Ray() {} 12 | __device__ Ray(const Vec3 &origin, const Vec3 &direction) 13 | : m_origin(origin), 14 | m_direction(direction) 15 | {} 16 | 17 | __device__ Vec3 origin() const { return m_origin; } 18 | __device__ Vec3 direction() const { return m_direction; } 19 | __device__ Vec3 at(float t) const { return m_origin + t * m_direction; } 20 | 21 | private: 22 | Vec3 m_origin; 23 | Vec3 m_direction; 24 | }; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /include/moana/core/texture.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "moana/scene/as_arena.hpp" 9 | 10 | namespace moana { 11 | 12 | class Texture { 13 | public: 14 | Texture(const std::string &filename); 15 | ~Texture(); 16 | 17 | cudaTextureObject_t createTextureObject(ASArena &arena); 18 | void determineAndSetPitch(); 19 | 20 | private: 21 | void loadImage(); 22 | 23 | std::string m_filename; 24 | float *m_data = nullptr; 25 | int m_width = 0; 26 | int m_height = 0; 27 | size_t m_pitch; 28 | }; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /include/moana/core/transform.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "moana/core/ray.hpp" 6 | #include "moana/core/vec3.hpp" 7 | 8 | namespace moana { 9 | 10 | class Transform { 11 | public: 12 | __host__ __device__ Transform() {} 13 | 14 | Transform(const float matrix[4][4]) 15 | { 16 | for (int row = 0; row < 4; row++ ) { 17 | for (int col = 0; col < 4; col++ ) { 18 | m_matrix[row][col] = matrix[row][col]; 19 | } 20 | } 21 | } 22 | 23 | __device__ Vec3 applyPoint(const Vec3 &point) const 24 | { 25 | const float x = point.x(); 26 | const float y = point.y(); 27 | const float z = point.z(); 28 | 29 | return Vec3( 30 | m_matrix[0][0] * x + m_matrix[0][1] * y + m_matrix[0][2] * z + m_matrix[0][3], 31 | m_matrix[1][0] * x + m_matrix[1][1] * y + m_matrix[1][2] * z + m_matrix[1][3], 32 | m_matrix[2][0] * x + m_matrix[2][1] * y + m_matrix[2][2] * z + m_matrix[2][3] 33 | ); 34 | } 35 | 36 | __device__ Vec3 applyVector(const Vec3 &vector) const 37 | { 38 | const float x = vector.x(); 39 | const float y = vector.y(); 40 | const float z = vector.z(); 41 | 42 | return Vec3( 43 | m_matrix[0][0] * x + m_matrix[0][1] * y + m_matrix[0][2] * z, 44 | m_matrix[1][0] * x + m_matrix[1][1] * y + m_matrix[1][2] * z, 45 | m_matrix[2][0] * x + m_matrix[2][1] * y + m_matrix[2][2] * z 46 | ); 47 | } 48 | 49 | __device__ Ray apply(const Ray &ray) const 50 | { 51 | return Ray( 52 | applyPoint(ray.origin()), 53 | applyVector(ray.direction()) 54 | ); 55 | } 56 | 57 | private: 58 | float m_matrix[4][4]; 59 | }; 60 | 61 | Transform lookAt( 62 | const Vec3 &source, 63 | const Vec3 &target, 64 | const Vec3 &up, 65 | bool flipHandedness = false 66 | ); 67 | 68 | } 69 | -------------------------------------------------------------------------------- /include/moana/core/vec3.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace moana { 9 | 10 | class Vec3 { 11 | public: 12 | __host__ __device__ Vec3() {} 13 | __host__ __device__ Vec3(float e0, float e1, float e2) { e[0] = e0; e[1] = e1; e[2] = e2; } 14 | __host__ __device__ Vec3(float ee) { e[0] = ee; e[1] = ee; e[2] = ee; } 15 | __host__ __device__ inline float x() const { return e[0]; } 16 | __host__ __device__ inline float y() const { return e[1]; } 17 | __host__ __device__ inline float z() const { return e[2]; } 18 | __host__ __device__ inline float r() const { return e[0]; } 19 | __host__ __device__ inline float g() const { return e[1]; } 20 | __host__ __device__ inline float b() const { return e[2]; } 21 | 22 | __host__ __device__ inline const Vec3& operator+() const { return *this; } 23 | __host__ __device__ inline Vec3 operator-() const { return Vec3(-e[0], -e[1], -e[2]); } 24 | __host__ __device__ inline Vec3 operator*(float t) const { return Vec3(t * e[0], t * e[1], t * e[2]); } 25 | __host__ __device__ inline Vec3 operator*(const Vec3 &v2) const { return Vec3(v2[0] * e[0], v2[1] * e[1], v2[2] * e[2]); } 26 | __host__ __device__ inline float operator[](int i) const { return e[i]; } 27 | __host__ __device__ inline float& operator[](int i) { return e[i]; }; 28 | 29 | __host__ __device__ inline bool operator==(const Vec3 &v2) const { 30 | return e[0] == v2.e[0] 31 | && e[1] == v2.e[1] 32 | && e[2] == v2.e[2] 33 | ; 34 | } 35 | 36 | __host__ __device__ inline Vec3& operator+=(const Vec3 &v2); 37 | __host__ __device__ inline Vec3& operator-=(const Vec3 &v2); 38 | __host__ __device__ inline Vec3& operator*=(const Vec3 &v2); 39 | __host__ __device__ inline Vec3& operator/=(const Vec3 &v2); 40 | __host__ __device__ inline Vec3& operator*=(const float t); 41 | __host__ __device__ inline Vec3& operator/=(const float t); 42 | 43 | __host__ __device__ inline Vec3 operator-(const Vec3 &v) const { 44 | return Vec3(e[0] - v.e[0], e[1] - v.e[1], e[2] - v.e[2]); 45 | } 46 | 47 | __host__ __device__ inline float length() const { 48 | return sqrtf(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]); 49 | } 50 | 51 | __host__ __device__ inline bool isZero() const { 52 | return e[0] == 0.f && e[1] == 0.f && e[2] == 0.f; 53 | } 54 | 55 | __host__ __device__ inline Vec3 dot(const Vec3 &v) const { 56 | return e[0] * v.e[0] + e[1] * v.e[1] + e[2] * v.e[2]; 57 | } 58 | 59 | __host__ __device__ inline Vec3 reflect(const Vec3 &normal) const { 60 | return normal * dot(normal) * 2.f - *this; 61 | } 62 | 63 | float e[3]; 64 | }; 65 | 66 | inline Vec3& Vec3::operator+=(const Vec3 &v) 67 | { 68 | e[0] += v.e[0]; 69 | e[1] += v.e[1]; 70 | e[2] += v.e[2]; 71 | return *this; 72 | } 73 | 74 | inline Vec3& Vec3::operator*=(const Vec3 &v2) 75 | { 76 | e[0] *= v2[0]; 77 | e[1] *= v2[1]; 78 | e[2] *= v2[2]; 79 | 80 | return *this; 81 | } 82 | 83 | __host__ __device__ inline Vec3 cross(const Vec3 &v1, const Vec3 &v2) 84 | { 85 | return Vec3( 86 | (v1.e[1] * v2.e[2] - v1.e[2] * v2.e[1]), 87 | (-(v1.e[0] * v2.e[2] - v1.e[2] * v2.e[0])), 88 | (v1.e[0] * v2.e[1] - v1.e[1] * v2.e[0]) 89 | ); 90 | } 91 | 92 | __host__ __device__ inline float dot(const Vec3 &v1, const Vec3 &v2) 93 | { 94 | return v1.e[0] * v2.e[0] + v1.e[1] * v2.e[1] + v1.e[2] * v2.e[2]; 95 | } 96 | 97 | __host__ __device__ inline float absDot(const Vec3 &v1, const Vec3 &v2) 98 | { 99 | return fabsf(v1.e[0] * v2.e[0] + v1.e[1] * v2.e[1] + v1.e[2] * v2.e[2]); 100 | } 101 | 102 | __host__ __device__ inline Vec3 operator+(const Vec3 &v1, const Vec3 &v2) 103 | { 104 | return Vec3(v1.e[0] + v2.e[0], v1.e[1] + v2.e[1], v1.e[2] + v2.e[2]); 105 | } 106 | 107 | __host__ __device__ inline Vec3 operator*(float t, const Vec3 &v) 108 | { 109 | return Vec3(t * v.e[0], t * v.e[1], t * v.e[2]); 110 | } 111 | 112 | __host__ __device__ inline Vec3 operator/(Vec3 v, float t) 113 | { 114 | return Vec3(v.e[0] / t, v.e[1] / t, v.e[2] / t); 115 | } 116 | 117 | __host__ __device__ inline Vec3 normalized(Vec3 v) 118 | { 119 | return v / v.length(); 120 | } 121 | 122 | inline std::ostream &operator<<(std::ostream &os, const Vec3 &v) 123 | { 124 | return os << "Vec3: " << v.x() << " " << v.y() << " " << v.z(); 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /include/moana/cuda/bsdf.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace moana { 4 | 5 | enum class BSDFType { 6 | Diffuse, 7 | Water 8 | }; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /include/moana/cuda/environment_light.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "moana/core/bsdf_sample_record.hpp" 9 | #include "moana/core/texture.hpp" 10 | #include "moana/scene/as_arena.hpp" 11 | 12 | namespace moana { 13 | 14 | struct EnvironmentLightState { 15 | cudaTextureObject_t textureObject; 16 | Snapshot snapshot; 17 | }; 18 | 19 | class EnvironmentLight { 20 | public: 21 | void queryMemoryRequirements(); 22 | EnvironmentLightState snapshotTextureObject(ASArena &arena); 23 | 24 | static void calculateEnvironmentLighting( 25 | int width, 26 | int height, 27 | ASArena &arena, 28 | cudaTextureObject_t textureObject, 29 | float *devOcclusionBuffer, 30 | float *devDirectionBuffer, 31 | std::vector &outputBuffer 32 | ); 33 | 34 | private: 35 | std::unique_ptr m_texturePtr; 36 | }; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /include/moana/cuda/fresnel.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/cuda/snell.hpp" 4 | 5 | namespace moana { namespace Fresnel { 6 | 7 | __device__ static float divide(const float a, const float b) 8 | { 9 | // assert(b != 0.f); 10 | 11 | return a / b; 12 | } 13 | 14 | __device__ inline float dielectricReflectance( 15 | float cosThetaIncident, 16 | float etaIncident, 17 | float etaTransmitted 18 | ) { 19 | const float sinThetaTransmitted = Snell::transmittedSinTheta( 20 | cosThetaIncident, 21 | etaIncident, 22 | etaTransmitted 23 | ); 24 | 25 | if (sinThetaTransmitted > 1.f) { 26 | return 1.f; // Total internal reflection 27 | } 28 | 29 | const float cosThetaTransmitted = sqrtf(fmaxf(0.f, 1.f - sinThetaTransmitted * sinThetaTransmitted)); 30 | 31 | const float rParallel = divide( 32 | etaTransmitted * cosThetaIncident - etaIncident * cosThetaTransmitted, 33 | etaTransmitted * cosThetaIncident + etaIncident * cosThetaTransmitted 34 | ); 35 | 36 | const float rPerpendicular = divide( 37 | etaIncident * cosThetaIncident - etaTransmitted * cosThetaTransmitted, 38 | etaIncident * cosThetaIncident + etaTransmitted * cosThetaTransmitted 39 | ); 40 | 41 | return 0.5f * (rParallel * rParallel + rPerpendicular * rPerpendicular); 42 | } 43 | 44 | 45 | } } 46 | -------------------------------------------------------------------------------- /include/moana/cuda/snell.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "moana/cuda/trig.hpp" 6 | #include "moana/core/vec3.hpp" 7 | 8 | namespace moana { namespace Snell { 9 | 10 | __device__ inline bool refract( 11 | const Vec3 &incidentLocal, 12 | Vec3 *transmittedLocal, 13 | Vec3 normal, 14 | float etaIncident, 15 | float etaTransmitted 16 | ) { 17 | if (dot(incidentLocal, normal) < 0.f) { 18 | normal = normal * -1.f; 19 | 20 | const float temp = etaIncident; 21 | etaIncident = etaTransmitted; 22 | etaTransmitted = temp; 23 | } 24 | 25 | const Vec3 wIncidentPerpendicular = incidentLocal - (normal * incidentLocal.dot(normal)); 26 | const Vec3 wTransmittedPerpendicular = -wIncidentPerpendicular * (etaIncident / etaTransmitted); 27 | 28 | const float transmittedPerpendicularLength2 = wTransmittedPerpendicular.length() * wTransmittedPerpendicular.length(); 29 | const float wTransmittedParallelLength = sqrtf(fmaxf(0.f, 1.f - transmittedPerpendicularLength2)); 30 | const Vec3 wTransmittedParallel = normal * -wTransmittedParallelLength; 31 | 32 | const float cosThetaIncident = absDot(incidentLocal, normal); 33 | const float sin2ThetaIncident = Trig::sin2FromCos(cosThetaIncident); 34 | const float eta2 = (etaIncident / etaTransmitted) * (etaIncident / etaTransmitted); 35 | const float sin2ThetaTransmitted = eta2 * sin2ThetaIncident; 36 | 37 | *transmittedLocal = normalized(wTransmittedParallel + wTransmittedPerpendicular); 38 | 39 | if (sin2ThetaTransmitted >= 1.f) { // total internal reflection 40 | return false; 41 | } 42 | return true; 43 | } 44 | 45 | __device__ inline bool refract( 46 | const Vec3 &incidentLocal, 47 | Vec3 *transmittedLocal, 48 | float etaIncident, 49 | float etaTransmitted 50 | ) { 51 | return refract( 52 | incidentLocal, 53 | transmittedLocal, 54 | Vec3(0.f, 0.f, 1.f), 55 | etaIncident, 56 | etaTransmitted 57 | ); 58 | } 59 | 60 | __device__ inline float transmittedSinTheta( 61 | float cosThetaIncident, 62 | float etaIncident, 63 | float etaTransmitted 64 | ) { 65 | return (etaIncident / etaTransmitted) * Trig::sinThetaFromCosTheta(cosThetaIncident); 66 | } 67 | 68 | } } 69 | -------------------------------------------------------------------------------- /include/moana/cuda/surface_sample.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/vec3.hpp" 4 | #include "moana/cuda/world_frame.hpp" 5 | 6 | namespace moana { 7 | 8 | struct SurfaceSample { 9 | Vec3 point; 10 | Vec3 normal; 11 | float areaPDF; 12 | 13 | __device__ float solidAnglePDF(const Vec3 &referencePoint) const 14 | { 15 | const Vec3 lightDirection = point - referencePoint; 16 | const Vec3 lightWo = -normalized(lightDirection); 17 | const float distance = lightDirection.length(); 18 | 19 | const float distance2 = distance * distance; 20 | const float projectedArea = WorldFrame::absCosTheta(normal, lightWo); 21 | 22 | if (projectedArea == 0.f) { return 0.f; } 23 | return areaPDF * distance2 / projectedArea; 24 | } 25 | }; 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /include/moana/cuda/tangent_frame.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/vec3.hpp" 4 | 5 | namespace moana { namespace TangentFrame { 6 | __device__ inline float cosTheta(const Vec3 &vector) 7 | { 8 | return vector.z(); 9 | } 10 | 11 | __device__ inline float absCosTheta(const Vec3 &vector) 12 | { 13 | return fabsf(vector.z()); 14 | } 15 | 16 | __device__ inline float cos2Theta(const Vec3 &vector) 17 | { 18 | return vector.z() * vector.z(); 19 | } 20 | 21 | __device__ inline float sin2Theta(const Vec3 &vector) 22 | { 23 | return 1.f - cos2Theta(vector); 24 | } 25 | 26 | __device__ inline float tan2Theta(const Vec3 &vector) 27 | { 28 | return sin2Theta(vector) / cos2Theta(vector); 29 | } 30 | 31 | __device__ inline float sinTheta(const Vec3 &vector) 32 | { 33 | return sqrtf(fmaxf(0.f, 1.f - cos2Theta(vector))); 34 | } 35 | 36 | __device__ inline float tanTheta(const Vec3 &vector) 37 | { 38 | return sinTheta(vector) / cosTheta(vector); 39 | } 40 | 41 | __device__ inline float absTanTheta(const Vec3 &vector) 42 | { 43 | return fabsf(tanTheta(vector)); 44 | } 45 | 46 | } } 47 | -------------------------------------------------------------------------------- /include/moana/cuda/triangle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/vec3.hpp" 4 | #include "moana/cuda/surface_sample.hpp" 5 | 6 | namespace moana { 7 | 8 | class Triangle { 9 | public: 10 | __host__ __device__ Triangle( 11 | const Vec3 &p0, 12 | const Vec3 &p1, 13 | const Vec3 &p2 14 | ) : m_p0(p0), 15 | m_p1(p1), 16 | m_p2(p2) 17 | {} 18 | 19 | __device__ float area() const { 20 | const Vec3 e1 = m_p1 - m_p0; 21 | const Vec3 e2 = m_p2 - m_p0; 22 | 23 | const Vec3 crossed = cross(e1, e2); 24 | return fabsf(crossed.length() / 2.f); 25 | } 26 | 27 | __device__ SurfaceSample sample(float xi1, float xi2) const { 28 | const float r1 = xi1; 29 | const float r2 = xi2; 30 | 31 | const float a = 1 - sqrtf(r1); 32 | const float b = sqrtf(r1) * (1 - r2); 33 | const float c = 1 - a - b; 34 | 35 | const Vec3 point = m_p0 * a + m_p1 * b + m_p2 * c; 36 | 37 | const Vec3 e1 = m_p1 - m_p0; 38 | const Vec3 e2 = m_p2 - m_p0; 39 | const Vec3 normal = normalized(cross(e1, e2)); 40 | 41 | SurfaceSample sample = { 42 | .point = point, 43 | .normal = normal, 44 | .areaPDF = 1.f / area() 45 | }; 46 | return sample; 47 | } 48 | 49 | private: 50 | Vec3 m_p0, m_p1, m_p2; 51 | }; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /include/moana/cuda/trig.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace moana { namespace Trig { 4 | __device__ inline float sinFromCos(float cosTheta) 5 | { 6 | const float sin2Theta = 1.f - (cosTheta * cosTheta); 7 | return sqrtf(fmaxf(0.f, sin2Theta)); 8 | } 9 | 10 | __device__ inline float sinThetaFromCosTheta(float cosTheta) 11 | { 12 | const float result = sqrtf(fmaxf(0.f, 1.f - cosTheta * cosTheta)); 13 | return result; 14 | } 15 | 16 | __device__ inline float sin2FromCos(float cosTheta) 17 | { 18 | return fmaxf(0.f, 1.f - (cosTheta * cosTheta)); 19 | } 20 | 21 | __device__ inline float cosFromSin2(float sin2Theta) 22 | { 23 | return sqrtf( 24 | fmaxf(0.f, 1.f - sin2Theta) 25 | ); 26 | } 27 | } } 28 | -------------------------------------------------------------------------------- /include/moana/cuda/world_frame.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/vec3.hpp" 4 | 5 | namespace moana { namespace WorldFrame { 6 | __device__ inline float cosTheta(const Vec3 &normal, const Vec3 &w) 7 | { 8 | return fmaxf( 9 | 0.f, 10 | dot(normal, w) 11 | ); 12 | } 13 | 14 | __device__ inline float absCosTheta(const Vec3 &normal, const Vec3 &w) 15 | { 16 | return fabsf(dot(normal, w)); 17 | } 18 | } }; 19 | -------------------------------------------------------------------------------- /include/moana/driver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "moana/core/bsdf_sample_record.hpp" 10 | #include "moana/core/camera.hpp" 11 | #include "moana/cuda/environment_light.hpp" 12 | #include "moana/scene.hpp" 13 | #include "moana/scene/as_arena.hpp" 14 | #include "moana/scene/types.hpp" 15 | #include "moana/render/pipeline.hpp" 16 | #include "moana/types.hpp" 17 | 18 | namespace moana { 19 | 20 | enum class PipelineType { 21 | MainRay = 0, 22 | ShadowRay = 1 23 | }; 24 | 25 | class Driver { 26 | public: 27 | void init(); 28 | void launch( 29 | RenderRequest renderRequest, 30 | Cam cam, 31 | const std::string &exrFilename 32 | ); 33 | 34 | private: 35 | std::map m_optixStates; 36 | SceneState m_sceneState; 37 | }; 38 | 39 | } 40 | -------------------------------------------------------------------------------- /include/moana/io/image.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace moana { namespace Image { 7 | 8 | // radiances[0] == top-left red 9 | void save( 10 | int width, 11 | int height, 12 | const std::vector &radiances, 13 | const std::string &filename 14 | ); 15 | 16 | } } 17 | -------------------------------------------------------------------------------- /include/moana/parsers/obj_parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace moana { 11 | 12 | struct MeshRecord { 13 | std::vector vertices = {}; 14 | std::vector vertexIndices = {}; 15 | 16 | std::vector normals = {}; 17 | std::vector normalIndices = {}; 18 | 19 | int indexTripletCount = 0; 20 | 21 | int materialIndex = 0; 22 | bool hidden = true; 23 | 24 | std::string name; 25 | }; 26 | 27 | enum class ObjFaceFormat { 28 | DoubleFaceVertexAndNormal, 29 | SingleFaceVertexAndNormal, 30 | Unknown 31 | }; 32 | 33 | enum class ParseState { 34 | Header = 0, 35 | Vertices, 36 | Normals, 37 | MeshName, 38 | Material, 39 | Faces, 40 | Complete, 41 | Error, 42 | }; 43 | 44 | class ObjParser { 45 | public: 46 | ObjParser( 47 | std::unique_ptr objFilePtr, 48 | const std::vector &mtlLookup 49 | ); 50 | 51 | ObjParser( 52 | const std::string &objFilename, 53 | const std::vector &mtlLookup 54 | ); 55 | 56 | std::vector parse(); 57 | 58 | private: 59 | struct GeometryOffsets { 60 | int verticesOffset = 0; 61 | int normalsOffset = 0; 62 | }; 63 | 64 | MeshRecord parseMesh(); 65 | 66 | void parseLine(std::string_view &line); 67 | 68 | void processVertex(std::string_view &vertexArgs, MeshRecord &record); 69 | void processNormal(std::string_view &normalArgs, MeshRecord &record); 70 | void processFace(std::string_view &faceArgs, MeshRecord &record); 71 | 72 | void processSingleFaceVertexAndNormal(std::string_view &faceArgs, MeshRecord &record); 73 | void processDoubleFaceVertexAndNormal(std::string_view &faceArgs, MeshRecord &record); 74 | 75 | void processTriangle( 76 | int vertexIndex0, int vertexIndex1, int vertexIndex2, 77 | int normalIndex0, int normalIndex1, int normalIndex2, 78 | MeshRecord &record 79 | ); 80 | 81 | template 82 | void correctIndex(const std::vector &indices, int offset, int *index); 83 | 84 | template 85 | void correctIndices( 86 | const std::vector &indices, 87 | int offset, 88 | int *index0, 89 | int *index1, 90 | int *index2 91 | ); 92 | 93 | ParseState parseHeader( 94 | std::string_view command, 95 | std::string_view rest, 96 | MeshRecord &record 97 | ); 98 | 99 | ParseState parseVertices( 100 | std::string_view command, 101 | std::string_view rest, 102 | MeshRecord &record 103 | ); 104 | 105 | ParseState parseNormals( 106 | std::string_view command, 107 | std::string_view rest, 108 | MeshRecord &record 109 | ); 110 | 111 | ParseState parseMeshName( 112 | std::string_view command, 113 | std::string_view rest, 114 | MeshRecord &record 115 | ); 116 | 117 | ParseState parseMaterial( 118 | std::string_view command, 119 | std::string_view rest, 120 | MeshRecord &record 121 | ); 122 | 123 | ParseState parseFaces( 124 | std::string_view command, 125 | std::string_view rest, 126 | MeshRecord &record 127 | ); 128 | 129 | std::unique_ptr m_objFilePtr; 130 | const std::vector m_mtlLookup; 131 | 132 | ObjFaceFormat m_faceFormat; 133 | 134 | GeometryOffsets m_offsets; 135 | }; 136 | 137 | } 138 | -------------------------------------------------------------------------------- /include/moana/parsers/string_util.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace moana { namespace StringUtil { 7 | 8 | std::optional lTrim(const std::string_view &token); 9 | 10 | } } 11 | -------------------------------------------------------------------------------- /include/moana/render/pipeline.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "moana/cuda/bsdf.hpp" 6 | #include "moana/scene/types.hpp" 7 | 8 | namespace moana { 9 | 10 | struct RayGenData {}; 11 | struct MissData {}; 12 | struct HitGroupData { 13 | float3 baseColor; 14 | int textureIndex; 15 | int materialID; 16 | BSDFType bsdfType; 17 | 18 | float *normals; 19 | int *normalIndices; 20 | }; 21 | 22 | struct OptixState { 23 | OptixPipeline pipeline = 0; 24 | OptixShaderBindingTable sbt = {}; 25 | }; 26 | 27 | } 28 | 29 | namespace moana { namespace Pipeline { 30 | 31 | void initOptixState( 32 | OptixState &optixState, 33 | OptixDeviceContext context, 34 | SceneState &sceneState 35 | ); 36 | 37 | } } 38 | 39 | namespace moana { namespace ShadowPipeline { 40 | 41 | void initOptixState( 42 | OptixState &optixState, 43 | OptixDeviceContext context, 44 | SceneState &sceneState 45 | ); 46 | 47 | } } 48 | -------------------------------------------------------------------------------- /include/moana/render/renderer.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "moana/driver.hpp" 8 | #include "moana/scene.hpp" 9 | #include "moana/scene/types.hpp" 10 | #include "moana/types.hpp" 11 | 12 | namespace moana { namespace Renderer { 13 | 14 | struct Params { 15 | OptixTraversableHandle handle; 16 | 17 | float *depthBuffer; 18 | float *xiBuffer; 19 | float *cosThetaWiBuffer; 20 | BSDFSampleRecord *sampleRecordInBuffer; 21 | BSDFSampleRecord *sampleRecordOutBuffer; 22 | float *occlusionBuffer; 23 | float *missDirectionBuffer; 24 | float *colorBuffer; 25 | float *barycentricBuffer; 26 | int *idBuffer; 27 | char *shadowOcclusionBuffer; 28 | float *shadowWeightBuffer; 29 | 30 | Camera camera; 31 | int bounce; 32 | int sampleCount; 33 | }; 34 | 35 | void launch( 36 | RenderRequest request, 37 | std::map &optixStates, 38 | SceneState &sceneState, 39 | Cam cam, 40 | const std::string &exrFilename 41 | ); 42 | 43 | } } 44 | -------------------------------------------------------------------------------- /include/moana/scene.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/camera.hpp" 4 | 5 | namespace moana { 6 | 7 | enum class Cam { 8 | BeachCam, 9 | BirdseyeCam, 10 | DunesACam, 11 | GrassCam, 12 | PalmsCam, 13 | RootsCam, 14 | ShotCam 15 | }; 16 | 17 | class Scene { 18 | public: 19 | Scene(Cam cam); 20 | 21 | Camera getCamera(int width, int height) const; 22 | 23 | private: 24 | Cam m_cam; 25 | }; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /include/moana/scene/as_arena.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace moana { 8 | 9 | struct Snapshot { 10 | void *dataPtr; 11 | size_t sizeInBytes; 12 | }; 13 | 14 | class ASArena { 15 | public: 16 | 17 | ASArena(); 18 | 19 | void init(size_t bytes); 20 | 21 | CUdeviceptr allocOutput(size_t bytes); 22 | void returnCompactedOutput(size_t bytes); 23 | 24 | Snapshot createSnapshot(); 25 | void restoreSnapshot(Snapshot snapshot); 26 | 27 | CUdeviceptr pushTemp(size_t bytes); 28 | void popTemp(); 29 | 30 | void releaseAll(); 31 | 32 | private: 33 | CUdeviceptr m_basePtr; 34 | size_t m_poolSizeInBytes; 35 | 36 | size_t m_outputOffset; 37 | size_t m_tempOffset; 38 | std::vector m_tempOffsetStack; 39 | }; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /include/moana/scene/types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "moana/cuda/environment_light.hpp" 9 | #include "moana/parsers/obj_parser.hpp" 10 | #include "moana/scene/as_arena.hpp" 11 | 12 | namespace moana { 13 | 14 | struct HostSBTRecord { 15 | CUdeviceptr d_normals; 16 | CUdeviceptr d_normalIndices; 17 | int materialID; 18 | int textureIndex; 19 | }; 20 | 21 | struct GeometryResult { 22 | OptixTraversableHandle handle; 23 | Snapshot snapshot; 24 | std::vector hostSBTRecords = {}; 25 | }; 26 | 27 | struct Instances { 28 | int count; 29 | float *transforms; 30 | }; 31 | 32 | struct SceneState { 33 | ASArena arena; 34 | std::vector geometries; 35 | EnvironmentLightState environmentState; 36 | }; 37 | 38 | } 39 | -------------------------------------------------------------------------------- /include/moana/types.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace moana { 4 | 5 | struct RenderRequest { 6 | int spp = 999999; 7 | int bounces = 9; 8 | int width = 1024; 9 | int height = 429; 10 | }; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /optix/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(ptx_files OBJECT kernel.cu) 2 | target_include_directories(ptx_files PRIVATE "${PROJECT_SOURCE_DIR}/include") 3 | target_include_directories(ptx_files PRIVATE "${PROJECT_CURRENT_SOURCE_DIR}") 4 | target_include_directories(ptx_files PRIVATE "${OptiX_INCLUDE}") 5 | target_include_directories(ptx_files PRIVATE "${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}") 6 | target_include_directories(ptx_files PRIVATE "${PROJECT_SOURCE_DIR}/ext/optix_sdk") 7 | set_property(TARGET ptx_files PROPERTY CUDA_PTX_COMPILATION ON) 8 | set_property(TARGET ptx_files PROPERTY POSITION_INDEPENDENT_CODE ON) 9 | target_compile_options(ptx_files PRIVATE $<$: --use_fast_math>) 10 | 11 | add_custom_target( 12 | ptx_headers 13 | COMMAND ${CMAKE_COMMAND} 14 | "-DCPP_FILE=${PROJECT_SOURCE_DIR}/src/render/kernel.hpp" 15 | "-DPTX_FILE=$" 16 | "-DVARIABLE_NAME=mainRaySource" 17 | "-DNAMESPACE=PTX" 18 | "-DCUDA_BIN2C_EXECUTABLE=bin2c" 19 | -P "${PROJECT_SOURCE_DIR}/cmake/ptx2cpp.cmake" 20 | DEPENDS ptx_files 21 | COMMENT "Convert ptx files to header file" 22 | ) 23 | 24 | # fixme: macro 25 | add_library(shadow_ptx_files OBJECT shadow_ray_kernel.cu) 26 | target_include_directories(shadow_ptx_files PRIVATE "${PROJECT_SOURCE_DIR}/include") 27 | target_include_directories(shadow_ptx_files PRIVATE "${PROJECT_CURRENT_SOURCE_DIR}") 28 | target_include_directories(shadow_ptx_files PRIVATE "${OptiX_INCLUDE}") 29 | target_include_directories(shadow_ptx_files PRIVATE "${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}") 30 | target_include_directories(shadow_ptx_files PRIVATE "${PROJECT_SOURCE_DIR}/ext/optix_sdk") 31 | set_property(TARGET shadow_ptx_files PROPERTY CUDA_PTX_COMPILATION ON) 32 | set_property(TARGET shadow_ptx_files PROPERTY POSITION_INDEPENDENT_CODE ON) 33 | target_compile_options(shadow_ptx_files PRIVATE $<$: --use_fast_math>) 34 | 35 | add_custom_target( 36 | shadow_ray_ptx_headers 37 | COMMAND ${CMAKE_COMMAND} 38 | "-DCPP_FILE=${PROJECT_SOURCE_DIR}/src/render/shadow_ray_kernel.hpp" 39 | "-DPTX_FILE=$" 40 | "-DVARIABLE_NAME=shadowRaySource" 41 | "-DNAMESPACE=PTX" 42 | "-DCUDA_BIN2C_EXECUTABLE=bin2c" 43 | -P "${PROJECT_SOURCE_DIR}/cmake/ptx2cpp.cmake" 44 | DEPENDS shadow_ptx_files 45 | COMMENT "Convert ptx files to header file" 46 | ) 47 | 48 | -------------------------------------------------------------------------------- /optix/bsdfs/lambertian.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/bsdf_sample_record.hpp" 4 | #include "moana/core/frame.hpp" 5 | #include "ray_data.hpp" 6 | #include "sample.hpp" 7 | 8 | namespace moana { namespace Lambertian { 9 | 10 | __forceinline__ __device__ BSDFSampleRecord sample( 11 | uint3 index, 12 | uint3 dim, 13 | const PerRayData &prd, 14 | const float *xiBuffer 15 | ) { 16 | const int xiIndex = 2 * (index.y * dim.x + index.x); 17 | const float xi1 = xiBuffer[xiIndex + 0]; 18 | const float xi2 = xiBuffer[xiIndex + 1]; 19 | 20 | const Frame frame(prd.normal); 21 | const Vec3 wiLocal = Sample::uniformHemisphere(xi1, xi2); 22 | const float weight = 2.f; 23 | 24 | const BSDFSampleRecord record = { 25 | .isValid = true, 26 | .point = prd.point, 27 | .wiLocal = wiLocal, 28 | .normal = prd.normal, 29 | .frame = frame, 30 | .weight = weight, 31 | .isDelta = false, 32 | }; 33 | 34 | return record; 35 | } 36 | 37 | } } 38 | -------------------------------------------------------------------------------- /optix/bsdfs/water.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/bsdf_sample_record.hpp" 4 | #include "moana/core/frame.hpp" 5 | #include "moana/cuda/fresnel.hpp" 6 | #include "moana/cuda/tangent_frame.hpp" 7 | #include "ray_data.hpp" 8 | #include "util.hpp" 9 | 10 | namespace moana { namespace Water { 11 | 12 | __forceinline__ __device__ BSDFSampleRecord sample( 13 | uint3 index, 14 | uint3 dim, 15 | const PerRayData &prd, 16 | const float *xiBuffer 17 | ) { 18 | const Frame frame(prd.normal); 19 | 20 | const int xiIndex = 2 * (index.y * dim.x + index.x); 21 | const float xi1 = xiBuffer[xiIndex + 0]; // fixme 22 | 23 | const Vec3 wo = frame.toLocal(prd.woWorld); 24 | 25 | float etaIncident = 1.f; 26 | float etaTransmitted = 1.33f; 27 | 28 | if (prd.isInside) { 29 | const float temp = etaIncident; 30 | etaIncident = etaTransmitted; 31 | etaTransmitted = temp; 32 | } 33 | 34 | Vec3 wi(0.f); 35 | const bool doesRefract = Snell::refract( 36 | wo, 37 | &wi, 38 | etaIncident, 39 | etaTransmitted 40 | ); 41 | 42 | const float fresnelReflectance = Fresnel::dielectricReflectance( 43 | TangentFrame::absCosTheta(wo), 44 | etaIncident, 45 | etaTransmitted 46 | ); 47 | 48 | if (xi1 < fresnelReflectance) { 49 | wi = wo.reflect(Vec3(0.f, 0.f, 1.f)); 50 | 51 | const float cosTheta = TangentFrame::absCosTheta(wi); 52 | const float throughput = cosTheta == 0.f 53 | ? 0.f 54 | : fresnelReflectance / cosTheta 55 | ; 56 | const BSDFSampleRecord record = { 57 | .isValid = true, 58 | .point = prd.point, 59 | .wiLocal = wi, 60 | .normal = prd.normal, 61 | .frame = frame, 62 | .weight = throughput / fresnelReflectance, 63 | .isDelta = true, 64 | }; 65 | 66 | return record; 67 | } else { 68 | const float fresnelTransmittance = 1.f - fresnelReflectance; 69 | 70 | const float cosTheta = TangentFrame::absCosTheta(wi); 71 | const float throughput = cosTheta == 0.f 72 | ? 0.f 73 | : fresnelTransmittance / cosTheta 74 | ; 75 | 76 | // PBRT page 961 "Non-symmetry Due to Refraction" 77 | // Always incident / transmitted because we swap at top of 78 | // function if we're going inside-out 79 | const float nonSymmetricEtaCorrection = util::square( 80 | etaIncident / etaTransmitted 81 | ); 82 | 83 | const BSDFSampleRecord record = { 84 | .isValid = true, 85 | .point = prd.point, 86 | .wiLocal = wi, 87 | .normal = prd.normal, 88 | .frame = frame, 89 | .weight = throughput * nonSymmetricEtaCorrection / fresnelTransmittance, 90 | .isDelta = true, 91 | }; 92 | 93 | return record; 94 | } 95 | 96 | } 97 | 98 | } } 99 | -------------------------------------------------------------------------------- /optix/optix_sdk.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions 6 | // are met: 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // * Neither the name of NVIDIA CORPORATION nor the names of its 13 | // contributors may be used to endorse or promote products derived 14 | // from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | // 28 | #pragma once 29 | 30 | #include "cuda/curve.h" 31 | 32 | // Get curve hit-point in world coordinates. 33 | static __forceinline__ __device__ float3 getHitPoint() 34 | { 35 | const float t = optixGetRayTmax(); 36 | const float3 rayOrigin = optixGetWorldRayOrigin(); 37 | const float3 rayDirection = optixGetWorldRayDirection(); 38 | 39 | return rayOrigin + t * rayDirection; 40 | } 41 | 42 | static __forceinline__ __device__ float3 normalCubic( const int primitiveIndex ) 43 | { 44 | const OptixTraversableHandle gas = optixGetGASTraversableHandle(); 45 | const unsigned int gasSbtIndex = optixGetSbtGASIndex(); 46 | float4 controlPoints[4]; 47 | 48 | optixGetCubicBSplineVertexData( gas, primitiveIndex, gasSbtIndex, 0.0f, controlPoints ); 49 | 50 | CubicBSplineSegment interpolator( controlPoints ); 51 | float3 hitPoint = getHitPoint(); 52 | // interpolators work in object space 53 | hitPoint = optixTransformPointFromWorldToObjectSpace( hitPoint ); 54 | const float3 normal = surfaceNormal( interpolator, optixGetCurveParameter(), hitPoint ); 55 | return optixTransformNormalFromObjectToWorldSpace( normal ); 56 | } 57 | -------------------------------------------------------------------------------- /optix/random.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions 8 | // are met: 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above copyright 12 | // notice, this list of conditions and the following disclaimer in the 13 | // documentation and/or other materials provided with the distribution. 14 | // * Neither the name of NVIDIA CORPORATION nor the names of its 15 | // contributors may be used to endorse or promote products derived 16 | // from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 19 | // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 22 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 26 | // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | 31 | template 32 | static __host__ __device__ __inline__ unsigned int tea( unsigned int val0, unsigned int val1 ) 33 | { 34 | unsigned int v0 = val0; 35 | unsigned int v1 = val1; 36 | unsigned int s0 = 0; 37 | 38 | for( unsigned int n = 0; n < N; n++ ) 39 | { 40 | s0 += 0x9e3779b9; 41 | v0 += ((v1<<4)+0xa341316c)^(v1+s0)^((v1>>5)+0xc8013ea4); 42 | v1 += ((v0<<4)+0xad90777d)^(v0+s0)^((v0>>5)+0x7e95761e); 43 | } 44 | 45 | return v0; 46 | } 47 | 48 | // Generate random unsigned int in [0, 2^24) 49 | static __host__ __device__ __inline__ unsigned int lcg(unsigned int &prev) 50 | { 51 | const unsigned int LCG_A = 1664525u; 52 | const unsigned int LCG_C = 1013904223u; 53 | prev = (LCG_A * prev + LCG_C); 54 | return prev & 0x00FFFFFF; 55 | } 56 | 57 | static __host__ __device__ __inline__ unsigned int lcg2(unsigned int &prev) 58 | { 59 | prev = (prev*8121 + 28411) % 134456; 60 | return prev; 61 | } 62 | 63 | // Generate random float in [0, 1) 64 | static __host__ __device__ __inline__ float rnd(unsigned int &prev) 65 | { 66 | return ((float) lcg(prev) / (float) 0x01000000); 67 | } 68 | 69 | static __host__ __device__ __inline__ unsigned int rot_seed( unsigned int seed, unsigned int frame ) 70 | { 71 | return seed ^ frame; 72 | } 73 | -------------------------------------------------------------------------------- /optix/ray_data.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/vec3.hpp" 4 | #include "moana/cuda/bsdf.hpp" 5 | 6 | namespace moana { 7 | 8 | struct PerRayData { 9 | bool isHit; 10 | float t; 11 | float3 point; 12 | Vec3 normal; 13 | Vec3 woWorld; 14 | float3 baseColor; 15 | int materialID; 16 | BSDFType bsdfType; 17 | int primitiveID; 18 | int textureIndex; 19 | float2 barycentrics; 20 | bool isInside; 21 | }; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /optix/sample.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "moana/core/vec3.hpp" 4 | 5 | namespace moana { namespace Sample { 6 | 7 | __device__ inline Vec3 uniformHemisphere(float xi1, float xi2) 8 | { 9 | const float z = xi1; 10 | const float r = sqrtf(fmaxf(0.f, 1.f - z * z)); 11 | 12 | const float phi = 2 * M_PI * xi2; 13 | const float x = r * cos(phi); 14 | const float y = r * sin(phi); 15 | 16 | return Vec3(x, y, z); 17 | } 18 | 19 | __device__ inline float uniformHemispherePDF(const Vec3& vector) 20 | { 21 | if (vector.z() < 0.f) { return 0.f; } 22 | 23 | return 1.f / (2.f * M_PI); 24 | } 25 | 26 | } } 27 | -------------------------------------------------------------------------------- /optix/shadow_ray_kernel.cu: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "moana/core/bsdf_sample_record.hpp" 6 | #include "moana/core/camera.hpp" 7 | #include "moana/core/frame.hpp" 8 | #include "moana/core/ray.hpp" 9 | #include "moana/cuda/triangle.hpp" 10 | #include "moana/driver.hpp" 11 | #include "moana/render/renderer.hpp" 12 | #include "optix_sdk.hpp" 13 | #include "random.hpp" 14 | #include "sample.hpp" 15 | #include "util.hpp" 16 | 17 | using namespace moana; 18 | 19 | struct PerRayData { 20 | bool isHit; 21 | }; 22 | 23 | extern "C" { 24 | __constant__ Renderer::Params params; 25 | } 26 | 27 | __forceinline__ __device__ static PerRayData *getPRD() 28 | { 29 | const unsigned int u0 = optixGetPayload_0(); 30 | const unsigned int u1 = optixGetPayload_1(); 31 | return reinterpret_cast(util::unpackPointer(u0, u1)); 32 | } 33 | 34 | extern "C" __global__ void __miss__ms() 35 | { 36 | PerRayData *prd = getPRD(); 37 | prd->isHit = false; 38 | } 39 | 40 | extern "C" __global__ void __closesthit__ch() 41 | { 42 | } 43 | 44 | extern "C" __global__ void __raygen__rg() 45 | { 46 | const uint3 index = optixGetLaunchIndex(); 47 | const uint3 dim = optixGetLaunchDimensions(); 48 | 49 | const int shadowOcclusionIndex = 1 * (index.y * dim.x + index.x); 50 | 51 | const int sampleRecordIndex = 1 * (index.y * dim.x + index.x); 52 | const BSDFSampleRecord &sampleRecord = params.sampleRecordOutBuffer[sampleRecordIndex]; 53 | if (!sampleRecord.isValid) { 54 | params.shadowOcclusionBuffer[shadowOcclusionIndex] = 1; 55 | 56 | return; 57 | } 58 | 59 | const int shadowWeightIndex = 1 * (index.y * dim.x + index.x); 60 | if (sampleRecord.isDelta) { 61 | params.shadowWeightBuffer[shadowWeightIndex] = 0.f; 62 | 63 | return; 64 | } 65 | 66 | unsigned int seed = tea<4>( 67 | index.y * dim.x + index.x, 68 | params.sampleCount + (dim.x * dim.y * params.bounce) 69 | ); 70 | const float xi1 = rnd(seed); 71 | const float xi2 = rnd(seed); 72 | const float xi3 = rnd(seed); 73 | 74 | const Triangle t1( 75 | Vec3(101346.539, 202660.438, 189948.188), 76 | Vec3(106779.617, 187339.562, 201599.453), 77 | Vec3(83220.3828, 202660.438, 198400.547) 78 | ); 79 | const Triangle t2( 80 | Vec3(101346.539, 202660.438, 189948.188), 81 | Vec3(88653.4609, 187339.562, 210051.812), 82 | Vec3(88653.4609, 187339.562, 210051.812) 83 | ); 84 | 85 | const Triangle *sampleTriangle; 86 | if (xi1 < 0.5f) { 87 | sampleTriangle = &t1; 88 | } else { 89 | sampleTriangle = &t2; 90 | } 91 | 92 | const SurfaceSample lightSample = sampleTriangle->sample(xi2, xi3); 93 | 94 | const Vec3 origin(sampleRecord.point.x, sampleRecord.point.y, sampleRecord.point.z); 95 | const Vec3 lightPoint = lightSample.point; 96 | const Vec3 lightDirection = lightPoint - origin; 97 | const Vec3 wi = normalized(lightDirection); 98 | const float tMax = lightDirection.length(); 99 | 100 | PerRayData prd; 101 | prd.isHit = true; 102 | 103 | unsigned int p0, p1; 104 | util::packPointer(&prd, p0, p1); 105 | 106 | optixTrace( 107 | params.handle, 108 | float3{ origin.x(), origin.y(), origin.z() }, 109 | float3{ wi.x(), wi.y(), wi.z() }, 110 | 2e-3, 111 | tMax - 1e-4, 112 | 0.f, 113 | OptixVisibilityMask(255), 114 | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT | OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT, 115 | 0, 1, 0, // SBT params 116 | p0, p1 117 | ); 118 | 119 | const Vec3 lightNormal = Vec3(-0.323744059f, -0.642787874f, -0.694271863f); 120 | 121 | if (prd.isHit) { 122 | params.shadowOcclusionBuffer[shadowOcclusionIndex] = 1; 123 | } 124 | 125 | params.shadowWeightBuffer[shadowWeightIndex] = 1.f 126 | * fabsf(dot(lightNormal, -wi)) 127 | * fmaxf(0.f, dot(wi, sampleRecord.normal)) 128 | * (20000.f * 20000.f) / (lightDirection.length() * lightDirection.length()) 129 | * (1.f / M_PI) 130 | ; 131 | } 132 | -------------------------------------------------------------------------------- /optix/util.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace moana { namespace util { 4 | 5 | __forceinline__ __device__ void *unpackPointer(unsigned int i0, unsigned int i1) 6 | { 7 | const unsigned long long uptr = static_cast(i0) << 32 | i1; 8 | void *ptr = reinterpret_cast(uptr); 9 | return ptr; 10 | } 11 | 12 | __forceinline__ __device__ void packPointer( 13 | void *ptr, 14 | unsigned int &i0, 15 | unsigned int &i1 16 | ) { 17 | const unsigned long long uptr = reinterpret_cast(ptr); 18 | i0 = uptr >> 32; 19 | i1 = uptr & 0x00000000ffffffff; 20 | } 21 | 22 | __forceinline__ __device__ float square(float x) { 23 | return x * x; 24 | } 25 | 26 | } } 27 | -------------------------------------------------------------------------------- /refs/beachCam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chellmuth/gpu-motunui/1369c98408c4c59bfddff45ae00281f6463527ec/refs/beachCam.png -------------------------------------------------------------------------------- /refs/birdseyeCam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chellmuth/gpu-motunui/1369c98408c4c59bfddff45ae00281f6463527ec/refs/birdseyeCam.png -------------------------------------------------------------------------------- /refs/dunesACam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chellmuth/gpu-motunui/1369c98408c4c59bfddff45ae00281f6463527ec/refs/dunesACam.png -------------------------------------------------------------------------------- /refs/grassCam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chellmuth/gpu-motunui/1369c98408c4c59bfddff45ae00281f6463527ec/refs/grassCam.png -------------------------------------------------------------------------------- /refs/palmsCam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chellmuth/gpu-motunui/1369c98408c4c59bfddff45ae00281f6463527ec/refs/palmsCam.png -------------------------------------------------------------------------------- /refs/rootsCam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chellmuth/gpu-motunui/1369c98408c4c59bfddff45ae00281f6463527ec/refs/rootsCam.png -------------------------------------------------------------------------------- /refs/shotCam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chellmuth/gpu-motunui/1369c98408c4c59bfddff45ae00281f6463527ec/refs/shotCam.png -------------------------------------------------------------------------------- /scene/.gitignore: -------------------------------------------------------------------------------- 1 | * -------------------------------------------------------------------------------- /scripts/.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | -------------------------------------------------------------------------------- /scripts/curves.py: -------------------------------------------------------------------------------- 1 | import json 2 | import struct 3 | 4 | def reflect(reflected_point, pivot_point): 5 | return [ 6 | pivot_point[0] + (pivot_point[0] - reflected_point[0]), 7 | pivot_point[1] + (pivot_point[1] - reflected_point[1]), 8 | pivot_point[2] + (pivot_point[2] - reflected_point[2]), 9 | ] 10 | 11 | def pin_curve(curve): 12 | p_first = reflect(curve[1], curve[0]) 13 | p_last = reflect(curve[-2], curve[-1]) 14 | 15 | return [ p_first ] + curve + [ p_last ] 16 | 17 | def write_curve_bin(curve_info, bin_path): 18 | print("Writing:", curve_info.json_path) 19 | 20 | curves = json.load(open(curve_info.json_path)) 21 | print(" Curve count:", len(curves)) 22 | 23 | f = open(bin_path, "wb") 24 | 25 | curve_lengths = set() 26 | for curve in curves: 27 | curve_lengths.add(len(curve)) 28 | 29 | # Strand count 30 | f.write(struct.pack("i", len(curves))) 31 | 32 | # Vertices per strand 33 | assert(len(curve_lengths) == 1) 34 | f.write(struct.pack("i", len(curves[0]) + 2)) # phantom points to pin the curve 35 | 36 | # Widths: 37 | # 1. Root 38 | # 2. Tip 39 | f.write(struct.pack("2f", curve_info.width_root, curve_info.width_tip)) 40 | 41 | # Vertex data 42 | for curve in curves: 43 | pinned_curve = pin_curve(curve) 44 | for control_point in pinned_curve: 45 | f.write(struct.pack("3f", *control_point)) 46 | 47 | # def read_curve(): 48 | # f = open("../scene/curve.bin", "rb") 49 | 50 | # length, = struct.unpack("i", f.read(4)) 51 | # print(length) 52 | 53 | # for _ in range(length): 54 | # for _ in range(6): 55 | # x, y, z = struct.unpack("3f", f.read(4 * 3)) 56 | # print(x, y, z) 57 | 58 | # break 59 | -------------------------------------------------------------------------------- /scripts/dupe_detector.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | import files 4 | import params 5 | from obj import obj_tokens 6 | 7 | DoubleMeshRecord = collections.namedtuple("DoubleMeshRecord", [ 8 | "obj_filename", 9 | "mesh", 10 | "count", 11 | ]) 12 | 13 | def find_double_meshes(obj_filename): 14 | mesh_counts = collections.defaultdict(int) 15 | 16 | with open(obj_filename, "r") as obj: 17 | for line in obj: 18 | tokens = line.strip().split() 19 | if not tokens: continue 20 | if tokens[0] == "g": 21 | mesh = tokens[1] 22 | if mesh == "default": continue 23 | 24 | mesh_counts[mesh] += 1 25 | 26 | records = [] 27 | for mesh, count in mesh_counts.items(): 28 | if count > 1: 29 | record = DoubleMeshRecord( 30 | obj_filename.relative_to(params.MoanaPath), 31 | mesh, 32 | count 33 | ) 34 | records.append(record) 35 | 36 | return records 37 | 38 | def check_default_mesh_on_all_geometry(obj_filename): 39 | current_mesh = None 40 | 41 | for command, rest in obj_tokens(obj_filename): 42 | if command == "g": 43 | current_mesh = rest 44 | elif command in [ "v", "vn" ]: 45 | if current_mesh != "default": 46 | return False 47 | 48 | return True 49 | 50 | def check_independent_meshes(obj_filename): 51 | vertex_offset = 0 52 | normal_offset = 0 53 | 54 | vertex_count = 0 55 | normal_count = 0 56 | 57 | for command, rest in obj_tokens(obj_filename): 58 | if command == "v": 59 | vertex_count += 1 60 | elif command == "n": 61 | normal_count += 1 62 | elif command == "g": 63 | if rest.startswith("default"): 64 | vertex_offset = vertex_count 65 | normal_offset = normal_count 66 | elif command == "f": 67 | v0, n0, v1, n1, v2, n2, v3, n3 = [ 68 | int(num) 69 | for num in rest.replace("/", " ").split(" ") 70 | if num 71 | ] 72 | 73 | valid_indices = [ 74 | v0 - vertex_offset >= 1, 75 | v1 - vertex_offset >= 1, 76 | v2 - vertex_offset >= 1, 77 | n0 - normal_offset >= 1, 78 | n1 - normal_offset >= 1, 79 | n2 - normal_offset >= 1, 80 | ] 81 | 82 | if not all(valid_indices): 83 | print(obj_filename) 84 | 85 | def check_duplicate_mesh(obj_filename, mesh): 86 | first_mesh_vertices = [] 87 | first_mesh_normals = [] 88 | first_face_indices = [] 89 | second_face_indices = [] 90 | 91 | current_vertices = [] 92 | current_normals = [] 93 | 94 | assert_next_line_not_usemtl = False 95 | 96 | found_first_mesh = False 97 | collect_first_face = False 98 | collect_second_face = False 99 | for command, rest in obj_tokens(obj_filename): 100 | if command == "v": 101 | current_vertices.append(rest) 102 | elif command == "n": 103 | current_normals.append(rest) 104 | elif command == "g": 105 | collect_first_face = False 106 | 107 | if collect_second_face: 108 | break 109 | 110 | if rest.startswith("default"): 111 | current_vertices = [] 112 | current_normals = [] 113 | 114 | elif rest.startswith(mesh): 115 | if found_first_mesh: 116 | conditions = [ 117 | current_vertices == first_mesh_vertices, 118 | current_normals == first_mesh_normals, 119 | ] 120 | if not all(conditions): 121 | return False 122 | 123 | collect_second_face = True 124 | assert_next_line_not_usemtl = True 125 | continue 126 | else: 127 | first_mesh_vertices = current_vertices 128 | first_mesh_normals = current_normals 129 | 130 | found_first_mesh = True 131 | collect_first_face = True 132 | elif command == "usemtl" and assert_next_line_not_usemtl: 133 | return False 134 | elif command == "f": 135 | assert not (collect_first_face and collect_second_face) 136 | 137 | if collect_first_face: 138 | indices = [ 139 | int(num) 140 | for num in rest.replace("/", " ").split(" ") 141 | if num 142 | ] 143 | first_face_indices.extend(indices) 144 | elif collect_second_face: 145 | indices = [ 146 | int(num) 147 | for num in rest.replace("/", " ").split(" ") 148 | if num 149 | ] 150 | second_face_indices.extend(indices) 151 | 152 | assert_next_line_not_usemtl = False 153 | 154 | assert len(first_face_indices) > 0 155 | assert len(second_face_indices) > 0 156 | 157 | # Finished parsing the second mesh's faces 158 | indices_differences = [ 159 | i - j 160 | for i, j 161 | in zip(second_face_indices, first_face_indices) 162 | ] 163 | vertex_difference = indices_differences[0] 164 | normal_difference = indices_differences[1] 165 | 166 | return all( 167 | i % 2 == 0 and diff == vertex_difference or diff == normal_difference 168 | for i, diff in enumerate(indices_differences) 169 | ) 170 | 171 | if __name__ == "__main__": 172 | for element_name in params.elements: 173 | valid = True 174 | print(f"Checking default mesh use {element_name}: ", end="") 175 | for obj_filename in files.find_obj_files(element_name): 176 | if not check_default_mesh_on_all_geometry(obj_filename): 177 | print() 178 | print(obj_filename) 179 | valid = False 180 | if valid: 181 | print("OK!") 182 | 183 | for element_name in params.elements: 184 | print(f"Checking independent meshes {element_name}:") 185 | for obj_filename in files.find_obj_files(element_name): 186 | check_independent_meshes(obj_filename) 187 | 188 | for element_name in params.elements: 189 | print(f"Checking double meshes {element_name}:") 190 | for obj_filename in files.find_obj_files(element_name): 191 | records = find_double_meshes(obj_filename) 192 | for record in records: 193 | print(f" [{record.obj_filename}] {record.mesh}={record.count}") 194 | 195 | print(f" Checking dupe: ", end="") 196 | if check_duplicate_mesh(obj_filename, record.mesh): 197 | print("OKAY!") 198 | else: 199 | print("BAD!") 200 | -------------------------------------------------------------------------------- /scripts/files.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | from pathlib import Path 4 | 5 | import hardcoded_data 6 | from params import MoanaPath 7 | 8 | class PtexLookup: 9 | def __init__(self, elements): 10 | self.lookup = [] 11 | self.ptxs = [] 12 | 13 | for element_name in elements: 14 | ptx_files = sorted(find_ptx_files(element_name, full_path=False)) 15 | mapped_files = [ 16 | (element_name, ptx_file.stem) 17 | for ptx_file 18 | in ptx_files 19 | ] 20 | 21 | self.lookup.extend(mapped_files) 22 | self.ptxs.extend(ptx_files) 23 | 24 | def has_texture(self, element_name, stem): 25 | if (element_name, stem) in self.lookup: 26 | return True 27 | 28 | if element_name in hardcoded_data.cross_element_texture_access: 29 | cross_element = hardcoded_data.cross_element_texture_access[element_name] 30 | return (cross_element, stem) in self.lookup 31 | 32 | def index_of_stem(self, element_name, stem): 33 | original_key = (element_name, stem) 34 | if original_key in self.lookup: 35 | return self.lookup.index(original_key) 36 | 37 | cross_element = hardcoded_data.cross_element_texture_access[element_name] 38 | cross_key = (cross_element, stem) 39 | return self.lookup.index(cross_key) 40 | 41 | def filename_list(self): 42 | return self.ptxs 43 | 44 | def find_ptx_files(element_name, full_path=True): 45 | results = [] 46 | 47 | root_path = MoanaPath / f"textures/{element_name}" 48 | for root, directories, filenames in os.walk(root_path): 49 | if "Displacement" in root: continue 50 | 51 | for filename in filenames: 52 | if filename.endswith(".ptx"): 53 | path = Path(root) / filename 54 | if full_path: 55 | results.append(path) 56 | else: 57 | results.append(path.relative_to(MoanaPath)) 58 | 59 | return results 60 | 61 | def find_obj_files(element_name): 62 | element_path = f"json/{element_name}/{element_name}.json" 63 | element_json = json.load(open(MoanaPath / element_path)) 64 | 65 | roots = [element_json] 66 | roots.extend([ 67 | instanced_copy 68 | for instanced_copy 69 | in element_json.get("instancedCopies", {}).values() 70 | ]) 71 | 72 | results = set() 73 | for root in roots: 74 | key = "geomObjFile" 75 | if key in root: 76 | results.add(root[key]) 77 | 78 | primitives = root.get("instancedPrimitiveJsonFiles", {}) 79 | for primitives_item in primitives.values(): 80 | if primitives_item["type"] == "archive": 81 | results.update(primitives_item["archives"]) 82 | 83 | return [ 84 | MoanaPath / obj_file for obj_file in sorted(results) 85 | ] 86 | 87 | def find_material_json_file(element_name): 88 | element_path = f"json/{element_name}/{element_name}.json" 89 | element_json = json.load(open(MoanaPath / element_path)) 90 | 91 | return MoanaPath / element_json["matFile"] 92 | -------------------------------------------------------------------------------- /scripts/hardcoded_data.py: -------------------------------------------------------------------------------- 1 | cross_element_texture_access = { 2 | "isMountainB": "isPalmRig", 3 | "isDunesA": "isHibiscus", 4 | "isDunesB": "isIronwoodA1", 5 | } 6 | 7 | overflow_elements = set([ 8 | "isIronwoodA1", 9 | "isIronwoodB", 10 | ]) 11 | 12 | split_primitive_instances_elements = set([ 13 | "isBeach" 14 | ]) 15 | -------------------------------------------------------------------------------- /scripts/materials.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import json 3 | import pprint 4 | 5 | from params import MoanaPath 6 | 7 | SBTRecord = collections.namedtuple("SBTRecord", [ "name", "base_color"]) 8 | 9 | def build_sbt_manager(elements): 10 | print("Processing materials:") 11 | 12 | # Collect material information for SBT 13 | sbt_manager = SBTManager() 14 | for element_name in elements: 15 | print(f"Processing: {element_name}") 16 | 17 | element_path = f"json/{element_name}/{element_name}.json" 18 | element_json = json.load(open(MoanaPath / element_path)) 19 | 20 | material_digest_path = MoanaPath / element_json["matFile"] 21 | sbt_manager.add_material_digest(element_name, material_digest_path) 22 | 23 | return sbt_manager 24 | 25 | class SBTManager: 26 | def __init__(self): 27 | self.records_by_element = {} 28 | self.curve_assignments = {} 29 | 30 | def add_material_digest(self, element, digest_path): 31 | records = [] 32 | 33 | material_json = json.load(open(digest_path)) 34 | for name, properties in material_json.items(): 35 | if name == "hidden": 36 | base_color = [ 0., 0., 1. ] 37 | else: 38 | base_color = properties["baseColor"][:3] 39 | 40 | record = SBTRecord(name, base_color) 41 | records.append(record) 42 | 43 | for assignee in properties["assignment"]: 44 | self.curve_assignments[(element, assignee)] = name 45 | 46 | self.records_by_element[element] = records 47 | 48 | def get_base_colors(self): 49 | result = [ (0., 0., 0.) ] # unmapped default material 50 | for element_name in sorted(self.records_by_element.keys()): 51 | element_records = sorted( 52 | self.records_by_element[element_name], 53 | key=lambda r: r.name 54 | ) 55 | print([e.name for e in element_records]) 56 | for record in element_records: 57 | result.append(record.base_color) 58 | 59 | return result 60 | 61 | def get_base_colors_annotated(self, gamma_correct=True): 62 | exponent = 1 63 | if gamma_correct: 64 | exponent = 2.2 65 | 66 | result = [ ((0., 0., 0.), "missing material") ] 67 | for element_name in sorted(self.records_by_element.keys()): 68 | element_records = sorted( 69 | self.records_by_element[element_name], 70 | key=lambda r: r.name 71 | ) 72 | 73 | for i, record in enumerate(element_records): 74 | comment = f"{element_name}: {record.name}" 75 | result.append(( 76 | [ c ** exponent for c in record.base_color ], 77 | comment 78 | )) 79 | 80 | return result 81 | 82 | def get_bsdf_types_annotated(self): 83 | result = [ ("BSDFType::Diffuse", "missing material") ] 84 | for element_name in sorted(self.records_by_element.keys()): 85 | element_records = sorted( 86 | self.records_by_element[element_name], 87 | key=lambda r: r.name 88 | ) 89 | 90 | for i, record in enumerate(element_records): 91 | comment = f"{element_name}: {record.name}" 92 | if record.name == "water": 93 | bsdf_type = "BSDFType::Water" 94 | else: 95 | bsdf_type = "BSDFType::Diffuse" 96 | 97 | result.append((bsdf_type, comment)) 98 | 99 | return result 100 | 101 | def get_names(self, search_element): 102 | records = self.records_by_element[search_element] 103 | return sorted( 104 | record.name 105 | for record in records 106 | ) 107 | 108 | def get_material_offset(self, search_element): 109 | offset = 1 # account for default material 110 | for element_name in sorted(self.records_by_element.keys()): 111 | if element_name == search_element: 112 | return offset 113 | 114 | offset += len(self.records_by_element[element_name]) 115 | 116 | raise ValueError("Invalid search element") 117 | 118 | def get_mtl_index_for_curve(self, element_name, curve_name): 119 | try: 120 | material_name = self.curve_assignments[(element_name, curve_name)] 121 | return self.get_names(element_name).index(material_name) 122 | except KeyError: 123 | # fixme 124 | assert element_name == "isCoastline" 125 | assert curve_name == "xgGrass" 126 | return 0 127 | 128 | # Items are (element_name, material_name) tuples 129 | def get_material_list(self): 130 | nested_materials = [ 131 | (element, material) 132 | for element in sorted(self.records_by_element.keys()) 133 | for material in self.get_names(element) 134 | ] 135 | 136 | # account for default material 137 | return [()] + nested_materials 138 | -------------------------------------------------------------------------------- /scripts/obj.py: -------------------------------------------------------------------------------- 1 | from params import MoanaPath, Root, RootedPath 2 | 3 | def obj_tokens(obj_filename): 4 | with open(obj_filename, "r") as obj: 5 | for line in obj: 6 | tokens = line.strip().split(" ", 1) 7 | if not tokens: continue 8 | 9 | command = tokens[0] 10 | if len(tokens) > 1: 11 | yield command, tokens[1] 12 | else: 13 | yield command, None 14 | 15 | 16 | def split(obj_path): 17 | out_filename1 = f"{obj_path.stem}-1.obj" 18 | out_filename2 = f"{obj_path.stem}-2.obj" 19 | 20 | count = 0 21 | for _ in obj_tokens(obj_path): 22 | count += 1 23 | 24 | target = count // 2 25 | 26 | in_section1 = True 27 | section1_lines = [] 28 | section2_lines = [] 29 | 30 | vertex_offset = 0 31 | normal_offset = 0 32 | 33 | for i, (command, rest) in enumerate(obj_tokens(obj_path)): 34 | if in_section1 \ 35 | and i > target \ 36 | and command == "g" and rest == "default": 37 | 38 | print(f"Splitting at line {i + 1}") 39 | in_section1 = False 40 | 41 | if in_section1: 42 | if command == "v": 43 | vertex_offset += 1 44 | elif command == "vn": 45 | normal_offset += 1 46 | 47 | section1_lines.append(f"{command or ''} {rest or ''}\n") 48 | else: 49 | if command == "f": 50 | v0, n0, v1, n1, v2, n2, v3, n3 = [ 51 | int(num) 52 | for num in rest.replace("/", " ").split(" ") 53 | if num 54 | ] 55 | 56 | rest = " ".join([ 57 | f"{v0 - vertex_offset}//{n0 - normal_offset}", 58 | f"{v1 - vertex_offset}//{n1 - normal_offset}", 59 | f"{v2 - vertex_offset}//{n2 - normal_offset}", 60 | f"{v3 - vertex_offset}//{n3 - normal_offset}", 61 | ]) 62 | 63 | section2_lines.append(f"{command or ''} {rest or ''}\n") 64 | 65 | out_path1 = RootedPath(out_filename1, Root.Generated) 66 | with open(out_path1.fs_path, "w") as f: 67 | f.writelines(section1_lines) 68 | 69 | out_path2 = RootedPath(out_filename2, Root.Generated) 70 | with open(out_path2.fs_path, "w") as f: 71 | f.writelines(section2_lines) 72 | 73 | return (out_path1, out_path2) 74 | 75 | if __name__ == "__main__": 76 | split( 77 | MoanaPath / "obj/isIronwoodA1/isIronwoodA1.obj", 78 | Path("../scene") 79 | ) 80 | -------------------------------------------------------------------------------- /scripts/params.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import enum 3 | import os 4 | from pathlib import Path 5 | 6 | MoanaPath = Path(os.environ["MOANA_ROOT"]) / "island" 7 | ScenePath = Path("../scene") 8 | 9 | class Root(enum.Enum): 10 | Moana = 1 11 | Generated = 2 12 | 13 | class RootedPath(collections.namedtuple("RootedPath", ["path", "root"])): 14 | __slots__ = () 15 | 16 | @property 17 | def fs_path(self): 18 | if self.root == Root.Moana: 19 | return MoanaPath / self.path 20 | elif self.root == Root.Generated: 21 | return ScenePath / self.path 22 | else: 23 | raise RuntimeError("Unknown root value") 24 | 25 | @property 26 | def code_path(self): 27 | if self.root == Root.Moana: 28 | return f"moanaRoot + \"/island/{self.path}\"" 29 | elif self.root == Root.Generated: 30 | return f"\"{ScenePath / self.path}\"" 31 | else: 32 | raise RuntimeError("Unknown root value") 33 | 34 | 35 | elements = [ 36 | "isBayCedarA1", 37 | "isBeach", 38 | "isCoastline", 39 | "isCoral", 40 | "isDunesA", 41 | "isDunesB", 42 | "isGardeniaA", 43 | "isHibiscus", 44 | "isHibiscusYoung", 45 | "isIronwoodA1", 46 | "isIronwoodB", 47 | "isKava", 48 | "isLavaRocks", 49 | "isMountainA", 50 | "isMountainB", 51 | "isNaupakaA", 52 | "isPalmDead", 53 | "isPalmRig", 54 | "isPandanusA", 55 | "osOcean", 56 | ] 57 | 58 | skip_list = [ 59 | # "isBeach" 60 | ] 61 | -------------------------------------------------------------------------------- /scripts/textures.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import json 3 | from pathlib import Path 4 | 5 | import code 6 | import files 7 | import params 8 | 9 | def generate_texture_lookup_data(texture_index_lookup): 10 | items = "\n".join( 11 | f"X(\"{element_name}\", \"{material}\", \"{mesh}\", {index})" 12 | for (element_name, material, mesh), index 13 | in texture_index_lookup.items() 14 | ) 15 | return items 16 | 17 | def generate_texture_lookup_code(): 18 | master_ptx_file_list = [] 19 | for element_name in params.elements: 20 | ptx_files = files.find_ptx_files(element_name, full_path=False) 21 | master_ptx_file_list.extend(ptx_files) 22 | 23 | # Lots of false positives, includes all meshes for a given element 24 | # Could work backwards and build from meshes found in .obj files 25 | mesh_names_by_directory = collections.defaultdict(list) 26 | for ptx_file in master_ptx_file_list: 27 | mesh_name = ptx_file.stem 28 | mesh_names_by_directory[ptx_file.parent].append(mesh_name) 29 | 30 | texture_directory_lookup = {} 31 | for element_name in params.elements: 32 | materials_file = files.find_material_json_file(element_name) 33 | materials_json = json.load(open(materials_file, "r")) 34 | 35 | for material, material_json in materials_json.items(): 36 | texture_directory = material_json.get("colorMap", "") 37 | key = (element_name, material) 38 | texture_directory_lookup[key] = Path(texture_directory) 39 | 40 | # fixme: move to overrides 41 | texture_directory_lookup[("isDunesB", "soilSimple")] = Path("textures/isDunesB/Color") 42 | 43 | texture_index_lookup = {} 44 | for (element, material), directory in texture_directory_lookup.items(): 45 | available_mesh_names = mesh_names_by_directory[directory] 46 | for mesh_name in available_mesh_names: 47 | ptx_file = directory / f"{mesh_name}.ptx" 48 | ptx_index = master_ptx_file_list.index(ptx_file) 49 | texture_index_lookup[(element, material, mesh_name)] = ptx_index 50 | 51 | lookup_code = generate_texture_lookup_data(texture_index_lookup) 52 | with open("../src/scene/data/texture_lookup_data.cpp", "w") as f: 53 | f.write(lookup_code) 54 | 55 | filenames_code = code.generate_texture_filenames_data(master_ptx_file_list) 56 | with open("../src/scene/data/texture_offsets_data.cpp", "w") as f: 57 | f.write(filenames_code) 58 | 59 | if __name__ == "__main__": 60 | generate_texture_lookup_code() 61 | -------------------------------------------------------------------------------- /scripts/transforms.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | def corrected_transform(transform): 4 | # Moana column-major indices: 5 | # 6 | # 0 4 8 12 7 | # 1 5 9 13 8 | # 2 6 10 14 9 | # 3 7 11 15 10 | 11 | # Row-major, clipped indices 12 | return [ 13 | transform[0], transform[4], transform[8], transform[12], 14 | transform[1], transform[5], transform[9], transform[13], 15 | transform[2], transform[6], transform[10], transform[14], 16 | ] 17 | 18 | def write_transforms(filename, transforms, skip_correction=False): 19 | print("Writing:", filename) 20 | print(" Transform count:", len(transforms)) 21 | output_file = open(filename, "wb") 22 | 23 | count_bin = struct.pack("i", len(transforms)) 24 | output_file.write(count_bin) 25 | 26 | for transform in transforms: 27 | if not skip_correction: 28 | transform = corrected_transform(transform) 29 | 30 | transform_bin = struct.pack("12f", *transform) 31 | output_file.write(transform_bin) 32 | -------------------------------------------------------------------------------- /src/assert_macros.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | namespace moana { 9 | 10 | inline void cudaAssert(cudaError_t code, const char *file, int line, bool abort = true) 11 | { 12 | if (code != cudaSuccess) { 13 | std::cerr << "CUDA error: " << cudaGetErrorString(code) << std::endl 14 | << " file: " << file << std::endl 15 | << " line: " << line << std::endl; 16 | 17 | if (abort) { exit(code); } 18 | } 19 | } 20 | 21 | inline void optixAssert(OptixResult code, const char *file, int line, bool abort = true) 22 | { 23 | if (code != OPTIX_SUCCESS) { 24 | std::cerr << "Optix error file: " << file 25 | << " code: " << code 26 | << " line: " << line 27 | << std::endl; 28 | 29 | if (abort) { exit(code); } 30 | } 31 | } 32 | 33 | } 34 | 35 | #define CHECK_CUDA(result) { cudaAssert((result), __FILE__, __LINE__); } 36 | #define CHECK_OPTIX(result) { optixAssert((result), __FILE__, __LINE__); } 37 | -------------------------------------------------------------------------------- /src/core/camera.cpp: -------------------------------------------------------------------------------- 1 | #include "moana/core/camera.hpp" 2 | 3 | #include 4 | 5 | namespace moana { 6 | 7 | Camera::Camera( 8 | const Vec3 &origin, 9 | const Vec3 &target, 10 | const Vec3 &up, 11 | float verticalFOV, 12 | const Resolution &resolution, 13 | bool flipHandedness 14 | ) : m_origin(origin), 15 | m_target(target), 16 | m_up(up), 17 | m_verticalFOV(verticalFOV), 18 | m_resolution(resolution), 19 | m_flipHandedness(flipHandedness) 20 | { 21 | m_cameraToWorld = lookAt(m_origin, m_target, m_up, m_flipHandedness); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/core/ptex_texture.cpp: -------------------------------------------------------------------------------- 1 | #include "ptex_texture.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace moana { 11 | 12 | constexpr int cacheCount = 3; 13 | static std::array caches; 14 | 15 | struct : public PtexErrorHandler { 16 | void reportError(const char *error) override { std::cout << error << std::endl; } 17 | } errorHandler; 18 | 19 | PtexTexture::PtexTexture(const std::string &texturePath) 20 | : m_texturePath(texturePath) 21 | { 22 | if (!caches[0]) { 23 | for (int i = 0; i < cacheCount; i++) { 24 | caches[i] = Ptex::PtexCache::create(100, 1ull << 32, true, nullptr, &errorHandler); 25 | } 26 | } 27 | } 28 | 29 | Vec3 PtexTexture::lookup(float2 uv, int faceIndex) const 30 | { 31 | // Handle wrapping 32 | float u = uv.x - (int)floorf(uv.x); 33 | float v = uv.y - (int)floorf(uv.y); 34 | 35 | const int threadNum = omp_get_thread_num(); 36 | Ptex::PtexCache *cache = caches[threadNum % cacheCount]; 37 | 38 | Ptex::String error; 39 | Ptex::PtexTexture *texture = cache->get(m_texturePath.c_str(), error); 40 | Ptex::PtexFilter::Options opts(Ptex::PtexFilter::FilterType::f_bspline); 41 | Ptex::PtexFilter *filter = Ptex::PtexFilter::getFilter(texture, opts); 42 | 43 | float result[3]; 44 | filter->eval( 45 | result, 46 | 0, 47 | texture->numChannels(), 48 | faceIndex, 49 | uv.x, 50 | uv.y, 51 | 0.f, 52 | 0.f, 53 | 0.f, 54 | 0.f 55 | ); 56 | 57 | filter->release(); 58 | texture->release(); 59 | 60 | return Vec3( 61 | std::pow(result[0], 2.2f), 62 | std::pow(result[1], 2.2f), 63 | std::pow(result[2], 2.2f) 64 | ); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/core/ptex_texture.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "moana/core/vec3.hpp" 8 | 9 | namespace moana { 10 | 11 | class PtexTexture { 12 | public: 13 | PtexTexture(const std::string &texturePath); 14 | Vec3 lookup(float2 uv, int faceIndex) const; 15 | 16 | private: 17 | std::string m_texturePath; 18 | }; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/core/texture.cpp: -------------------------------------------------------------------------------- 1 | #include "moana/core/texture.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include "tinyexr.h" 7 | 8 | #include "assert_macros.hpp" 9 | 10 | namespace moana { 11 | 12 | Texture::Texture(const std::string &filename) 13 | : m_filename(filename) 14 | {} 15 | 16 | void Texture::determineAndSetPitch() 17 | { 18 | loadImage(); 19 | 20 | CUdeviceptr d_environment; 21 | const size_t bufferSizeInBytes = sizeof(float) * 4 * m_width * m_height; 22 | 23 | size_t pitch; 24 | CHECK_CUDA(cudaMallocPitch( 25 | reinterpret_cast(&d_environment), 26 | &pitch, 27 | sizeof(float) * 4 * m_width, 28 | m_height 29 | )); 30 | 31 | m_pitch = pitch; 32 | 33 | CHECK_CUDA(cudaFree(reinterpret_cast(d_environment))); 34 | } 35 | 36 | void Texture::loadImage() 37 | { 38 | const char *error = nullptr; 39 | const int code = LoadEXR(&m_data, &m_width, &m_height, m_filename.c_str(), &error); 40 | if (code == TINYEXR_SUCCESS) { 41 | std::cout << "Loaded texture {" 42 | << " width: " << m_width 43 | << " height: " << m_height 44 | << " }" << std::endl; 45 | } else { 46 | fprintf(stderr, "ENVIRONMENT MAP ERROR: %s\n", error); 47 | FreeEXRErrorMessage(error); 48 | } 49 | } 50 | 51 | cudaTextureObject_t Texture::createTextureObject(ASArena &arena) 52 | { 53 | if (!m_data) { 54 | throw std::runtime_error("Must call determineAndSetPitch() before creating texture object"); 55 | } 56 | 57 | const int width = m_width; 58 | const int height = m_height; 59 | 60 | const size_t hostBufferSizeInBytes = sizeof(float) * 4 * width * height; 61 | const size_t deviceBufferSizeInBytes = m_pitch * height; 62 | 63 | std::cout << m_data[0*4 + 0] << " " << m_data[0*4 + 1] << " " << m_data[0*4 + 2] << " " << m_data[0*4 + 3] << std::endl 64 | << m_data[1*4 + 4] << " " << m_data[1*4 + 5] << " " << m_data[1*4 + 6] << " " << m_data[1*4 + 7] << std::endl 65 | << m_data[2*4 + 4] << " " << m_data[2*4 + 5] << " " << m_data[2*4 + 6] << " " << m_data[2*4 + 7] << std::endl 66 | << m_data[3*4 + 4] << " " << m_data[3*4 + 5] << " " << m_data[3*4 + 6] << " " << m_data[3*4 + 7] << std::endl 67 | << m_data[4*4 + 4] << " " << m_data[4*4 + 5] << " " << m_data[4*4 + 6] << " " << m_data[4*4 + 7] << std::endl; 68 | 69 | CUdeviceptr d_environment = arena.allocOutput(deviceBufferSizeInBytes); 70 | 71 | CHECK_CUDA(cudaMemcpy2D( 72 | reinterpret_cast(d_environment), 73 | m_pitch, 74 | m_data, 75 | sizeof(float) * 4 * width, 76 | sizeof(float) * 4 * width, 77 | height, 78 | cudaMemcpyHostToDevice 79 | )); 80 | 81 | cudaResourceDesc resDesc; 82 | memset(&resDesc, 0, sizeof(resDesc)); 83 | resDesc.resType = cudaResourceTypePitch2D; 84 | resDesc.res.pitch2D.devPtr = reinterpret_cast(d_environment); 85 | resDesc.res.pitch2D.desc.x = 32; 86 | resDesc.res.pitch2D.desc.y = 32; 87 | resDesc.res.pitch2D.desc.z = 32; 88 | resDesc.res.pitch2D.desc.w = 32; 89 | resDesc.res.pitch2D.desc.f = cudaChannelFormatKindFloat; 90 | resDesc.res.pitch2D.width = width; 91 | resDesc.res.pitch2D.height = height; 92 | resDesc.res.pitch2D.pitchInBytes = m_pitch; 93 | 94 | cudaTextureDesc texDesc; 95 | memset(&texDesc, 0, sizeof(texDesc)); 96 | texDesc.addressMode[0] = cudaAddressModeClamp; 97 | texDesc.addressMode[1] = cudaAddressModeClamp; 98 | texDesc.filterMode = cudaFilterModeLinear; 99 | texDesc.readMode = cudaReadModeElementType; 100 | texDesc.normalizedCoords = 1; 101 | 102 | cudaTextureObject_t texObj = 0; 103 | CHECK_CUDA(cudaCreateTextureObject(&texObj, &resDesc, &texDesc, NULL)); 104 | 105 | return texObj; 106 | } 107 | 108 | Texture::~Texture() 109 | { 110 | free(m_data); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/core/transform.cpp: -------------------------------------------------------------------------------- 1 | #include "moana/core/transform.hpp" 2 | 3 | #include 4 | 5 | namespace moana { 6 | 7 | Transform lookAt( 8 | const Vec3 &source, 9 | const Vec3 &target, 10 | const Vec3 &up, 11 | bool flipHandedness 12 | ) { 13 | const Vec3 direction = normalized(source - target); 14 | 15 | if (direction == up) { 16 | std::cerr << "Look direction cannot equal up vector - quitting!" << std::endl; 17 | exit(1); 18 | } 19 | 20 | const Vec3 xAxis = normalized(cross(normalized(up), direction)); 21 | const Vec3 yAxis = normalized(cross(direction, xAxis)); 22 | 23 | const float sign = flipHandedness ? -1.f : 1.f; 24 | 25 | float matrix[4][4] { 26 | { sign * xAxis.x(), yAxis.x(), direction.x(), source.x() }, 27 | { sign * xAxis.y(), yAxis.y(), direction.y(), source.y() }, 28 | { sign * xAxis.z(), yAxis.z(), direction.z(), source.z() }, 29 | { 0.f, 0.f, 0.f, 1.f } 30 | }; 31 | 32 | return Transform(matrix); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/cuda/environment_light.cu: -------------------------------------------------------------------------------- 1 | #include "moana/cuda/environment_light.hpp" 2 | 3 | #include "assert_macros.hpp" 4 | #include "moana/core/coordinates.hpp" 5 | #include "moana/core/vec3.hpp" 6 | 7 | namespace moana { 8 | 9 | // fixme 10 | static constexpr float rotationOffset = 115.f / 180.f * M_PI; 11 | 12 | __global__ static void environmentLightKernel( 13 | int width, 14 | int height, 15 | cudaTextureObject_t textureObject, 16 | float *occlusionBuffer, 17 | float *directionBuffer, 18 | float *outputBuffer 19 | ) { 20 | const int row = threadIdx.y + blockIdx.y * blockDim.y; 21 | const int col = threadIdx.x + blockIdx.x * blockDim.x; 22 | 23 | if ((row >= height) || (col >= width)) { return; } 24 | 25 | const int directionIndex = 3 * (row * width + col); 26 | const int occlusionIndex = 1 * (row * width + col); 27 | if (occlusionBuffer[occlusionIndex] != 0.f) { return; } 28 | 29 | Vec3 direction( 30 | directionBuffer[directionIndex + 0], 31 | directionBuffer[directionIndex + 1], 32 | directionBuffer[directionIndex + 2] 33 | ); 34 | 35 | // Pixels that have already been lit in previous bounces 36 | if (direction.isZero()) { return; } 37 | 38 | float phi, theta; 39 | Coordinates::cartesianToSpherical(direction, &phi, &theta); 40 | 41 | phi += rotationOffset; 42 | if (phi > 2.f * M_PI) { 43 | phi -= 2.f * M_PI; 44 | } 45 | 46 | float4 environment = tex2D( 47 | textureObject, 48 | phi / (M_PI * 2.f), 49 | theta / M_PI 50 | ); 51 | 52 | const int outputIndex = 3 * (row * width + col); 53 | outputBuffer[outputIndex + 0] = environment.x; 54 | outputBuffer[outputIndex + 1] = environment.y; 55 | outputBuffer[outputIndex + 2] = environment.z; 56 | } 57 | 58 | void EnvironmentLight::calculateEnvironmentLighting( 59 | int width, 60 | int height, 61 | ASArena &arena, 62 | cudaTextureObject_t textureObject, 63 | float *devOcclusionBuffer, 64 | float *devDirectionBuffer, 65 | std::vector &outputBuffer 66 | ) { 67 | const size_t outputBufferSizeInBytes = outputBuffer.size() * sizeof(float); 68 | CUdeviceptr d_outputBuffer = 0; 69 | 70 | d_outputBuffer = arena.pushTemp(outputBufferSizeInBytes); 71 | 72 | CHECK_CUDA(cudaMemset( 73 | reinterpret_cast(d_outputBuffer), 74 | 0, 75 | outputBufferSizeInBytes 76 | )); 77 | 78 | const int blockWidth = 16; 79 | const int blockHeight = 16; 80 | 81 | const dim3 blocks(width / blockWidth + 1, height / blockHeight + 1); 82 | const dim3 threads(blockWidth, blockHeight); 83 | 84 | environmentLightKernel<<>>( 85 | width, 86 | height, 87 | textureObject, 88 | devOcclusionBuffer, 89 | devDirectionBuffer, 90 | reinterpret_cast(d_outputBuffer) 91 | ); 92 | 93 | CHECK_CUDA(cudaMemcpy( 94 | outputBuffer.data(), 95 | reinterpret_cast(d_outputBuffer), 96 | outputBufferSizeInBytes, 97 | cudaMemcpyDeviceToHost 98 | )); 99 | 100 | arena.popTemp(); // d_outputBuffer 101 | 102 | CHECK_CUDA(cudaDeviceSynchronize()); 103 | } 104 | 105 | void EnvironmentLight::queryMemoryRequirements() 106 | { 107 | std::string moanaRoot = MOANA_ROOT; 108 | m_texturePtr = std::make_unique(moanaRoot + "/island/textures/islandsun.exr"); 109 | m_texturePtr->determineAndSetPitch(); 110 | } 111 | 112 | EnvironmentLightState EnvironmentLight::snapshotTextureObject(ASArena &arena) 113 | { 114 | EnvironmentLightState environmentState; 115 | environmentState.textureObject = m_texturePtr->createTextureObject(arena); 116 | environmentState.snapshot = arena.createSnapshot(); 117 | 118 | return environmentState; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/driver.cpp: -------------------------------------------------------------------------------- 1 | #include "moana/driver.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "assert_macros.hpp" 14 | #include "moana/render/renderer.hpp" 15 | #include "scene/container.hpp" 16 | 17 | namespace moana { 18 | 19 | static void contextLogCallback( 20 | unsigned int level, 21 | const char *tag, 22 | const char *message, 23 | void * /*cbdata */ 24 | ) 25 | { 26 | std::cerr << "[" << std::setw(2) << level << "][" << std::setw(12) << tag << "]: " 27 | << message << std::endl; 28 | } 29 | 30 | static OptixDeviceContext createContext() 31 | { 32 | CHECK_CUDA(cudaFree(0)); // initialize CUDA 33 | CHECK_OPTIX(optixInit()); 34 | omp_set_nested(1); 35 | 36 | OptixDeviceContextOptions options = {}; 37 | options.logCallbackFunction = &contextLogCallback; 38 | options.logCallbackLevel = 4; 39 | 40 | OptixDeviceContext context; 41 | CUcontext cuContext = 0; // current context 42 | CHECK_OPTIX(optixDeviceContextCreate(cuContext, &options, &context)); 43 | 44 | return context; 45 | } 46 | 47 | void Driver::init() 48 | { 49 | OptixDeviceContext context = createContext(); 50 | 51 | EnvironmentLight environmentLight; 52 | environmentLight.queryMemoryRequirements(); 53 | 54 | size_t gb = 1024 * 1024 * 1024; 55 | m_sceneState.arena.init(6.7 * gb); 56 | 57 | m_sceneState.environmentState = environmentLight.snapshotTextureObject(m_sceneState.arena); 58 | m_sceneState.arena.releaseAll(); 59 | 60 | m_sceneState.geometries = Container::createGeometryResults(context, m_sceneState.arena); 61 | 62 | Pipeline::initOptixState(m_optixStates[PipelineType::MainRay], context, m_sceneState); 63 | ShadowPipeline::initOptixState(m_optixStates[PipelineType::ShadowRay], context, m_sceneState); 64 | 65 | CHECK_CUDA(cudaDeviceSynchronize()); 66 | } 67 | 68 | void Driver::launch( 69 | RenderRequest renderRequest, 70 | Cam cam, 71 | const std::string &exrFilename 72 | ) { 73 | std::cout << "Rendering: " << exrFilename << std::endl; 74 | Renderer::launch( 75 | renderRequest, 76 | m_optixStates, 77 | m_sceneState, 78 | cam, 79 | exrFilename 80 | ); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/io/image.cpp: -------------------------------------------------------------------------------- 1 | #include "moana/io/image.hpp" 2 | 3 | #define TINYEXR_IMPLEMENTATION 4 | #include "tinyexr.h" 5 | 6 | namespace moana { namespace Image { 7 | 8 | void save( 9 | int width, 10 | int height, 11 | const std::vector &radiances, 12 | const std::string &filename 13 | ) { 14 | EXRHeader header; 15 | InitEXRHeader(&header); 16 | 17 | EXRImage image; 18 | InitEXRImage(&image); 19 | 20 | image.num_channels = 3; 21 | 22 | std::vector images[3]; 23 | images[0].resize(width * height); 24 | images[1].resize(width * height); 25 | images[2].resize(width * height); 26 | 27 | for (int row = 0; row < height; row++) { 28 | for (int col = 0; col < width; col++) { 29 | const int pixelIndex = row * width + col; 30 | const int exrIndex = row * width + col; 31 | 32 | images[0][exrIndex] = radiances[3 * pixelIndex + 0]; 33 | images[1][exrIndex] = radiances[3 * pixelIndex + 1]; 34 | images[2][exrIndex] = radiances[3 * pixelIndex + 2]; 35 | } 36 | } 37 | 38 | float* image_ptr[3]; 39 | image_ptr[0] = &(images[2].at(0)); // B 40 | image_ptr[1] = &(images[1].at(0)); // G 41 | image_ptr[2] = &(images[0].at(0)); // R 42 | 43 | image.images = (unsigned char**)image_ptr; 44 | image.width = width; 45 | image.height = height; 46 | 47 | header.num_channels = 3; 48 | header.channels = (EXRChannelInfo *)malloc(sizeof(EXRChannelInfo) * header.num_channels); 49 | 50 | // Must be BGR(A) order, since most of EXR viewers expect this channel order. 51 | strncpy(header.channels[0].name, "B", 255); header.channels[0].name[strlen("B")] = '\0'; 52 | strncpy(header.channels[1].name, "G", 255); header.channels[1].name[strlen("G")] = '\0'; 53 | strncpy(header.channels[2].name, "R", 255); header.channels[2].name[strlen("R")] = '\0'; 54 | 55 | header.pixel_types = (int *)malloc(sizeof(int) * header.num_channels); 56 | header.requested_pixel_types = (int *)malloc(sizeof(int) * header.num_channels); 57 | for (int i = 0; i < header.num_channels; i++) { 58 | header.pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image 59 | header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_HALF; // pixel type of output image to be stored in .EXR 60 | } 61 | 62 | const char *err; 63 | 64 | std::string outputExr = filename; 65 | 66 | int ret = SaveEXRImageToFile(&image, &header, outputExr.c_str(), &err); 67 | if (ret != TINYEXR_SUCCESS) { 68 | fprintf(stderr, "Save EXR err: %s\n", err); 69 | return; 70 | } 71 | // printf("Saved exr file. [ %s ] \n", outputExr.c_str()); 72 | 73 | free(header.channels); 74 | free(header.pixel_types); 75 | free(header.requested_pixel_types); 76 | } 77 | 78 | } } 79 | -------------------------------------------------------------------------------- /src/parsers/curve_parser.cpp: -------------------------------------------------------------------------------- 1 | #include "parsers/curve_parser.hpp" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "assert_macros.hpp" 10 | 11 | namespace moana { 12 | 13 | Curve::Curve(const std::string &filename) 14 | : m_filename(filename) 15 | {} 16 | 17 | OptixTraversableHandle Curve::gasFromCurve( 18 | OptixDeviceContext context, 19 | ASArena &arena 20 | ) { 21 | std::ifstream curveFile(m_filename); 22 | 23 | int strandCount; 24 | curveFile.read((char *)&strandCount, sizeof(int)); 25 | std::cout << "Strand count: " << strandCount << std::endl; 26 | 27 | int verticesPerStrand; 28 | curveFile.read((char *)&verticesPerStrand, sizeof(int)); 29 | std::cout << "Vertices per strand: " << verticesPerStrand << std::endl; 30 | 31 | const int degree = 3; 32 | const int segmentsPerStrand = verticesPerStrand - degree; 33 | const int segmentCount = strandCount * segmentsPerStrand; 34 | std::cout << "Segment count: " << segmentCount << std::endl; 35 | 36 | float rootWidth; 37 | float tipWidth; 38 | curveFile.read((char *)&rootWidth, sizeof(float)); 39 | curveFile.read((char *)&tipWidth, sizeof(float)); 40 | 41 | const float rootRadius = rootWidth / 2.f; 42 | const float tipRadius = tipWidth / 2.f; 43 | 44 | std::cout << "Root width: " << rootRadius << std::endl 45 | << "Tip width: " << tipRadius << std::endl; 46 | 47 | const int totalVertexCount = strandCount * verticesPerStrand; 48 | const int totalFloatCount = totalVertexCount * 3; 49 | std::cout << "Total vertices: " << totalVertexCount << std::endl; 50 | std::cout << "Total floats: " << totalFloatCount << std::endl; 51 | 52 | std::vector controlPoints(totalFloatCount); 53 | curveFile.read( 54 | (char *)controlPoints.data(), 55 | sizeof(float) * totalFloatCount 56 | ); 57 | 58 | CUdeviceptr d_vertices = 0; 59 | size_t verticesSizeInBytes = totalFloatCount * sizeof(float); 60 | CHECK_CUDA(cudaMalloc( 61 | reinterpret_cast(&d_vertices), 62 | verticesSizeInBytes 63 | )); 64 | CHECK_CUDA(cudaMemcpy( 65 | reinterpret_cast(d_vertices), 66 | controlPoints.data(), 67 | verticesSizeInBytes, 68 | cudaMemcpyHostToDevice 69 | )); 70 | 71 | const float range = tipRadius - rootRadius; 72 | std::vector widths(totalVertexCount); 73 | 74 | // TODO: Which is right? 75 | // for (int j = 0; j < verticesPerStrand; j++) { 76 | // const float lerpT = 1.f * (j - 1) / (verticesPerStrand - 1); 77 | // widths[i * verticesPerStrand + j] = rootRadius + (range * lerpT); 78 | // } 79 | 80 | // Make sure the phantom points aren't part of the radius interpolation 81 | for (int i = 0; i < strandCount; i++) { 82 | widths[i * verticesPerStrand + 0] = rootRadius; 83 | 84 | for (int j = 1; j < verticesPerStrand - 1; j++) { 85 | const float lerpT = 1.f * (j - 1) / (verticesPerStrand - 3); 86 | widths[i * verticesPerStrand + j] = rootRadius + (range * lerpT); 87 | } 88 | 89 | widths[i * verticesPerStrand + verticesPerStrand - 1] = tipRadius; 90 | } 91 | 92 | CUdeviceptr d_widths = 0; 93 | size_t widthsSizeInBytes = totalVertexCount * sizeof(float); 94 | CHECK_CUDA(cudaMalloc( 95 | reinterpret_cast(&d_widths), 96 | widthsSizeInBytes 97 | )); 98 | CHECK_CUDA(cudaMemcpy( 99 | reinterpret_cast(d_widths), 100 | widths.data(), 101 | widthsSizeInBytes, 102 | cudaMemcpyHostToDevice 103 | )); 104 | 105 | std::vector indices; 106 | for (int i = 0; i < strandCount; i++) { 107 | for (int j = 0; j < segmentsPerStrand; j++) { 108 | indices.push_back(i * verticesPerStrand + j); 109 | } 110 | } 111 | 112 | CUdeviceptr d_indices = 0; 113 | size_t indicesSizeInBytes = segmentCount * sizeof(int); 114 | CHECK_CUDA(cudaMalloc( 115 | reinterpret_cast(&d_indices), 116 | indicesSizeInBytes 117 | )); 118 | CHECK_CUDA(cudaMemcpy( 119 | reinterpret_cast(d_indices), 120 | indices.data(), 121 | indicesSizeInBytes, 122 | cudaMemcpyHostToDevice 123 | )); 124 | 125 | OptixAccelBuildOptions accelOptions = {}; 126 | accelOptions.buildFlags = OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS; // fixme; use user data 127 | accelOptions.operation = OPTIX_BUILD_OPERATION_BUILD; // no updates 128 | 129 | // Setup build input 130 | uint32_t inputFlags[] = { OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT }; 131 | OptixBuildInput curveInput = {}; 132 | curveInput.type = OPTIX_BUILD_INPUT_TYPE_CURVES; 133 | 134 | curveInput.curveArray.curveType = OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE; 135 | curveInput.curveArray.numPrimitives = segmentCount; 136 | curveInput.curveArray.vertexBuffers = &d_vertices; 137 | curveInput.curveArray.numVertices = static_cast(totalVertexCount); 138 | curveInput.curveArray.vertexStrideInBytes = sizeof(float) * 3; 139 | curveInput.curveArray.widthBuffers = &d_widths; 140 | curveInput.curveArray.widthStrideInBytes = sizeof(float); 141 | curveInput.curveArray.normalBuffers = 0; 142 | curveInput.curveArray.normalStrideInBytes = 0; 143 | curveInput.curveArray.indexBuffer = d_indices; 144 | curveInput.curveArray.indexStrideInBytes = sizeof(int); 145 | curveInput.curveArray.flag = OPTIX_GEOMETRY_FLAG_NONE; 146 | curveInput.curveArray.primitiveIndexOffset = 0; 147 | 148 | // Calculate max memory size 149 | OptixAccelBufferSizes gasBufferSizes; 150 | CHECK_OPTIX(optixAccelComputeMemoryUsage( 151 | context, 152 | &accelOptions, 153 | &curveInput, 154 | 1, // build input count 155 | &gasBufferSizes 156 | )); 157 | 158 | std::cout << " Curve GAS:" << std::endl; 159 | std::cout << " Output Buffer size(mb): " 160 | << (gasBufferSizes.outputSizeInBytes / (1024. * 1024.)) 161 | << std::endl 162 | << " Temp Buffer size(mb): " 163 | << (gasBufferSizes.tempSizeInBytes / (1024. * 1024.)) 164 | << std::endl 165 | << " Vertices size(mb): " 166 | << (verticesSizeInBytes / (1024. * 1024.)) 167 | << std::endl 168 | << " Indices size(mb): " 169 | << (indicesSizeInBytes / (1024. * 1024.)) 170 | << std::endl; 171 | 172 | CUdeviceptr d_tempBufferGas; 173 | CHECK_CUDA(cudaMalloc( 174 | reinterpret_cast(&d_tempBufferGas), 175 | gasBufferSizes.tempSizeInBytes 176 | )); 177 | 178 | CUdeviceptr d_gasOutputBuffer = arena.allocOutput(gasBufferSizes.outputSizeInBytes); 179 | 180 | OptixTraversableHandle handle; 181 | CHECK_OPTIX(optixAccelBuild( 182 | context, 183 | 0, // default CUDA stream 184 | &accelOptions, 185 | &curveInput, 186 | 1, // build input count 187 | d_tempBufferGas, 188 | gasBufferSizes.tempSizeInBytes, 189 | d_gasOutputBuffer, 190 | gasBufferSizes.outputSizeInBytes, 191 | &handle, 192 | nullptr, 0 // emitted property params 193 | )); 194 | 195 | CHECK_CUDA(cudaFree(reinterpret_cast(d_vertices))); 196 | CHECK_CUDA(cudaFree(reinterpret_cast(d_indices))); 197 | CHECK_CUDA(cudaFree(reinterpret_cast(d_widths))); 198 | CHECK_CUDA(cudaFree(reinterpret_cast(d_tempBufferGas))); 199 | 200 | return handle; 201 | } 202 | 203 | } 204 | -------------------------------------------------------------------------------- /src/parsers/curve_parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "moana/scene/as_arena.hpp" 8 | 9 | namespace moana { 10 | 11 | class Curve { 12 | public: 13 | Curve(const std::string &filename); 14 | 15 | OptixTraversableHandle gasFromCurve( 16 | OptixDeviceContext context, 17 | ASArena &arena 18 | ); 19 | 20 | private: 21 | std::string m_filename; 22 | }; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/parsers/string_util.cpp: -------------------------------------------------------------------------------- 1 | #include "moana/parsers/string_util.hpp" 2 | 3 | namespace moana { namespace StringUtil { 4 | 5 | std::optional lTrim(const std::string_view &token) 6 | { 7 | std::string::size_type firstContentIndex = token.find_first_not_of(" \t"); 8 | if (firstContentIndex == 0) { 9 | return token; 10 | } else if (firstContentIndex == std::string::npos) { 11 | return std::nullopt; 12 | } 13 | 14 | return token.substr(firstContentIndex); 15 | } 16 | 17 | } } 18 | -------------------------------------------------------------------------------- /src/render/.gitignore: -------------------------------------------------------------------------------- 1 | kernel.hpp 2 | shadow_ray_kernel.hpp 3 | -------------------------------------------------------------------------------- /src/render/pipeline.cpp: -------------------------------------------------------------------------------- 1 | #include "moana/render/pipeline.hpp" 2 | 3 | #include "kernel.hpp" 4 | #include "shadow_ray_kernel.hpp" 5 | #include "pipeline_helper.hpp" 6 | 7 | namespace moana { namespace Pipeline { 8 | 9 | void initOptixState( 10 | OptixState &optixState, 11 | OptixDeviceContext context, 12 | SceneState &sceneState 13 | ) { 14 | return PipelineHelper::initOptixState( 15 | optixState, 16 | context, 17 | sceneState, 18 | PTX::mainRaySource 19 | ); 20 | } 21 | 22 | } } 23 | 24 | namespace moana { namespace ShadowPipeline { 25 | 26 | void initOptixState( 27 | OptixState &optixState, 28 | OptixDeviceContext context, 29 | SceneState &sceneState 30 | ) { 31 | return PipelineHelper::initOptixState( 32 | optixState, 33 | context, 34 | sceneState, 35 | PTX::shadowRaySource 36 | ); 37 | } 38 | 39 | } } 40 | -------------------------------------------------------------------------------- /src/render/pipeline_helper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "moana/render/pipeline.hpp" 9 | 10 | namespace moana { namespace PipelineHelper { 11 | 12 | void initOptixState( 13 | OptixState &optixState, 14 | OptixDeviceContext context, 15 | const SceneState &sceneState, 16 | const std::string &ptxSource 17 | ); 18 | 19 | } } 20 | -------------------------------------------------------------------------------- /src/render/timing.cpp: -------------------------------------------------------------------------------- 1 | #include "render/timing.hpp" 2 | 3 | namespace moana { 4 | 5 | Timing::Timing() 6 | : m_startTimes(), 7 | m_durations(), 8 | m_lock() 9 | {} 10 | 11 | void Timing::start(TimedSection section) 12 | { 13 | m_lock.lock(); 14 | m_startTimes[section] = std::chrono::steady_clock::now(); 15 | m_lock.unlock(); 16 | } 17 | 18 | void Timing::end(TimedSection section) 19 | { 20 | m_lock.lock(); 21 | m_durations[section] = std::chrono::steady_clock::now() - m_startTimes[section]; 22 | m_lock.unlock(); 23 | } 24 | 25 | float Timing::getMilliseconds(TimedSection section) 26 | { 27 | using namespace std::chrono; 28 | 29 | m_lock.lock(); 30 | const auto duration = duration_cast(m_durations[section]); 31 | m_lock.unlock(); 32 | 33 | return duration.count() / 1000.f; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/render/timing.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | namespace moana { 9 | 10 | enum class TimedSection { 11 | Sample, 12 | PtexLookups, 13 | DirectLighting 14 | }; 15 | 16 | class Timing { 17 | public: 18 | Timing(); 19 | 20 | void start(TimedSection section); 21 | void end(TimedSection section); 22 | float getMilliseconds(TimedSection section); 23 | 24 | private: 25 | std::map m_startTimes; 26 | std::map m_durations; 27 | 28 | std::mutex m_lock; 29 | }; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/scene.cpp: -------------------------------------------------------------------------------- 1 | #include "moana/scene.hpp" 2 | 3 | #include "moana/core/vec3.hpp" 4 | 5 | namespace moana { 6 | 7 | Scene::Scene(Cam cam) 8 | : m_cam(cam) 9 | {} 10 | 11 | Camera Scene::getCamera(int width, int height) const 12 | { 13 | struct CameraParams { 14 | Vec3 origin; 15 | Vec3 target; 16 | Vec3 up; 17 | }; 18 | 19 | float fovDegrees = 24.386729394448643f; 20 | 21 | CameraParams params; 22 | switch (m_cam) { 23 | case Cam::BeachCam: { 24 | params.origin = Vec3( 25 | -510.5239066714681f, 26 | 87.30874393630907f, 27 | 181.77019700660784f 28 | ); 29 | params.target = Vec3( 30 | 152.46530457260906f, 31 | 30.939794764162578f, 32 | -72.72751680648216f 33 | ); 34 | params.up = Vec3( 35 | 0.0738708545527661f, 36 | 0.996864591331903f, 37 | -0.02835636430013811f 38 | ); 39 | break; 40 | } 41 | case Cam::BirdseyeCam: { 42 | params.origin = Vec3( 43 | 3.5526606717518376f, 44 | 850.6418895294337f, 45 | 747.5497754610369f 46 | ); 47 | params.target = Vec3( 48 | 237.07531671546286f, 49 | 52.9718477246937f, 50 | -263.9479752910547f 51 | ); 52 | params.up = Vec3( 53 | 0.1370609562125062f, 54 | 0.7929456689992689f, 55 | -0.5936762251407878f 56 | ); 57 | break; 58 | } 59 | case Cam::DunesACam: { 60 | params.origin = Vec3( 61 | -71.3357952505853f, 62 | 78.734578313642f, 63 | 108.92994817257102f 64 | ); 65 | params.target = Vec3( 66 | -271.1048187567149f, 67 | 80.80085405252899f, 68 | -297.0543150237934f 69 | ); 70 | params.up = Vec3( 71 | 0.002016176422133449f, 72 | 0.9999895730713552f, 73 | 0.004097411524808375f 74 | ); 75 | break; 76 | } 77 | case Cam::GrassCam: { 78 | params.origin = Vec3( 79 | -5.171248679251219f, 80 | 20.334400261222573f, 81 | -89.97306056602213f 82 | ); 83 | params.target = Vec3( 84 | 18.549566601169055f, 85 | 8.00826275343514f, 86 | -107.84797699232291f 87 | ); 88 | params.up = Vec3( 89 | 0.3061184080739167f, 90 | 0.9236231643732346f, 91 | -0.23067676621511765f 92 | ); 93 | break; 94 | } 95 | case Cam::PalmsCam: { 96 | params.origin = Vec3( 97 | -124.02546471925854f, 98 | 405.62214562283157f, 99 | 369.1730463283022f 100 | ); 101 | params.target = Vec3( 102 | 472.3129244023174f, 103 | 571.462848388009f, 104 | 16.499506125608377f 105 | ); 106 | params.up = Vec3( 107 | -0.2003759454709524f, 108 | 0.9725259665269878f, 109 | 0.11850200381162401f 110 | ); 111 | break; 112 | } 113 | case Cam::RootsCam: { 114 | params.origin = Vec3( 115 | -53.247679762217224f, 116 | 63.459326699391625f, 117 | -57.57774331317834f 118 | ); 119 | params.target = Vec3( 120 | -44.0959264818672f, 121 | 56.9923848671219f, 122 | -68.5620187630634f 123 | ); 124 | params.up = Vec3( 125 | 0.2638047892040311f, 126 | 0.9111276124080613f, 127 | -0.31662834222571157f 128 | ); 129 | break; 130 | } 131 | case Cam::ShotCam: { 132 | params.origin = Vec3( 133 | -1139.01589265f, 134 | 23.28673313185658f, 135 | 1479.7947229f 136 | ); 137 | params.target = Vec3( 138 | 244.81433650665076f, 139 | 238.8071478842799f, 140 | 560.3801168449178f 141 | ); 142 | params.up = Vec3( 143 | -0.10714942339176316f, 144 | 0.9916909792130254f, 145 | 0.07118990669600059f 146 | ); 147 | 148 | fovDegrees = 32.503438547851374f; 149 | break; 150 | } 151 | default: { 152 | throw std::runtime_error("Cam not supported"); 153 | } 154 | } 155 | 156 | return Camera( 157 | params.origin, 158 | params.target, 159 | params.up, 160 | fovDegrees / 180.f * M_PI, 161 | { width, height }, 162 | false 163 | ); 164 | 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /src/scene/archive.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/archive.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "assert_macros.hpp" 10 | #include "moana/parsers/obj_parser.hpp" 11 | #include "scene/gas.hpp" 12 | #include "scene/ias.hpp" 13 | #include "scene/instances_bin.hpp" 14 | 15 | namespace moana { 16 | 17 | Archive::Archive( 18 | const std::vector &binPaths, 19 | const std::vector &handleIndices, 20 | const std::vector &handles 21 | ) : m_binPaths(binPaths), 22 | m_handleIndices(handleIndices), 23 | m_handles(handles) 24 | {} 25 | 26 | void Archive::processRecords( 27 | OptixDeviceContext context, 28 | ASArena &arena, 29 | std::vector &records, 30 | const std::vector &sbtOffsets 31 | ) const { 32 | assert(m_binPaths.size() == m_handleIndices.size()); 33 | 34 | const int archivesSize = m_binPaths.size(); 35 | for (int i = 0; i < archivesSize; i++) { 36 | const std::string binPath = m_binPaths[i]; 37 | 38 | std::cout << "Processing " << binPath << std::endl; 39 | 40 | std::cout << " Instances:" << std::endl; 41 | const Instances instancesResult = InstancesBin::parse(binPath); 42 | std::cout << " Count: " << instancesResult.count << std::endl; 43 | 44 | const int handleIndex = m_handleIndices[i]; 45 | IAS::createOptixInstanceRecords( 46 | context, 47 | records, 48 | instancesResult, 49 | m_handles[handleIndex], 50 | sbtOffsets[handleIndex] 51 | ); 52 | } 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/scene/archive.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "moana/scene/as_arena.hpp" 9 | 10 | namespace moana { 11 | 12 | class Archive { 13 | public: 14 | Archive( 15 | const std::vector &binPaths, 16 | const std::vector &handleIndices, 17 | const std::vector &handles 18 | ); 19 | 20 | void processRecords( 21 | OptixDeviceContext context, 22 | ASArena &arena, 23 | std::vector &records, 24 | const std::vector &sbtOffsets 25 | ) const; 26 | 27 | private: 28 | std::vector m_binPaths; 29 | std::vector m_handleIndices; 30 | std::vector m_handles; 31 | }; 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/scene/as_arena.cpp: -------------------------------------------------------------------------------- 1 | #include "moana/scene/as_arena.hpp" 2 | 3 | #include 4 | 5 | #include "assert_macros.hpp" 6 | 7 | namespace moana { 8 | 9 | static constexpr size_t ByteAlignment = 128; 10 | 11 | static size_t roundUp(size_t location, size_t alignment) 12 | { 13 | if (location % alignment == 0) { return location; } 14 | 15 | return location + alignment - (location % alignment); 16 | } 17 | 18 | ASArena::ASArena() 19 | {} 20 | 21 | void ASArena::init(size_t poolSizeInBytes) 22 | { 23 | poolSizeInBytes = roundUp(poolSizeInBytes, ByteAlignment); 24 | 25 | assert(poolSizeInBytes % ByteAlignment == 0); 26 | 27 | CHECK_CUDA(cudaMalloc( 28 | reinterpret_cast(&m_basePtr), 29 | poolSizeInBytes 30 | )); 31 | CHECK_CUDA(cudaDeviceSynchronize()); 32 | assert(m_basePtr % ByteAlignment == 0); 33 | 34 | m_poolSizeInBytes = poolSizeInBytes; 35 | m_outputOffset = 0; 36 | m_tempOffset = poolSizeInBytes; 37 | } 38 | 39 | CUdeviceptr ASArena::allocOutput(size_t bytes) 40 | { 41 | m_outputOffset = roundUp(m_outputOffset, ByteAlignment); 42 | 43 | CUdeviceptr pointer = m_basePtr + m_outputOffset; 44 | 45 | m_outputOffset += bytes; 46 | if (m_outputOffset >= m_tempOffset) { 47 | std::cout << "Arena Memory:" << std::endl 48 | << " Requested(mb): " << bytes / (1024. * 1024.) << std::endl 49 | << " Output(mb): " << m_outputOffset / (1024. * 1024.) << std::endl 50 | << " Temp(mb): " << (m_poolSizeInBytes - m_tempOffset) / (1024. * 1024.) << std::endl; 51 | 52 | throw std::runtime_error("Not enough arena memory"); 53 | } 54 | 55 | return pointer; 56 | } 57 | 58 | void ASArena::returnCompactedOutput(size_t bytes) 59 | { 60 | m_outputOffset -= bytes; 61 | } 62 | 63 | CUdeviceptr ASArena::pushTemp(size_t bytes) 64 | { 65 | bytes = roundUp(bytes, ByteAlignment); 66 | 67 | m_tempOffset -= bytes; 68 | m_tempOffsetStack.push_back(bytes); 69 | 70 | if (m_tempOffset <= m_outputOffset) { 71 | std::cout << "Arena Memory:" << std::endl 72 | << " Requested(mb): " << bytes / (1024. * 1024.) << std::endl 73 | << " Output(mb): " << m_outputOffset / (1024. * 1024.) << std::endl 74 | << " Temp(mb): " << (m_poolSizeInBytes - m_tempOffset) / (1024. * 1024.) << std::endl; 75 | 76 | throw std::runtime_error("Not enough arena memory"); 77 | } 78 | 79 | CUdeviceptr pointer = m_basePtr + m_tempOffset; 80 | return pointer; 81 | } 82 | 83 | void ASArena::popTemp() 84 | { 85 | if (m_tempOffsetStack.empty()) { 86 | throw std::runtime_error("No temp memory to pop!"); 87 | } 88 | 89 | size_t currentTempSize = m_tempOffsetStack.back(); 90 | m_tempOffset += currentTempSize; 91 | 92 | m_tempOffsetStack.pop_back(); 93 | } 94 | 95 | Snapshot ASArena::createSnapshot() 96 | { 97 | Snapshot snapshot; 98 | CHECK_CUDA(cudaMallocHost(&snapshot.dataPtr, m_outputOffset)); 99 | snapshot.sizeInBytes = m_outputOffset; 100 | 101 | CHECK_CUDA(cudaMemcpy( 102 | snapshot.dataPtr, 103 | reinterpret_cast(m_basePtr), 104 | m_outputOffset, 105 | cudaMemcpyDeviceToHost 106 | )); 107 | CHECK_CUDA(cudaDeviceSynchronize()); 108 | 109 | return snapshot; 110 | } 111 | 112 | void ASArena::restoreSnapshot(Snapshot snapshot) 113 | { 114 | assert(snapshot.sizeInBytes <= m_poolSizeInBytes); 115 | if (snapshot.sizeInBytes > m_tempOffset) { 116 | throw std::runtime_error("Not enough arena memory"); 117 | } 118 | 119 | m_outputOffset = snapshot.sizeInBytes; 120 | CHECK_CUDA(cudaMemcpy( 121 | reinterpret_cast(m_basePtr), 122 | snapshot.dataPtr, 123 | snapshot.sizeInBytes, 124 | cudaMemcpyHostToDevice 125 | )); 126 | CHECK_CUDA(cudaDeviceSynchronize()); 127 | } 128 | 129 | void ASArena::releaseAll() 130 | { 131 | m_outputOffset = 0; 132 | 133 | assert(m_tempOffsetStack.empty()); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/scene/bay_cedar_a1_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/bay_cedar_a1_element.hpp" 2 | 3 | namespace moana { 4 | 5 | BayCedarA1Element::BayCedarA1Element() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isBayCedarA1"; 10 | 11 | m_mtlLookup = { 12 | "bark", 13 | "barkSimple", 14 | "leaves", 15 | }; 16 | 17 | m_materialOffset = 1; 18 | 19 | m_baseObjs = { 20 | moanaRoot + "/island/obj/isBayCedarA1/isBayCedarA1.obj", 21 | }; 22 | 23 | m_objArchivePaths = { 24 | moanaRoot + "/island/obj/isBayCedarA1/archives/archivebaycedar0001_mod.obj", 25 | }; 26 | 27 | m_elementInstancesBinPaths = { 28 | "../scene/isBayCedarA1.bin", 29 | }; 30 | 31 | m_primitiveInstancesBinPaths = { 32 | {"../scene/isBayCedarA1_xgBonsai--archivebaycedar0001_mod.bin"}, 33 | }; 34 | 35 | m_primitiveInstancesHandleIndices = { 36 | {0}, 37 | }; 38 | 39 | m_curveBinPathsByElementInstance = { 40 | {}, 41 | }; 42 | 43 | m_curveMtlIndicesByElementInstance = { 44 | {}, 45 | }; 46 | 47 | 48 | } 49 | 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/scene/bay_cedar_a1_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class BayCedarA1Element : public Element { 8 | public: 9 | BayCedarA1Element(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/beach_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class BeachElement : public Element { 8 | public: 9 | BeachElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/coastline_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/coastline_element.hpp" 2 | 3 | namespace moana { 4 | 5 | CoastlineElement::CoastlineElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isCoastline"; 10 | 11 | m_mtlLookup = { 12 | "archiveFibers", 13 | "archiveLeaflet", 14 | "sandSimple", 15 | }; 16 | 17 | m_materialOffset = 18; 18 | 19 | m_baseObjs = { 20 | moanaRoot + "/island/obj/isCoastline/isCoastline.obj", 21 | }; 22 | 23 | m_objArchivePaths = { 24 | moanaRoot + "/island/obj/isCoastline/archives/xgFibers_archivepineneedle0001_mod.obj", 25 | moanaRoot + "/island/obj/isCoastline/archives/xgFibers_archivepineneedle0002_mod.obj", 26 | moanaRoot + "/island/obj/isCoastline/archives/xgFibers_archivepineneedle0003_mod.obj", 27 | moanaRoot + "/island/obj/isCoastline/archives/xgFibers_archiveseedpodb_mod.obj", 28 | moanaRoot + "/island/obj/isCoastline/archives/xgPalmDebris_archiveLeaflet0123_geo.obj", 29 | moanaRoot + "/island/obj/isCoastline/archives/xgPalmDebris_archiveLeaflet0124_geo.obj", 30 | moanaRoot + "/island/obj/isCoastline/archives/xgPalmDebris_archiveLeaflet0125_geo.obj", 31 | moanaRoot + "/island/obj/isCoastline/archives/xgPalmDebris_archiveLeaflet0126_geo.obj", 32 | moanaRoot + "/island/obj/isCoastline/archives/xgPalmDebris_archiveLeaflet0127_geo.obj", 33 | }; 34 | 35 | m_elementInstancesBinPaths = { 36 | "../scene/isCoastline.bin", 37 | }; 38 | 39 | m_primitiveInstancesBinPaths = { 40 | {"../scene/isCoastline_xgPalmDebris--xgPalmDebris_archiveLeaflet0125_geo.bin", "../scene/isCoastline_xgPalmDebris--xgPalmDebris_archiveLeaflet0127_geo.bin", "../scene/isCoastline_xgPalmDebris--xgPalmDebris_archiveLeaflet0124_geo.bin", "../scene/isCoastline_xgPalmDebris--xgPalmDebris_archiveLeaflet0123_geo.bin", "../scene/isCoastline_xgPalmDebris--xgPalmDebris_archiveLeaflet0126_geo.bin", "../scene/isCoastline_xgFibers--xgFibers_archiveseedpodb_mod.bin", "../scene/isCoastline_xgFibers--xgFibers_archivepineneedle0002_mod.bin", "../scene/isCoastline_xgFibers--xgFibers_archivepineneedle0003_mod.bin", "../scene/isCoastline_xgFibers--xgFibers_archivepineneedle0001_mod.bin"}, 41 | }; 42 | 43 | m_primitiveInstancesHandleIndices = { 44 | {6, 8, 5, 4, 7, 3, 1, 2, 0}, 45 | }; 46 | 47 | m_curveBinPathsByElementInstance = { 48 | {"../scene/curves__isCoastline_xgGrass.bin"}, 49 | }; 50 | 51 | m_curveMtlIndicesByElementInstance = { 52 | {0}, 53 | }; 54 | 55 | 56 | } 57 | 58 | 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/scene/coastline_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class CoastlineElement : public Element { 8 | public: 9 | CoastlineElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/container.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/container.hpp" 2 | 3 | #include 4 | 5 | #include "scene/bay_cedar_a1_element.hpp" 6 | #include "scene/beach_element.hpp" 7 | #include "scene/coastline_element.hpp" 8 | #include "scene/coral_element.hpp" 9 | #include "scene/dunes_a_element.hpp" 10 | #include "scene/dunes_b_element.hpp" 11 | #include "scene/element.hpp" 12 | #include "scene/gardenia_a_element.hpp" 13 | #include "scene/hibiscus_element.hpp" 14 | #include "scene/hibiscus_young_element.hpp" 15 | #include "scene/ias.hpp" 16 | #include "scene/ironwood_a1_element.hpp" 17 | #include "scene/ironwood_b_element.hpp" 18 | #include "scene/kava_element.hpp" 19 | #include "scene/lava_rocks_element.hpp" 20 | #include "scene/mountain_a_element.hpp" 21 | #include "scene/mountain_b_element.hpp" 22 | #include "scene/naupaka_a_element.hpp" 23 | #include "scene/ocean_element.hpp" 24 | #include "scene/palm_dead_element.hpp" 25 | #include "scene/palm_rig_element.hpp" 26 | #include "scene/pandanus_a_element.hpp" 27 | 28 | #include 29 | #include 30 | 31 | namespace moana { namespace Container { 32 | 33 | std::vector createGeometryResults( 34 | OptixDeviceContext context, 35 | ASArena &arena 36 | ) { 37 | std::vector geometries; 38 | 39 | std::unique_ptr elementPtrs[] = { 40 | std::make_unique(), 41 | std::make_unique(), 42 | std::make_unique(), 43 | std::make_unique(), 44 | std::make_unique(), 45 | std::make_unique(), 46 | std::make_unique(), 47 | std::make_unique(), 48 | std::make_unique(), 49 | std::make_unique(), 50 | std::make_unique(), 51 | std::make_unique(), 52 | std::make_unique(), 53 | std::make_unique(), 54 | std::make_unique(), 55 | std::make_unique(), 56 | std::make_unique(), 57 | std::make_unique(), 58 | std::make_unique(), 59 | std::make_unique(), 60 | std::make_unique(), 61 | std::make_unique(), 62 | }; 63 | 64 | int elementSBTOffset = 0; 65 | for (const auto &elementPtr : elementPtrs) { 66 | auto result = elementPtr->buildAcceleration(context, arena, elementSBTOffset); 67 | elementSBTOffset += result.hostSBTRecords.size(); 68 | 69 | geometries.push_back(result); 70 | } 71 | 72 | return geometries; 73 | } 74 | 75 | } } 76 | -------------------------------------------------------------------------------- /src/scene/container.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "moana/scene/as_arena.hpp" 8 | #include "moana/scene/types.hpp" 9 | 10 | namespace moana { namespace Container { 11 | 12 | std::vector createGeometryResults( 13 | OptixDeviceContext context, 14 | ASArena &arena 15 | ); 16 | 17 | } } 18 | -------------------------------------------------------------------------------- /src/scene/coral_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class CoralElement : public Element { 8 | public: 9 | CoralElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/dunes_a_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/dunes_a_element.hpp" 2 | 3 | namespace moana { 4 | 5 | DunesAElement::DunesAElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isDunesA"; 10 | 11 | m_mtlLookup = { 12 | "archiveHibiscusFlower", 13 | "archiveLeaflet", 14 | "archiveMuskFern", 15 | "archivePalm", 16 | "base", 17 | "shoots", 18 | "soil", 19 | "underDunes", 20 | "xgDebris", 21 | "xgRoots", 22 | "xgShootRoots", 23 | }; 24 | 25 | m_materialOffset = 26; 26 | 27 | m_baseObjs = { 28 | moanaRoot + "/island/obj/isDunesA/isDunesA.obj", 29 | }; 30 | 31 | m_objArchivePaths = { 32 | moanaRoot + "/island/obj/isDunesA/archives/xgDebris_archivepineneedle0001_mod.obj", 33 | moanaRoot + "/island/obj/isDunesA/archives/xgDebris_archivepineneedle0002_mod.obj", 34 | moanaRoot + "/island/obj/isDunesA/archives/xgDebris_archivepineneedle0003_mod.obj", 35 | moanaRoot + "/island/obj/isDunesA/archives/xgDebris_archiveseedpoda_mod.obj", 36 | moanaRoot + "/island/obj/isDunesA/archives/xgDebris_archiveseedpodb_mod.obj", 37 | moanaRoot + "/island/obj/isDunesA/archives/xgHibiscusFlower_archiveHibiscusFlower0002_mod.obj", 38 | moanaRoot + "/island/obj/isDunesA/archives/xgHibiscusFlower_archiveHibiscusFlower0003_mod.obj", 39 | moanaRoot + "/island/obj/isDunesA/archives/xgHibiscusFlower_archiveHibiscusFlower0004_mod.obj", 40 | moanaRoot + "/island/obj/isDunesA/archives/xgHibiscusFlower_archiveHibiscusFlower0005_mod.obj", 41 | moanaRoot + "/island/obj/isDunesA/archives/xgHibiscusFlower_archiveHibiscusFlower0006_mod.obj", 42 | moanaRoot + "/island/obj/isDunesA/archives/xgHibiscusFlower_archiveHibiscusFlower0007_mod.obj", 43 | moanaRoot + "/island/obj/isDunesA/archives/xgHibiscusFlower_archiveHibiscusFlower0008_mod.obj", 44 | moanaRoot + "/island/obj/isDunesA/archives/xgHibiscusFlower_archiveHibiscusFlower0009_mod.obj", 45 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0001_mod.obj", 46 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0002_mod.obj", 47 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0003_mod.obj", 48 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0004_mod.obj", 49 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0005_mod.obj", 50 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0006_mod.obj", 51 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0007_mod.obj", 52 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0008_mod.obj", 53 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0009_mod.obj", 54 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0010_mod.obj", 55 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0011_mod.obj", 56 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0012_mod.obj", 57 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0013_mod.obj", 58 | moanaRoot + "/island/obj/isDunesA/archives/xgMuskFern_fern0014_mod.obj", 59 | moanaRoot + "/island/obj/isDunesA/archives/xgPalmDebris_archiveLeaflet0123_geo.obj", 60 | moanaRoot + "/island/obj/isDunesA/archives/xgPalmDebris_archiveLeaflet0124_geo.obj", 61 | moanaRoot + "/island/obj/isDunesA/archives/xgPalmDebris_archiveLeaflet0125_geo.obj", 62 | moanaRoot + "/island/obj/isDunesA/archives/xgPalmDebris_archiveLeaflet0126_geo.obj", 63 | moanaRoot + "/island/obj/isDunesA/archives/xgPalmDebris_archiveLeaflet0127_geo.obj", 64 | moanaRoot + "/island/obj/isDunesA/archives/xgPalmDebris_archivePalmdead0004_mod.obj", 65 | }; 66 | 67 | m_elementInstancesBinPaths = { 68 | "../scene/isDunesA.bin", 69 | }; 70 | 71 | m_primitiveInstancesBinPaths = { 72 | {"../scene/isDunesA_xgPalmDebris--xgPalmDebris_archivePalmdead0004_mod.bin", "../scene/isDunesA_xgPalmDebris--xgPalmDebris_archiveLeaflet0124_geo.bin", "../scene/isDunesA_xgPalmDebris--xgPalmDebris_archiveLeaflet0126_geo.bin", "../scene/isDunesA_xgPalmDebris--xgPalmDebris_archiveLeaflet0123_geo.bin", "../scene/isDunesA_xgPalmDebris--xgPalmDebris_archiveLeaflet0127_geo.bin", "../scene/isDunesA_xgPalmDebris--xgPalmDebris_archiveLeaflet0125_geo.bin", "../scene/isDunesA_xgDebris--xgDebris_archiveseedpodb_mod.bin", "../scene/isDunesA_xgDebris--xgDebris_archiveseedpoda_mod.bin", "../scene/isDunesA_xgDebris--xgDebris_archivepineneedle0003_mod.bin", "../scene/isDunesA_xgDebris--xgDebris_archivepineneedle0002_mod.bin", "../scene/isDunesA_xgDebris--xgDebris_archivepineneedle0001_mod.bin", "../scene/isDunesA_xgHibiscusFlower--xgHibiscusFlower_archiveHibiscusFlower0009_mod.bin", "../scene/isDunesA_xgHibiscusFlower--xgHibiscusFlower_archiveHibiscusFlower0005_mod.bin", "../scene/isDunesA_xgHibiscusFlower--xgHibiscusFlower_archiveHibiscusFlower0008_mod.bin", "../scene/isDunesA_xgHibiscusFlower--xgHibiscusFlower_archiveHibiscusFlower0004_mod.bin", "../scene/isDunesA_xgHibiscusFlower--xgHibiscusFlower_archiveHibiscusFlower0007_mod.bin", "../scene/isDunesA_xgHibiscusFlower--xgHibiscusFlower_archiveHibiscusFlower0006_mod.bin", "../scene/isDunesA_xgHibiscusFlower--xgHibiscusFlower_archiveHibiscusFlower0003_mod.bin", "../scene/isDunesA_xgHibiscusFlower--xgHibiscusFlower_archiveHibiscusFlower0002_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0011_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0002_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0012_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0004_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0005_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0010_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0006_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0008_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0009_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0007_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0003_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0013_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0001_mod.bin", "../scene/isDunesA_xgMuskFern--xgMuskFern_fern0014_mod.bin"}, 73 | }; 74 | 75 | m_primitiveInstancesHandleIndices = { 76 | {32, 28, 30, 27, 31, 29, 4, 3, 2, 1, 0, 12, 8, 11, 7, 10, 9, 6, 5, 23, 14, 24, 16, 17, 22, 18, 20, 21, 19, 15, 25, 13, 26}, 77 | }; 78 | 79 | m_curveBinPathsByElementInstance = { 80 | {"../scene/curves__isDunesA_xgRoots.bin", "../scene/curves__isDunesA_xgShootRoots.bin"}, 81 | }; 82 | 83 | m_curveMtlIndicesByElementInstance = { 84 | {9, 10}, 85 | }; 86 | 87 | 88 | } 89 | 90 | 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/scene/dunes_a_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class DunesAElement : public Element { 8 | public: 9 | DunesAElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/dunes_b_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/dunes_b_element.hpp" 2 | 3 | namespace moana { 4 | 5 | DunesBElement::DunesBElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isDunesB"; 10 | 11 | m_mtlLookup = { 12 | "isBayCedar_bark", 13 | "isBayCedar_barkSimple", 14 | "isBayCedar_leaves", 15 | "isIronwoodA_archive_bark", 16 | "isIronwoodA_barkSimple", 17 | "isIronwoodA_leaves", 18 | "isPandanus_leavesLower", 19 | "isPandanus_leavesSimple", 20 | "isPandanus_trunk", 21 | "soilSimple", 22 | "xgRoots", 23 | }; 24 | 25 | m_materialOffset = 37; 26 | 27 | m_baseObjs = { 28 | moanaRoot + "/island/obj/isDunesB/isDunesB.obj", 29 | }; 30 | 31 | m_objArchivePaths = { 32 | moanaRoot + "/island/obj/isDunesB/archives/xgPandanus_isPandanusAlo_base.obj", 33 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0001_geo.obj", 34 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0002_geo.obj", 35 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0003_geo.obj", 36 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0004_geo.obj", 37 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0005_geo.obj", 38 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0006_geo.obj", 39 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0007_geo.obj", 40 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0008_geo.obj", 41 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0009_geo.obj", 42 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0010_geo.obj", 43 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0011_geo.obj", 44 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0012_geo.obj", 45 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0013_geo.obj", 46 | moanaRoot + "/island/obj/isDunesB/archives/xgRoots_archiveroot0014_geo.obj", 47 | moanaRoot + "/island/obj/isIronwoodA1/isIronwoodA1_variantA_lo.obj", 48 | moanaRoot + "/island/obj/isIronwoodA1/isIronwoodA1_variantB_lo.obj", 49 | }; 50 | 51 | m_elementInstancesBinPaths = { 52 | "../scene/isDunesB.bin", 53 | }; 54 | 55 | m_primitiveInstancesBinPaths = { 56 | {"../scene/isDunesB_xgTreeSkyLine--isIronwoodA1_variantA_lo.bin", "../scene/isDunesB_xgTreeSkyLine--isIronwoodA1_variantB_lo.bin", "../scene/isDunesB_xgPandanus--xgPandanus_isPandanusAlo_base.bin", "../scene/isDunesB_xgTreeSpecific--isIronwoodA1_variantA_lo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0001_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0012_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0003_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0002_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0014_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0007_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0009_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0004_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0006_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0010_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0005_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0013_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0011_geo.bin", "../scene/isDunesB_xgRoots--xgRoots_archiveroot0008_geo.bin"}, 57 | }; 58 | 59 | m_primitiveInstancesHandleIndices = { 60 | {15, 16, 0, 15, 1, 12, 3, 2, 14, 7, 9, 4, 6, 10, 5, 13, 11, 8}, 61 | }; 62 | 63 | m_curveBinPathsByElementInstance = { 64 | {}, 65 | }; 66 | 67 | m_curveMtlIndicesByElementInstance = { 68 | {}, 69 | }; 70 | 71 | 72 | } 73 | 74 | 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/scene/dunes_b_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class DunesBElement : public Element { 8 | public: 9 | DunesBElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include "moana/scene/as_arena.hpp" 9 | #include "moana/scene/types.hpp" 10 | 11 | namespace moana { 12 | 13 | class Element { 14 | public: 15 | virtual GeometryResult buildAcceleration( 16 | OptixDeviceContext context, 17 | ASArena &arena, 18 | int elementSBTOffset 19 | ); 20 | 21 | protected: 22 | std::string m_elementName; 23 | 24 | // Element geometries. See isPalmRig for example where every element instance 25 | // has unique geometry 26 | std::vector m_baseObjs; 27 | 28 | // Transform bin paths for each element instance with unique geometry 29 | std::vector m_elementInstancesBinPaths; 30 | 31 | // List of all .obj files used in archives 32 | std::vector m_objArchivePaths; 33 | 34 | // Transforms for each archive (compiled from their json digest) 35 | std::vector > m_primitiveInstancesBinPaths; 36 | 37 | // Indices that are used to lookup handles (built earlier in the pipeline) 38 | // to primitive GAS's 39 | std::vector > m_primitiveInstancesHandleIndices; 40 | 41 | // Path to curve binaries for each element instance 42 | std::vector > m_curveBinPathsByElementInstance; 43 | 44 | // List ordering how the element's materials map to the SBT 45 | std::vector m_mtlLookup; 46 | 47 | // Curve materials aren't defined in the obj like archives, store them here 48 | std::vector > m_curveMtlIndicesByElementInstance; 49 | 50 | int m_materialOffset = 0; 51 | bool m_shouldSplitPrimitiveInstances = false; 52 | }; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/scene/gardenia_a_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/gardenia_a_element.hpp" 2 | 3 | namespace moana { 4 | 5 | GardeniaAElement::GardeniaAElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isGardeniaA"; 10 | 11 | m_mtlLookup = { 12 | "bark", 13 | "barkSimple", 14 | "instances", 15 | "leaves", 16 | }; 17 | 18 | m_materialOffset = 48; 19 | 20 | m_baseObjs = { 21 | moanaRoot + "/island/obj/isGardeniaA/isGardeniaA.obj", 22 | }; 23 | 24 | m_objArchivePaths = { 25 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardenia0001_mod.obj", 26 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardenia0002_mod.obj", 27 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardenia0003_mod.obj", 28 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardenia0004_mod.obj", 29 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardenia0005_mod.obj", 30 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardenia0006_mod.obj", 31 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardenia0007_mod.obj", 32 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardenia0008_mod.obj", 33 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardenia0009_mod.obj", 34 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardeniaflw0001_mod.obj", 35 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardeniaflw0002_mod.obj", 36 | moanaRoot + "/island/obj/isGardeniaA/archives/archivegardeniaflw0003_mod.obj", 37 | }; 38 | 39 | m_elementInstancesBinPaths = { 40 | "../scene/isGardeniaA.bin", 41 | }; 42 | 43 | m_primitiveInstancesBinPaths = { 44 | {"../scene/isGardeniaA_xgBonsai--archivegardenia0008_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardenia0006_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardenia0007_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardenia0002_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardenia0003_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardenia0005_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardeniaflw0001_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardenia0001_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardenia0004_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardenia0009_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardeniaflw0002_mod.bin", "../scene/isGardeniaA_xgBonsai--archivegardeniaflw0003_mod.bin"}, 45 | }; 46 | 47 | m_primitiveInstancesHandleIndices = { 48 | {7, 5, 6, 1, 2, 4, 9, 0, 3, 8, 10, 11}, 49 | }; 50 | 51 | m_curveBinPathsByElementInstance = { 52 | {}, 53 | }; 54 | 55 | m_curveMtlIndicesByElementInstance = { 56 | {}, 57 | }; 58 | 59 | 60 | } 61 | 62 | 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/scene/gardenia_a_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class GardeniaAElement : public Element { 8 | public: 9 | GardeniaAElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/gas.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/gas.hpp" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "assert_macros.hpp" 10 | #include "util/enumerate.hpp" 11 | 12 | namespace moana { namespace GAS { 13 | 14 | OptixTraversableHandle gasInfoFromMeshRecords( 15 | OptixDeviceContext context, 16 | ASArena &arena, 17 | const std::vector &records, 18 | int primitiveIndexOffset 19 | ) { 20 | OptixAccelBuildOptions accelOptions = {}; 21 | accelOptions.buildFlags = OPTIX_BUILD_FLAG_ALLOW_RANDOM_VERTEX_ACCESS; // fixme; use user data 22 | accelOptions.operation = OPTIX_BUILD_OPERATION_BUILD; // no updates 23 | 24 | const int buildInputCount = records.size(); 25 | std::vector triangleInputs(buildInputCount); // fixme: So many buildInputCount > 100k 26 | memset(triangleInputs.data(), 0, sizeof(OptixBuildInput) * buildInputCount); 27 | 28 | std::vector verticesToFree(buildInputCount); 29 | std::vector vertexIndicesToFree(buildInputCount); 30 | 31 | uint32_t inputFlags[] = { OPTIX_GEOMETRY_FLAG_DISABLE_ANYHIT }; 32 | for (const auto &[i, record] : enumerate(records)) { 33 | size_t verticesSizeInBytes = record.vertices.size() * sizeof(float); 34 | CUdeviceptr d_vertices = arena.pushTemp(verticesSizeInBytes); 35 | CHECK_CUDA(cudaMemcpy( 36 | reinterpret_cast(d_vertices), 37 | record.vertices.data(), 38 | verticesSizeInBytes, 39 | cudaMemcpyHostToDevice 40 | )); 41 | 42 | size_t vertexIndicesSizeInBytes = record.vertexIndices.size() * sizeof(int); 43 | CUdeviceptr d_vertexIndices = arena.pushTemp(vertexIndicesSizeInBytes); 44 | CHECK_CUDA(cudaMemcpy( 45 | reinterpret_cast(d_vertexIndices), 46 | record.vertexIndices.data(), 47 | vertexIndicesSizeInBytes, 48 | cudaMemcpyHostToDevice 49 | )); 50 | 51 | verticesToFree[i] = d_vertices; 52 | vertexIndicesToFree[i] = d_vertexIndices; 53 | 54 | // Setup build input 55 | triangleInputs[i].type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; 56 | 57 | triangleInputs[i].triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; 58 | triangleInputs[i].triangleArray.numVertices = record.vertices.size() / 3; 59 | triangleInputs[i].triangleArray.vertexBuffers = &verticesToFree[i]; 60 | 61 | triangleInputs[i].triangleArray.numIndexTriplets = record.indexTripletCount; 62 | triangleInputs[i].triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; 63 | triangleInputs[i].triangleArray.indexBuffer = d_vertexIndices; 64 | 65 | triangleInputs[i].triangleArray.flags = inputFlags; 66 | triangleInputs[i].triangleArray.primitiveIndexOffset = 0; 67 | triangleInputs[i].triangleArray.numSbtRecords = 1; 68 | } 69 | 70 | // Calculate max memory size 71 | OptixAccelBufferSizes gasBufferSizes; 72 | CHECK_OPTIX(optixAccelComputeMemoryUsage( 73 | context, 74 | &accelOptions, 75 | triangleInputs.data(), 76 | buildInputCount, 77 | &gasBufferSizes 78 | )); 79 | 80 | std::cout << " GAS:" << std::endl; 81 | std::cout << " Output Buffer size(mb): " 82 | << (gasBufferSizes.outputSizeInBytes / (1024. * 1024.)) 83 | << std::endl 84 | << " Temp Buffer size(mb): " 85 | << (gasBufferSizes.tempSizeInBytes / (1024. * 1024.)) 86 | << std::endl 87 | << std::endl; 88 | 89 | CUdeviceptr d_tempBufferGas = arena.pushTemp(gasBufferSizes.tempSizeInBytes); 90 | CUdeviceptr d_gasOutputBuffer = arena.allocOutput(gasBufferSizes.outputSizeInBytes); 91 | 92 | OptixTraversableHandle handle; 93 | CHECK_OPTIX(optixAccelBuild( 94 | context, 95 | 0, // default CUDA stream 96 | &accelOptions, 97 | triangleInputs.data(), 98 | buildInputCount, 99 | d_tempBufferGas, 100 | gasBufferSizes.tempSizeInBytes, 101 | d_gasOutputBuffer, 102 | gasBufferSizes.outputSizeInBytes, 103 | &handle, 104 | nullptr, 0 // emitted property params 105 | )); 106 | 107 | CHECK_CUDA(cudaDeviceSynchronize()); 108 | 109 | for (auto d_vertices : verticesToFree) { 110 | arena.popTemp(); 111 | } 112 | for (auto d_vertexIndices : vertexIndicesToFree) { 113 | arena.popTemp(); 114 | } 115 | arena.popTemp(); 116 | 117 | return handle; 118 | } 119 | 120 | } } 121 | -------------------------------------------------------------------------------- /src/scene/gas.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "moana/parsers/obj_parser.hpp" 6 | #include "moana/scene/as_arena.hpp" 7 | 8 | namespace moana { namespace GAS { 9 | 10 | OptixTraversableHandle gasInfoFromMeshRecords( 11 | OptixDeviceContext context, 12 | ASArena &arena, 13 | const std::vector &records, 14 | int primitiveIndexOffset = 0 15 | ); 16 | 17 | } } 18 | -------------------------------------------------------------------------------- /src/scene/hibiscus_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/hibiscus_element.hpp" 2 | 3 | namespace moana { 4 | 5 | HibiscusElement::HibiscusElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isHibiscus"; 10 | 11 | m_mtlLookup = { 12 | "branches", 13 | "flowerHibiscus", 14 | "leafHibiscus", 15 | "trunk", 16 | }; 17 | 18 | m_materialOffset = 52; 19 | 20 | m_baseObjs = { 21 | moanaRoot + "/island/obj/isHibiscus/isHibiscus.obj", 22 | }; 23 | 24 | m_objArchivePaths = { 25 | moanaRoot + "/island/obj/isHibiscus/archives/archiveHibiscusFlower0001_mod.obj", 26 | moanaRoot + "/island/obj/isHibiscus/archives/archiveHibiscusLeaf0001_mod.obj", 27 | moanaRoot + "/island/obj/isHibiscus/archives/archiveHibiscusLeaf0002_mod.obj", 28 | moanaRoot + "/island/obj/isHibiscus/archives/archiveHibiscusLeaf0003_mod.obj", 29 | }; 30 | 31 | m_elementInstancesBinPaths = { 32 | "../scene/isHibiscus.bin", 33 | }; 34 | 35 | m_primitiveInstancesBinPaths = { 36 | {"../scene/isHibiscus_xgBonsai--archiveHibiscusLeaf0001_mod.bin", "../scene/isHibiscus_xgBonsai--archiveHibiscusFlower0001_mod.bin", "../scene/isHibiscus_xgBonsai--archiveHibiscusLeaf0003_mod.bin", "../scene/isHibiscus_xgBonsai--archiveHibiscusLeaf0002_mod.bin"}, 37 | }; 38 | 39 | m_primitiveInstancesHandleIndices = { 40 | {1, 0, 3, 2}, 41 | }; 42 | 43 | m_curveBinPathsByElementInstance = { 44 | {}, 45 | }; 46 | 47 | m_curveMtlIndicesByElementInstance = { 48 | {}, 49 | }; 50 | 51 | 52 | } 53 | 54 | 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/scene/hibiscus_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class HibiscusElement : public Element { 8 | public: 9 | HibiscusElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/hibiscus_young_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/hibiscus_young_element.hpp" 2 | 3 | namespace moana { 4 | 5 | HibiscusYoungElement::HibiscusYoungElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isHibiscusYoung"; 10 | 11 | m_mtlLookup = { 12 | "branches", 13 | "flowerHibiscus", 14 | "leafHibiscus", 15 | "trunk", 16 | }; 17 | 18 | m_materialOffset = 56; 19 | 20 | m_baseObjs = { 21 | moanaRoot + "/island/obj/isHibiscusYoung/isHibiscusYoung.obj", 22 | }; 23 | 24 | m_objArchivePaths = { 25 | moanaRoot + "/island/obj/isHibiscus/archives/archiveHibiscusFlower0001_mod.obj", 26 | moanaRoot + "/island/obj/isHibiscus/archives/archiveHibiscusLeaf0001_mod.obj", 27 | moanaRoot + "/island/obj/isHibiscus/archives/archiveHibiscusLeaf0002_mod.obj", 28 | moanaRoot + "/island/obj/isHibiscus/archives/archiveHibiscusLeaf0003_mod.obj", 29 | }; 30 | 31 | m_elementInstancesBinPaths = { 32 | "../scene/isHibiscusYoung.bin", 33 | }; 34 | 35 | m_primitiveInstancesBinPaths = { 36 | {"../scene/isHibiscusYoung_xgBonsai--archiveHibiscusLeaf0003_mod.bin", "../scene/isHibiscusYoung_xgBonsai--archiveHibiscusLeaf0002_mod.bin", "../scene/isHibiscusYoung_xgBonsai--archiveHibiscusLeaf0001_mod.bin", "../scene/isHibiscusYoung_xgBonsai--archiveHibiscusFlower0001_mod.bin"}, 37 | }; 38 | 39 | m_primitiveInstancesHandleIndices = { 40 | {3, 2, 1, 0}, 41 | }; 42 | 43 | m_curveBinPathsByElementInstance = { 44 | {}, 45 | }; 46 | 47 | m_curveMtlIndicesByElementInstance = { 48 | {}, 49 | }; 50 | 51 | 52 | } 53 | 54 | 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/scene/hibiscus_young_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class HibiscusYoungElement : public Element { 8 | public: 9 | HibiscusYoungElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/ias.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/ias.hpp" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "assert_macros.hpp" 9 | 10 | namespace moana { namespace IAS { 11 | 12 | void createOptixInstanceRecords( 13 | OptixDeviceContext context, 14 | std::vector &records, 15 | const Instances &instances, 16 | const OptixTraversableHandle &traversableHandle, 17 | int sbtOffset 18 | ) { 19 | int offset = records.size(); 20 | for (int i = 0; i < instances.count; i++) { 21 | OptixInstance instance; 22 | memcpy( 23 | instance.transform, 24 | &instances.transforms[i * 12], 25 | sizeof(float) * 12 26 | ); 27 | 28 | instance.instanceId = offset + i; 29 | instance.visibilityMask = 255; 30 | instance.sbtOffset = sbtOffset; 31 | instance.flags = OPTIX_INSTANCE_FLAG_NONE; 32 | instance.traversableHandle = traversableHandle; 33 | 34 | records.push_back(instance); 35 | } 36 | } 37 | 38 | OptixTraversableHandle iasFromInstanceRecords( 39 | OptixDeviceContext context, 40 | ASArena &arena, 41 | const std::vector &records, 42 | bool shouldCompact 43 | ) { 44 | CUdeviceptr d_instances; 45 | const size_t instancesSizeInBytes = sizeof(OptixInstance) * records.size(); 46 | std::cout << "IAS:" << std::endl 47 | << " Records: " << records.size() << std::endl 48 | << " Records size(mb): " << (instancesSizeInBytes / (1024. * 1024.)) << std::endl; 49 | 50 | d_instances = arena.pushTemp(instancesSizeInBytes); 51 | CHECK_CUDA(cudaMemcpy( 52 | reinterpret_cast(d_instances), 53 | records.data(), 54 | instancesSizeInBytes, 55 | cudaMemcpyHostToDevice 56 | )); 57 | 58 | OptixBuildInput instanceInput = {}; 59 | instanceInput.type = OPTIX_BUILD_INPUT_TYPE_INSTANCES; 60 | instanceInput.instanceArray.instances = d_instances; 61 | instanceInput.instanceArray.numInstances = records.size(); 62 | 63 | OptixAccelBuildOptions accelOptions = {}; 64 | accelOptions.buildFlags = OPTIX_BUILD_FLAG_ALLOW_COMPACTION; 65 | accelOptions.operation = OPTIX_BUILD_OPERATION_BUILD; 66 | 67 | OptixAccelBufferSizes iasBufferSizes; 68 | CHECK_OPTIX(optixAccelComputeMemoryUsage( 69 | context, 70 | &accelOptions, 71 | &instanceInput, 72 | 1, // num build inputs 73 | &iasBufferSizes 74 | )); 75 | 76 | std::cout << " Output Buffer size(mb): " 77 | << (iasBufferSizes.outputSizeInBytes / (1024. * 1024.)) << std::endl 78 | << " Temp Buffer size(mb): " 79 | << (iasBufferSizes.tempSizeInBytes / (1024. * 1024.)) << std::endl; 80 | 81 | CUdeviceptr d_tempBuffer = arena.pushTemp(iasBufferSizes.tempSizeInBytes); 82 | CUdeviceptr d_iasOutputBuffer = arena.allocOutput(iasBufferSizes.outputSizeInBytes); 83 | 84 | CUdeviceptr d_compactedSize = arena.pushTemp(sizeof(size_t)); 85 | OptixAccelEmitDesc property; 86 | property.type = OPTIX_PROPERTY_TYPE_COMPACTED_SIZE; 87 | property.result = d_compactedSize; 88 | 89 | OptixTraversableHandle handle; 90 | CHECK_OPTIX(optixAccelBuild( 91 | context, 92 | 0, // CUDA stream 93 | &accelOptions, 94 | &instanceInput, 95 | 1, // num build inputs 96 | d_tempBuffer, 97 | iasBufferSizes.tempSizeInBytes, 98 | d_iasOutputBuffer, 99 | iasBufferSizes.outputSizeInBytes, 100 | &handle, 101 | &property, 102 | 1 103 | )); 104 | CHECK_CUDA(cudaDeviceSynchronize()); 105 | 106 | arena.popTemp(); // tempBuffer 107 | arena.popTemp(); // OptixInstance records 108 | 109 | size_t compactedSize; 110 | CHECK_CUDA(cudaMemcpy( 111 | &compactedSize, 112 | reinterpret_cast(d_compactedSize), 113 | sizeof(size_t), 114 | cudaMemcpyDeviceToHost 115 | )); 116 | 117 | arena.popTemp(); // compactedSize 118 | 119 | if (!shouldCompact) { return handle; } 120 | 121 | std::cout << " Compacted Buffer size(mb): " << compactedSize / (1024. * 1024.) << std::endl; 122 | 123 | CUdeviceptr d_compactedOutputBuffer = arena.pushTemp(compactedSize); 124 | OptixTraversableHandle compactedHandle; 125 | CHECK_OPTIX(optixAccelCompact( 126 | context, 127 | 0, 128 | handle, 129 | d_compactedOutputBuffer, 130 | compactedSize, 131 | &compactedHandle 132 | )); 133 | 134 | CHECK_CUDA(cudaMemcpy( 135 | reinterpret_cast(d_iasOutputBuffer), 136 | reinterpret_cast(d_compactedOutputBuffer), 137 | compactedSize, 138 | cudaMemcpyDeviceToDevice 139 | )); 140 | 141 | OptixAccelRelocationInfo relocationInfo; 142 | CHECK_OPTIX(optixAccelGetRelocationInfo(context, compactedHandle, &relocationInfo)); 143 | 144 | OptixTraversableHandle relocatedHandle; 145 | CHECK_OPTIX(optixAccelRelocate( 146 | context, 147 | 0, 148 | &relocationInfo, 149 | 0, 150 | 0, 151 | d_iasOutputBuffer, 152 | compactedSize, 153 | &relocatedHandle 154 | )); 155 | 156 | arena.returnCompactedOutput(iasBufferSizes.outputSizeInBytes - compactedSize); 157 | arena.popTemp(); // compactedOutputBuffer 158 | 159 | return relocatedHandle; 160 | } 161 | 162 | } } 163 | -------------------------------------------------------------------------------- /src/scene/ias.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "moana/scene/as_arena.hpp" 8 | #include "moana/scene/types.hpp" 9 | 10 | namespace moana { namespace IAS { 11 | 12 | void createOptixInstanceRecords( 13 | OptixDeviceContext context, 14 | std::vector &records, 15 | const Instances &instances, 16 | const OptixTraversableHandle &traversableHandle, 17 | int sbtOffset = 0 // not needed when traversableHandle is an IAS 18 | ); 19 | 20 | OptixTraversableHandle iasFromInstanceRecords( 21 | OptixDeviceContext context, 22 | ASArena &arena, 23 | const std::vector &records, 24 | bool shouldCompact = false 25 | ); 26 | 27 | } } 28 | -------------------------------------------------------------------------------- /src/scene/instances_bin.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/instances_bin.hpp" 2 | 3 | #include 4 | 5 | namespace moana { namespace InstancesBin { 6 | 7 | Instances parse(const std::string &filepath) 8 | { 9 | constexpr int transformSize = 12; 10 | std::ifstream instanceFile(filepath); 11 | 12 | Instances result; 13 | instanceFile.read((char *)&result.count, sizeof(int)); 14 | 15 | int offset = 0; 16 | result.transforms = new float[transformSize * result.count]; 17 | while (instanceFile.peek() != EOF) { 18 | instanceFile.read((char *)&result.transforms[offset], sizeof(float) * transformSize); 19 | offset += transformSize; 20 | } 21 | 22 | return result; 23 | } 24 | 25 | } } 26 | -------------------------------------------------------------------------------- /src/scene/instances_bin.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "moana/scene/types.hpp" 6 | 7 | namespace moana { namespace InstancesBin { 8 | 9 | Instances parse(const std::string &filepath); 10 | 11 | } } 12 | -------------------------------------------------------------------------------- /src/scene/ironwood_a1_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/ironwood_a1_element.hpp" 2 | 3 | namespace moana { 4 | 5 | IronwoodA1Element::IronwoodA1Element() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isIronwoodA1"; 10 | 11 | m_mtlLookup = { 12 | "archive_bark", 13 | "archive_pineNeedles", 14 | "archive_seedPod", 15 | "bark", 16 | "barkSimple", 17 | "leaves", 18 | }; 19 | 20 | m_materialOffset = 60; 21 | 22 | m_baseObjs = { 23 | "../scene/isIronwoodA1-1.obj", 24 | }; 25 | 26 | m_objArchivePaths = { 27 | moanaRoot + "/island/obj/isIronwoodA1/archives/archiveseedpodb_mod.obj", 28 | }; 29 | 30 | m_elementInstancesBinPaths = { 31 | "../scene/isIronwoodA1.bin", 32 | }; 33 | 34 | m_primitiveInstancesBinPaths = { 35 | {"../scene/isIronwoodA1_xgBonsai--archiveseedpodb_mod.bin"}, 36 | }; 37 | 38 | m_primitiveInstancesHandleIndices = { 39 | {0}, 40 | }; 41 | 42 | m_curveBinPathsByElementInstance = { 43 | {}, 44 | }; 45 | 46 | m_curveMtlIndicesByElementInstance = { 47 | {}, 48 | }; 49 | 50 | 51 | } 52 | 53 | 54 | IronwoodA1ElementOverflow::IronwoodA1ElementOverflow() 55 | { 56 | const std::string moanaRoot = MOANA_ROOT; 57 | 58 | m_elementName = "isIronwoodA1"; 59 | 60 | m_mtlLookup = { 61 | "archive_bark", 62 | "archive_pineNeedles", 63 | "archive_seedPod", 64 | "bark", 65 | "barkSimple", 66 | "leaves", 67 | }; 68 | 69 | m_materialOffset = 60; 70 | 71 | m_baseObjs = { 72 | "../scene/isIronwoodA1-2.obj", 73 | }; 74 | 75 | m_objArchivePaths = { 76 | 77 | }; 78 | 79 | m_elementInstancesBinPaths = { 80 | "../scene/isIronwoodA1.bin", 81 | }; 82 | 83 | m_primitiveInstancesBinPaths = { 84 | {}, 85 | }; 86 | 87 | m_primitiveInstancesHandleIndices = { 88 | {}, 89 | }; 90 | 91 | m_curveBinPathsByElementInstance = { 92 | {}, 93 | }; 94 | 95 | m_curveMtlIndicesByElementInstance = { 96 | {}, 97 | }; 98 | 99 | 100 | } 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/scene/ironwood_a1_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class IronwoodA1Element : public Element { 8 | public: 9 | IronwoodA1Element(); 10 | }; 11 | 12 | 13 | class IronwoodA1ElementOverflow : public Element { 14 | public: 15 | IronwoodA1ElementOverflow(); 16 | }; 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/scene/ironwood_b_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/ironwood_b_element.hpp" 2 | 3 | namespace moana { 4 | 5 | IronwoodBElement::IronwoodBElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isIronwoodB"; 10 | 11 | m_mtlLookup = { 12 | "archive_bark", 13 | "archive_pineNeedles", 14 | "archive_seedPod", 15 | "bark", 16 | "barkSimple", 17 | "leaves", 18 | }; 19 | 20 | m_materialOffset = 66; 21 | 22 | m_baseObjs = { 23 | "../scene/isIronwoodB-1.obj", 24 | }; 25 | 26 | m_objArchivePaths = { 27 | moanaRoot + "/island/obj/isIronwoodB/archives/archiveseedpodb_mod.obj", 28 | }; 29 | 30 | m_elementInstancesBinPaths = { 31 | "../scene/isIronwoodB.bin", 32 | }; 33 | 34 | m_primitiveInstancesBinPaths = { 35 | {"../scene/isIronwoodB_xgBonsai--archiveseedpodb_mod.bin"}, 36 | }; 37 | 38 | m_primitiveInstancesHandleIndices = { 39 | {0}, 40 | }; 41 | 42 | m_curveBinPathsByElementInstance = { 43 | {}, 44 | }; 45 | 46 | m_curveMtlIndicesByElementInstance = { 47 | {}, 48 | }; 49 | 50 | 51 | } 52 | 53 | 54 | IronwoodBElementOverflow::IronwoodBElementOverflow() 55 | { 56 | const std::string moanaRoot = MOANA_ROOT; 57 | 58 | m_elementName = "isIronwoodB"; 59 | 60 | m_mtlLookup = { 61 | "archive_bark", 62 | "archive_pineNeedles", 63 | "archive_seedPod", 64 | "bark", 65 | "barkSimple", 66 | "leaves", 67 | }; 68 | 69 | m_materialOffset = 66; 70 | 71 | m_baseObjs = { 72 | "../scene/isIronwoodB-2.obj", 73 | }; 74 | 75 | m_objArchivePaths = { 76 | 77 | }; 78 | 79 | m_elementInstancesBinPaths = { 80 | "../scene/isIronwoodB.bin", 81 | }; 82 | 83 | m_primitiveInstancesBinPaths = { 84 | {}, 85 | }; 86 | 87 | m_primitiveInstancesHandleIndices = { 88 | {}, 89 | }; 90 | 91 | m_curveBinPathsByElementInstance = { 92 | {}, 93 | }; 94 | 95 | m_curveMtlIndicesByElementInstance = { 96 | {}, 97 | }; 98 | 99 | 100 | } 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/scene/ironwood_b_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class IronwoodBElement : public Element { 8 | public: 9 | IronwoodBElement(); 10 | }; 11 | 12 | 13 | class IronwoodBElementOverflow : public Element { 14 | public: 15 | IronwoodBElementOverflow(); 16 | }; 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/scene/kava_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/kava_element.hpp" 2 | 3 | namespace moana { 4 | 5 | KavaElement::KavaElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isKava"; 10 | 11 | m_mtlLookup = { 12 | "bark", 13 | "barkSimple", 14 | "leaves", 15 | }; 16 | 17 | m_materialOffset = 72; 18 | 19 | m_baseObjs = { 20 | moanaRoot + "/island/obj/isKava/isKava.obj", 21 | }; 22 | 23 | m_objArchivePaths = { 24 | moanaRoot + "/island/obj/isKava/archives/archive_kava0001_mod.obj", 25 | }; 26 | 27 | m_elementInstancesBinPaths = { 28 | "../scene/isKava.bin", 29 | }; 30 | 31 | m_primitiveInstancesBinPaths = { 32 | {"../scene/isKava_xgBonsai--archive_kava0001_mod.bin"}, 33 | }; 34 | 35 | m_primitiveInstancesHandleIndices = { 36 | {0}, 37 | }; 38 | 39 | m_curveBinPathsByElementInstance = { 40 | {}, 41 | }; 42 | 43 | m_curveMtlIndicesByElementInstance = { 44 | {}, 45 | }; 46 | 47 | 48 | } 49 | 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/scene/kava_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class KavaElement : public Element { 8 | public: 9 | KavaElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/lava_rocks_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/lava_rocks_element.hpp" 2 | 3 | namespace moana { 4 | 5 | LavaRocksElement::LavaRocksElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isLavaRocks"; 10 | 11 | m_mtlLookup = { 12 | "default", 13 | "volcanicRock", 14 | }; 15 | 16 | m_materialOffset = 75; 17 | 18 | m_baseObjs = { 19 | moanaRoot + "/island/obj/isLavaRocks/isLavaRocks.obj", 20 | moanaRoot + "/island/obj/isLavaRocks/isLavaRocks1.obj", 21 | }; 22 | 23 | m_objArchivePaths = { 24 | 25 | }; 26 | 27 | m_elementInstancesBinPaths = { 28 | "../scene/isLavaRocks.bin", 29 | "../scene/isLavaRocks1.bin", 30 | }; 31 | 32 | m_primitiveInstancesBinPaths = { 33 | {}, 34 | {}, 35 | }; 36 | 37 | m_primitiveInstancesHandleIndices = { 38 | {}, 39 | {}, 40 | }; 41 | 42 | m_curveBinPathsByElementInstance = { 43 | {}, 44 | {}, 45 | }; 46 | 47 | m_curveMtlIndicesByElementInstance = { 48 | {}, 49 | {}, 50 | }; 51 | 52 | 53 | } 54 | 55 | 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/scene/lava_rocks_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class LavaRocksElement : public Element { 8 | public: 9 | LavaRocksElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/materials.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include "moana/cuda/bsdf.hpp" 8 | 9 | namespace moana { namespace Materials { 10 | 11 | extern std::vector baseColors; 12 | extern std::vector bsdfTypes; 13 | 14 | } } 15 | -------------------------------------------------------------------------------- /src/scene/mountain_a_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/mountain_a_element.hpp" 2 | 3 | namespace moana { 4 | 5 | MountainAElement::MountainAElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isMountainA"; 10 | 11 | m_mtlLookup = { 12 | "branches", 13 | "breadFruit", 14 | "fronds", 15 | "leavesOnHillside", 16 | "mountainLo", 17 | "trunk", 18 | }; 19 | 20 | m_materialOffset = 77; 21 | 22 | m_baseObjs = { 23 | moanaRoot + "/island/obj/isMountainA/isMountainA.obj", 24 | }; 25 | 26 | m_objArchivePaths = { 27 | moanaRoot + "/island/obj/isMountainA/archives/xgBreadFruit_archiveBreadFruitBaked.obj", 28 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig.obj", 29 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig1.obj", 30 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig12.obj", 31 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig13.obj", 32 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig14.obj", 33 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig15.obj", 34 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig16.obj", 35 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig17.obj", 36 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig2.obj", 37 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig3.obj", 38 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig4.obj", 39 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig5.obj", 40 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig6.obj", 41 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig7.obj", 42 | moanaRoot + "/island/obj/isMountainA/archives/xgCocoPalms_isPalmRig8.obj", 43 | moanaRoot + "/island/obj/isMountainA/archives/xgFoliageC_treeMadronaBaked_canopyOnly_lo.obj", 44 | }; 45 | 46 | m_elementInstancesBinPaths = { 47 | "../scene/isMountainA.bin", 48 | }; 49 | 50 | m_primitiveInstancesBinPaths = { 51 | {"../scene/isMountainA_xgFoliageC--xgFoliageC_treeMadronaBaked_canopyOnly_lo.bin", "../scene/isMountainA_xgBreadFruit--xgBreadFruit_archiveBreadFruitBaked.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig5.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig6.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig13.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig14.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig3.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig1.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig16.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig15.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig4.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig12.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig8.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig2.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig7.bin", "../scene/isMountainA_xgCocoPalms--xgCocoPalms_isPalmRig17.bin"}, 52 | }; 53 | 54 | m_primitiveInstancesHandleIndices = { 55 | {16, 0, 12, 13, 4, 5, 10, 2, 7, 6, 11, 1, 3, 15, 9, 14, 8}, 56 | }; 57 | 58 | m_curveBinPathsByElementInstance = { 59 | {}, 60 | }; 61 | 62 | m_curveMtlIndicesByElementInstance = { 63 | {}, 64 | }; 65 | 66 | 67 | } 68 | 69 | 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/scene/mountain_a_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class MountainAElement : public Element { 8 | public: 9 | MountainAElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/mountain_b_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/mountain_b_element.hpp" 2 | 3 | namespace moana { 4 | 5 | MountainBElement::MountainBElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isMountainB"; 10 | 11 | m_mtlLookup = { 12 | "branches", 13 | "breadFruit", 14 | "ferns", 15 | "fronds", 16 | "leavesOnHillside", 17 | "loGrowth", 18 | "mountainLo", 19 | "trunk", 20 | "trunkDetailed", 21 | }; 22 | 23 | m_materialOffset = 83; 24 | 25 | m_baseObjs = { 26 | moanaRoot + "/island/obj/isMountainB/isMountainB.obj", 27 | }; 28 | 29 | m_objArchivePaths = { 30 | moanaRoot + "/island/obj/isMountainB/archives/xgBreadFruit_archiveBreadFruitBaked.obj", 31 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig.obj", 32 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig1.obj", 33 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig12.obj", 34 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig13.obj", 35 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig14.obj", 36 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig15.obj", 37 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig16.obj", 38 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig17.obj", 39 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig2.obj", 40 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig3.obj", 41 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig6.obj", 42 | moanaRoot + "/island/obj/isMountainB/archives/xgCocoPalms_isPalmRig8.obj", 43 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0001_mod.obj", 44 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0002_mod.obj", 45 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0003_mod.obj", 46 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0004_mod.obj", 47 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0005_mod.obj", 48 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0006_mod.obj", 49 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0007_mod.obj", 50 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0008_mod.obj", 51 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0009_mod.obj", 52 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0010_mod.obj", 53 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0011_mod.obj", 54 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0012_mod.obj", 55 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0013_mod.obj", 56 | moanaRoot + "/island/obj/isMountainB/archives/xgFern_fern0014_mod.obj", 57 | moanaRoot + "/island/obj/isMountainB/archives/xgFoliageA_treeMadronaBaked_canopyOnly_lo.obj", 58 | moanaRoot + "/island/obj/isMountainB/archives/xgFoliageAd_treeMadronaBaked_canopyOnly_lo.obj", 59 | moanaRoot + "/island/obj/isMountainB/archives/xgFoliageB_treeMadronaBaked_canopyOnly_lo.obj", 60 | moanaRoot + "/island/obj/isMountainB/archives/xgFoliageC_treeMadronaBaked_canopyOnly_lo.obj", 61 | }; 62 | 63 | m_elementInstancesBinPaths = { 64 | "../scene/isMountainB.bin", 65 | }; 66 | 67 | m_primitiveInstancesBinPaths = { 68 | {"../scene/isMountainB_xgFoliageB--xgFoliageB_treeMadronaBaked_canopyOnly_lo.bin", "../scene/isMountainB_xgFoliageC--xgFoliageC_treeMadronaBaked_canopyOnly_lo.bin", "../scene/isMountainB_xgFoliageA--xgFoliageA_treeMadronaBaked_canopyOnly_lo.bin", "../scene/isMountainB_xgFoliageAd--xgFoliageAd_treeMadronaBaked_canopyOnly_lo.bin", "../scene/isMountainB_xgBreadFruit--xgBreadFruit_archiveBreadFruitBaked.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig3.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig14.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig17.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig8.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig12.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig2.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig1.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig16.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig15.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig6.bin", "../scene/isMountainB_xgCocoPalms--xgCocoPalms_isPalmRig13.bin", "../scene/isMountainB_xgFern--xgFern_fern0006_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0013_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0005_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0007_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0009_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0004_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0001_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0011_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0012_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0014_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0008_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0010_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0002_mod.bin", "../scene/isMountainB_xgFern--xgFern_fern0003_mod.bin"}, 69 | }; 70 | 71 | m_primitiveInstancesHandleIndices = { 72 | {29, 30, 27, 28, 0, 10, 5, 8, 12, 3, 1, 9, 2, 7, 6, 11, 4, 18, 25, 17, 19, 21, 16, 13, 23, 24, 26, 20, 22, 14, 15}, 73 | }; 74 | 75 | m_curveBinPathsByElementInstance = { 76 | {}, 77 | }; 78 | 79 | m_curveMtlIndicesByElementInstance = { 80 | {}, 81 | }; 82 | 83 | 84 | } 85 | 86 | 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/scene/mountain_b_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class MountainBElement : public Element { 8 | public: 9 | MountainBElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/naupaka_a_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/naupaka_a_element.hpp" 2 | 3 | namespace moana { 4 | 5 | NaupakaAElement::NaupakaAElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isNaupakaA"; 10 | 11 | m_mtlLookup = { 12 | "hidden", 13 | "leaves", 14 | "stem", 15 | }; 16 | 17 | m_materialOffset = 92; 18 | 19 | m_baseObjs = { 20 | moanaRoot + "/island/obj/isNaupakaA/isNaupakaA.obj", 21 | moanaRoot + "/island/obj/isNaupakaA/isNaupakaA1.obj", 22 | moanaRoot + "/island/obj/isNaupakaA/isNaupakaA3.obj", 23 | moanaRoot + "/island/obj/isNaupakaA/isNaupakaA2.obj", 24 | }; 25 | 26 | m_objArchivePaths = { 27 | moanaRoot + "/island/obj/isNaupakaA/archives/xgBonsai_isNaupakaBon_bon_hero_ALL.obj", 28 | }; 29 | 30 | m_elementInstancesBinPaths = { 31 | "../scene/isNaupakaA.bin", 32 | "../scene/isNaupakaA1.bin", 33 | "../scene/isNaupakaA3.bin", 34 | "../scene/isNaupakaA2.bin", 35 | }; 36 | 37 | m_primitiveInstancesBinPaths = { 38 | {"../scene/isNaupakaA_xgBonsai--xgBonsai_isNaupakaBon_bon_hero_ALL.bin"}, 39 | {"../scene/isNaupakaA1_xgBonsai--xgBonsai_isNaupakaBon_bon_hero_ALL.bin"}, 40 | {"../scene/isNaupakaA3_xgBonsai--xgBonsai_isNaupakaBon_bon_hero_ALL.bin"}, 41 | {"../scene/isNaupakaA2_xgBonsai--xgBonsai_isNaupakaBon_bon_hero_ALL.bin"}, 42 | }; 43 | 44 | m_primitiveInstancesHandleIndices = { 45 | {0}, 46 | {0}, 47 | {0}, 48 | {0}, 49 | }; 50 | 51 | m_curveBinPathsByElementInstance = { 52 | {}, 53 | {}, 54 | {}, 55 | {}, 56 | }; 57 | 58 | m_curveMtlIndicesByElementInstance = { 59 | {}, 60 | {}, 61 | {}, 62 | {}, 63 | }; 64 | 65 | 66 | } 67 | 68 | 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/scene/naupaka_a_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class NaupakaAElement : public Element { 8 | public: 9 | NaupakaAElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/ocean_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/ocean_element.hpp" 2 | 3 | namespace moana { 4 | 5 | OceanElement::OceanElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "osOcean"; 10 | 11 | m_mtlLookup = { 12 | "water", 13 | }; 14 | 15 | m_materialOffset = 103; 16 | 17 | m_baseObjs = { 18 | moanaRoot + "/island/obj/osOcean/osOcean.obj", 19 | }; 20 | 21 | m_objArchivePaths = { 22 | 23 | }; 24 | 25 | m_elementInstancesBinPaths = { 26 | "../scene/osOcean.bin", 27 | }; 28 | 29 | m_primitiveInstancesBinPaths = { 30 | {}, 31 | }; 32 | 33 | m_primitiveInstancesHandleIndices = { 34 | {}, 35 | }; 36 | 37 | m_curveBinPathsByElementInstance = { 38 | {}, 39 | }; 40 | 41 | m_curveMtlIndicesByElementInstance = { 42 | {}, 43 | }; 44 | 45 | 46 | } 47 | 48 | 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/scene/ocean_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class OceanElement : public Element { 8 | public: 9 | OceanElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/palm_dead_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/palm_dead_element.hpp" 2 | 3 | namespace moana { 4 | 5 | PalmDeadElement::PalmDeadElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isPalmDead"; 10 | 11 | m_mtlLookup = { 12 | "roots", 13 | "trunk", 14 | }; 15 | 16 | m_materialOffset = 95; 17 | 18 | m_baseObjs = { 19 | moanaRoot + "/island/obj/isPalmDead/isPalmDead.obj", 20 | }; 21 | 22 | m_objArchivePaths = { 23 | 24 | }; 25 | 26 | m_elementInstancesBinPaths = { 27 | "../scene/isPalmDead.bin", 28 | }; 29 | 30 | m_primitiveInstancesBinPaths = { 31 | {}, 32 | }; 33 | 34 | m_primitiveInstancesHandleIndices = { 35 | {}, 36 | }; 37 | 38 | m_curveBinPathsByElementInstance = { 39 | {}, 40 | }; 41 | 42 | m_curveMtlIndicesByElementInstance = { 43 | {}, 44 | }; 45 | 46 | 47 | } 48 | 49 | 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/scene/palm_dead_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class PalmDeadElement : public Element { 8 | public: 9 | PalmDeadElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/palm_rig_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/palm_rig_element.hpp" 2 | 3 | namespace moana { 4 | 5 | PalmRigElement::PalmRigElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isPalmRig"; 10 | 11 | m_mtlLookup = { 12 | "branches", 13 | "fronds", 14 | "trunk", 15 | }; 16 | 17 | m_materialOffset = 97; 18 | 19 | m_baseObjs = { 20 | moanaRoot + "/island/obj/isPalmRig/isPalmRig.obj", 21 | moanaRoot + "/island/obj/isPalmRig/isPalmRig18.obj", 22 | moanaRoot + "/island/obj/isPalmRig/isPalmRig19.obj", 23 | moanaRoot + "/island/obj/isPalmRig/isPalmRig16.obj", 24 | moanaRoot + "/island/obj/isPalmRig/isPalmRig17.obj", 25 | moanaRoot + "/island/obj/isPalmRig/isPalmRig14.obj", 26 | moanaRoot + "/island/obj/isPalmRig/isPalmRig15.obj", 27 | moanaRoot + "/island/obj/isPalmRig/isPalmRig12.obj", 28 | moanaRoot + "/island/obj/isPalmRig/isPalmRig13.obj", 29 | moanaRoot + "/island/obj/isPalmRig/isPalmRig10.obj", 30 | moanaRoot + "/island/obj/isPalmRig/isPalmRig11.obj", 31 | moanaRoot + "/island/obj/isPalmRig/isPalmRig30.obj", 32 | moanaRoot + "/island/obj/isPalmRig/isPalmRig31.obj", 33 | moanaRoot + "/island/obj/isPalmRig/isPalmRig32.obj", 34 | moanaRoot + "/island/obj/isPalmRig/isPalmRig33.obj", 35 | moanaRoot + "/island/obj/isPalmRig/isPalmRig8.obj", 36 | moanaRoot + "/island/obj/isPalmRig/isPalmRig9.obj", 37 | moanaRoot + "/island/obj/isPalmRig/isPalmRig4.obj", 38 | moanaRoot + "/island/obj/isPalmRig/isPalmRig5.obj", 39 | moanaRoot + "/island/obj/isPalmRig/isPalmRig6.obj", 40 | moanaRoot + "/island/obj/isPalmRig/isPalmRig7.obj", 41 | moanaRoot + "/island/obj/isPalmRig/isPalmRig2.obj", 42 | moanaRoot + "/island/obj/isPalmRig/isPalmRig3.obj", 43 | moanaRoot + "/island/obj/isPalmRig/isPalmRig27.obj", 44 | moanaRoot + "/island/obj/isPalmRig/isPalmRig26.obj", 45 | moanaRoot + "/island/obj/isPalmRig/isPalmRig25.obj", 46 | moanaRoot + "/island/obj/isPalmRig/isPalmRig24.obj", 47 | moanaRoot + "/island/obj/isPalmRig/isPalmRig23.obj", 48 | moanaRoot + "/island/obj/isPalmRig/isPalmRig22.obj", 49 | moanaRoot + "/island/obj/isPalmRig/isPalmRig21.obj", 50 | moanaRoot + "/island/obj/isPalmRig/isPalmRig20.obj", 51 | moanaRoot + "/island/obj/isPalmRig/isPalmRig29.obj", 52 | moanaRoot + "/island/obj/isPalmRig/isPalmRig28.obj", 53 | }; 54 | 55 | m_objArchivePaths = { 56 | 57 | }; 58 | 59 | m_elementInstancesBinPaths = { 60 | "../scene/isPalmRig.bin", 61 | "../scene/isPalmRig18.bin", 62 | "../scene/isPalmRig19.bin", 63 | "../scene/isPalmRig16.bin", 64 | "../scene/isPalmRig17.bin", 65 | "../scene/isPalmRig14.bin", 66 | "../scene/isPalmRig15.bin", 67 | "../scene/isPalmRig12.bin", 68 | "../scene/isPalmRig13.bin", 69 | "../scene/isPalmRig10.bin", 70 | "../scene/isPalmRig11.bin", 71 | "../scene/isPalmRig30.bin", 72 | "../scene/isPalmRig31.bin", 73 | "../scene/isPalmRig32.bin", 74 | "../scene/isPalmRig33.bin", 75 | "../scene/isPalmRig8.bin", 76 | "../scene/isPalmRig9.bin", 77 | "../scene/isPalmRig4.bin", 78 | "../scene/isPalmRig5.bin", 79 | "../scene/isPalmRig6.bin", 80 | "../scene/isPalmRig7.bin", 81 | "../scene/isPalmRig2.bin", 82 | "../scene/isPalmRig3.bin", 83 | "../scene/isPalmRig27.bin", 84 | "../scene/isPalmRig26.bin", 85 | "../scene/isPalmRig25.bin", 86 | "../scene/isPalmRig24.bin", 87 | "../scene/isPalmRig23.bin", 88 | "../scene/isPalmRig22.bin", 89 | "../scene/isPalmRig21.bin", 90 | "../scene/isPalmRig20.bin", 91 | "../scene/isPalmRig29.bin", 92 | "../scene/isPalmRig28.bin", 93 | }; 94 | 95 | m_primitiveInstancesBinPaths = { 96 | {}, 97 | {}, 98 | {}, 99 | {}, 100 | {}, 101 | {}, 102 | {}, 103 | {}, 104 | {}, 105 | {}, 106 | {}, 107 | {}, 108 | {}, 109 | {}, 110 | {}, 111 | {}, 112 | {}, 113 | {}, 114 | {}, 115 | {}, 116 | {}, 117 | {}, 118 | {}, 119 | {}, 120 | {}, 121 | {}, 122 | {}, 123 | {}, 124 | {}, 125 | {}, 126 | {}, 127 | {}, 128 | {}, 129 | }; 130 | 131 | m_primitiveInstancesHandleIndices = { 132 | {}, 133 | {}, 134 | {}, 135 | {}, 136 | {}, 137 | {}, 138 | {}, 139 | {}, 140 | {}, 141 | {}, 142 | {}, 143 | {}, 144 | {}, 145 | {}, 146 | {}, 147 | {}, 148 | {}, 149 | {}, 150 | {}, 151 | {}, 152 | {}, 153 | {}, 154 | {}, 155 | {}, 156 | {}, 157 | {}, 158 | {}, 159 | {}, 160 | {}, 161 | {}, 162 | {}, 163 | {}, 164 | {}, 165 | }; 166 | 167 | m_curveBinPathsByElementInstance = { 168 | {"../scene/curves__isPalmRig_xgFrondsA.bin"}, 169 | {"../scene/curves__isPalmRig18_xgFrondsA.bin"}, 170 | {"../scene/curves__isPalmRig19_xgFrondsA.bin"}, 171 | {"../scene/curves__isPalmRig16_xgFrondsA.bin"}, 172 | {"../scene/curves__isPalmRig17_xgFrondsA.bin"}, 173 | {"../scene/curves__isPalmRig14_xgFrondsA.bin"}, 174 | {"../scene/curves__isPalmRig15_xgFrondsA.bin"}, 175 | {"../scene/curves__isPalmRig12_xgFrondsA.bin"}, 176 | {"../scene/curves__isPalmRig13_xgFrondsA.bin"}, 177 | {"../scene/curves__isPalmRig10_xgFrondsA.bin"}, 178 | {"../scene/curves__isPalmRig11_xgFrondsA.bin"}, 179 | {"../scene/curves__isPalmRig30_xgFrondsA.bin"}, 180 | {"../scene/curves__isPalmRig31_xgFrondsA.bin"}, 181 | {"../scene/curves__isPalmRig32_xgFrondsA.bin"}, 182 | {"../scene/curves__isPalmRig33_xgFrondsA.bin"}, 183 | {"../scene/curves__isPalmRig8_xgFrondsA.bin"}, 184 | {"../scene/curves__isPalmRig9_xgFrondsA.bin"}, 185 | {"../scene/curves__isPalmRig4_xgFrondsA.bin"}, 186 | {"../scene/curves__isPalmRig5_xgFrondsA.bin"}, 187 | {"../scene/curves__isPalmRig6_xgFrondsA.bin"}, 188 | {"../scene/curves__isPalmRig7_xgFrondsA.bin"}, 189 | {"../scene/curves__isPalmRig2_xgFrondsA.bin"}, 190 | {"../scene/curves__isPalmRig3_xgFrondsA.bin"}, 191 | {"../scene/curves__isPalmRig27_xgFrondsA.bin"}, 192 | {"../scene/curves__isPalmRig26_xgFrondsA.bin"}, 193 | {"../scene/curves__isPalmRig25_xgFrondsA.bin"}, 194 | {"../scene/curves__isPalmRig24_xgFrondsA.bin"}, 195 | {"../scene/curves__isPalmRig23_xgFrondsA.bin"}, 196 | {"../scene/curves__isPalmRig22_xgFrondsA.bin"}, 197 | {"../scene/curves__isPalmRig21_xgFrondsA.bin"}, 198 | {"../scene/curves__isPalmRig20_xgFrondsA.bin"}, 199 | {"../scene/curves__isPalmRig29_xgFrondsA.bin"}, 200 | {"../scene/curves__isPalmRig28_xgFrondsA.bin"}, 201 | }; 202 | 203 | m_curveMtlIndicesByElementInstance = { 204 | {1}, 205 | {1}, 206 | {1}, 207 | {1}, 208 | {1}, 209 | {1}, 210 | {1}, 211 | {1}, 212 | {1}, 213 | {1}, 214 | {1}, 215 | {1}, 216 | {1}, 217 | {1}, 218 | {1}, 219 | {1}, 220 | {1}, 221 | {1}, 222 | {1}, 223 | {1}, 224 | {1}, 225 | {1}, 226 | {1}, 227 | {1}, 228 | {1}, 229 | {1}, 230 | {1}, 231 | {1}, 232 | {1}, 233 | {1}, 234 | {1}, 235 | {1}, 236 | {1}, 237 | }; 238 | 239 | 240 | } 241 | 242 | 243 | 244 | 245 | } 246 | -------------------------------------------------------------------------------- /src/scene/palm_rig_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class PalmRigElement : public Element { 8 | public: 9 | PalmRigElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/pandanus_a_element.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/pandanus_a_element.hpp" 2 | 3 | namespace moana { 4 | 5 | PandanusAElement::PandanusAElement() 6 | { 7 | const std::string moanaRoot = MOANA_ROOT; 8 | 9 | m_elementName = "isPandanusA"; 10 | 11 | m_mtlLookup = { 12 | "leaves", 13 | "leavesLower", 14 | "trunk", 15 | }; 16 | 17 | m_materialOffset = 100; 18 | 19 | m_baseObjs = { 20 | moanaRoot + "/island/obj/isPandanusA/isPandanusA.obj", 21 | }; 22 | 23 | m_objArchivePaths = { 24 | 25 | }; 26 | 27 | m_elementInstancesBinPaths = { 28 | "../scene/isPandanusA.bin", 29 | }; 30 | 31 | m_primitiveInstancesBinPaths = { 32 | {}, 33 | }; 34 | 35 | m_primitiveInstancesHandleIndices = { 36 | {}, 37 | }; 38 | 39 | m_curveBinPathsByElementInstance = { 40 | {"../scene/curves__isPandanusA_xgLeavesH.bin", "../scene/curves__isPandanusA_xgLeavesI.bin", "../scene/curves__isPandanusA_xgLeavesLower.bin", "../scene/curves__isPandanusA_xgLeavesA.bin", "../scene/curves__isPandanusA_xgLeavesB.bin", "../scene/curves__isPandanusA_xgLeavesC.bin", "../scene/curves__isPandanusA_xgLeavesD.bin", "../scene/curves__isPandanusA_xgLeavesE.bin", "../scene/curves__isPandanusA_xgLeavesF.bin", "../scene/curves__isPandanusA_xgLeavesG.bin"}, 41 | }; 42 | 43 | m_curveMtlIndicesByElementInstance = { 44 | {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, 45 | }; 46 | 47 | 48 | } 49 | 50 | 51 | 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/scene/pandanus_a_element.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "scene/element.hpp" 4 | 5 | namespace moana { 6 | 7 | class PandanusAElement : public Element { 8 | public: 9 | PandanusAElement(); 10 | }; 11 | 12 | 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/scene/texture_lookup.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/texture_lookup.hpp" 2 | 3 | #include 4 | #include 5 | 6 | namespace moana { namespace TextureLookup { 7 | 8 | static const std::pair, int> data[] = { 9 | #define X(k1, k2, k3, i) { std::make_tuple(k1, k2, k3), i }, 10 | #include "scene/data/texture_lookup_data.cpp" 11 | #undef X 12 | }; 13 | 14 | using TextureIndexKey = std::tuple; 15 | static const std::map lookup(std::begin(data), std::end(data)); 16 | 17 | int indexForMesh( 18 | const std::string &element, 19 | const std::string &material, 20 | const std::string &mesh 21 | ) { 22 | const TextureIndexKey key = std::make_tuple(element, material, mesh); 23 | if (lookup.count(key) > 0) { 24 | return lookup.at(key); 25 | } 26 | return -1; 27 | } 28 | 29 | } } 30 | -------------------------------------------------------------------------------- /src/scene/texture_lookup.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace moana { namespace TextureLookup { 7 | 8 | using TextureIndexKey = std::tuple; 9 | 10 | int indexForMesh( 11 | const std::string &element, 12 | const std::string &material, 13 | const std::string &mesh 14 | ); 15 | 16 | } } 17 | -------------------------------------------------------------------------------- /src/scene/texture_offsets.cpp: -------------------------------------------------------------------------------- 1 | #include "scene/texture_offsets.hpp" 2 | 3 | namespace moana { namespace Textures { 4 | 5 | static const char *data[] = { 6 | #define X(x) x, 7 | #include "scene/data/texture_offsets_data.cpp" 8 | #undef X 9 | }; 10 | 11 | std::vector textureFilenames(std::begin(data), std::end(data)); 12 | 13 | } } 14 | -------------------------------------------------------------------------------- /src/scene/texture_offsets.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace moana { namespace Textures { 7 | 8 | extern std::vector textureFilenames; 9 | 10 | } } 11 | -------------------------------------------------------------------------------- /src/util/color_map.cpp: -------------------------------------------------------------------------------- 1 | #include "util/color_map.hpp" 2 | 3 | namespace moana { 4 | 5 | float3 ColorMap::get(int index) 6 | { 7 | if (m_colorMap.count(index) == 0) { 8 | const float r = m_rng.next(); 9 | const float g = m_rng.next(); 10 | const float b = m_rng.next(); 11 | 12 | const float3 color = float3{r, g, b}; 13 | m_colorMap[index] = color; 14 | } 15 | 16 | return m_colorMap[index]; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/util/color_map.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace moana { 9 | 10 | class RandomGenerator { 11 | public: 12 | RandomGenerator() 13 | : m_generator(m_device()), 14 | m_distribution(0.f, 1.f - std::numeric_limits::epsilon()) 15 | {} 16 | 17 | float next() { 18 | return m_distribution(m_generator); 19 | } 20 | 21 | private: 22 | std::random_device m_device; 23 | std::mt19937 m_generator; 24 | std::uniform_real_distribution m_distribution; 25 | }; 26 | 27 | class ColorMap { 28 | public: 29 | float3 get(int index); 30 | 31 | private: 32 | std::map m_colorMap; 33 | RandomGenerator m_rng; 34 | }; 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/util/enumerate.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // http://reedbeta.com/blog/python-like-enumerate-in-cpp17/ 4 | 5 | #include 6 | 7 | namespace moana { 8 | 9 | template ())), 11 | typename = decltype(std::end(std::declval()))> 12 | constexpr auto enumerate(T && iterable) 13 | { 14 | struct iterator 15 | { 16 | size_t i; 17 | TIter iter; 18 | bool operator != (const iterator & other) const { return iter != other.iter; } 19 | void operator ++ () { ++i; ++iter; } 20 | auto operator * () const { return std::tie(i, *iter); } 21 | }; 22 | struct iterable_wrapper 23 | { 24 | T iterable; 25 | auto begin() { return iterator{ 0, std::begin(iterable) }; } 26 | auto end() { return iterator{ 0, std::end(iterable) }; } 27 | }; 28 | return iterable_wrapper{ std::forward(iterable) }; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(${PROJECT_SOURCE_DIR}/ext/Catch2 Catch2) 2 | add_executable(test 3 | test.cpp 4 | 5 | test_obj_parser.cpp 6 | ) 7 | target_link_libraries(test Catch2::Catch2 moana) 8 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_MAIN 2 | #include 3 | -------------------------------------------------------------------------------- /test/test_obj_parser.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | using namespace moana; 11 | 12 | static std::string obj1 = R"( 13 | g default 14 | v 0 1 2 15 | v 3 4 5 16 | v 6 7 8 17 | v 9 10 11 18 | vn 12 13 14 19 | vn 15 16 17 20 | vn 18 19 20 21 | vn 20 21 22 22 | s 1 23 | g mesh_name 24 | usemtl custom_mtl 25 | f 1//4 2//3 3//2 4//1 26 | )"; 27 | 28 | TEST_CASE("parse a simple obj", "[obj]") { 29 | const std::vector mtlLookup = { "custom_mtl" }; 30 | 31 | ObjParser parser( 32 | std::make_unique(obj1), 33 | mtlLookup 34 | ); 35 | 36 | auto records = parser.parse(); 37 | REQUIRE(records.size() == 1); 38 | 39 | auto record = records[0]; 40 | std::vector expectedVertices = { 41 | 0.f, 1.f, 2.f, 42 | 3.f, 4.f, 5.f, 43 | 6.f, 7.f, 8.f, 44 | 9.f, 10.f, 11.f 45 | }; 46 | REQUIRE(record.vertices == expectedVertices); 47 | 48 | std::vector expectedVertexIndices = { 49 | 0, 1, 2, 50 | 0, 2, 3, 51 | }; 52 | REQUIRE(record.vertexIndices == expectedVertexIndices); 53 | 54 | std::vector expectedNormals = { 55 | 12.f, 13.f, 14.f, 56 | 15.f, 16.f, 17.f, 57 | 18.f, 19.f, 20.f, 58 | 20.f, 21.f, 22.f, 59 | }; 60 | REQUIRE(record.normals == expectedNormals); 61 | 62 | std::vector expectedNormalIndices = { 63 | 3, 2, 1, 64 | 3, 1, 0, 65 | }; 66 | REQUIRE(record.normalIndices == expectedNormalIndices); 67 | 68 | REQUIRE(record.indexTripletCount == 2); 69 | REQUIRE(record.materialIndex == 0); 70 | REQUIRE(!record.hidden); 71 | } 72 | 73 | static std::string obj2 = R"( 74 | g default 75 | v 0 1 2 76 | v 3 4 5 77 | v 6 7 8 78 | v 9 10 11 79 | vn 12 13 14 80 | vn 15 16 17 81 | vn 18 19 20 82 | vn 20 21 22 83 | s 1 84 | g mesh_name1 85 | usemtl custom_mtl 86 | f 1//4 2//3 3//2 4//1 87 | g default 88 | v 23 24 25 89 | v 26 27 28 90 | v 29 30 31 91 | v 32 33 34 92 | vn 35 36 37 93 | vn 38 39 40 94 | vn 41 42 43 95 | vn 44 45 46 96 | s 1 97 | g mesh_name2 98 | usemtl custom_mtl 99 | f 5//8 6//7 7//6 8//5 100 | )"; 101 | 102 | TEST_CASE("parse an obj with two meshes", "[obj]") { 103 | const std::vector mtlLookup = { "custom_mtl" }; 104 | 105 | ObjParser parser( 106 | std::make_unique(obj2), 107 | mtlLookup 108 | ); 109 | 110 | auto records = parser.parse(); 111 | REQUIRE(records.size() == 2); 112 | 113 | { 114 | auto record = records[0]; 115 | std::vector expectedVertices = { 116 | 0.f, 1.f, 2.f, 117 | 3.f, 4.f, 5.f, 118 | 6.f, 7.f, 8.f, 119 | 9.f, 10.f, 11.f 120 | }; 121 | REQUIRE(record.vertices == expectedVertices); 122 | 123 | std::vector expectedVertexIndices = { 124 | 0, 1, 2, 125 | 0, 2, 3, 126 | }; 127 | REQUIRE(record.vertexIndices == expectedVertexIndices); 128 | 129 | std::vector expectedNormals = { 130 | 12.f, 13.f, 14.f, 131 | 15.f, 16.f, 17.f, 132 | 18.f, 19.f, 20.f, 133 | 20.f, 21.f, 22.f, 134 | }; 135 | REQUIRE(record.normals == expectedNormals); 136 | 137 | std::vector expectedNormalIndices = { 138 | 3, 2, 1, 139 | 3, 1, 0, 140 | }; 141 | REQUIRE(record.normalIndices == expectedNormalIndices); 142 | 143 | REQUIRE(record.indexTripletCount == 2); 144 | REQUIRE(record.materialIndex == 0); 145 | REQUIRE(!record.hidden); 146 | } 147 | { 148 | auto record = records[1]; 149 | std::vector expectedVertices = { 150 | 23.f, 24.f, 25.f, 151 | 26.f, 27.f, 28.f, 152 | 29.f, 30.f, 31.f, 153 | 32.f, 33.f, 34.f, 154 | }; 155 | REQUIRE(record.vertices == expectedVertices); 156 | 157 | std::vector expectedVertexIndices = { 158 | 0, 1, 2, 159 | 0, 2, 3, 160 | }; 161 | REQUIRE(record.vertexIndices == expectedVertexIndices); 162 | 163 | std::vector expectedNormals = { 164 | 35.f, 36.f, 37.f, 165 | 38.f, 39.f, 40.f, 166 | 41.f, 42.f, 43.f, 167 | 44.f, 45.f, 46.f, 168 | }; 169 | REQUIRE(record.normals == expectedNormals); 170 | 171 | std::vector expectedNormalIndices = { 172 | 3, 2, 1, 173 | 3, 1, 0, 174 | }; 175 | REQUIRE(record.normalIndices == expectedNormalIndices); 176 | 177 | REQUIRE(record.indexTripletCount == 2); 178 | REQUIRE(record.materialIndex == 0); 179 | REQUIRE(!record.hidden); 180 | } 181 | } 182 | 183 | static std::string obj3 = R"( 184 | g default 185 | v 0 1 2 186 | v 3 4 5 187 | v 6 7 8 188 | v 9 10 11 189 | vn 12 13 14 190 | vn 15 16 17 191 | vn 18 19 20 192 | vn 20 21 22 193 | s 1 194 | g mesh_name 195 | usemtl hidden 196 | f 1//4 2//3 3//2 4//1 197 | )"; 198 | 199 | TEST_CASE("skip hidden meshes", "[obj]") { 200 | const std::vector mtlLookup = {}; 201 | 202 | ObjParser parser( 203 | std::make_unique(obj3), 204 | mtlLookup 205 | ); 206 | 207 | auto records = parser.parse(); 208 | REQUIRE(records.size() == 0); 209 | } 210 | 211 | static std::string obj4 = R"( 212 | g default 213 | v 0 1 2 214 | v 3 4 5 215 | v 6 7 8 216 | v 9 10 11 217 | vn 12 13 14 218 | vn 15 16 17 219 | vn 18 19 20 220 | vn 20 21 22 221 | s 1 222 | g mesh_name 223 | f 1//4 2//3 3//2 4//1 224 | )"; 225 | 226 | TEST_CASE("mark shadow meshes hidden (no usemtl)", "[obj]") { 227 | const std::vector mtlLookup = {}; 228 | 229 | ObjParser parser( 230 | std::make_unique(obj4), 231 | mtlLookup 232 | ); 233 | 234 | auto records = parser.parse(); 235 | REQUIRE(records.size() == 0); 236 | } 237 | --------------------------------------------------------------------------------