├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── README.md ├── UnityOptixCSharp ├── OptixController.cs ├── OptixExampleUsage.cs ├── OptixLibraryInterface.cs ├── OptixPointCloud.cs ├── OptixSensor.cs ├── Properties │ └── AssemblyInfo.cs ├── UnityOptix.DotSettings ├── UnityOptix.csproj └── packages.config ├── UnityOptixPluginCompiled ├── optix_prime.1.dll ├── sutil_sdk.dll └── unityOptixPlugin.dll ├── UnityOptixPluginMaterials ├── InstancedShader.shader └── PointCloudPointMat.mat └── unityOptixPlugin ├── CMakeLists.txt ├── IUnityGraphics.h ├── IUnityGraphicsD3D11.h ├── IUnityInterface.h ├── OptixPlugin.cpp ├── OptixPlugin.h ├── PlatformBase.h ├── RenderAPI.cpp ├── RenderAPI.h ├── RenderAPI_D3D11.cpp ├── primeCommon.cpp ├── primeCommon.h └── primeKernels.cu /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | UnityOptixCSharp/obj/ -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016, 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 | # Welcome to the OptiX SDK build. We have chosen CMake, because it can generate multiple 30 | # build systems for multiple architectures from a single script. There are many resources 31 | # for CMake on-line at http://www.cmake.org and their wiki page, 32 | # http://www.cmake.org/Wiki/CMake, in addition to the documentation that comes with the 33 | # distribution. There is also a book available if you wish to delve more deeply into 34 | # various topics. 35 | 36 | # If you wish to create your own project and use the SDK as a template there are a number 37 | # of things you should do. 38 | # 39 | # 1. You should copy the contents of the SDK to a place of your choice. 40 | # 41 | # 2. You can remove any sample's directory you don't wish to build. Be careful about 42 | # the following directories. 43 | # 44 | # a. CMake - contains helper scripts that make this all work. You should keep this. 45 | # 46 | # b. sutil and putil 47 | # - Almost all of the samples make use of this shared code one way or another, so 48 | # you should probably keep them until you have your own frameowrk for your 49 | # code. 50 | # 51 | # d. data - This directory contains the cow.obj file used as an example for 52 | # many of the samples. You can move cow.obj anywhere as long as 53 | # you fix all the file paths in the samples you wish to use it in. 54 | # 55 | # 3. You should update the list of sub directories that CMake needs to process below (look 56 | # for the comment "List of samples found in subdirectories.") 57 | # 58 | 59 | # The basic flow of execution of this file is to do the following. 60 | # 61 | # 1. Setup the project and other global settings. This involves processing some helper 62 | # scripts. 63 | # 64 | # 2. Look for external dependencies, such as glut, DirectX, CUDA, and OptiX. 65 | # 66 | # 3. Process all the subdirectories' CMakeLists.txt files. These files create all the 67 | # executable and library targets that are used to build the SDK. 68 | # 69 | # 4. As a convenience on Windows, copy the OptiX dlls into the build directories, so OptiX 70 | # doesn't have to be in the path to run the samples. 71 | # 72 | # 5. Set a CMake variable that indicates we have configured for the first time. This 73 | # allows us to override and set varibles' defaults while allowing them to be modified 74 | # later. 75 | 76 | # If you have any questions, don't feel shy about posting to the OptiX forums: 77 | # http://developer.nvidia.com/forums/index.php?showforum=43 78 | 79 | 80 | # This sets up the name of our project. For our purposes the main thing this controls is 81 | # the name of the VS solution file. 82 | project(Unity-Optix-Plugin) 83 | 84 | # This enforces a particular version of CMake that we require to process the script files 85 | # properly. 86 | cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR) 87 | 88 | # As of CMake 2.6 policies were introduced in order to provide a mechanism for 89 | # adding backwards compatibility one feature at a time. We will just specify 90 | # that all policies will use version 2.6 symantics. 91 | cmake_policy(VERSION 2.6) 92 | 93 | # Add paths to our CMake code to the module path, so they can be found automatically by 94 | # CMake. 95 | set(CMAKE_MODULE_PATH 96 | "${CMAKE_SOURCE_DIR}/CMake" 97 | ${CMAKE_MODULE_PATH} 98 | ) 99 | 100 | # Set the default build to Release. Note this doesn't do anything for the VS 101 | # default build target which defaults to Debug when you first start it. 102 | IF(NOT CMAKE_BUILD_TYPE) 103 | SET(CMAKE_BUILD_TYPE "Release" CACHE STRING 104 | "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." 105 | FORCE) 106 | ENDIF(NOT CMAKE_BUILD_TYPE) 107 | 108 | # Tells CMake to build all the libraries as shared libraries by default. This can be 109 | # overrided by individual libraries later. 110 | set(BUILD_SHARED_LIBS ON) 111 | 112 | ########## 113 | # Process our custom setup scripts here. 114 | 115 | # Include all CMake Macros. 116 | include(Macros) 117 | # Determine information about the compiler 118 | include (CompilerInfo) 119 | # Check for specific machine/compiler options. 120 | include (ConfigCompilerFlags) 121 | 122 | # Turn off the warning that NVCC issues when generating PTX from our CUDA samples. This 123 | # is a custom extension to the FindCUDA code distributed by CMake. 124 | OPTION(CUDA_REMOVE_GLOBAL_MEMORY_SPACE_WARNING "Suppress the \"Advisory: Cannot tell what pointer points to, assuming global memory space\" warning nvcc makes." ON) 125 | 126 | # For Xcode 5, gcc is actually clang, so we have to tell CUDA to treat the compiler as 127 | # clang, so that it doesn't mistake it for something else. 128 | if(USING_CLANG_C) 129 | set(CUDA_HOST_COMPILER "clang" CACHE FILEPATH "Host side compiler used by NVCC") 130 | endif() 131 | 132 | # CUDA 8 is broken for generating dependencies during configure 133 | option(CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE "Generate dependencies during configure time instead of only during build time." OFF) 134 | 135 | # Find at least a 5.0 version of CUDA. 136 | find_package(CUDA 5.0 REQUIRED) 137 | 138 | # Present the CUDA_64_BIT_DEVICE_CODE on the default set of options. 139 | mark_as_advanced(CLEAR CUDA_64_BIT_DEVICE_CODE) 140 | 141 | 142 | # Add some useful default arguments to the nvcc flags. This is an example of how we use 143 | # PASSED_FIRST_CONFIGURE. Once you have configured, this variable is TRUE and following 144 | # block of code will not be executed leaving you free to edit the values as much as you 145 | # wish from the GUI or from ccmake. 146 | if(NOT PASSED_FIRST_CONFIGURE) 147 | list(FIND CUDA_NVCC_FLAGS "-arch" index) 148 | if(index EQUAL -1) 149 | list(APPEND CUDA_NVCC_FLAGS -arch sm_30) 150 | set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} CACHE LIST "Semi-colon delimit multiple arguments." FORCE) 151 | endif() 152 | set(flag "--use_fast_math") 153 | list(FIND CUDA_NVCC_FLAGS ${flag} index) 154 | if(index EQUAL -1) 155 | list(APPEND CUDA_NVCC_FLAGS ${flag}) 156 | set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} CACHE LIST "Semi-colon delimit multiple arguments." FORCE) 157 | endif() 158 | 159 | if (CUDA_VERSION VERSION_LESS "3.0") 160 | set(flag "--keep") 161 | list(FIND CUDA_NVCC_FLAGS ${flag} index) 162 | if(index EQUAL -1) 163 | list(APPEND CUDA_NVCC_FLAGS ${flag}) 164 | set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} CACHE LIST "Semi-colon delimit multiple arguments." FORCE) 165 | endif() 166 | endif() 167 | 168 | if( APPLE ) 169 | # Undef'ing __BLOCKS__ for OSX builds. This is due to a name clash between OSX 10.6 170 | # C headers and CUDA headers 171 | set(flag "-U__BLOCKS__") 172 | list(FIND CUDA_NVCC_FLAGS ${flag} index) 173 | if(index EQUAL -1) 174 | list(APPEND CUDA_NVCC_FLAGS ${flag}) 175 | set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} CACHE LIST "Semi-colon delimit multiple arguments." FORCE) 176 | endif() 177 | endif() 178 | endif(NOT PASSED_FIRST_CONFIGURE) 179 | 180 | # This passes a preprocessor definition to cl.exe when processing CUDA code. 181 | if(USING_WINDOWS_CL) 182 | list(APPEND CUDA_NVCC_FLAGS --compiler-options /D_USE_MATH_DEFINES) 183 | endif() 184 | 185 | # Put all the runtime stuff in the same directory. By default, CMake puts each targets' 186 | # output into their own directory. We want all the targets to be put in the same 187 | # directory, and we can do this by setting these variables. 188 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") 189 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") 190 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") 191 | 192 | # Create a flag for mac which will allow apps to add the local cuda toolkit 193 | # install path to the app's rpath. 194 | if( APPLE ) 195 | set( CUDA_TOOLKIT_RPATH_FLAG "-Wl,-rpath,${CUDA_TOOLKIT_ROOT_DIR}/lib" ) 196 | endif() 197 | 198 | # Locate the NVRT distribution. Search the SDK first, then look in the system. 199 | set(OptiX_INSTALL_DIR "${CMAKE_SOURCE_DIR}/../" CACHE PATH "Path to OptiX installed location.") 200 | 201 | # Search for the OptiX libraries and include files. 202 | find_package(OptiX REQUIRED) 203 | 204 | # Add the path to the OptiX headers to our include paths. 205 | include_directories( 206 | "${OptiX_INCLUDE}" 207 | ) 208 | 209 | ################################################################## 210 | # SUtil compilation 211 | 212 | set(SAMPLES_PTX_DIR "${CMAKE_BINARY_DIR}/lib/ptx") 213 | set(SAMPLES_DIR "${CMAKE_CURRENT_SOURCE_DIR}") 214 | 215 | set(CUDA_GENERATED_OUTPUT_DIR ${SAMPLES_PTX_DIR}) 216 | 217 | if (WIN32) 218 | string(REPLACE "/" "\\\\" SAMPLES_PTX_DIR ${SAMPLES_PTX_DIR}) 219 | else (WIN32) 220 | if ( USING_GNU_C AND NOT APPLE) 221 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DM_PI=3.14159265358979323846" ) 222 | endif() 223 | endif (WIN32) 224 | 225 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sampleConfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/sampleConfig.h @ONLY) 226 | 227 | # Path to sutil.h that all the samples need 228 | include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/sutil 229 | ${CMAKE_CURRENT_SOURCE_DIR} 230 | ${OptiX_INCLUDE}/optixu 231 | ${CMAKE_CURRENT_BINARY_DIR} 232 | ${CUDA_INCLUDE_DIRS} ) 233 | 234 | include(FindSUtilGLUT) 235 | 236 | set(SAMPLES_CUDA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cuda) 237 | 238 | ######################################################### 239 | # OPTIX_add_sample_executable 240 | # 241 | # Convience function for adding samples to the code. You can copy the contents of this 242 | # funtion into your individual project if you wish to customize the behavior. Note that 243 | # in CMake, functions have their own scope, whereas macros use the scope of the caller. 244 | function(OPTIX_add_sample_executable target_name) 245 | 246 | # These calls will group PTX and CUDA files into their own directories in the Visual 247 | # Studio projects. 248 | source_group("PTX Files" REGULAR_EXPRESSION ".+\\.ptx$") 249 | source_group("CUDA Files" REGULAR_EXPRESSION ".+\\.cu$") 250 | 251 | # Separate the sources from the CMake and CUDA options fed to the macro. This code 252 | # comes from the CUDA_COMPILE_PTX macro found in FindCUDA.cmake. We are copying the 253 | # code here, so that we can use our own name for the target. target_name is used in the 254 | # creation of the output file names, and we want this to be unique for each target in 255 | # the SDK. 256 | CUDA_GET_SOURCES_AND_OPTIONS(source_files cmake_options options ${ARGN}) 257 | 258 | # Create the rules to build the PTX from the CUDA files. 259 | CUDA_WRAP_SRCS( ${target_name} PTX generated_files ${source_files} ${cmake_options} 260 | OPTIONS ${options} ) 261 | 262 | # Here is where we create the rule to make the executable. We define a target name and 263 | # list all the source files used to create the target. In addition we also pass along 264 | # the cmake_options parsed out of the arguments. 265 | add_executable(${target_name} 266 | ${source_files} 267 | ${generated_files} 268 | ${cmake_options} 269 | ) 270 | 271 | # Most of the samples link against the sutil library and the optix library. Here is the 272 | # rule that specifies this linkage. 273 | target_link_libraries( ${target_name} 274 | sutil_sdk 275 | optix 276 | ${optix_rpath} 277 | ) 278 | if(USING_GNU_CXX) 279 | target_link_libraries( ${target_name} m ) # Explicitly link against math library (C samples don't do that by default) 280 | endif() 281 | endfunction() 282 | 283 | ######################################################### 284 | # List of samples found in subdirectories. 285 | # 286 | # If you wish to start your own sample, you can copy one of the sample's directories. 287 | # Just make sure you rename all the occurances of the sample's name in the C code as well 288 | # and the CMakeLists.txt file. 289 | add_subdirectory(unityOptixPlugin) 290 | 291 | # Our sutil library. The rules to build it are found in the subdirectory. 292 | add_subdirectory(sutil) 293 | 294 | # This copies out dlls into the build directories, so that users no longer need to copy 295 | # them over in order to run the samples. This depends on the optixHello sample being compiled. 296 | # If you remove this sample from the list of compiled samples, then you should change 297 | # "optixHello" found below to the name of one of your other samples. 298 | if(WIN32) 299 | if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT APPLE) 300 | set(bit_dest "64") 301 | else() 302 | set(bit_dest "") 303 | endif() 304 | foreach(config ${CMAKE_CONFIGURATION_TYPES}) 305 | cmake_policy(SET CMP0026 OLD) # disable warning about LOCATION property 306 | get_target_property(loc optixHello ${config}_LOCATION) 307 | if(loc) 308 | # A little helper function 309 | function(copy_dll lib) 310 | get_filename_component(path ${loc} PATH) 311 | get_filename_component(name ${lib} NAME) 312 | #message("${CMAKE_COMMAND} -E copy_if_different ${lib} ${path}/${name}") 313 | execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different ${lib} ${path}/${name}) 314 | endfunction() 315 | 316 | # Copy the binary directory into the build 317 | file(GLOB dlls "${OptiX_INSTALL_DIR}/bin${bit_dest}/*.dll") 318 | foreach(file ${dlls}) 319 | copy_dll("${file}") 320 | endforeach() 321 | else() 322 | message(WARNING "Unable to find location to copy DLLs into the build") 323 | endif() 324 | endforeach() 325 | endif(WIN32) 326 | 327 | ################################################################# 328 | 329 | # Now that everything is done, indicate that we have finished configuring at least once. 330 | # We use this variable to set certain defaults only on the first pass, so that we don't 331 | # continually set them over and over again. 332 | set(PASSED_FIRST_CONFIGURE ON CACHE INTERNAL "Already Configured once?") 333 | 334 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Unity Optix Plugin by Alex Scott 2 | 3 | Usage Instructions: 4 | Requirements: 5 | - Unity 5 or greater. 6 | 7 | 1. Copy the contents from the UnityOptixPluginCompiled folder to the Plugins directory of your project. 8 | 9 | 2. Copy all the .cs files from the UnityOptixCSharp folder to somewhere in your project. Or optionally open the csproj file 10 | in Visual Studio and change the output directory to somewhere in your project. See compilation instructions (11). 11 | 12 | 3. Copy all the contents from the UnityOptixPluginMaterials folder to somewhere in your project. 13 | 14 | 4. In Unity add the OptixSensor component to a gameobject. Also add the OptixExampleUsage component to an empty 15 | gameobject to see an example of it's usage. 16 | 17 | 5. Add the following references to the OptixExampleUsage component: 18 | - Create a UI button and assign it's reference to the Sensor Trigger Button variable. 19 | - Set the Instance Mesh variable to whatever mesh you want the point cloud point mesh to be. The sphere primitive is recommended. 20 | - Set the Instance Material variable to PointCloudPointMat that was copied from the UnityOptixPluginMaterials folder. 21 | - Set the Optix Target Layer Mask to a specific layer that the detectable objects are on or simply set it to everything. 22 | 23 | 6. Run the application and click on the UI button. If anything is infront of your OptixSensor it will be rendered into a point cloud. 24 | 25 | 26 | Compilation instructions: 27 | Requirements: 28 | - Visual Studio 2015 with C++ compiler. 29 | - CMake 3.0 or greater. 30 | - NVIDIA Optix 4.1 or greater. 31 | - CUDA Toolkit 5.0 or greater. 32 | 33 | 1. Copy the UnityOptixPlugin folder to the C:\ProgramData\NVIDIA Corporation\OptiX SDK \SDK directory. 34 | 35 | 2. Copy the CMakeLists.txt (root one not the one in the UnityOptixPlugin folder) file to the 36 | C:\ProgramData\NVIDIA Corporation\OptiX SDK \SDK directory and overwrite the file there. 37 | 38 | 3. Start up cmake-gui from the Start Menu. 39 | 40 | 4. Select the C:\ProgramData\NVIDIA Corporation\OptiX SDK \SDK directory 41 | from the installation for the source file location. 42 | 43 | 5. Create a build directory that isn't the same as the source directory. For 44 | example, C:\ProgramData\NVIDIA Corporation\OptiX SDK \SDK\build. 45 | If you don't have permissions to write into the this directory (writing into 46 | the "C:/Program Files" directory can be restricted in some cases), pick a different 47 | directory where you do have write permissions. If you type in the directory 48 | (instead of using the "Browse Build..." button), CMake will ask you at the 49 | next step to create the directory for you if it doesn't already exist. 50 | 51 | 6. Press "Configure" button and select the version of Visual Studio you wish to 52 | use. Note that the 64-bit compiles are separate from the 32-bit compiles 53 | (e.g. look for "Visual Studio 12 2013 Win64"). Leave all other options on 54 | their default. Press "OK". This can take a while while source level 55 | dependencies for CUDA files are computed. 56 | 57 | 7. Press "Configure" again. Followed by "Generate". 58 | 59 | 8. Open the Unity-Optix-Plugin.sln solution file in the build directory you created. 60 | 61 | 9. Build the solution. There will be errors. 62 | 63 | 10. Open the properties windows on the unityOptixPlugin project and go to Configuration Properties -> C/C++ -> Preprocesor -> Preprocessor Definitions. 64 | Add to the list of definitions: OPTIXPLUGIN_EXPORTS. 65 | 66 | 11. Still in the unityOptixPlugin properties, go to Configuration Properties -> General. Change Target Extension to .dll. Change configuration type 67 | to .dll. Change the output directory to the plugins directory of your Unity project. 68 | 69 | 12. Repeat step 12 for the sutil_sdk project. 70 | 71 | 13. Build the solution again and you should be error free. -------------------------------------------------------------------------------- /UnityOptixCSharp/OptixController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Runtime.InteropServices; 5 | using UnityEngine; 6 | 7 | namespace World.Optix 8 | { 9 | // TODO -- Investigate rendering point cloud within C++ Plugin using D3D11 buffers 10 | // TODO -- Investigate CUDA implementation 11 | 12 | /// 13 | /// Simple data structure that caches an objects transform and mesh 14 | /// 15 | public class OptixTransform 16 | { 17 | public Transform transform; 18 | public Mesh mesh; 19 | public int isEnabled; 20 | 21 | public bool IsDirty 22 | { 23 | get { return transform.hasChanged; } 24 | set { transform.hasChanged = value; } 25 | } 26 | } 27 | 28 | /// 29 | /// Controller that allows you to modify settings and control Optix execution 30 | /// 31 | [AddComponentMenu("")] 32 | public class OptixController : MonoBehaviour 33 | { 34 | #region Vars 35 | 36 | private OptixTransform[] optixTransforms; 37 | private OptixSensor[] optixSensors; 38 | 39 | private bool isRaytracing; 40 | private bool sceneChanged; 41 | 42 | private float _optixTargetFPS; 43 | private LayerMask _optixTargetLayerMask; 44 | private string _optixTargetTag; 45 | private Transform _optixOrigin; 46 | private float _optixMaxDistanceFromOrigin; 47 | 48 | #endregion 49 | 50 | #region Init 51 | 52 | public void Init(float optixTargetFPS, LayerMask optixTargetLayerMask, string optixTargetTag, Transform optixOrigin, float optixMaxDistanceFromOrigin) 53 | { 54 | _optixTargetFPS = optixTargetFPS; 55 | _optixTargetLayerMask = optixTargetLayerMask; 56 | _optixTargetTag = optixTargetTag; 57 | _optixOrigin = optixOrigin; 58 | _optixMaxDistanceFromOrigin = optixMaxDistanceFromOrigin; 59 | 60 | CacheAllObjects(); 61 | 62 | if (optixTransforms.Length == 0) 63 | { 64 | Debug.LogWarning("No gameobjects found in scene. Ending OptixController execution."); 65 | return; 66 | } 67 | 68 | SendAllObjectsToOptix(); 69 | 70 | StartCoroutine(CallPluginAtEndOfFrames()); 71 | } 72 | 73 | // Finds and caches all gameobjects in the scene which have a MeshFilter attached to them. TODO: Selectively cache gameobjects based on layer or tag or component. 74 | private void CacheAllObjects() 75 | { 76 | MeshFilter[] meshFilters = FindObjectsOfType(); 77 | List optixTransformList = new List(); 78 | 79 | for (int iMeshFilter = 0; iMeshFilter < meshFilters.Length; iMeshFilter++) // For each object in the scene that has a MeshFilter component attached to it 80 | { 81 | if (CheckGameObjectMeetsRequirements(meshFilters[iMeshFilter].gameObject)) 82 | { 83 | optixTransformList.Add(new OptixTransform 84 | { 85 | mesh = meshFilters[iMeshFilter].mesh, 86 | transform = meshFilters[iMeshFilter].transform 87 | }); 88 | } 89 | } 90 | 91 | optixTransforms = optixTransformList.ToArray(); 92 | } 93 | 94 | // Checks to see if the gameobjects found by FindObjectsOfType adhere to the specified requirements such as layermask and tag 95 | private bool CheckGameObjectMeetsRequirements(GameObject gameObject) 96 | { 97 | if (_optixTargetLayerMask != (_optixTargetLayerMask | (1 << gameObject.layer))) // Checks to see if this gameobject is outside of the specified layermask 98 | { 99 | return false; 100 | } 101 | 102 | if (!string.IsNullOrEmpty(_optixTargetTag) && !gameObject.CompareTag(_optixTargetTag)) // Checks to see if this gameobject doesn't have the specified tag 103 | { 104 | return false; 105 | } 106 | 107 | return true; 108 | } 109 | 110 | // Sends the address of every cached meshes vertex buffer as well as localToWorld transform matrix to the Optix library 111 | private void SendAllObjectsToOptix() 112 | { 113 | GCHandle[] meshGCHandles = new GCHandle[optixTransforms.Length]; 114 | IntPtr[] meshVertexAddresses = new IntPtr[optixTransforms.Length]; 115 | Matrix4x4[] meshTranslationMatrices = new Matrix4x4[optixTransforms.Length]; 116 | int[] meshVertexCounts = new int[optixTransforms.Length]; 117 | int[] meshEnabledStatus = new int[optixTransforms.Length]; 118 | 119 | for (int iTransform = 0; iTransform < optixTransforms.Length; iTransform++) 120 | { 121 | // GCHandle is needed to find the memory address of the meshes vertices without doing an expensive copy 122 | meshGCHandles[iTransform] = GCHandle.Alloc(optixTransforms[iTransform].mesh.vertices, GCHandleType.Pinned); 123 | 124 | // The array pointer to the memory address of the verts 125 | meshVertexAddresses[iTransform] = meshGCHandles[iTransform].AddrOfPinnedObject(); 126 | 127 | // The local to world matrix of each OptixTransform 128 | meshTranslationMatrices[iTransform] = optixTransforms[iTransform].transform.localToWorldMatrix; 129 | 130 | // The number of vertices in the mesh 131 | meshVertexCounts[iTransform] = optixTransforms[iTransform].mesh.vertexCount; 132 | 133 | // The enabled status of each gameobject (is it within the required distance or not) 134 | optixTransforms[iTransform].isEnabled = CheckIfTransformIsEnabled(optixTransforms[iTransform].transform); 135 | meshEnabledStatus[iTransform] = optixTransforms[iTransform].isEnabled; 136 | } 137 | 138 | OptixLibraryInterface.SetAllObjectsFromUnity(optixTransforms.Length, meshVertexCounts, meshVertexAddresses, meshTranslationMatrices, meshEnabledStatus); 139 | 140 | // Free the GCHandles as we no longer want the GC to avoid removing our verts 141 | for (int iGCHandle = 0; iGCHandle < meshGCHandles.Length; iGCHandle++) 142 | { 143 | meshGCHandles[iGCHandle].Free(); 144 | } 145 | } 146 | 147 | 148 | #endregion 149 | 150 | #region Update 151 | 152 | // Update loop that is used by continous executions such as raytracing with point cloud rendering. Deals with updating transform matrices, distance culling and point cloud updating, all at a user-defined frame rate 153 | private IEnumerator RaytracingCoroutine(OptixPointCloud optixPointCloud) 154 | { 155 | while (isRaytracing) 156 | { 157 | if (!CheckOptixSensorComponentDirty()) 158 | { 159 | CheckOptixSensorTransformDirty(); 160 | } 161 | 162 | CheckEnabledStatusChanged(); 163 | CheckMatrixChanged(); 164 | 165 | if (sceneChanged) 166 | { 167 | sceneChanged = false; 168 | FireSensorAndUpdatePointCloud(optixPointCloud); 169 | } 170 | 171 | if (_optixTargetFPS == 0) // Prevents dividing by 0 error 172 | yield return null; 173 | else 174 | yield return new WaitForSeconds(1 / _optixTargetFPS); 175 | } 176 | } 177 | 178 | // Check if a transforms enabled status has changed and if it has update it in Optix 179 | private void CheckEnabledStatusChanged() 180 | { 181 | List updateTransformEnabled = new List(); 182 | List updateIndices = new List(); 183 | 184 | for (int iTransform = 0; iTransform < optixTransforms.Length; iTransform++) 185 | { 186 | int transformEnabled = CheckIfTransformIsEnabled(optixTransforms[iTransform].transform); 187 | 188 | if (optixTransforms[iTransform].isEnabled != transformEnabled) // Check if the transforms enabled status has changed 189 | { 190 | optixTransforms[iTransform].isEnabled = transformEnabled; 191 | updateIndices.Add(iTransform); 192 | updateTransformEnabled.Add(transformEnabled); 193 | } 194 | } 195 | 196 | if (updateTransformEnabled.Count > 0) 197 | { 198 | OptixLibraryInterface.UpdateGameObjectEnabledFromUnity(updateTransformEnabled.Count, updateIndices.ToArray(), updateTransformEnabled.ToArray()); 199 | sceneChanged = true; 200 | } 201 | } 202 | 203 | // Check if a transforms local to world matrix has changed and if it has update it in Optix 204 | private void CheckMatrixChanged() 205 | { 206 | List updateMatricies = new List(); 207 | List updateIndices = new List(); 208 | 209 | for (int iTransform = 0; iTransform < optixTransforms.Length; iTransform++) 210 | { 211 | if (optixTransforms[iTransform].IsDirty) // isDirty is set to true if any value within the object's transform has changed 212 | { 213 | optixTransforms[iTransform].IsDirty = false; 214 | 215 | updateMatricies.Add(optixTransforms[iTransform].transform.localToWorldMatrix); 216 | updateIndices.Add(iTransform); // Pass the index of the transform so we know which matrix to update in Optix 217 | } 218 | } 219 | 220 | if (updateMatricies.Count > 0) // If no enabled status' have changed, just update the matrices 221 | { 222 | OptixLibraryInterface.UpdateGameObjectMatrixFromUnity(updateMatricies.Count, updateIndices.ToArray(), updateMatricies.ToArray()); 223 | sceneChanged = true; 224 | } 225 | } 226 | 227 | private void CheckOptixSensorTransformDirty() 228 | { 229 | bool updateSensors = false; 230 | 231 | for (int iSensor = 0; iSensor < optixSensors.Length; iSensor++) 232 | { 233 | if (optixSensors[iSensor].IsTransformDirty) 234 | { 235 | optixSensors[iSensor].IsTransformDirty = false; 236 | updateSensors = true; 237 | } 238 | } 239 | 240 | if (updateSensors) 241 | { 242 | OptixLibraryInterface.TranslateAllSensorsFromUnity(optixSensors.Length, GetBaseValuesFromSensors(optixSensors)); 243 | sceneChanged = true; 244 | } 245 | } 246 | 247 | // Check if any of the sensors have had a value in the optix sensor component changed 248 | private bool CheckOptixSensorComponentDirty() 249 | { 250 | bool updateSensors = false; 251 | 252 | for (int iSensor = 0; iSensor < optixSensors.Length; iSensor++) 253 | { 254 | if (optixSensors[iSensor].IsComponentDirty) 255 | { 256 | optixSensors[iSensor].IsComponentDirty = false; 257 | optixSensors[iSensor].IsTransformDirty = false; 258 | updateSensors = true; 259 | } 260 | } 261 | 262 | if (updateSensors) 263 | { 264 | OptixLibraryInterface.SetAllSensorsFromUnity(optixSensors.Length, GetBaseValuesFromSensors(optixSensors)); 265 | sceneChanged = true; 266 | return true; 267 | } 268 | 269 | return false; 270 | } 271 | 272 | // Checks that a transform is within a certain distance of the optix origin and returns true or false (using ints to make data interop debugging easier) 273 | private int CheckIfTransformIsEnabled(Transform transform) 274 | { 275 | if (_optixOrigin == null) 276 | { 277 | return 1; 278 | } 279 | 280 | if (Vector3.Distance(transform.position, _optixOrigin.position) < _optixMaxDistanceFromOrigin) 281 | { 282 | return 1; 283 | } 284 | 285 | return 0; 286 | } 287 | 288 | #endregion 289 | 290 | #region Single execution 291 | 292 | /// 293 | /// Checks a ray to see if it intersects with any gameobjects. Runs once. 294 | /// 295 | public bool CheckSingleRayHit(Vector3 origin, Vector3 direction, float depth) 296 | { 297 | CheckEnabledStatusChanged(); 298 | CheckMatrixChanged(); 299 | 300 | if (OptixLibraryInterface.CheckSingleRayHit(origin, direction, depth)) 301 | { 302 | return true; 303 | } 304 | 305 | return false; 306 | } 307 | 308 | /// 309 | /// Checks a ray to see if it intersects with any gameobjects. Runs once. 310 | /// 311 | public bool CheckSingleRayHit(Ray ray, float depth) 312 | { 313 | CheckEnabledStatusChanged(); 314 | CheckMatrixChanged(); 315 | 316 | if (OptixLibraryInterface.CheckSingleRayHit(ray.origin, ray.direction, depth)) 317 | { 318 | return true; 319 | } 320 | 321 | return false; 322 | } 323 | 324 | /// 325 | /// Returns the hit position of a ray. If the ray doesn't intersect with any gameobject the returned position will be equal to Vector3.zero. Runs once. 326 | /// 327 | public Vector3 ReturnHitPositionFromSingleRay(Ray ray, float depth) 328 | { 329 | CheckEnabledStatusChanged(); 330 | CheckMatrixChanged(); 331 | 332 | return OptixLibraryInterface.ReturnSingleRayHit(ray.origin, ray.direction, depth); 333 | } 334 | 335 | /// 336 | /// Returns the hit position of a ray. If the ray doesn't intersect with any gameobject the returned position will be equal to Vector3.zero. Runs once. 337 | /// 338 | public Vector3 ReturnHitPositionFromSingleRay(Vector3 origin, Vector3 direction, float depth) 339 | { 340 | CheckEnabledStatusChanged(); 341 | CheckMatrixChanged(); 342 | 343 | return OptixLibraryInterface.ReturnSingleRayHit(origin, direction, depth); 344 | } 345 | 346 | /// 347 | /// Debug.Logs the number of hit positions from single/multiple optix sensors. Runs once. 348 | /// 349 | /// 350 | public int ReturnNumberOfHitPositionsSingle(OptixSensor[] optixSensors) 351 | { 352 | CheckEnabledStatusChanged(); 353 | CheckMatrixChanged(); 354 | 355 | this.optixSensors = optixSensors; 356 | OptixLibraryInterface.SetAllSensorsFromUnity(optixSensors.Length, GetBaseValuesFromSensors(optixSensors)); 357 | 358 | int returnHitPositionCount; 359 | OptixLibraryInterface.SensorFireAndReturnHitCount(out returnHitPositionCount); 360 | return returnHitPositionCount; 361 | } 362 | 363 | #endregion 364 | 365 | #region Continuous execution 366 | 367 | /// 368 | /// Renders the hit positions from single/multiple optix sensors into a point cloud. Runs continually until stopped by EndRaytracing(). 369 | /// 370 | public void RenderPointCloudFromSensorsContinuous(OptixSensor[] optixSensors, OptixPointCloud optixPointCloud) 371 | { 372 | this.optixSensors = optixSensors; 373 | OptixLibraryInterface.SetAllSensorsFromUnity(optixSensors.Length, GetBaseValuesFromSensors(optixSensors)); 374 | 375 | if (isRaytracing) 376 | { 377 | Debug.LogWarning("Attempting to start raytracing even though it is already executing."); 378 | return; 379 | } 380 | 381 | if (optixSensors == null) 382 | { 383 | Debug.LogWarning("Cannot have optixSensors set to null. Cancelling raytracing."); 384 | return; 385 | } 386 | 387 | isRaytracing = true; 388 | 389 | StartCoroutine(RaytracingCoroutine(optixPointCloud)); 390 | } 391 | 392 | /// 393 | /// Stops any continuous processes 394 | /// 395 | public void EndRaytracing() 396 | { 397 | isRaytracing = false; 398 | } 399 | 400 | private unsafe void FireSensorAndUpdatePointCloud(OptixPointCloud optixPointCloud) 401 | { 402 | Vector3* returnHitPositions; 403 | int returnHitPositionCount; 404 | 405 | using (OptixLibraryInterface.SensorFireAndReturnHitPositions(out returnHitPositions, out returnHitPositionCount)) 406 | { 407 | optixPointCloud.UpdatePositions(returnHitPositions, returnHitPositionCount); 408 | } 409 | } 410 | 411 | #endregion 412 | 413 | #region Helpers 414 | 415 | private OptixSensorBase[] GetBaseValuesFromSensors(OptixSensor[] sensors) 416 | { 417 | OptixSensorBase[] baseSensors = new OptixSensorBase[sensors.Length]; 418 | 419 | for (int iSensor = 0; iSensor < sensors.Length; iSensor++) 420 | { 421 | baseSensors[iSensor] = sensors[iSensor].OptixSensorBase; 422 | } 423 | 424 | return baseSensors; 425 | } 426 | 427 | #endregion 428 | 429 | private IEnumerator CallPluginAtEndOfFrames() 430 | { 431 | while (true) 432 | { 433 | // Wait until all frame rendering is done 434 | yield return new WaitForEndOfFrame(); 435 | 436 | // Set time for the plugin 437 | OptixLibraryInterface.SetTimeFromUnity(Time.realtimeSinceStartup); 438 | 439 | // Issue a plugin event with arbitrary integer identifier. 440 | // The plugin can distinguish between different 441 | // things it needs to do based on this ID. 442 | // For our simple plugin, it does not matter which ID we pass here. 443 | GL.IssuePluginEvent(OptixLibraryInterface.GetRenderEventFunc(), 1); 444 | } 445 | } 446 | } 447 | } 448 | -------------------------------------------------------------------------------- /UnityOptixCSharp/OptixExampleUsage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityEngine; 3 | using UnityEngine.UI; 4 | 5 | namespace World.Optix 6 | { 7 | public class OptixExampleUsage : MonoBehaviour 8 | { 9 | #region Vars 10 | 11 | public Button sensorTriggerButton; 12 | 13 | [Space(10)] 14 | [Header("Optix Config")] 15 | 16 | [Tooltip("Change the frequency that the ray tracing execution will occur. 60 FPS will mean it happens every frame, providing something has changed within the scene to warrant the execution.")] 17 | public float optixTargetFPS = 60; 18 | [Tooltip("Set the layer mask that will be applied at initalisation when searching the scene for valid gameobjects. Gameobjects that are not within the set layermask will not be included in Optix.")] 19 | public LayerMask optixTargetLayerMask; 20 | [Tooltip("Set the tag that all gameobjects will be compared to at initalisation when searching the scene for valid gameobjects. Gameobjects that do not have the set tag will not be included in Optix. Leave blank to allow all tags.")] 21 | public string optixTargetTag; 22 | [Tooltip("Set the transform/position of the centre of the scene. Use in conjunction with the below variable to declude objects that are too far away from the origin.")] 23 | public Transform optixOrigin; 24 | [Tooltip("Set the maximum distance that an object can be to be included in Optix. Use in conjunction with the above variable to declude objects that are too far away from the origin.")] 25 | public float optixMaxDistanceFromOrigin; 26 | 27 | [Space(10)] 28 | [Header("Point Cloud Config")] 29 | 30 | [Tooltip("A reference to the mesh that will be instanced by the shader which will represent each individual point cloud point.")] 31 | public Mesh instanceMesh; 32 | [Tooltip("A reference to the material that contains the instance shader which will render the point cloud.")] 33 | public Material instanceMaterial; 34 | [Tooltip("The size of each point in the point cloud.")] 35 | public float pointCloudPointSize = 0.05f; 36 | [Tooltip("The colour of each point in the point cloud.")] 37 | public Color pointCloudPointColour; 38 | 39 | private OptixSensor[] sensors; 40 | private OptixPointCloud optixPointCloud; 41 | private OptixController optixController; 42 | 43 | #endregion 44 | 45 | private void Start() 46 | { 47 | // Cache all Optix Sensors in the scene 48 | sensors = FindObjectsOfType(); 49 | 50 | optixController = gameObject.AddComponent(); 51 | optixController.Init(optixTargetFPS, optixTargetLayerMask, optixTargetTag, optixOrigin, optixMaxDistanceFromOrigin); 52 | 53 | optixPointCloud = gameObject.AddComponent(); 54 | optixPointCloud.Init(instanceMesh, instanceMaterial, pointCloudPointColour, pointCloudPointSize); 55 | 56 | sensorTriggerButton.onClick.AddListener(ButtonClick); 57 | } 58 | 59 | private void ButtonClick() 60 | { 61 | optixPointCloud.StartRendering(); 62 | optixController.RenderPointCloudFromSensorsContinuous(sensors, optixPointCloud); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /UnityOptixCSharp/OptixLibraryInterface.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32.SafeHandles; 2 | using System; 3 | using System.Runtime.InteropServices; 4 | using System.Text; 5 | using UnityEngine; 6 | 7 | namespace World.Optix 8 | { 9 | public struct OptixSensorBase 10 | { 11 | public Matrix4x4 localToWorldTranslationMatrix; 12 | 13 | public float sensorDepth; 14 | public float sensorHeight; 15 | public float sensorRadius; 16 | 17 | public float pointGap; 18 | public float totalPoints; 19 | } 20 | 21 | /// 22 | /// The interface for accessing the Optix library. Should only be used through the OptixController. 23 | /// 24 | public class OptixLibraryInterface : SafeHandleZeroOrMinusOneIsInvalid 25 | { 26 | #region Init Optix Functions 27 | 28 | [DllImport("unityOptixPlugin", CallingConvention = CallingConvention.Cdecl)] 29 | public static extern void SetAllObjectsFromUnity 30 | ( 31 | int totalMeshes, int[] vertexCount, IntPtr[] sourceVertices, Matrix4x4[] transformationMatrices, int[] transformEnabled 32 | ); 33 | 34 | [DllImport("unityOptixPlugin", CallingConvention = CallingConvention.Cdecl)] 35 | public static extern void SetAllSensorsFromUnity 36 | ( 37 | int totalSensors, OptixSensorBase[] sensors 38 | ); 39 | 40 | #endregion 41 | 42 | #region Update Optix Functions 43 | 44 | [DllImport("unityOptixPlugin", CallingConvention = CallingConvention.Cdecl)] 45 | public static extern void TranslateAllSensorsFromUnity 46 | ( 47 | int totalSensors, OptixSensorBase[] sensors 48 | ); 49 | 50 | [DllImport("unityOptixPlugin", CallingConvention = CallingConvention.Cdecl)] 51 | public static extern void UpdateGameObjectMatrixFromUnity 52 | ( 53 | int matrixCount, int[] matrixIndices, Matrix4x4[] transformationMatrices 54 | ); 55 | 56 | [DllImport("unityOptixPlugin", CallingConvention = CallingConvention.Cdecl)] 57 | public static extern void UpdateGameObjectEnabledFromUnity 58 | ( 59 | int transformCount, int[] transformIndices, int[] transformEnabled 60 | ); 61 | 62 | #endregion 63 | 64 | #region Sensor fire 65 | 66 | [DllImport("unityOptixPlugin", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] 67 | public static unsafe extern bool SensorFireAndReturnHitPositions 68 | ( 69 | out OptixLibraryInterface optixLibraryHandle, out Vector3* hitPositions, out int hitPositionCount 70 | ); 71 | 72 | [DllImport("unityOptixPlugin", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] 73 | public static extern bool SensorFireAndReturnHitCount 74 | ( 75 | out int hitPositionCount 76 | ); 77 | 78 | #endregion 79 | 80 | #region Single ray fire 81 | 82 | [DllImport("unityOptixPlugin", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] 83 | public static extern bool CheckSingleRayHit 84 | ( 85 | Vector3 origin, Vector3 direction, float depth 86 | ); 87 | 88 | [DllImport("unityOptixPlugin", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] 89 | public static extern Vector3 ReturnSingleRayHit 90 | ( 91 | Vector3 origin, Vector3 direction, float depth 92 | ); 93 | 94 | #endregion 95 | 96 | [DllImport("unityOptixPlugin", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] 97 | public static unsafe extern bool ReleaseItems 98 | ( 99 | IntPtr optixLibraryHandle 100 | ); 101 | 102 | [DllImport("unityOptixPlugin", CallingConvention = CallingConvention.Cdecl)] 103 | public static extern IntPtr GetRenderEventFunc(); 104 | 105 | [DllImport("unityOptixPlugin", CallingConvention = CallingConvention.Cdecl)] 106 | public static extern void SetTimeFromUnity(float t); 107 | 108 | public OptixLibraryInterface() 109 | : base(true) 110 | { 111 | } 112 | 113 | protected override bool ReleaseHandle() 114 | { 115 | return ReleaseItems(handle); 116 | } 117 | 118 | // This function is unsafe because memory as been allocated on the plugin side. When you have finished with the results from the function, 119 | // the ReleaseHandle function automatically passes the handle back to the plugin side which deallocates it. 120 | public static unsafe OptixLibraryInterface SensorFireAndReturnHitPositions(out Vector3* hitPositions, out int hitPositionCount) 121 | { 122 | OptixLibraryInterface optixLibraryHandle; 123 | 124 | if (!SensorFireAndReturnHitPositions(out optixLibraryHandle, out hitPositions, out hitPositionCount)) 125 | { 126 | throw new InvalidOperationException(); 127 | } 128 | 129 | return optixLibraryHandle; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /UnityOptixCSharp/OptixPointCloud.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using UnityEngine; 3 | 4 | namespace World.Optix 5 | { 6 | /// 7 | /// Renders an array of positions to a point cloud using the low-level function, Graphics.DrawMeshInstancedIndirect(). 8 | /// 9 | [AddComponentMenu("")] 10 | public class OptixPointCloud : MonoBehaviour 11 | { 12 | #region Vars 13 | 14 | private int instanceCount = -1; 15 | private ComputeBuffer positionBuffer; 16 | private ComputeBuffer argsBuffer; 17 | 18 | private bool rendering; 19 | 20 | private uint[] args = new uint[5] { 0, 0, 0, 0, 0 }; 21 | 22 | private Mesh _instancedMesh; 23 | private Material _instancedMaterial; 24 | private Color _pointCloudPointColour; 25 | private float _pointCloudPointSize; 26 | 27 | #endregion 28 | 29 | public void Init(Mesh instancedMesh, Material instancedMaterial, Color pointCloudPointColour, float pointCloudPointSize) 30 | { 31 | _instancedMesh = instancedMesh; 32 | _instancedMaterial = instancedMaterial; 33 | _pointCloudPointColour = pointCloudPointColour; 34 | _pointCloudPointSize = pointCloudPointSize; 35 | } 36 | 37 | /// 38 | /// Set the position data that is used to render the point cloud 39 | /// 40 | /// 41 | /// 42 | public unsafe void UpdatePositions(Vector3* positionData, int positionDataCount) 43 | { 44 | instanceCount = positionDataCount; 45 | 46 | if (instanceCount <= 0) 47 | return; // Do not attempt to update buffers if there is no data to update them with. Prevents error. 48 | 49 | if (positionBuffer != null) 50 | positionBuffer.Release(); 51 | 52 | positionBuffer = new ComputeBuffer(instanceCount, 16); 53 | 54 | Vector4[] positions = new Vector4[instanceCount]; 55 | 56 | for (int iPositionData = 0; iPositionData < positionDataCount; iPositionData++) 57 | { 58 | positions[iPositionData] = new Vector4(positionData[iPositionData].x, positionData[iPositionData].y, positionData[iPositionData].z, _pointCloudPointSize); 59 | } 60 | 61 | positionBuffer.SetData(positions); 62 | 63 | _instancedMaterial.SetBuffer("positionBuffer", positionBuffer); 64 | _instancedMaterial.SetColor("_PointColor", _pointCloudPointColour); 65 | 66 | // indirect args 67 | uint numIndices = (_instancedMesh != null) ? (uint)_instancedMesh.GetIndexCount(0) : 0; 68 | args[0] = numIndices; 69 | args[1] = (uint)instanceCount; 70 | 71 | argsBuffer.SetData(args); 72 | } 73 | 74 | /// 75 | /// Instruct the point cloud to start the render loop 76 | /// 77 | public void StartRendering() 78 | { 79 | rendering = true; 80 | argsBuffer = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments); 81 | StartCoroutine(RenderPointCloudCoroutine()); 82 | } 83 | 84 | /// 85 | /// End the point cloud render loop and release the buffers 86 | /// 87 | public void StopRendering() 88 | { 89 | rendering = false; 90 | 91 | if (positionBuffer != null) positionBuffer.Release(); 92 | positionBuffer = null; 93 | 94 | if (argsBuffer != null) argsBuffer.Release(); 95 | argsBuffer = null; 96 | 97 | instanceCount = -1; 98 | } 99 | 100 | private void Update() 101 | { 102 | if (instanceCount <= 0 || argsBuffer == null) 103 | return; 104 | 105 | // Render 106 | Graphics.DrawMeshInstancedIndirect(_instancedMesh, 0, _instancedMaterial, new Bounds(Vector3.zero, new Vector3(1000.0f, 1000.0f, 1000.0f)), argsBuffer, 0, null, UnityEngine.Rendering.ShadowCastingMode.Off, false, 9); 107 | } 108 | 109 | // Loop that deals with rendering the point cloud. This must happen every frame because if it doesn't then one frame the point cloud won't get rendered and it will look all jittery 110 | private IEnumerator RenderPointCloudCoroutine() 111 | { 112 | while (rendering) 113 | { 114 | Update(); 115 | yield return null; 116 | } 117 | } 118 | 119 | private void OnApplicationQuit() 120 | { 121 | StopRendering(); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /UnityOptixCSharp/OptixSensor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace World.Optix 5 | { 6 | public class OptixSensor : MonoBehaviour 7 | { 8 | [Range(1, 30)] 9 | public float sensorDepth = 14f; 10 | [Range(1, 20)] 11 | public float sensorHeight = 10f; 12 | [Range(1, 360)] 13 | public float radius = 30f; 14 | [Range(0.001f, 1)] 15 | public float stride = 0.2f; 16 | 17 | public bool IsTransformDirty 18 | { 19 | get { return transform.hasChanged; } 20 | set { transform.hasChanged = value; } 21 | } 22 | 23 | public bool IsComponentDirty { get; set; } 24 | 25 | public OptixSensorBase OptixSensorBase 26 | { 27 | get 28 | { 29 | return new OptixSensorBase 30 | { 31 | localToWorldTranslationMatrix = transform.localToWorldMatrix, 32 | 33 | sensorDepth = sensorDepth, 34 | sensorHeight = sensorHeight, 35 | sensorRadius = radius, 36 | pointGap = stride, 37 | totalPoints = GetTotalPoints() 38 | }; 39 | } 40 | } 41 | 42 | private Vector3 topLeft; 43 | private Vector3 topRight; 44 | private Vector3 botRight; 45 | private Vector3 botLeft; 46 | 47 | private Vector3 centre; 48 | private List topCurvePositions = new List(); 49 | private List botCurvePositions = new List(); 50 | 51 | private void UpdateValues() 52 | { 53 | centre = ((transform.position + (transform.forward * sensorDepth)) - transform.position); 54 | 55 | topRight = transform.position + (Quaternion.Euler(0, +(radius / 2), 0) * centre) + new Vector3(0f, sensorHeight / 2, 0f); 56 | topLeft = transform.position + (Quaternion.Euler(0, -(radius / 2), 0) * centre) + new Vector3(0f, sensorHeight / 2, 0f); 57 | botRight = transform.position + (Quaternion.Euler(0, +(radius / 2), 0) * centre) + new Vector3(0f, -sensorHeight / 2, 0f); 58 | botLeft = transform.position + (Quaternion.Euler(0, -(radius / 2), 0) * centre) + new Vector3(0f, -sensorHeight / 2, 0f); 59 | 60 | topCurvePositions.Clear(); 61 | botCurvePositions.Clear(); 62 | 63 | for (float iRadius = -(radius / 2); iRadius < (radius / 2); iRadius++) 64 | { 65 | topCurvePositions.Add(transform.position + (Quaternion.Euler(0, iRadius, 0) * centre) + new Vector3(0f, sensorHeight / 2, 0f)); 66 | botCurvePositions.Add(transform.position + (Quaternion.Euler(0, iRadius + 1, 0) * centre) + new Vector3(0f, -sensorHeight / 2, 0f)); 67 | } 68 | } 69 | 70 | void OnDrawGizmos() 71 | { 72 | UpdateValues(); // Should this be called in this function? 73 | 74 | Gizmos.color = Color.blue; 75 | 76 | for (int iCurvePos = 0; iCurvePos < botCurvePositions.Count - 1; iCurvePos++) 77 | { 78 | Gizmos.DrawLine(botCurvePositions[iCurvePos], botCurvePositions[iCurvePos + 1]); 79 | Gizmos.DrawLine(topCurvePositions[iCurvePos], topCurvePositions[iCurvePos + 1]); 80 | } 81 | 82 | Gizmos.DrawLine(transform.position, topLeft); 83 | Gizmos.DrawLine(transform.position, topRight); 84 | Gizmos.DrawLine(transform.position, botRight); 85 | Gizmos.DrawLine(transform.position, botLeft); 86 | 87 | Gizmos.DrawLine(topLeft, botLeft); 88 | Gizmos.DrawLine(topRight, botRight); 89 | } 90 | 91 | private float GetTotalPoints() 92 | { 93 | float rows = 0; 94 | float columns = 0; 95 | 96 | rows += Mathf.Ceil(sensorHeight / stride); 97 | columns += Mathf.Ceil(radius / stride); 98 | 99 | return (rows * columns); 100 | } 101 | 102 | private void OnValidate() 103 | { 104 | IsComponentDirty = true; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /UnityOptixCSharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("World.Optix")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("World.Optix")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5a45c1e5-860a-44e2-ac33-19a198cd89d7")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /UnityOptixCSharp/UnityOptix.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | CSharp60 -------------------------------------------------------------------------------- /UnityOptixCSharp/UnityOptix.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {63FFBF21-5A10-4F4F-93D1-DF27D71ED0E6} 8 | Library 9 | Properties 10 | World.Optix 11 | World.Optix 12 | v3.5 13 | 512 14 | 15 | 16 | True 17 | pdbonly 18 | prompt 19 | 4 20 | CS0649 21 | 22 | 23 | DEBUG;_WIN;ENABLE_PROFILER;UNITY;UNITY_5;UNITY_5_4;UNITY_64;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_WIN;UNITY_STANDALONE;UNITY_STANDALONE_WIN 24 | ..\..\ASTAS_OPTIX\virtenv_unityproject\Assets\Binaries\ 25 | true 26 | 27 | 28 | $(CmdDefines.Replace(' ',';'));_WIN;DEBUG;ENABLE_PROFILER;TODO_STANDALONE;UNITY;UNITY_5;UNITY_5_4;UNITY_64;UNITY_PLAYER;UNITY_STANDALONE;UNITY_STANDALONE_WIN 29 | ..\..\ASTAS_OPTIX\virtenv_unityproject\Assets\Binaries\ 30 | true 31 | 32 | 33 | 34 | ..\..\..\..\packages\NLog.4.4.5\lib\net35\NLog.dll 35 | True 36 | 37 | 38 | 39 | 40 | 41 | False 42 | ..\..\ASTAS_OPTIX\virtenv_unityproject\Source\Libraries\Unity\Managed\UnityEditor.dll 43 | False 44 | 45 | 46 | False 47 | ..\..\ASTAS_OPTIX\virtenv_unityproject\Source\Libraries\Unity\Managed\UnityEngine.dll 48 | False 49 | 50 | 51 | False 52 | ..\..\ASTAS_OPTIX\virtenv_unityproject\Source\Libraries\Unity\UnityExtensions\Unity\GUISystem\UnityEngine.UI.dll 53 | False 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 75 | -------------------------------------------------------------------------------- /UnityOptixCSharp/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /UnityOptixPluginCompiled/optix_prime.1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexander-scott/UnityOptixPlugin/84f2f75a882e831fad8397bba8371abe56b16c01/UnityOptixPluginCompiled/optix_prime.1.dll -------------------------------------------------------------------------------- /UnityOptixPluginCompiled/sutil_sdk.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexander-scott/UnityOptixPlugin/84f2f75a882e831fad8397bba8371abe56b16c01/UnityOptixPluginCompiled/sutil_sdk.dll -------------------------------------------------------------------------------- /UnityOptixPluginCompiled/unityOptixPlugin.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexander-scott/UnityOptixPlugin/84f2f75a882e831fad8397bba8371abe56b16c01/UnityOptixPluginCompiled/unityOptixPlugin.dll -------------------------------------------------------------------------------- /UnityOptixPluginMaterials/InstancedShader.shader: -------------------------------------------------------------------------------- 1 | Shader "Instanced/InstancedShader" 2 | { 3 | Properties 4 | { 5 | _MainTex("Albedo (RGB)", 2D) = "white" {} 6 | _Glossiness("Smoothness", Range(0,1)) = 0.5 7 | _Metallic("Metallic", Range(0,1)) = 0.0 8 | _PointColor("Point Color", Color) = (1, 1, 1, 1) 9 | } 10 | SubShader 11 | { 12 | Tags 13 | { 14 | "RenderType" = "Opaque" 15 | } 16 | 17 | LOD 200 18 | 19 | CGPROGRAM 20 | 21 | // Physically based Standard lighting model 22 | #pragma surface surf Standard addshadow 23 | #pragma multi_compile_instancing 24 | #pragma instancing_options procedural:setup 25 | 26 | sampler2D _MainTex; 27 | 28 | struct Input { 29 | float2 uv_MainTex; 30 | }; 31 | 32 | #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 33 | StructuredBuffer positionBuffer; 34 | #endif 35 | 36 | void rotate2D(inout float2 v, float r) 37 | { 38 | float s, c; 39 | sincos(r, s, c); 40 | v = float2(v.x * c - v.y * s, v.x * s + v.y * c); 41 | } 42 | 43 | void setup() 44 | { 45 | #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 46 | float4 data = positionBuffer[unity_InstanceID]; 47 | 48 | float rotation = data.w * data.w * 0.5f; 49 | rotate2D(data.xz, rotation); 50 | 51 | unity_ObjectToWorld._11_21_31_41 = float4(data.w, 0, 0, 0); 52 | unity_ObjectToWorld._12_22_32_42 = float4(0, data.w, 0, 0); 53 | unity_ObjectToWorld._13_23_33_43 = float4(0, 0, data.w, 0); 54 | unity_ObjectToWorld._14_24_34_44 = float4(data.xyz, 1); 55 | unity_WorldToObject = unity_ObjectToWorld; 56 | unity_WorldToObject._14_24_34 *= -1; 57 | unity_WorldToObject._11_22_33 = 1.0f / unity_WorldToObject._11_22_33; 58 | #endif 59 | } 60 | 61 | half _Glossiness; 62 | half _Metallic; 63 | float4 _PointColor; 64 | 65 | void surf(Input IN, inout SurfaceOutputStandard o) 66 | { 67 | fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _PointColor; 68 | o.Albedo = c.rgb; 69 | o.Metallic = _Metallic; 70 | o.Smoothness = _Glossiness; 71 | o.Alpha = c.a; 72 | } 73 | ENDCG 74 | } 75 | FallBack "Diffuse" 76 | } 77 | -------------------------------------------------------------------------------- /UnityOptixPluginMaterials/PointCloudPointMat.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexander-scott/UnityOptixPlugin/84f2f75a882e831fad8397bba8371abe56b16c01/UnityOptixPluginMaterials/PointCloudPointMat.mat -------------------------------------------------------------------------------- /unityOptixPlugin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions 6 | # are met: 7 | # * Redistributions of source code must retain the above copyright 8 | # notice, this list of conditions and the following disclaimer. 9 | # * Redistributions in binary form must reproduce the above copyright 10 | # notice, this list of conditions and the following disclaimer in the 11 | # documentation and/or other materials provided with the distribution. 12 | # * Neither the name of NVIDIA CORPORATION nor the names of its 13 | # contributors may be used to endorse or promote products derived 14 | # from this software without specific prior written permission. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | # 28 | 29 | set(COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../unityOptixPlugin) 30 | set_source_files_properties(${COMMON_DIR}/primeKernels.cu 31 | PROPERTIES CUDA_SOURCE_PROPERTY_FORMAT OBJ 32 | ) 33 | include_directories( 34 | "${COMMON_DIR}" 35 | ) 36 | 37 | # See top level CMakeLists.txt file for documentation of OPTIX_add_sample_executable. 38 | OPTIX_add_sample_executable( unityOptixPlugin 39 | OptixPlugin.cpp 40 | OptixPlugin.h 41 | IUnityGraphics.h 42 | IUnityGraphicsD3D11.h 43 | IUnityInterface.h 44 | PlatformBase.h 45 | RenderAPI.cpp 46 | RenderAPI.h 47 | RenderAPI_D3D11.cpp 48 | ${COMMON_DIR}/primeCommon.h 49 | ${COMMON_DIR}/primeCommon.cpp 50 | ${COMMON_DIR}/primeKernels.cu 51 | ) 52 | 53 | target_link_libraries( unityOptixPlugin 54 | optix_prime 55 | ${CUDA_LIBRARIES} 56 | ) 57 | -------------------------------------------------------------------------------- /unityOptixPlugin/IUnityGraphics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IUnityInterface.h" 3 | 4 | typedef enum UnityGfxRenderer 5 | { 6 | kUnityGfxRendererOpenGL = 0, // Legacy OpenGL 7 | kUnityGfxRendererD3D9 = 1, // Direct3D 9 8 | kUnityGfxRendererD3D11 = 2, // Direct3D 11 9 | kUnityGfxRendererGCM = 3, // PlayStation 3 10 | kUnityGfxRendererNull = 4, // "null" device (used in batch mode) 11 | kUnityGfxRendererXenon = 6, // Xbox 360 12 | kUnityGfxRendererOpenGLES20 = 8, // OpenGL ES 2.0 13 | kUnityGfxRendererOpenGLES30 = 11, // OpenGL ES 3.x 14 | kUnityGfxRendererGXM = 12, // PlayStation Vita 15 | kUnityGfxRendererPS4 = 13, // PlayStation 4 16 | kUnityGfxRendererXboxOne = 14, // Xbox One 17 | kUnityGfxRendererMetal = 16, // iOS Metal 18 | kUnityGfxRendererOpenGLCore = 17, // OpenGL core 19 | kUnityGfxRendererD3D12 = 18, // Direct3D 12 20 | } UnityGfxRenderer; 21 | 22 | typedef enum UnityGfxDeviceEventType 23 | { 24 | kUnityGfxDeviceEventInitialize = 0, 25 | kUnityGfxDeviceEventShutdown = 1, 26 | kUnityGfxDeviceEventBeforeReset = 2, 27 | kUnityGfxDeviceEventAfterReset = 3, 28 | } UnityGfxDeviceEventType; 29 | 30 | typedef void (UNITY_INTERFACE_API * IUnityGraphicsDeviceEventCallback)(UnityGfxDeviceEventType eventType); 31 | 32 | // Should only be used on the rendering thread unless noted otherwise. 33 | UNITY_DECLARE_INTERFACE(IUnityGraphics) 34 | { 35 | UnityGfxRenderer (UNITY_INTERFACE_API * GetRenderer)(); // Thread safe 36 | 37 | // This callback will be called when graphics device is created, destroyed, reset, etc. 38 | // It is possible to miss the kUnityGfxDeviceEventInitialize event in case plugin is loaded at a later time, 39 | // when the graphics device is already created. 40 | void (UNITY_INTERFACE_API * RegisterDeviceEventCallback)(IUnityGraphicsDeviceEventCallback callback); 41 | void (UNITY_INTERFACE_API * UnregisterDeviceEventCallback)(IUnityGraphicsDeviceEventCallback callback); 42 | }; 43 | UNITY_REGISTER_INTERFACE_GUID(0x7CBA0A9CA4DDB544ULL,0x8C5AD4926EB17B11ULL,IUnityGraphics) 44 | 45 | 46 | 47 | // Certain Unity APIs (GL.IssuePluginEvent, CommandBuffer.IssuePluginEvent) can callback into native plugins. 48 | // Provide them with an address to a function of this signature. 49 | typedef void (UNITY_INTERFACE_API * UnityRenderingEvent)(int eventId); 50 | -------------------------------------------------------------------------------- /unityOptixPlugin/IUnityGraphicsD3D11.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IUnityInterface.h" 3 | 4 | // Should only be used on the rendering thread unless noted otherwise. 5 | UNITY_DECLARE_INTERFACE(IUnityGraphicsD3D11) 6 | { 7 | ID3D11Device* (UNITY_INTERFACE_API * GetDevice)(); 8 | }; 9 | UNITY_REGISTER_INTERFACE_GUID(0xAAB37EF87A87D748ULL,0xBF76967F07EFB177ULL,IUnityGraphicsD3D11) 10 | -------------------------------------------------------------------------------- /unityOptixPlugin/IUnityInterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Unity native plugin API 4 | // Compatible with C99 5 | 6 | #if defined(__CYGWIN32__) 7 | #define UNITY_INTERFACE_API __stdcall 8 | #define UNITY_INTERFACE_EXPORT __declspec(dllexport) 9 | #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WINAPI_FAMILY) 10 | #define UNITY_INTERFACE_API __stdcall 11 | #define UNITY_INTERFACE_EXPORT __declspec(dllexport) 12 | #elif defined(__MACH__) || defined(__ANDROID__) || defined(__linux__) || defined(__QNX__) 13 | #define UNITY_INTERFACE_API 14 | #define UNITY_INTERFACE_EXPORT 15 | #else 16 | #define UNITY_INTERFACE_API 17 | #define UNITY_INTERFACE_EXPORT 18 | #endif 19 | 20 | 21 | 22 | // Unity Interface GUID 23 | // Ensures cross plugin uniqueness. 24 | // 25 | // Template specialization is used to produce a means of looking up a GUID from it's payload type at compile time. 26 | // The net result should compile down to passing around the GUID. 27 | // 28 | // UNITY_REGISTER_INTERFACE_GUID should be placed in the header file of any payload definition outside of all namespaces. 29 | // The payload structure and the registration GUID are all that is required to expose the interface to other systems. 30 | struct UnityInterfaceGUID 31 | { 32 | #ifdef __cplusplus 33 | UnityInterfaceGUID(unsigned long long high, unsigned long long low) 34 | : m_GUIDHigh(high) 35 | , m_GUIDLow(low) 36 | { 37 | } 38 | 39 | UnityInterfaceGUID(const UnityInterfaceGUID& other) 40 | { 41 | m_GUIDHigh = other.m_GUIDHigh; 42 | m_GUIDLow = other.m_GUIDLow; 43 | } 44 | 45 | UnityInterfaceGUID& operator=(const UnityInterfaceGUID& other) 46 | { 47 | m_GUIDHigh = other.m_GUIDHigh; 48 | m_GUIDLow = other.m_GUIDLow; 49 | return *this; 50 | } 51 | 52 | bool Equals(const UnityInterfaceGUID& other) const { return m_GUIDHigh == other.m_GUIDHigh && m_GUIDLow == other.m_GUIDLow; } 53 | bool LessThan(const UnityInterfaceGUID& other) const { return m_GUIDHigh < other.m_GUIDHigh || (m_GUIDHigh == other.m_GUIDHigh && m_GUIDLow < other.m_GUIDLow); } 54 | #endif 55 | unsigned long long m_GUIDHigh; 56 | unsigned long long m_GUIDLow; 57 | }; 58 | #ifdef __cplusplus 59 | inline bool operator==(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return left.Equals(right); } 60 | inline bool operator!=(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return !left.Equals(right); } 61 | inline bool operator< (const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return left.LessThan(right); } 62 | inline bool operator> (const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return right.LessThan(left); } 63 | inline bool operator>=(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return !operator< (left,right); } 64 | inline bool operator<=(const UnityInterfaceGUID& left, const UnityInterfaceGUID& right) { return !operator> (left,right); } 65 | #else 66 | typedef struct UnityInterfaceGUID UnityInterfaceGUID; 67 | #endif 68 | 69 | 70 | 71 | #define UNITY_GET_INTERFACE_GUID(TYPE) TYPE##_GUID 72 | #define UNITY_GET_INTERFACE(INTERFACES, TYPE) (TYPE*)INTERFACES->GetInterface(UNITY_GET_INTERFACE_GUID(TYPE)); 73 | 74 | #ifdef __cplusplus 75 | #define UNITY_DECLARE_INTERFACE(NAME) \ 76 | struct NAME : IUnityInterface 77 | 78 | template \ 79 | inline const UnityInterfaceGUID GetUnityInterfaceGUID(); \ 80 | 81 | #define UNITY_REGISTER_INTERFACE_GUID(HASHH, HASHL, TYPE) \ 82 | const UnityInterfaceGUID TYPE##_GUID(HASHH, HASHL); \ 83 | template<> \ 84 | inline const UnityInterfaceGUID GetUnityInterfaceGUID() \ 85 | { \ 86 | return UNITY_GET_INTERFACE_GUID(TYPE); \ 87 | } 88 | #else 89 | #define UNITY_DECLARE_INTERFACE(NAME) \ 90 | typedef struct NAME NAME; \ 91 | struct NAME 92 | 93 | #define UNITY_REGISTER_INTERFACE_GUID(HASHH, HASHL, TYPE) \ 94 | const UnityInterfaceGUID TYPE##_GUID = {HASHH, HASHL}; 95 | #endif 96 | 97 | 98 | 99 | #ifdef __cplusplus 100 | struct IUnityInterface 101 | { 102 | }; 103 | #else 104 | typedef void IUnityInterface; 105 | #endif 106 | 107 | 108 | 109 | typedef struct IUnityInterfaces 110 | { 111 | // Returns an interface matching the guid. 112 | // Returns nullptr if the given interface is unavailable in the active Unity runtime. 113 | IUnityInterface* (UNITY_INTERFACE_API * GetInterface)(UnityInterfaceGUID guid); 114 | 115 | // Registers a new interface. 116 | void (UNITY_INTERFACE_API * RegisterInterface)(UnityInterfaceGUID guid, IUnityInterface* ptr); 117 | 118 | #ifdef __cplusplus 119 | // Helper for GetInterface. 120 | template 121 | INTERFACE* Get() 122 | { 123 | return static_cast(GetInterface(GetUnityInterfaceGUID())); 124 | } 125 | 126 | // Helper for RegisterInterface. 127 | template 128 | void Register(IUnityInterface* ptr) 129 | { 130 | RegisterInterface(GetUnityInterfaceGUID(), ptr); 131 | } 132 | #endif 133 | } IUnityInterfaces; 134 | 135 | 136 | 137 | #ifdef __cplusplus 138 | extern "C" { 139 | #endif 140 | 141 | // If exported by a plugin, this function will be called when the plugin is loaded. 142 | void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces); 143 | // If exported by a plugin, this function will be called when the plugin is about to be unloaded. 144 | void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload(); 145 | 146 | #ifdef __cplusplus 147 | } 148 | #endif 149 | -------------------------------------------------------------------------------- /unityOptixPlugin/OptixPlugin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of NVIDIA CORPORATION nor the names of its 13 | * contributors may be used to endorse or promote products derived 14 | * from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "primeCommon.h" 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "OptixPlugin.h" 39 | 40 | #include "PlatformBase.h" 41 | #include "RenderAPI.h" 42 | 43 | // ------------------------------------------------------------------------------------- 44 | // Init Optix Functions 45 | // ------------------------------------------------------------------------------------- 46 | 47 | // Sets the models and matrices of each object from Unity for use in Optix later. Called on application initalisation. 48 | OPTIXPLUGIN_API void SetAllObjectsFromUnity(int totalTrans, int* meshVertexCounts, float** meshVerticies, optix::Matrix4x4* transformationMatrices, int* transformEnabled) 49 | { 50 | contextType = RTP_CONTEXT_TYPE_CPU; 51 | bufferType = RTP_BUFFER_TYPE_HOST; 52 | 53 | context = Context::create(contextType); 54 | 55 | totalObjects = totalTrans; 56 | 57 | objectModels.resize(totalObjects); 58 | objectTranslationMatrices.resize(totalObjects); 59 | objectEnabledStatus.resize(totalObjects); 60 | 61 | for (int i = 0; i < totalObjects; ++i) // For every mesh in meshVerticies 62 | { 63 | // Create a float3 formatted buffer (each triplet of floats in the array is now a vector3 in the order x,y,z) 64 | BufferDesc bufferDesc = context->createBufferDesc(RTP_BUFFER_FORMAT_VERTEX_FLOAT3, RTP_BUFFER_TYPE_HOST, meshVerticies[i]); 65 | bufferDesc->setRange(0, meshVertexCounts[i]); 66 | 67 | // Create an Optix Prime Model from the float3's 68 | objectModels[i] = context->createModel(); 69 | objectModels[i]->setTriangles(bufferDesc); 70 | objectModels[i]->update(0); 71 | 72 | // Convert the Matrix4x4 translation matrix into the format required by Optix Prime (Matrix4x3) and then store it 73 | objectTranslationMatrices[i] = GetSimpleMatrixFromUnityMatrix(transformationMatrices[i]); 74 | 75 | objectEnabledStatus[i] = transformEnabled[i]; 76 | } 77 | } 78 | 79 | // Generates and caches the base rays from the optix sensors and does an inital translation 80 | OPTIXPLUGIN_API void SetAllSensorsFromUnity(int sensorCount, OptixSensorBase* sensors) 81 | { 82 | CreateRaysFromSensorBounds(sensors, sensorCount); 83 | if (raysBuffer.type() == RTP_BUFFER_TYPE_HOST) 84 | { 85 | TranslateRays(sensors, sensorCount); 86 | } 87 | } 88 | 89 | // ------------------------------------------------------------------------------------- 90 | // Optix Update Functions 91 | // ------------------------------------------------------------------------------------- 92 | 93 | // Translate all rays generated by the sensors by their localToWorld translation matrices 94 | OPTIXPLUGIN_API void TranslateAllSensorsFromUnity(int sensorCount, OptixSensorBase* sensors) 95 | { 96 | if (raysBuffer.type() == RTP_BUFFER_TYPE_HOST) 97 | { 98 | TranslateRays(sensors, sensorCount); 99 | } 100 | else 101 | { 102 | CreateRaysFromSensorBounds(sensors, sensorCount); 103 | } 104 | } 105 | 106 | // Updates multiple objects enabled status (whether it is inside a certain range or not) 107 | OPTIXPLUGIN_API void UpdateGameObjectEnabledFromUnity(int objectCount, int* objectIndex, int* objectEnabled) 108 | { 109 | for (int iObject = 0; iObject < objectCount; ++iObject) 110 | { 111 | objectEnabledStatus[objectIndex[iObject]] = objectEnabled[iObject]; 112 | } 113 | } 114 | 115 | // Updates multiple objects's localToWorld translation matrices 116 | OPTIXPLUGIN_API void UpdateGameObjectMatrixFromUnity(int matrixCount, int* matrixIndex, optix::Matrix4x4* transformationMatrices) 117 | { 118 | for (int iMatrix = 0; iMatrix < matrixCount; iMatrix++) 119 | { 120 | objectTranslationMatrices[matrixIndex[iMatrix]] = GetSimpleMatrixFromUnityMatrix(transformationMatrices[iMatrix]); 121 | } 122 | } 123 | 124 | // ------------------------------------------------------------------------------------- 125 | // Optix Execute Functions 126 | // ------------------------------------------------------------------------------------- 127 | 128 | // Fires rays at every point in a sensors view bounds and then returns the hit position back to Unity 129 | OPTIXPLUGIN_API bool SensorFireAndReturnHitPositions(ItemListHandle * hItems, float3 ** itemsFound, int * itemCount) 130 | { 131 | std::vector instances; 132 | std::vector matrixes; 133 | 134 | CreateInstances(instances, matrixes); 135 | 136 | if (instances.size() == 0) 137 | return true; 138 | 139 | // Create our scene from the models and their translation matrices 140 | Model scene = context->createModel(); 141 | scene->setInstances(instances.size(), RTP_BUFFER_TYPE_HOST, &instances[0], 142 | RTP_BUFFER_FORMAT_TRANSFORM_FLOAT4x3, RTP_BUFFER_TYPE_HOST, &matrixes[0]); 143 | scene->update(0); 144 | 145 | Buffer hitsBuffer(raysBuffer.count(), bufferType, LOCKED); // Buffer that will hold all the hit positions (if there are any) 146 | 147 | Query query = scene->createQuery(RTP_QUERY_TYPE_CLOSEST); // Query type is set to closest as all we want to know is if and where a intersection occurs 148 | query->setRays(raysBuffer.count(), Ray::format, raysBuffer.type(), raysBuffer.ptr()); 149 | query->setHits(hitsBuffer.count(), Hit::format, hitsBuffer.type(), hitsBuffer.ptr()); 150 | query->execute(0); 151 | 152 | auto hitPositions = new std::vector; // Allocate these on the heap as they will be returned to Unity and deleted later 153 | const Hit* hits = hitsBuffer.hostPtr(); 154 | const Ray* rays = raysBuffer.hostPtr(); 155 | 156 | for (int iHit = 0; iHit < hitsBuffer.count(); iHit++) 157 | { 158 | // hit.t is the distance from the origin that the ray intersected with something. Anything above 0 is an intersection 159 | if (hits[iHit].t > 0.0f) 160 | { 161 | // Calculate the actual intersection point using the ray that caused the hit and the distance along the ray 162 | float3 hitPoint = rays[iHit].origin + rays[iHit].dir * hits[iHit].t; 163 | hitPositions->push_back(hitPoint); 164 | } 165 | } 166 | 167 | *hItems = reinterpret_cast(hitPositions); // Cast this to a handle so it's easier for us to manage 168 | *itemsFound = hitPositions->data(); 169 | *itemCount = hitPositions->size(); 170 | 171 | return true; 172 | } 173 | 174 | OPTIXPLUGIN_API bool SensorFireAndReturnHitCount(int * itemCount) 175 | { 176 | std::vector instances; 177 | std::vector matrixes; 178 | CreateInstances(instances, matrixes); 179 | 180 | if (instances.size() == 0) 181 | return true; 182 | 183 | // Create our scene from the models and their translation matrices 184 | Model scene = context->createModel(); 185 | scene->setInstances(instances.size(), RTP_BUFFER_TYPE_HOST, &instances[0], 186 | RTP_BUFFER_FORMAT_TRANSFORM_FLOAT4x3, RTP_BUFFER_TYPE_HOST, &matrixes[0]); 187 | scene->update(0); 188 | 189 | Buffer hitsBuffer(raysBuffer.count(), bufferType, LOCKED); // Buffer that will hold all the hit positions (if there are any) 190 | 191 | Query query = scene->createQuery(RTP_QUERY_TYPE_CLOSEST); // Query type is set to closest as all we want to know is if and where a intersection occurs 192 | query->setRays(raysBuffer.count(), Ray::format, raysBuffer.type(), raysBuffer.ptr()); 193 | query->setHits(hitsBuffer.count(), Hit::format, hitsBuffer.type(), hitsBuffer.ptr()); 194 | query->execute(0); 195 | 196 | const Hit* hits = hitsBuffer.hostPtr(); 197 | 198 | for (int iHit = 0; iHit < hitsBuffer.count(); iHit++) 199 | { 200 | // hit.t is the distance from the origin that the ray intersected with something. Anything above 0 is an intersection 201 | if (hits[iHit].t > 0.0f) 202 | { 203 | itemCount[0]++; 204 | } 205 | } 206 | 207 | return true; 208 | } 209 | 210 | OPTIXPLUGIN_API bool CheckSingleRayHit(float3 origin, float3 direction, float depth) 211 | { 212 | std::vector instances; 213 | std::vector matrixes; 214 | CreateInstances(instances, matrixes); 215 | 216 | if (instances.size() == 0) 217 | return false; 218 | 219 | // Create our scene from the models and their translation matrices 220 | Model scene = context->createModel(); 221 | scene->setInstances(instances.size(), RTP_BUFFER_TYPE_HOST, &instances[0], 222 | RTP_BUFFER_FORMAT_TRANSFORM_FLOAT4x3, RTP_BUFFER_TYPE_HOST, &matrixes[0]); 223 | scene->update(0); 224 | 225 | Buffer raysBuffer(0, bufferType, LOCKED); // Buffer that will hold the ray that Optix will fire 226 | raysBuffer.alloc(1); 227 | 228 | Ray r = { origin, 0.0f, direction, depth }; 229 | raysBuffer.ptr()[0] = r; 230 | 231 | Buffer hitsBuffer(raysBuffer.count(), bufferType, LOCKED); // Buffer that will hold all the hit positions (if there are any) 232 | 233 | Query query = scene->createQuery(RTP_QUERY_TYPE_CLOSEST); // Query type is set to closest as all we want to know is if and where a intersection occurs 234 | query->setRays(raysBuffer.count(), Ray::format, raysBuffer.type(), raysBuffer.ptr()); 235 | query->setHits(hitsBuffer.count(), Hit::format, hitsBuffer.type(), hitsBuffer.ptr()); 236 | query->execute(0); 237 | 238 | if (hitsBuffer.ptr()[0].t > 0) 239 | { 240 | return true; 241 | } 242 | else 243 | { 244 | return false; 245 | } 246 | } 247 | 248 | OPTIXPLUGIN_API float3 ReturnSingleRayHit(float3 origin, float3 direction, float depth) 249 | { 250 | std::vector instances; 251 | std::vector matrixes; 252 | CreateInstances(instances, matrixes); 253 | 254 | if (instances.size() == 0) 255 | return make_float3(0, 0, 0); 256 | 257 | // Create our scene from the models and their translation matrices 258 | Model scene = context->createModel(); 259 | scene->setInstances(instances.size(), RTP_BUFFER_TYPE_HOST, &instances[0], 260 | RTP_BUFFER_FORMAT_TRANSFORM_FLOAT4x3, RTP_BUFFER_TYPE_HOST, &matrixes[0]); 261 | scene->update(0); 262 | 263 | Buffer raysBuffer(0, bufferType, LOCKED); // Buffer that will hold the ray that Optix will fire 264 | raysBuffer.alloc(1); 265 | 266 | Ray r = { origin, 0.0f, direction, depth }; 267 | raysBuffer.ptr()[0] = r; 268 | 269 | Buffer hitsBuffer(raysBuffer.count(), bufferType, LOCKED); // Buffer that will hold all the hit positions (if there are any) 270 | 271 | Query query = scene->createQuery(RTP_QUERY_TYPE_CLOSEST); // Query type is set to closest as all we want to know is if and where a intersection occurs 272 | query->setRays(raysBuffer.count(), Ray::format, raysBuffer.type(), raysBuffer.ptr()); 273 | query->setHits(hitsBuffer.count(), Hit::format, hitsBuffer.type(), hitsBuffer.ptr()); 274 | query->execute(0); 275 | 276 | if (hitsBuffer.ptr()[0].t > 0) 277 | { 278 | return raysBuffer.ptr()[0].origin + raysBuffer.ptr()[0].dir * hitsBuffer.ptr()[0].t; 279 | } 280 | else 281 | { 282 | return make_float3(0, 0, 0); 283 | } 284 | } 285 | 286 | // ------------------------------------------------------------------------------------- 287 | // Optix Cleanup Functions 288 | // ------------------------------------------------------------------------------------- 289 | 290 | // Deletes all the items allocated on the heap after they have finished being used by Unity 291 | OPTIXPLUGIN_API bool ReleaseItems(ItemListHandle hItems) 292 | { 293 | auto items = reinterpret_cast*>(hItems); 294 | delete items; 295 | 296 | return true; 297 | } 298 | 299 | // ------------------------------------------------------------------------------------- 300 | // Helper Functions 301 | // ------------------------------------------------------------------------------------- 302 | 303 | // Generates the RTPModel instances for the actual query execution 304 | void CreateInstances(std::vector& instances, std::vector& matrixes) 305 | { 306 | instances.reserve(totalObjects); 307 | matrixes.reserve(totalObjects); 308 | 309 | for (int i = 0; i < totalObjects; i++) 310 | { 311 | if (objectEnabledStatus[i] == 1) 312 | { 313 | instances.push_back(objectModels[i]->getRTPmodel()); 314 | matrixes.push_back(objectTranslationMatrices[i]); 315 | } 316 | } 317 | } 318 | 319 | // Generates rays across a sensor bounds based on certain parameters such as sensor radius, height and ray gap 320 | void CreateRaysFromSensorBounds(OptixSensorBase* sensors, int sensorCount) 321 | { 322 | float totalPoints = 0; 323 | 324 | for (int iSensor = 0; iSensor < sensorCount; iSensor++) 325 | { 326 | totalPoints += sensors[iSensor].totalPoints; 327 | } 328 | 329 | baseRays.resize(totalPoints); 330 | 331 | if (raysBuffer.type() == RTP_BUFFER_TYPE_HOST) 332 | { 333 | int idx = 0; 334 | for (int iSensor = 0; iSensor < sensorCount; iSensor++) 335 | { 336 | // For every row and column within the sensor bounds 337 | for (float iHeight = sensors[iSensor].sensorHeight / 2; iHeight > -sensors[iSensor].sensorHeight / 2; iHeight -= sensors[iSensor].pointGap) 338 | { 339 | for (float iRadius = -sensors[iSensor].sensorRadius / 2; iRadius < sensors[iSensor].sensorRadius / 2; iRadius += sensors[iSensor].pointGap, idx++) 340 | { 341 | if (idx < totalPoints) // This avoids an error where idx becomes larger than raysbuffer somehow?!?!?!? 342 | { 343 | // Calculate the centre point of the sensor bounds based on origin, direction and depth 344 | float3 centre = ((make_float3(0, 0, 1) * sensors[iSensor].sensorDepth)); 345 | 346 | // Create a direction vector from origin to the centre + the current height index value 347 | float4 targetDir = make_float4(centre + make_float3(0, iHeight, 0)) 348 | * optix::Matrix4x4::rotate((iRadius * M_PI) / 180, make_float3(0, 1, 0)); // Multiply this vector by a rotation matrix to rotate the direction by radius index value in the y axis 349 | 350 | // Normalise the value and convert back to a float3 for the Ray structure 351 | float3 targetDirection = optix::normalize(make_float3(targetDir)); 352 | 353 | Ray r = { make_float3(0,0,0), 0.0f, targetDirection, sensors[iSensor].sensorDepth }; 354 | baseRays[idx] = r; 355 | } 356 | } 357 | } 358 | } 359 | } 360 | else 361 | { 362 | // CUDA 363 | int startIndex = 0; 364 | for (int iSensor = 0; iSensor < sensorCount; iSensor++, startIndex += sensors[iSensor].totalPoints) 365 | { 366 | GenerateRaysOnDevice((float4*)raysBuffer.ptr(), sensors[iSensor], startIndex); 367 | } 368 | } 369 | } 370 | 371 | // Translates the baseRays by the OptixSensor's localToWorld translation matrix and adds it to the raysBuffers 372 | void TranslateRays(OptixSensorBase* sensors, int sensorCount) 373 | { 374 | float totalPoints = 0; 375 | 376 | for (int iSensor = 0; iSensor < sensorCount; iSensor++) 377 | { 378 | totalPoints += sensors[iSensor].totalPoints; 379 | } 380 | 381 | raysBuffer.free(); 382 | raysBuffer.alloc(totalPoints); 383 | 384 | int idx = 0; 385 | Ray* rays = raysBuffer.ptr(); 386 | 387 | for (int iSensor = 0; iSensor < sensorCount; iSensor++) 388 | { 389 | for (int i = 0; i < sensors[iSensor].totalPoints; i++, idx++) 390 | { 391 | // Is this the most efficent way to translate the ray? 392 | rays[idx].origin.x = baseRays[idx].origin.x + sensors[iSensor].localToWorldTranslationMatrix[12]; 393 | rays[idx].origin.y = baseRays[idx].origin.y + sensors[iSensor].localToWorldTranslationMatrix[13]; 394 | rays[idx].origin.z = baseRays[idx].origin.z + sensors[iSensor].localToWorldTranslationMatrix[14]; 395 | 396 | rays[idx].tmin = baseRays[idx].tmin; 397 | rays[idx].tmax = baseRays[idx].tmax; 398 | 399 | rays[idx].dir = make_float3(make_float4(baseRays[idx].dir) * sensors[iSensor].localToWorldTranslationMatrix); 400 | } 401 | } 402 | } 403 | 404 | // This function is used to convert the Matrix4x4 from Unity to the format required by Optix Prime 405 | SimpleMatrix4x3 GetSimpleMatrixFromUnityMatrix(const optix::Matrix4x4 M) 406 | { 407 | return SimpleMatrix4x3( 408 | M[0], M[4], M[8], M[12], 409 | M[1], M[5], M[9], M[13], 410 | M[2], M[6], M[10], M[14] 411 | ); 412 | } 413 | 414 | // ------------------------------------------------------------------------------------- 415 | // Unity Graphics via the Render Thread 416 | // ------------------------------------------------------------------------------------- 417 | 418 | static float g_Time; 419 | extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetTimeFromUnity(float t) { g_Time = t; } 420 | 421 | static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType); 422 | 423 | static IUnityInterfaces* s_UnityInterfaces = NULL; 424 | static IUnityGraphics* s_Graphics = NULL; 425 | 426 | extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces) 427 | { 428 | s_UnityInterfaces = unityInterfaces; 429 | s_Graphics = s_UnityInterfaces->Get(); 430 | s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent); 431 | 432 | // Run OnGraphicsDeviceEvent(initialize) manually on plugin load 433 | OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize); 434 | } 435 | 436 | extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload() 437 | { 438 | s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent); 439 | } 440 | 441 | static RenderAPI* s_CurrentAPI = NULL; 442 | static UnityGfxRenderer s_DeviceType = kUnityGfxRendererNull; 443 | 444 | static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType) 445 | { 446 | // Create graphics API implementation upon initialization 447 | if (eventType == kUnityGfxDeviceEventInitialize) 448 | { 449 | assert(s_CurrentAPI == NULL); 450 | s_DeviceType = s_Graphics->GetRenderer(); 451 | s_CurrentAPI = CreateRenderAPI(s_DeviceType); 452 | } 453 | 454 | // Let the implementation process the device related events 455 | if (s_CurrentAPI) 456 | { 457 | s_CurrentAPI->ProcessDeviceEvent(eventType, s_UnityInterfaces); 458 | } 459 | 460 | // Cleanup graphics API implementation upon shutdown 461 | if (eventType == kUnityGfxDeviceEventShutdown) 462 | { 463 | delete s_CurrentAPI; 464 | s_CurrentAPI = NULL; 465 | s_DeviceType = kUnityGfxRendererNull; 466 | } 467 | } 468 | 469 | static void UNITY_INTERFACE_API OnRenderEvent(int eventID) 470 | { 471 | // Unknown / unsupported graphics device type? Do nothing 472 | if (s_CurrentAPI == NULL) 473 | return; 474 | 475 | // USE D3D11 BUFFER HERE TO RENDER POINT CLOUD 476 | } 477 | 478 | extern "C" UnityRenderingEvent UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API GetRenderEventFunc() 479 | { 480 | return OnRenderEvent; 481 | } -------------------------------------------------------------------------------- /unityOptixPlugin/OptixPlugin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef OPTIXPLUGIN_EXPORTS 4 | #define OPTIXPLUGIN_API __declspec(dllexport) 5 | #else 6 | #define OPTIXPLUGIN_API __declspec(dllimport) 7 | #endif 8 | 9 | using namespace optix::prime; 10 | 11 | // ------------------------------------------------------------------------------------- 12 | // Optix Data Structures 13 | // ------------------------------------------------------------------------------------- 14 | 15 | class OptixSensorBase 16 | { 17 | public: 18 | optix::Matrix4x4 localToWorldTranslationMatrix; 19 | 20 | float sensorDepth; 21 | float sensorHeight; 22 | float sensorRadius; 23 | 24 | float pointGap; 25 | float totalPoints; 26 | }; 27 | 28 | extern "C" 29 | { 30 | void GenerateRaysOnDevice(float4* rays, OptixSensorBase sensor, int startIndex); 31 | } 32 | 33 | // ------------------------------------------------------------------------------------- 34 | // Optix Variables 35 | // ------------------------------------------------------------------------------------- 36 | 37 | typedef intptr_t ItemListHandle; 38 | 39 | static RTPcontexttype contextType = RTP_CONTEXT_TYPE_CPU; 40 | static RTPbuffertype bufferType = RTP_BUFFER_TYPE_HOST; 41 | 42 | static Context context; 43 | 44 | static std::vector objectModels; 45 | static std::vector objectTranslationMatrices; 46 | static std::vector objectEnabledStatus; 47 | static int totalObjects; 48 | 49 | static std::vector baseRays; 50 | static Buffer raysBuffer(0, bufferType, LOCKED); 51 | 52 | // ------------------------------------------------------------------------------------- 53 | // Init Optix Functions 54 | // ------------------------------------------------------------------------------------- 55 | 56 | extern "C" OPTIXPLUGIN_API void SetAllObjectsFromUnity 57 | ( 58 | int totalTrans, int* meshVertexCounts, float** meshVerticies, optix::Matrix4x4* transformationMatrices, int* transformEnabled 59 | ); 60 | 61 | extern "C" OPTIXPLUGIN_API void SetAllSensorsFromUnity 62 | ( 63 | int sensorCount, OptixSensorBase* sensors 64 | ); 65 | 66 | // ------------------------------------------------------------------------------------- 67 | // Optix Update Functions 68 | // ------------------------------------------------------------------------------------- 69 | 70 | extern "C" OPTIXPLUGIN_API void TranslateAllSensorsFromUnity 71 | ( 72 | int sensorCount, OptixSensorBase* sensors 73 | ); 74 | 75 | extern "C" OPTIXPLUGIN_API void UpdateGameObjectEnabledFromUnity 76 | ( 77 | int transformCount, int* transformIndices, int* transformsEnabled 78 | ); 79 | 80 | 81 | extern "C" OPTIXPLUGIN_API void UpdateGameObjectMatrixFromUnity 82 | ( 83 | int matrixCount, int* matrixIndex, optix::Matrix4x4* transformationMatrices 84 | ); 85 | 86 | // ------------------------------------------------------------------------------------- 87 | // Optix Execute Functions 88 | // ------------------------------------------------------------------------------------- 89 | 90 | extern "C" OPTIXPLUGIN_API bool SensorFireAndReturnHitPositions 91 | ( 92 | ItemListHandle* hItems, float3** itemsFound, int* itemCount 93 | ); 94 | 95 | extern "C" OPTIXPLUGIN_API bool SensorFireAndReturnHitCount 96 | ( 97 | int* itemCount, OptixSensorBase* sensors, int sensorCount 98 | ); 99 | 100 | extern "C" OPTIXPLUGIN_API bool CheckSingleRayHit 101 | ( 102 | float3 origin, float3 direction, float depth 103 | ); 104 | 105 | extern "C" OPTIXPLUGIN_API float3 ReturnSingleRayHit 106 | ( 107 | float3 origin, float3 direction, float depth 108 | ); 109 | 110 | // ------------------------------------------------------------------------------------- 111 | // Optix Cleanup Functions 112 | // ------------------------------------------------------------------------------------- 113 | 114 | extern "C" OPTIXPLUGIN_API bool ReleaseItems(ItemListHandle hItems); 115 | 116 | // ------------------------------------------------------------------------------------- 117 | // Helper Functions 118 | // ------------------------------------------------------------------------------------- 119 | 120 | void CreateInstances 121 | ( 122 | std::vector& instances, std::vector& matrixes 123 | ); 124 | 125 | void CreateRaysFromSensorBounds 126 | ( 127 | OptixSensorBase* sensors, int sensorCount 128 | ); 129 | 130 | void TranslateRays 131 | ( 132 | OptixSensorBase* sensors, int sensorCount 133 | ); 134 | 135 | SimpleMatrix4x3 GetSimpleMatrixFromUnityMatrix 136 | ( 137 | const optix::Matrix4x4 M 138 | ); -------------------------------------------------------------------------------- /unityOptixPlugin/PlatformBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Standard base includes, defines that indicate our current platform, etc. 4 | 5 | #include 6 | 7 | 8 | // Which platform we are on? 9 | // UNITY_WIN - Windows (regular win32) 10 | // UNITY_OSX - Mac OS X 11 | // UNITY_LINUX - Linux 12 | // UNITY_IPHONE - iOS 13 | // UNITY_ANDROID - Android 14 | // UNITY_METRO - WSA or UWP 15 | // UNITY_WEBGL - WebGL 16 | #if _MSC_VER 17 | #define UNITY_WIN 1 18 | #elif defined(__APPLE__) 19 | #if defined(__arm__) || defined(__arm64__) 20 | #define UNITY_IPHONE 1 21 | #else 22 | #define UNITY_OSX 1 23 | #endif 24 | #elif defined(UNITY_METRO) || defined(UNITY_ANDROID) || defined(UNITY_LINUX) || defined(UNITY_WEBGL) 25 | // these are defined externally 26 | #elif defined(__EMSCRIPTEN__) 27 | // this is already defined in Unity 5.6 28 | #define UNITY_WEBGL 1 29 | #else 30 | #error "Unknown platform!" 31 | #endif 32 | 33 | 34 | 35 | // Which graphics device APIs we possibly support? 36 | #if UNITY_METRO 37 | #define SUPPORT_D3D11 1 38 | #if WINDOWS_UWP 39 | #define SUPPORT_D3D12 1 40 | #endif 41 | #elif UNITY_WIN 42 | #define SUPPORT_D3D9 1 43 | #define SUPPORT_D3D11 1 // comment this out if you don't have D3D11 header/library files 44 | #define SUPPORT_D3D12 0 //@TODO: enable by default? comment this out if you don't have D3D12 header/library files 45 | #define SUPPORT_OPENGL_LEGACY 1 46 | #define SUPPORT_OPENGL_UNIFIED 1 47 | #define SUPPORT_OPENGL_CORE 1 48 | #elif UNITY_IPHONE || UNITY_ANDROID || UNITY_WEBGL 49 | #define SUPPORT_OPENGL_UNIFIED 1 50 | #define SUPPORT_OPENGL_ES 1 51 | #elif UNITY_OSX || UNITY_LINUX 52 | #define SUPPORT_OPENGL_LEGACY 1 53 | #define SUPPORT_OPENGL_UNIFIED 1 54 | #define SUPPORT_OPENGL_CORE 1 55 | #endif 56 | 57 | #if UNITY_IPHONE || UNITY_OSX 58 | #define SUPPORT_METAL 1 59 | #endif 60 | 61 | 62 | 63 | // COM-like Release macro 64 | #ifndef SAFE_RELEASE 65 | #define SAFE_RELEASE(a) if (a) { a->Release(); a = NULL; } 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /unityOptixPlugin/RenderAPI.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderAPI.h" 2 | #include "PlatformBase.h" 3 | #include "IUnityGraphics.h" 4 | 5 | 6 | RenderAPI* CreateRenderAPI(UnityGfxRenderer apiType) 7 | { 8 | # if SUPPORT_D3D11 9 | if (apiType == kUnityGfxRendererD3D11) 10 | { 11 | extern RenderAPI* CreateRenderAPI_D3D11(); 12 | return CreateRenderAPI_D3D11(); 13 | } 14 | # endif // if SUPPORT_D3D11 15 | // 16 | //# if SUPPORT_D3D9 17 | // if (apiType == kUnityGfxRendererD3D9) 18 | // { 19 | // extern RenderAPI* CreateRenderAPI_D3D9(); 20 | // return CreateRenderAPI_D3D9(); 21 | // } 22 | //# endif // if SUPPORT_D3D9 23 | // 24 | //# if SUPPORT_D3D12 25 | // if (apiType == kUnityGfxRendererD3D12) 26 | // { 27 | // extern RenderAPI* CreateRenderAPI_D3D12(); 28 | // return CreateRenderAPI_D3D12(); 29 | // } 30 | //# endif // if SUPPORT_D3D9 31 | // 32 | // 33 | //# if SUPPORT_OPENGL_UNIFIED 34 | // if (apiType == kUnityGfxRendererOpenGLCore || apiType == kUnityGfxRendererOpenGLES20 || apiType == kUnityGfxRendererOpenGLES30) 35 | // { 36 | // extern RenderAPI* CreateRenderAPI_OpenGLCoreES(UnityGfxRenderer apiType); 37 | // return CreateRenderAPI_OpenGLCoreES(apiType); 38 | // } 39 | //# endif // if SUPPORT_OPENGL_UNIFIED 40 | // 41 | //# if SUPPORT_OPENGL_LEGACY 42 | // if (apiType == kUnityGfxRendererOpenGL) 43 | // { 44 | // extern RenderAPI* CreateRenderAPI_OpenGL2(); 45 | // return CreateRenderAPI_OpenGL2(); 46 | // } 47 | //# endif // if SUPPORT_OPENGL_LEGACY 48 | // 49 | //# if SUPPORT_METAL 50 | // if (apiType == kUnityGfxRendererMetal) 51 | // { 52 | // extern RenderAPI* CreateRenderAPI_Metal(); 53 | // return CreateRenderAPI_Metal(); 54 | // } 55 | //# endif // if SUPPORT_METAL 56 | // 57 | // 58 | // Unknown or unsupported graphics API 59 | return NULL; 60 | } 61 | -------------------------------------------------------------------------------- /unityOptixPlugin/RenderAPI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "IUnityGraphics.h" 4 | 5 | #include 6 | 7 | struct IUnityInterfaces; 8 | 9 | 10 | // Super-simple "graphics abstraction". This is nothing like how a proper platform abstraction layer would look like; 11 | // all this does is a base interface for whatever our plugin sample needs. 12 | 13 | class RenderAPI 14 | { 15 | public: 16 | virtual ~RenderAPI() { } 17 | 18 | 19 | // Process general event like initialization, shutdown, device loss/reset etc. 20 | virtual void ProcessDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces* interfaces) = 0; 21 | 22 | // Is the API using "reversed" (1.0 at near plane, 0.0 at far plane) depth buffer? 23 | // Reversed Z is used on modern platforms, and improves depth buffer precision. 24 | virtual bool GetUsesReverseZ() = 0; 25 | 26 | // Draw some triangle geometry, using some simple rendering state. 27 | // Upon call into our plug-in the render state can be almost completely arbitrary depending 28 | // on what was rendered in Unity before. Here, we turn off culling, blending, depth writes etc. 29 | // and draw the triangles with a given world matrix. The triangle data is 30 | // float3 (position) and byte4 (color) per vertex. 31 | virtual void DrawSimpleTriangles(const float worldMatrix[16], int triangleCount, const void* verticesFloat3Byte4) = 0; 32 | 33 | 34 | // Begin modifying texture data. You need to pass texture width/height too, since some graphics APIs 35 | // (e.g. OpenGL ES) do not have a good way to query that from the texture itself... 36 | // 37 | // Returns pointer into the data buffer to write into (or NULL on failure), and pitch in bytes of a single texture row. 38 | virtual void* BeginModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int* outRowPitch) = 0; 39 | // End modifying texture data. 40 | virtual void EndModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int rowPitch, void* dataPtr) = 0; 41 | 42 | 43 | // Begin modifying vertex buffer data. 44 | // Returns pointer into the data buffer to write into (or NULL on failure), and buffer size. 45 | virtual void* BeginModifyVertexBuffer(void* bufferHandle, size_t* outBufferSize) = 0; 46 | // End modifying vertex buffer data. 47 | virtual void EndModifyVertexBuffer(void* bufferHandle) = 0; 48 | }; 49 | 50 | 51 | // Create a graphics API implementation instance for the given API type. 52 | RenderAPI* CreateRenderAPI(UnityGfxRenderer apiType); 53 | 54 | -------------------------------------------------------------------------------- /unityOptixPlugin/RenderAPI_D3D11.cpp: -------------------------------------------------------------------------------- 1 | #include "RenderAPI.h" 2 | #include "PlatformBase.h" 3 | 4 | // Direct3D 11 implementation of RenderAPI. 5 | 6 | #if SUPPORT_D3D11 7 | 8 | #include 9 | #include 10 | #include "IUnityGraphicsD3D11.h" 11 | 12 | 13 | class RenderAPI_D3D11 : public RenderAPI 14 | { 15 | public: 16 | RenderAPI_D3D11(); 17 | virtual ~RenderAPI_D3D11() { } 18 | 19 | virtual void ProcessDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces* interfaces); 20 | 21 | virtual bool GetUsesReverseZ() { return (int)m_Device->GetFeatureLevel() >= (int)D3D_FEATURE_LEVEL_10_0; } 22 | 23 | virtual void DrawSimpleTriangles(const float worldMatrix[16], int triangleCount, const void* verticesFloat3Byte4); 24 | 25 | virtual void* BeginModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int* outRowPitch); 26 | virtual void EndModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int rowPitch, void* dataPtr); 27 | 28 | virtual void* BeginModifyVertexBuffer(void* bufferHandle, size_t* outBufferSize); 29 | virtual void EndModifyVertexBuffer(void* bufferHandle); 30 | 31 | private: 32 | void CreateResources(); 33 | void ReleaseResources(); 34 | 35 | private: 36 | ID3D11Device* m_Device; 37 | ID3D11Buffer* m_VB; // vertex buffer 38 | ID3D11Buffer* m_CB; // constant buffer 39 | ID3D11VertexShader* m_VertexShader; 40 | ID3D11PixelShader* m_PixelShader; 41 | ID3D11InputLayout* m_InputLayout; 42 | ID3D11RasterizerState* m_RasterState; 43 | ID3D11BlendState* m_BlendState; 44 | ID3D11DepthStencilState* m_DepthState; 45 | }; 46 | 47 | 48 | RenderAPI* CreateRenderAPI_D3D11() 49 | { 50 | return new RenderAPI_D3D11(); 51 | } 52 | 53 | 54 | // Simple compiled shader bytecode. 55 | // 56 | // Shader source that was used: 57 | #if 0 58 | cbuffer MyCB : register(b0) 59 | { 60 | float4x4 worldMatrix; 61 | } 62 | void VS(float3 pos : POSITION, float4 color : COLOR, out float4 ocolor : COLOR, out float4 opos : SV_Position) 63 | { 64 | opos = mul(worldMatrix, float4(pos, 1)); 65 | ocolor = color; 66 | } 67 | float4 PS(float4 color : COLOR) : SV_TARGET 68 | { 69 | return color; 70 | } 71 | #endif // #if 0 72 | // 73 | // Which then was compiled with: 74 | // fxc /Tvs_4_0_level_9_3 /EVS source.hlsl /Fh outVS.h /Qstrip_reflect /Qstrip_debug /Qstrip_priv 75 | // fxc /Tps_4_0_level_9_3 /EPS source.hlsl /Fh outPS.h /Qstrip_reflect /Qstrip_debug /Qstrip_priv 76 | // and results pasted & formatted to take less lines here 77 | const BYTE kVertexShaderCode[] = 78 | { 79 | 68,88,66,67,86,189,21,50,166,106,171,1,10,62,115,48,224,137,163,129,1,0,0,0,168,2,0,0,4,0,0,0,48,0,0,0,0,1,0,0,4,2,0,0,84,2,0,0, 80 | 65,111,110,57,200,0,0,0,200,0,0,0,0,2,254,255,148,0,0,0,52,0,0,0,1,0,36,0,0,0,48,0,0,0,48,0,0,0,36,0,1,0,48,0,0,0,0,0, 81 | 4,0,1,0,0,0,0,0,0,0,0,0,1,2,254,255,31,0,0,2,5,0,0,128,0,0,15,144,31,0,0,2,5,0,1,128,1,0,15,144,5,0,0,3,0,0,15,128, 82 | 0,0,85,144,2,0,228,160,4,0,0,4,0,0,15,128,1,0,228,160,0,0,0,144,0,0,228,128,4,0,0,4,0,0,15,128,3,0,228,160,0,0,170,144,0,0,228,128, 83 | 2,0,0,3,0,0,15,128,0,0,228,128,4,0,228,160,4,0,0,4,0,0,3,192,0,0,255,128,0,0,228,160,0,0,228,128,1,0,0,2,0,0,12,192,0,0,228,128, 84 | 1,0,0,2,0,0,15,224,1,0,228,144,255,255,0,0,83,72,68,82,252,0,0,0,64,0,1,0,63,0,0,0,89,0,0,4,70,142,32,0,0,0,0,0,4,0,0,0, 85 | 95,0,0,3,114,16,16,0,0,0,0,0,95,0,0,3,242,16,16,0,1,0,0,0,101,0,0,3,242,32,16,0,0,0,0,0,103,0,0,4,242,32,16,0,1,0,0,0, 86 | 1,0,0,0,104,0,0,2,1,0,0,0,54,0,0,5,242,32,16,0,0,0,0,0,70,30,16,0,1,0,0,0,56,0,0,8,242,0,16,0,0,0,0,0,86,21,16,0, 87 | 0,0,0,0,70,142,32,0,0,0,0,0,1,0,0,0,50,0,0,10,242,0,16,0,0,0,0,0,70,142,32,0,0,0,0,0,0,0,0,0,6,16,16,0,0,0,0,0, 88 | 70,14,16,0,0,0,0,0,50,0,0,10,242,0,16,0,0,0,0,0,70,142,32,0,0,0,0,0,2,0,0,0,166,26,16,0,0,0,0,0,70,14,16,0,0,0,0,0, 89 | 0,0,0,8,242,32,16,0,1,0,0,0,70,14,16,0,0,0,0,0,70,142,32,0,0,0,0,0,3,0,0,0,62,0,0,1,73,83,71,78,72,0,0,0,2,0,0,0, 90 | 8,0,0,0,56,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,7,7,0,0,65,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0, 91 | 15,15,0,0,80,79,83,73,84,73,79,78,0,67,79,76,79,82,0,171,79,83,71,78,76,0,0,0,2,0,0,0,8,0,0,0,56,0,0,0,0,0,0,0,0,0,0,0, 92 | 3,0,0,0,0,0,0,0,15,0,0,0,62,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,15,0,0,0,67,79,76,79,82,0,83,86,95,80,111,115, 93 | 105,116,105,111,110,0,171,171 94 | }; 95 | const BYTE kPixelShaderCode[]= 96 | { 97 | 68,88,66,67,196,65,213,199,14,78,29,150,87,236,231,156,203,125,244,112,1,0,0,0,32,1,0,0,4,0,0,0,48,0,0,0,124,0,0,0,188,0,0,0,236,0,0,0, 98 | 65,111,110,57,68,0,0,0,68,0,0,0,0,2,255,255,32,0,0,0,36,0,0,0,0,0,36,0,0,0,36,0,0,0,36,0,0,0,36,0,0,0,36,0,1,2,255,255, 99 | 31,0,0,2,0,0,0,128,0,0,15,176,1,0,0,2,0,8,15,128,0,0,228,176,255,255,0,0,83,72,68,82,56,0,0,0,64,0,0,0,14,0,0,0,98,16,0,3, 100 | 242,16,16,0,0,0,0,0,101,0,0,3,242,32,16,0,0,0,0,0,54,0,0,5,242,32,16,0,0,0,0,0,70,30,16,0,0,0,0,0,62,0,0,1,73,83,71,78, 101 | 40,0,0,0,1,0,0,0,8,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,15,15,0,0,67,79,76,79,82,0,171,171,79,83,71,78, 102 | 44,0,0,0,1,0,0,0,8,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,15,0,0,0,83,86,95,84,65,82,71,69,84,0,171,171 103 | }; 104 | 105 | 106 | RenderAPI_D3D11::RenderAPI_D3D11() 107 | : m_Device(NULL) 108 | , m_VB(NULL) 109 | , m_CB(NULL) 110 | , m_VertexShader(NULL) 111 | , m_PixelShader(NULL) 112 | , m_InputLayout(NULL) 113 | , m_RasterState(NULL) 114 | , m_BlendState(NULL) 115 | , m_DepthState(NULL) 116 | { 117 | } 118 | 119 | 120 | void RenderAPI_D3D11::ProcessDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces* interfaces) 121 | { 122 | switch (type) 123 | { 124 | case kUnityGfxDeviceEventInitialize: 125 | { 126 | IUnityGraphicsD3D11* d3d = interfaces->Get(); 127 | m_Device = d3d->GetDevice(); 128 | CreateResources(); 129 | break; 130 | } 131 | case kUnityGfxDeviceEventShutdown: 132 | ReleaseResources(); 133 | break; 134 | } 135 | } 136 | 137 | 138 | void RenderAPI_D3D11::CreateResources() 139 | { 140 | D3D11_BUFFER_DESC desc; 141 | memset(&desc, 0, sizeof(desc)); 142 | 143 | // vertex buffer 144 | desc.Usage = D3D11_USAGE_DEFAULT; 145 | desc.ByteWidth = 1024; 146 | desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 147 | m_Device->CreateBuffer(&desc, NULL, &m_VB); 148 | 149 | // constant buffer 150 | desc.Usage = D3D11_USAGE_DEFAULT; 151 | desc.ByteWidth = 64; // hold 1 matrix 152 | desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; 153 | desc.CPUAccessFlags = 0; 154 | m_Device->CreateBuffer(&desc, NULL, &m_CB); 155 | 156 | // shaders 157 | HRESULT hr; 158 | hr = m_Device->CreateVertexShader(kVertexShaderCode, sizeof(kVertexShaderCode), nullptr, &m_VertexShader); 159 | if (FAILED(hr)) 160 | OutputDebugStringA("Failed to create vertex shader.\n"); 161 | hr = m_Device->CreatePixelShader(kPixelShaderCode, sizeof(kPixelShaderCode), nullptr, &m_PixelShader); 162 | if (FAILED(hr)) 163 | OutputDebugStringA("Failed to create pixel shader.\n"); 164 | 165 | // input layout 166 | if (m_VertexShader) 167 | { 168 | D3D11_INPUT_ELEMENT_DESC s_DX11InputElementDesc[] = 169 | { 170 | { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 171 | { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, 172 | }; 173 | m_Device->CreateInputLayout(s_DX11InputElementDesc, 2, kVertexShaderCode, sizeof(kVertexShaderCode), &m_InputLayout); 174 | } 175 | 176 | // render states 177 | D3D11_RASTERIZER_DESC rsdesc; 178 | memset(&rsdesc, 0, sizeof(rsdesc)); 179 | rsdesc.FillMode = D3D11_FILL_SOLID; 180 | rsdesc.CullMode = D3D11_CULL_NONE; 181 | rsdesc.DepthClipEnable = TRUE; 182 | m_Device->CreateRasterizerState(&rsdesc, &m_RasterState); 183 | 184 | D3D11_DEPTH_STENCIL_DESC dsdesc; 185 | memset(&dsdesc, 0, sizeof(dsdesc)); 186 | dsdesc.DepthEnable = TRUE; 187 | dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; 188 | dsdesc.DepthFunc = GetUsesReverseZ() ? D3D11_COMPARISON_GREATER_EQUAL : D3D11_COMPARISON_LESS_EQUAL; 189 | m_Device->CreateDepthStencilState(&dsdesc, &m_DepthState); 190 | 191 | D3D11_BLEND_DESC bdesc; 192 | memset(&bdesc, 0, sizeof(bdesc)); 193 | bdesc.RenderTarget[0].BlendEnable = FALSE; 194 | bdesc.RenderTarget[0].RenderTargetWriteMask = 0xF; 195 | m_Device->CreateBlendState(&bdesc, &m_BlendState); 196 | } 197 | 198 | 199 | void RenderAPI_D3D11::ReleaseResources() 200 | { 201 | SAFE_RELEASE(m_VB); 202 | SAFE_RELEASE(m_CB); 203 | SAFE_RELEASE(m_VertexShader); 204 | SAFE_RELEASE(m_PixelShader); 205 | SAFE_RELEASE(m_InputLayout); 206 | SAFE_RELEASE(m_RasterState); 207 | SAFE_RELEASE(m_BlendState); 208 | SAFE_RELEASE(m_DepthState); 209 | } 210 | 211 | 212 | void RenderAPI_D3D11::DrawSimpleTriangles(const float worldMatrix[16], int triangleCount, const void* verticesFloat3Byte4) 213 | { 214 | ID3D11DeviceContext* ctx = NULL; 215 | m_Device->GetImmediateContext(&ctx); 216 | 217 | // Set basic render state 218 | ctx->OMSetDepthStencilState(m_DepthState, 0); 219 | ctx->RSSetState(m_RasterState); 220 | ctx->OMSetBlendState(m_BlendState, NULL, 0xFFFFFFFF); 221 | 222 | // Update constant buffer - just the world matrix in our case 223 | ctx->UpdateSubresource(m_CB, 0, NULL, worldMatrix, 64, 0); 224 | 225 | // Set shaders 226 | ctx->VSSetConstantBuffers(0, 1, &m_CB); 227 | ctx->VSSetShader(m_VertexShader, NULL, 0); 228 | ctx->PSSetShader(m_PixelShader, NULL, 0); 229 | 230 | // Update vertex buffer 231 | const int kVertexSize = 12 + 4; 232 | ctx->UpdateSubresource(m_VB, 0, NULL, verticesFloat3Byte4, triangleCount * 3 * kVertexSize, 0); 233 | 234 | // set input assembler data and draw 235 | ctx->IASetInputLayout(m_InputLayout); 236 | ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); 237 | UINT stride = kVertexSize; 238 | UINT offset = 0; 239 | ctx->IASetVertexBuffers(0, 1, &m_VB, &stride, &offset); 240 | ctx->Draw(triangleCount * 3, 0); 241 | 242 | ctx->Release(); 243 | } 244 | 245 | 246 | void* RenderAPI_D3D11::BeginModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int* outRowPitch) 247 | { 248 | const int rowPitch = textureWidth * 4; 249 | // Just allocate a system memory buffer here for simplicity 250 | unsigned char* data = new unsigned char[rowPitch * textureHeight]; 251 | *outRowPitch = rowPitch; 252 | return data; 253 | } 254 | 255 | 256 | void RenderAPI_D3D11::EndModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int rowPitch, void* dataPtr) 257 | { 258 | ID3D11Texture2D* d3dtex = (ID3D11Texture2D*)textureHandle; 259 | assert(d3dtex); 260 | 261 | ID3D11DeviceContext* ctx = NULL; 262 | m_Device->GetImmediateContext(&ctx); 263 | // Update texture data, and free the memory buffer 264 | ctx->UpdateSubresource(d3dtex, 0, NULL, dataPtr, rowPitch, 0); 265 | delete[] (unsigned char*)dataPtr; 266 | ctx->Release(); 267 | } 268 | 269 | 270 | void* RenderAPI_D3D11::BeginModifyVertexBuffer(void* bufferHandle, size_t* outBufferSize) 271 | { 272 | ID3D11Buffer* d3dbuf = (ID3D11Buffer*)bufferHandle; 273 | assert(d3dbuf); 274 | D3D11_BUFFER_DESC desc; 275 | d3dbuf->GetDesc(&desc); 276 | *outBufferSize = desc.ByteWidth; 277 | 278 | ID3D11DeviceContext* ctx = NULL; 279 | m_Device->GetImmediateContext(&ctx); 280 | D3D11_MAPPED_SUBRESOURCE mapped; 281 | ctx->Map(d3dbuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); 282 | ctx->Release(); 283 | 284 | return mapped.pData; 285 | } 286 | 287 | 288 | void RenderAPI_D3D11::EndModifyVertexBuffer(void* bufferHandle) 289 | { 290 | ID3D11Buffer* d3dbuf = (ID3D11Buffer*)bufferHandle; 291 | assert(d3dbuf); 292 | 293 | ID3D11DeviceContext* ctx = NULL; 294 | m_Device->GetImmediateContext(&ctx); 295 | ctx->Unmap(d3dbuf, 0); 296 | ctx->Release(); 297 | } 298 | 299 | #endif // #if SUPPORT_D3D11 300 | -------------------------------------------------------------------------------- /unityOptixPlugin/primeCommon.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of NVIDIA CORPORATION nor the names of its 13 | * contributors may be used to endorse or promote products derived 14 | * from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include "primeCommon.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include 36 | #include 37 | 38 | //------------------------------------------------------------------------------ 39 | // 40 | // External functions from simplePrimeKernels.cu 41 | // 42 | extern "C" 43 | { 44 | void translateRaysOnDevice(float4* rays, size_t count, float3 offset ); 45 | void createRaysOrthoOnDevice( float4* rays, 46 | int width, int height, 47 | float x0, float y0, 48 | float z, 49 | float dx, float dy, 50 | int yOffset, int yStride, unsigned rayMask ); 51 | void createRaysPerspOnDevice( float4* rays, 52 | int width, int height, 53 | float3 eye, 54 | float3 U, float3 V, float3 W ); 55 | } 56 | 57 | //------------------------------------------------------------------------------ 58 | // ceiling( x/y ) where x and y are integers 59 | inline int idivCeil( int x, int y ) { return (x + y - 1)/y; } 60 | 61 | //------------------------------------------------------------------------------ 62 | inline float __int_as_float (int val) 63 | { 64 | union {float f; int i;} var; 65 | var.i = val; 66 | return var.f; 67 | } 68 | 69 | //------------------------------------------------------------------------------ 70 | void createRaysOrtho( Buffer& raysBuffer, int width, int* height, 71 | const float3& bbmin, const float3& bbmax, float margin, unsigned rayMask, int yOffset, int yStride ) 72 | { 73 | float3 bbspan = bbmax - bbmin; 74 | 75 | // set height according to aspect ratio of bounding box 76 | *height = (int)(width * bbspan.y / bbspan.x); 77 | 78 | float dx = bbspan.x * (1 + 2*margin) / width; 79 | float dy = bbspan.y * (1 + 2*margin) / *height; 80 | float x0 = bbmin.x - bbspan.x*margin + dx/2; 81 | float y0 = bbmin.y - bbspan.y*margin + dy/2; 82 | float z = bbmin.z - std::max(bbspan.z,1.0f)*.001f; 83 | int rows = idivCeil( (*height - yOffset), yStride ); 84 | raysBuffer.alloc( width * rows ); 85 | 86 | if( raysBuffer.type() == RTP_BUFFER_TYPE_HOST ) 87 | { 88 | Ray* rays = raysBuffer.ptr(); 89 | float y = y0 + dy*yOffset; 90 | size_t idx = 0; 91 | for( int iy = yOffset; iy < *height; iy += yStride ) 92 | { 93 | float x = x0; 94 | for( int ix = 0; ix < width; ix++ ) 95 | { 96 | float tminOrMask = 0.0f; 97 | if( rayMask ) 98 | tminOrMask = __int_as_float( rayMask ); 99 | 100 | Ray r = { make_float3(x,y,z), tminOrMask, make_float3(0,0,1), 1e34f }; 101 | rays[idx++] = r; 102 | x += dx; 103 | } 104 | y += dy*yStride; 105 | } 106 | } 107 | else if( raysBuffer.type() == RTP_BUFFER_TYPE_CUDA_LINEAR ) 108 | { 109 | createRaysOrthoOnDevice( (float4*)raysBuffer.ptr(), width, *height, x0, y0, z, dx, dy, yOffset, yStride, rayMask ); 110 | } 111 | } 112 | 113 | //------------------------------------------------------------------------------ 114 | // Compute a left-handed coordinate frame for the camera 115 | void computeUVW( float3 eye, float3 lookat, float3 up, float3& U, float3& V, float3& W ) 116 | { 117 | W = optix::normalize( lookat - eye ); 118 | U = optix::normalize( optix::cross( W, up ) ); 119 | V = optix::cross( U, W ); 120 | } 121 | 122 | //------------------------------------------------------------------------------ 123 | void createRaysPersp( Buffer& raysBuffer, int width, int height, const float3& eye, const float3& lookAt, const float vfov /* = 60.0f */ ) 124 | { 125 | float aspectRatio = float(width)/height; 126 | float vScale = float( tan( vfov/2 * M_PI/180 ) ); 127 | float uScale = vScale * aspectRatio; 128 | 129 | float3 U, V, W; 130 | computeUVW( eye, lookAt, make_float3( 0.0f, 1.0f, 0.0f ), U, V, W ); 131 | U *= uScale; 132 | V *= vScale; 133 | 134 | raysBuffer.alloc( width * height ); 135 | if( raysBuffer.type() == RTP_BUFFER_TYPE_HOST ) 136 | { 137 | Ray* rays = raysBuffer.ptr(); 138 | 139 | int idx=0; 140 | for( int h=0; h < height; h++ ) 141 | { 142 | float v = float(h)/height * 2.0f - 1.0f; 143 | for( int w=0; w < width; w++ ) 144 | { 145 | float u = float(w)/width * 2.0f - 1.0f; 146 | float3 dir = optix::normalize(u*U + v*V + W); 147 | Ray r = { eye, 0.0f, dir, 1e34f }; 148 | rays[idx++] = r; 149 | } 150 | } 151 | } 152 | else if( raysBuffer.type() == RTP_BUFFER_TYPE_CUDA_LINEAR ) 153 | { 154 | createRaysPerspOnDevice( (float4*)raysBuffer.ptr(), width, height, eye, U, V, W ); 155 | } 156 | } 157 | 158 | //------------------------------------------------------------------------------ 159 | void translateRays( Buffer& raysBuffer, const float3& offset ) 160 | { 161 | if( raysBuffer.type() == RTP_BUFFER_TYPE_HOST ) 162 | { 163 | Ray* rays = raysBuffer.ptr(); 164 | for( size_t r=0; r < raysBuffer.count(); r++ ) 165 | rays[r].origin = rays[r].origin + offset; 166 | } 167 | else if( raysBuffer.type() == RTP_BUFFER_TYPE_CUDA_LINEAR ) 168 | { 169 | translateRaysOnDevice( (float4*)raysBuffer.ptr(), raysBuffer.count(), offset ); 170 | } 171 | } 172 | 173 | //------------------------------------------------------------------------------ 174 | void shadeHits( std::vector& image, Buffer& hitsBuffer, PrimeMesh& mesh ) 175 | { 176 | float3 backgroundColor = { 0.2f, 0.2f, 0.2f }; 177 | 178 | int3* indices = mesh.getVertexIndices(); 179 | float3* vertices = mesh.getVertexData(); 180 | const Hit* hits = hitsBuffer.hostPtr(); 181 | for( size_t i=0; i < hitsBuffer.count(); i++ ) 182 | { 183 | if( hits[i].t < 0.0f ) 184 | { 185 | image[i] = backgroundColor; 186 | } 187 | else 188 | { 189 | int3 tri = indices[hits[i].triId]; 190 | float3 v0 = vertices[tri.x]; 191 | float3 v1 = vertices[tri.y]; 192 | float3 v2 = vertices[tri.z]; 193 | float3 e0 = v1-v0; 194 | float3 e1 = v2-v0; 195 | float3 n = optix::normalize( optix::cross( e0, e1 ) ); 196 | 197 | image[i] = 0.5f*n + make_float3( 0.5f, 0.5f, 0.5f ); 198 | } 199 | } 200 | } 201 | 202 | //------------------------------------------------------------------------------ 203 | float3 transformPoint(const SimpleMatrix4x3& M, const float3& p) 204 | { 205 | return make_float3( 206 | M.f0*p.x + M.f1*p.y + M.f2*p.z + M.f3, 207 | M.f4*p.x + M.f5*p.y + M.f6*p.z + M.f7, 208 | M.f8*p.x + M.f9*p.y + M.f10*p.z + M.f11 ); 209 | } 210 | 211 | //------------------------------------------------------------------------------ 212 | // Transform normal by inverse transpose of transform matrix M 213 | float3 transformNormal( const SimpleMatrix4x3& Minv, const float3& n) 214 | { 215 | return make_float3( 216 | Minv.f0*n.x + Minv.f4*n.y + Minv.f8*n.z, 217 | Minv.f1*n.x + Minv.f5*n.y + Minv.f9*n.z, 218 | Minv.f2*n.x + Minv.f6*n.y + Minv.f10*n.z ); 219 | } 220 | 221 | //------------------------------------------------------------------------------ 222 | void shadeHits( std::vector& image, Buffer& hitsBuffer, std::vector& modelIds, std::vector& models, float3 eye, std::vector& invTransforms ) 223 | { 224 | float3 backgroundColor = { 1.0f, 1.0f, 1.0f }; 225 | 226 | const HitInstancing* hits = hitsBuffer.hostPtr(); 227 | for( size_t i=0; i < hitsBuffer.count(); ++i ) 228 | { 229 | if( hits[i].t < 0.0f ) 230 | { 231 | image[i] = backgroundColor; 232 | } 233 | else 234 | { 235 | int modelId = modelIds[hits[i].instId]; 236 | PrimeMesh& mesh = models[modelId]; 237 | int3* indices = mesh.getVertexIndices(); 238 | float3* vertices = mesh.getVertexData(); 239 | SimpleMatrix4x3& Minv = invTransforms[hits[i].instId]; 240 | 241 | // Compute normal in object space 242 | int3 tri = indices[hits[i].triId]; 243 | float3 v0 = vertices[tri.x]; 244 | float3 v1 = vertices[tri.y]; 245 | float3 v2 = vertices[tri.z]; 246 | float3 e0 = v1-v0; 247 | float3 e1 = v2-v0; 248 | float3 n = optix::cross( e0, e1 ); // save normalization for later 249 | 250 | // Flip normal if facing away from eye 251 | float3 eyeO = transformPoint( Minv, eye ); 252 | float3 dir = v0 - eyeO; 253 | if( optix::dot(n, dir) > 0 ) 254 | n = -n; 255 | 256 | // Transform to world space 257 | n = optix::normalize( transformNormal( Minv, n ) ); 258 | 259 | // Compute color 260 | image[i] = 0.5f*n + make_float3( 0.5f, 0.5f, 0.5f ); 261 | } 262 | } 263 | } 264 | //------------------------------------------------------------------------------ 265 | void writePpm( const char* filename, const float* image, int width, int height ) 266 | { 267 | std::ofstream out( filename, std::ios::out | std::ios::binary ); 268 | if( !out ) 269 | { 270 | std::cerr << "Cannot open file " << filename << "'" << std::endl; 271 | return; 272 | } 273 | 274 | out << "P6\n" << width << " " << height << "\n255" << std::endl; 275 | for( int y=height-1; y >= 0; --y ) // flip vertically 276 | { 277 | for( int x = 0; x < width*3; ++x ) 278 | { 279 | float val = image[y*width*3 + x]; 280 | unsigned char cval = val < 0.0f ? 0u : val > 1.0f ? 255u : static_cast( val*255.0f ); 281 | out.put( cval ); 282 | } 283 | } 284 | 285 | std::cout << "Wrote file " << filename << std::endl; 286 | } 287 | 288 | //------------------------------------------------------------------------------ 289 | void resetAllDevices() 290 | { 291 | int deviceCount; 292 | CHK_CUDA( cudaGetDeviceCount( &deviceCount ) ); 293 | for( int i=0; i < deviceCount; ++i ) 294 | { 295 | CHK_CUDA( cudaSetDevice(i) ); 296 | CHK_CUDA( cudaDeviceReset() ); 297 | } 298 | } 299 | 300 | 301 | -------------------------------------------------------------------------------- /unityOptixPlugin/primeCommon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of NVIDIA CORPORATION nor the names of its 13 | * contributors may be used to endorse or promote products derived 14 | * from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #ifndef __simple_prime_common_h__ 30 | #define __simple_prime_common_h__ 31 | 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | //------------------------------------------------------------------------------ 43 | struct SimpleMatrix4x3 44 | { 45 | float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11; 46 | SimpleMatrix4x3( 47 | float v0=0, float v1=0, float v2=0, float v3=0, 48 | float v4=0, float v5=0, float v6=0, float v7=0, 49 | float v8=0, float v9=0, float v10=0, float v11=0 ) 50 | : f0(v0), f1(v1), f2(v2), f3(v3) 51 | , f4(v4), f5(v5), f6(v6), f7(v7) 52 | , f8(v8), f9(v9), f10(v10), f11(v11) 53 | {} 54 | }; 55 | 56 | //------------------------------------------------------------------------------ 57 | // 58 | // Ray and hit structures for query input and output 59 | // 60 | struct Ray 61 | { 62 | static const RTPbufferformat format = RTP_BUFFER_FORMAT_RAY_ORIGIN_TMIN_DIRECTION_TMAX; 63 | 64 | float3 origin; 65 | float tmin; 66 | float3 dir; 67 | float tmax; 68 | }; 69 | 70 | struct Hit 71 | { 72 | static const RTPbufferformat format = RTP_BUFFER_FORMAT_HIT_T_TRIID_U_V; 73 | 74 | float t; 75 | int triId; 76 | float u; 77 | float v; 78 | }; 79 | 80 | struct HitInstancing 81 | { 82 | static const RTPbufferformat format = RTP_BUFFER_FORMAT_HIT_T_TRIID_INSTID_U_V; 83 | 84 | float t; 85 | int triId; 86 | int instId; 87 | float u; 88 | float v; 89 | }; 90 | 91 | //------------------------------------------------------------------------------ 92 | // A wrapper that provides more convenient return types 93 | class PrimeMesh : public Mesh 94 | { 95 | public: 96 | float3 getBBoxMin() { return ptr_to_float3( bbox_min ); } 97 | float3 getBBoxMax() { return ptr_to_float3( bbox_max ); } 98 | int3* getVertexIndices() { return reinterpret_cast( tri_indices ); } 99 | float3* getVertexData() { return reinterpret_cast( positions ); } 100 | 101 | private: 102 | float3 ptr_to_float3( const float* v ) { return make_float3( v[0], v[1], v[2] ); } 103 | }; 104 | 105 | //------------------------------------------------------------------------------ 106 | // Generate rays in an orthographic view frustum. 107 | void createRaysOrtho( Buffer& raysBuffer, int width, int* height, 108 | const float3& bbmin, const float3& bbmax, float margin, unsigned rayMask=0, int yOffset=0, int yStride=1 ); 109 | 110 | //------------------------------------------------------------------------------ 111 | // Generate rays in a perspective view frustum. 112 | void createRaysPersp( Buffer& raysBuffer, int width, int height, 113 | const float3& eye, const float3& lookAt, const float vfov=60.0f ); 114 | 115 | //------------------------------------------------------------------------------ 116 | // Offset ray origins. 117 | void translateRays( Buffer& raysBuffer, const float3& offset ); 118 | 119 | //------------------------------------------------------------------------------ 120 | // Perform simple shading via normal visualization. 121 | void shadeHits( std::vector& image, Buffer& hitsBuffer, PrimeMesh& mesh ); 122 | void shadeHits( std::vector& image, Buffer& hitsBuffer, std::vector& modelIds, std::vector& meshes, float3 eye, std::vector& invTransforms ); 123 | 124 | //------------------------------------------------------------------------------ 125 | // Write PPM image to a file. 126 | void writePpm( const char* filename, const float* image, int width, int height ); 127 | 128 | //------------------------------------------------------------------------------ 129 | // Resets all devices 130 | void resetAllDevices(); 131 | 132 | 133 | #endif // __simple_prime_common_h__ 134 | -------------------------------------------------------------------------------- /unityOptixPlugin/primeKernels.cu: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of NVIDIA CORPORATION nor the names of its 13 | * contributors may be used to endorse or promote products derived 14 | * from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 23 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | class OptixSensorBase 35 | { 36 | public: 37 | optix::Matrix4x4 localToWorldTranslationMatrix; 38 | 39 | float sensorDepth; 40 | float sensorHeight; 41 | float sensorRadius; 42 | 43 | float pointGap; 44 | float totalPoints; 45 | }; 46 | 47 | //------------------------------------------------------------------------------ 48 | // Return ceil(x/y) for integers x and y 49 | inline int idivCeil( int x, int y ) 50 | { 51 | return (x + y-1)/y; 52 | } 53 | 54 | //------------------------------------------------------------------------------ 55 | __global__ void createRaysOrthoKernel(float4* rays, int width, int height, float x0, float y0, float z, float dx, float dy, unsigned rayMask ) 56 | { 57 | int rayx = threadIdx.x + blockIdx.x*blockDim.x; 58 | int rayy = threadIdx.y + blockIdx.y*blockDim.y; 59 | if( rayx >= width || rayy >= height ) 60 | return; 61 | 62 | float tMinOrMask = 0.0f; 63 | if( rayMask ) 64 | tMinOrMask = __int_as_float( rayMask ); 65 | 66 | int idx = rayx + rayy*width; 67 | rays[2*idx+0] = make_float4( x0+rayx*dx, y0+rayy*dy, z, tMinOrMask ); // origin, tmin 68 | rays[2*idx+1] = make_float4( 0, 0, 1, 1e34f ); // dir, tmax 69 | } 70 | 71 | //------------------------------------------------------------------------------ 72 | extern "C" void createRaysOrthoOnDevice( float4* rays, int width, int height, float x0, float y0, float z, float dx, float dy, int yOffset, int yStride, unsigned rayMask ) 73 | { 74 | int rows = idivCeil( (height-yOffset), yStride ); 75 | dim3 blockSize( 32, 16 ); 76 | dim3 gridSize( idivCeil( width, blockSize.x ), idivCeil( rows, blockSize.y ) ); 77 | createRaysOrthoKernel<<>>( rays, width, rows, x0, y0+dy*yOffset, z, dx, dy*yStride, rayMask ); 78 | } 79 | 80 | //------------------------------------------------------------------------------ 81 | __global__ void createRaysPerspKernel(float4* rays, int width, int height, float3 eye, float3 U, float3 V, float3 W ) 82 | { 83 | int rayx = threadIdx.x + blockIdx.x*blockDim.x; 84 | int rayy = threadIdx.y + blockIdx.y*blockDim.y; 85 | if( rayx >= width || rayy >= height ) 86 | return; 87 | 88 | int idx = rayx + rayy*width; 89 | 90 | float2 d = make_float2((float)rayx, (float)rayy) / make_float2((float)width, (float)height) * 2.f - 1.f; 91 | 92 | float3 ray_origin = eye; 93 | float3 ray_direction = optix::normalize(d.x*U + d.y*V + W); 94 | 95 | rays[2*idx+0] = make_float4( ray_origin.x, ray_origin.y, ray_origin.z, 0.0f ); // origin, tmin 96 | rays[2*idx+1] = make_float4( ray_direction.x, ray_direction.y, ray_direction.z, 1e34f ); // dir, tmax 97 | } 98 | 99 | //------------------------------------------------------------------------------ 100 | extern "C" void createRaysPerspOnDevice( float4* rays, int width, int height, float3 eye, float3 U, float3 V, float3 W ) 101 | { 102 | dim3 blockSize( 32, 16 ); 103 | dim3 gridSize( idivCeil( width, blockSize.x ), idivCeil( height, blockSize.y ) ); 104 | createRaysPerspKernel<<>>(rays, width, height, eye, U, V, W ); 105 | } 106 | 107 | //------------------------------------------------------------------------------ 108 | __global__ void translateRaysKernel(float4* rays, int count, float3 offset) 109 | { 110 | int idx = threadIdx.x + blockIdx.x*blockDim.x; 111 | if( idx >= count ) 112 | return; 113 | 114 | float4 prev = rays[2*idx+0]; 115 | rays[2*idx+0] = make_float4( prev.x + offset.x, prev.y + offset.y, prev.z + offset.z, prev.w ); // origin, tmin 116 | } 117 | 118 | //------------------------------------------------------------------------------ 119 | extern "C" void translateRaysOnDevice(float4* rays, size_t count, float3 offset) 120 | { 121 | int blockSize = 512; 122 | int blockCount = idivCeil((int)count, blockSize); 123 | translateRaysKernel<<>>( rays, (int)count, offset ); 124 | } 125 | 126 | __global__ void GenerateRaysKernel(float4* rays, OptixSensorBase sensor, int startIndex) 127 | { 128 | int idx = startIndex + (threadIdx.x + blockIdx.x*blockDim.x); 129 | 130 | // For every row and column within the sensor bounds 131 | for (float iHeight = sensor.sensorHeight / 2; iHeight > -sensor.sensorHeight / 2; iHeight -= sensor.pointGap) 132 | { 133 | for (float iRadius = -sensor.sensorRadius / 2; iRadius < sensor.sensorRadius / 2; iRadius += sensor.pointGap, idx++) 134 | { 135 | // Calculate the centre point of the sensor bounds based on origin, direction and depth 136 | float3 centre = ((make_float3(0, 0, 1) * sensor.sensorDepth)); 137 | 138 | // Create a direction vector from origin to the centre + the current height index value 139 | float4 targetDir = make_float4(centre + make_float3(0, iHeight, 0)) 140 | * optix::Matrix4x4::rotate((iRadius * M_PI) / 180, make_float3(0, 1, 0)); // Multiply this vector by a rotation matrix to rotate the direction by radius index value in the y axis 141 | 142 | // Normalise the value and convert back to a float3 for the Ray structure 143 | float3 targetDirection = optix::normalize(make_float3(targetDir)); 144 | 145 | rays[2 * idx + 0] = make_float4(0, 0, 0, 0.0f); // origin, tmin 146 | rays[2 * idx + 1] = make_float4(targetDirection.x, targetDirection.y, targetDirection.z, sensor.sensorDepth); // dir, tmax 147 | } 148 | } 149 | } 150 | 151 | extern "C" void GenerateRaysOnDevice(float4* rays, OptixSensorBase sensor, int startIndex) 152 | { 153 | int blockSize = 512; 154 | int blockCount = idivCeil((int)sensor.totalPoints, blockSize); 155 | GenerateRaysKernel<<>>(rays, sensor, startIndex); 156 | } 157 | --------------------------------------------------------------------------------