├── .dockerignore ├── .gitignore ├── Dockerfile ├── LICENSE ├── MANIFEST.in ├── README.md ├── driver ├── acceleration.cpp ├── acceleration.h ├── buffer.cpp ├── buffer.h ├── context.cpp ├── context.h ├── destroyable.cpp ├── destroyable.h ├── geometry.cpp ├── geometry.h ├── geometry_group.cpp ├── geometry_group.h ├── geometry_instance.cpp ├── geometry_instance.h ├── group.cpp ├── group.h ├── main.cpp ├── material.cpp ├── material.h ├── program.cpp ├── program.h ├── scoped.cpp ├── scoped.h ├── selector.cpp ├── selector.h ├── shared_includes.h ├── texture_sampler.cpp ├── texture_sampler.h ├── transform.cpp ├── transform.h ├── variable.cpp └── variable.h ├── examples ├── __init__.py ├── buffers_of_buffers │ ├── __init__.py │ ├── buffers_of_buffers.py │ ├── commonStructs.h │ ├── common_structs.py │ ├── constantbg.cu │ ├── helpers.h │ ├── optixBuffersOfBuffers.cu │ ├── parallelogram.cu │ ├── phong.cu │ ├── phong.h │ ├── pinhole_camera.cu │ └── sphere_texcoord.cu ├── common.py ├── hello │ ├── __init__.py │ ├── draw_color.cu │ └── hello.py ├── sphere │ ├── __init__.py │ ├── constantbg.cu │ ├── helpers.h │ ├── normal_shader.cu │ ├── pinhole_camera.cu │ ├── sphere.cu │ └── sphere.py └── texture_sampler │ ├── __init__.py │ ├── draw_texture.cu │ └── texture_sampler.py ├── pyoptix ├── __init__.py ├── acceleration.py ├── buffer.py ├── compiler.py ├── context.py ├── entry_point.py ├── enums.py ├── geometry.py ├── geometry_group.py ├── geometry_instance.py ├── group.py ├── material.py ├── mixins │ ├── __init__.py │ ├── bindless.py │ ├── destroyable.py │ ├── graphnode.py │ ├── hascontext.py │ ├── parent.py │ └── scoped.py ├── program.py ├── selector.py ├── texture_sampler.py ├── transform.py ├── utils.py └── variable.py ├── requirements.txt └── setup.py /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | LICENSE 4 | README.md 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.pyc 3 | *~ 4 | *.log 5 | *.egg-info/ 6 | .idea 7 | dist 8 | build 9 | pip-log.txt 10 | docker-compose.yml 11 | 12 | # virtual environment 13 | venv 14 | bin 15 | include 16 | lib 17 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG OPTIX_IMAGE=optix 2 | FROM $OPTIX_IMAGE 3 | MAINTAINER Yigit Ozen 4 | 5 | ARG DEBIAN_FRONTEND=noninteractive 6 | 7 | RUN apt-get update && apt-get install -y --no-install-recommends \ 8 | build-essential software-properties-common pkg-config \ 9 | zsh nano vim wget curl git rsync cmake unzip ssh \ 10 | freeglut3 libxmu6 libglu1-mesa \ 11 | python3-dev python3-pip python3-setuptools python3-numpy \ 12 | python3-pillow python3-pil.imagetk libboost-python-dev \ 13 | python3-pyqt5 python3-pyqt5.qtmultimedia python3-pyqt5.qtopengl \ 14 | python3-pyqt5.qtpositioning python3-pyqt5.qtquick python3-pyqt5.qtx11extras 15 | 16 | WORKDIR /usr/src/pyoptix 17 | 18 | COPY . . 19 | 20 | RUN python3 setup.py install 21 | 22 | CMD /bin/bash 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Yigit Ozen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # include all files under driver directory to the distribution 2 | graft driver 3 | -------------------------------------------------------------------------------- /driver/acceleration.cpp: -------------------------------------------------------------------------------- 1 | #include "acceleration.h" 2 | 3 | 4 | NativeAccelerationWrapper::NativeAccelerationWrapper(optix::Acceleration acceleration) { 5 | this->acceleration = acceleration; 6 | this->set_destroyable_object(this->acceleration.get()); 7 | } 8 | 9 | NativeAccelerationWrapper::~NativeAccelerationWrapper() { 10 | if (!is_destroyed) this->acceleration->destroy(); 11 | } 12 | 13 | void NativeAccelerationWrapper::set_property(const std::string& name, const std::string& value) { 14 | this->acceleration->setProperty(name, value); 15 | } 16 | 17 | std::string NativeAccelerationWrapper::get_property(const std::string& name) { 18 | return this->acceleration->getProperty(name); 19 | } 20 | 21 | void NativeAccelerationWrapper::mark_dirty() { 22 | this->acceleration->markDirty(); 23 | } 24 | 25 | bool NativeAccelerationWrapper::is_dirty() { 26 | return this->acceleration->isDirty(); 27 | } 28 | 29 | optix::Acceleration NativeAccelerationWrapper::get_native() { 30 | return acceleration; 31 | } 32 | 33 | void NativeAccelerationWrapper::boost_python_expose() { 34 | boost::python::class_ >( 35 | "NativeAccelerationWrapper", 36 | "Wraps optix::Acceleration class", 37 | boost::python::no_init) 38 | 39 | .def("set_property", &NativeAccelerationWrapper::set_property) 40 | .def("get_property", &NativeAccelerationWrapper::get_property) 41 | .def("mark_dirty", &NativeAccelerationWrapper::mark_dirty) 42 | .def("is_dirty", &NativeAccelerationWrapper::is_dirty); 43 | } 44 | -------------------------------------------------------------------------------- /driver/acceleration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "destroyable.h" 4 | 5 | class NativeAccelerationWrapper: public NativeDestroyableWrapper 6 | { 7 | private: 8 | optix::Acceleration acceleration; 9 | 10 | public: 11 | NativeAccelerationWrapper(optix::Acceleration acceleration); 12 | ~NativeAccelerationWrapper(); 13 | void set_property(const std::string& name, const std::string& value); 14 | std::string get_property(const std::string& name); 15 | void mark_dirty(); 16 | bool is_dirty(); 17 | optix::Acceleration get_native(); 18 | static void boost_python_expose(); 19 | }; 20 | -------------------------------------------------------------------------------- /driver/buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "buffer.h" 2 | 3 | 4 | NativeBufferWrapper::NativeBufferWrapper(optix::Buffer buffer) { 5 | this->buffer = buffer; 6 | this->set_destroyable_object(this->buffer.get()); 7 | } 8 | 9 | NativeBufferWrapper::~NativeBufferWrapper() { 10 | if (!is_destroyed && auto_destroy) this->buffer->destroy(); 11 | } 12 | 13 | int NativeBufferWrapper::get_id() { 14 | return this->buffer->getId(); 15 | } 16 | 17 | void NativeBufferWrapper::mark_dirty() { 18 | this->buffer->markDirty(); 19 | } 20 | 21 | void NativeBufferWrapper::set_format(RTformat format) { 22 | this->buffer->setFormat(format); 23 | } 24 | 25 | RTformat NativeBufferWrapper::get_format() { 26 | return this->buffer->getFormat(); 27 | } 28 | 29 | void NativeBufferWrapper::set_size(boost::python::list& sizes) { 30 | int dim = boost::python::len(sizes); 31 | 32 | std::vector sizes_vector = std::vector(); 33 | 34 | for(int i = 0; i < dim; i++) 35 | sizes_vector.push_back(boost::python::extract(sizes[i])); 36 | 37 | set_size_with_vector_int(sizes_vector); 38 | } 39 | 40 | void NativeBufferWrapper::set_size_with_vector_int(std::vector sizes_vector) { 41 | int dim = sizes_vector.size(); 42 | 43 | if(dim == 1) 44 | this->buffer->setSize(sizes_vector.at(0)); 45 | else if(dim == 2) 46 | this->buffer->setSize(sizes_vector.at(0), sizes_vector.at(1)); 47 | else if(dim == 3) 48 | this->buffer->setSize(sizes_vector.at(0), sizes_vector.at(1), sizes_vector.at(2)); 49 | else { 50 | PyErr_SetString(PyExc_ValueError, "Invalid number of dimensions"); 51 | boost::python::throw_error_already_set(); 52 | } 53 | } 54 | 55 | unsigned long NativeBufferWrapper::get_buffer_size_in_bytes() { 56 | std::vector size = this->get_size(); 57 | int element_size = this->buffer->getElementSize(); 58 | 59 | if(size.size() == 0) 60 | return 0; 61 | 62 | unsigned long total_bytes = element_size; 63 | 64 | for(unsigned int i = 0; i < size.size(); i++) 65 | total_bytes *= size.at(i); 66 | 67 | return total_bytes; 68 | } 69 | 70 | unsigned long NativeBufferWrapper::get_mip_level_size_in_bytes(unsigned int level) { 71 | std::vector size = this->get_mip_level_size(level); 72 | int element_size = this->buffer->getElementSize(); 73 | 74 | if(size.size() == 0) 75 | return 0; 76 | 77 | unsigned long total_bytes = element_size; 78 | 79 | for(unsigned int i = 0; i < size.size(); i++) 80 | total_bytes *= size.at(i); 81 | 82 | return total_bytes; 83 | } 84 | 85 | std::vector NativeBufferWrapper::get_size() { 86 | int dim = this->buffer->getDimensionality(); 87 | std::vector res = std::vector(); 88 | RTsize x, y, z; 89 | this->buffer->getSize(x, y, z); 90 | 91 | if (dim > 0) { 92 | res.push_back(int(x)); 93 | } 94 | if (dim > 1) { 95 | res.push_back(int(y)); 96 | } 97 | if (dim > 2) { 98 | res.push_back(int(z)); 99 | } 100 | return res; 101 | } 102 | 103 | void NativeBufferWrapper::set_element_size(int size_in_bytes) { 104 | this->buffer->setElementSize(size_in_bytes); 105 | } 106 | 107 | int NativeBufferWrapper::get_element_size() { 108 | return this->buffer->getElementSize(); 109 | } 110 | 111 | void NativeBufferWrapper::copy_into_array(PyObject* array) { 112 | void* buff_ptr = this->buffer->map(); 113 | Py_buffer pb; 114 | PyObject_GetBuffer(array, &pb, PyBUF_SIMPLE); 115 | memcpy(pb.buf, buff_ptr, pb.len); 116 | PyBuffer_Release(&pb); 117 | this->buffer->unmap(); 118 | } 119 | 120 | void NativeBufferWrapper::copy_from_array(PyObject* array) { 121 | void* buff_ptr = this->buffer->map(); 122 | Py_buffer pb; 123 | PyObject_GetBuffer(array, &pb, PyBUF_SIMPLE); 124 | memcpy(buff_ptr, pb.buf, pb.len); 125 | PyBuffer_Release(&pb); 126 | this->buffer->unmap(); 127 | } 128 | 129 | void NativeBufferWrapper::copy_mip_level_from_array(unsigned int level, PyObject* array) { 130 | #if OPTIX_VERSION < 3090 131 | PyErr_SetString(PyExc_NotImplementedError, "OptiX versions before 3.9.0 don't have mipmapping functions"); 132 | boost::python::throw_error_already_set(); 133 | #else 134 | void* buff_ptr = this->buffer->map(level); 135 | Py_buffer pb; 136 | PyObject_GetBuffer(array, &pb, PyBUF_SIMPLE); 137 | memcpy(buff_ptr, pb.buf, pb.len); 138 | PyBuffer_Release(&pb); 139 | this->buffer->unmap(level); 140 | #endif 141 | } 142 | 143 | unsigned int NativeBufferWrapper::get_mip_level_count() { 144 | #if OPTIX_VERSION < 3090 145 | PyErr_SetString(PyExc_NotImplementedError, "OptiX versions before 3.9.0 don't have mipmapping functions"); 146 | boost::python::throw_error_already_set(); 147 | return 0; 148 | #else 149 | return this->buffer->getMipLevelCount(); 150 | #endif 151 | } 152 | 153 | void NativeBufferWrapper::set_mip_level_count(unsigned int level_count) { 154 | #if OPTIX_VERSION < 3090 155 | PyErr_SetString(PyExc_NotImplementedError, "OptiX versions before 3.9.0 don't have mipmapping functions"); 156 | boost::python::throw_error_already_set(); 157 | #else 158 | this->buffer->setMipLevelCount(level_count); 159 | #endif 160 | } 161 | 162 | std::vector NativeBufferWrapper::get_mip_level_size(unsigned int level) { 163 | #if OPTIX_VERSION < 3090 164 | PyErr_SetString(PyExc_NotImplementedError, "OptiX versions before 3.9.0 don't have mipmapping functions"); 165 | boost::python::throw_error_already_set(); 166 | return std::vector(); 167 | #else 168 | int dim = this->buffer->getDimensionality(); 169 | std::vector res = std::vector(); 170 | RTsize x, y, z; 171 | this->buffer->getMipLevelSize(level, x, y, z); 172 | 173 | if (dim > 0) { 174 | res.push_back(int(x)); 175 | } 176 | if (dim > 1) { 177 | res.push_back(int(y)); 178 | } 179 | if (dim > 2) { 180 | res.push_back(int(z)); 181 | } 182 | return res; 183 | #endif 184 | } 185 | 186 | optix::Buffer NativeBufferWrapper::get_native_buffer() { 187 | return this->buffer; 188 | } 189 | 190 | void NativeBufferWrapper::boost_python_expose() { 191 | boost::python::class_ >( 192 | "NativeBufferWrapper", 193 | "Wraps optix::Buffer class", 194 | boost::python::no_init) 195 | 196 | .def("get_id", &NativeBufferWrapper::get_id) 197 | .def("mark_dirty", &NativeBufferWrapper::mark_dirty) 198 | .def("set_format", &NativeBufferWrapper::set_format) 199 | .def("get_format", &NativeBufferWrapper::get_format) 200 | .def("set_size", &NativeBufferWrapper::set_size) 201 | .def("get_size", &NativeBufferWrapper::get_size) 202 | .def("get_size_in_bytes", &NativeBufferWrapper::get_buffer_size_in_bytes) 203 | .def("set_element_size", &NativeBufferWrapper::set_element_size) 204 | .def("get_element_size", &NativeBufferWrapper::get_element_size) 205 | .def("copy_into_array", &NativeBufferWrapper::copy_into_array) 206 | .def("copy_from_array", &NativeBufferWrapper::copy_from_array) 207 | .def("copy_mip_level_from_array", &NativeBufferWrapper::copy_mip_level_from_array) 208 | .def("set_mip_level_count", &NativeBufferWrapper::set_mip_level_count) 209 | .def("get_mip_level_count", &NativeBufferWrapper::get_mip_level_count) 210 | .def("get_mip_level_size", &NativeBufferWrapper::get_mip_level_size) 211 | .def("get_mip_level_size_in_bytes", &NativeBufferWrapper::get_mip_level_size_in_bytes); 212 | } 213 | -------------------------------------------------------------------------------- /driver/buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "destroyable.h" 4 | 5 | 6 | class NativeBufferWrapper : public NativeDestroyableWrapper 7 | { 8 | private: 9 | optix::Buffer buffer; 10 | 11 | public: 12 | NativeBufferWrapper(optix::Buffer buffer); 13 | ~NativeBufferWrapper(); 14 | int get_id(); 15 | void mark_dirty(); 16 | void set_format(RTformat format); 17 | RTformat get_format(); 18 | std::vector get_size(); 19 | void set_size(boost::python::list& sizes); 20 | void set_size_with_vector_int(std::vector sizes_vector); 21 | unsigned long get_buffer_size_in_bytes(); 22 | unsigned long get_mip_level_size_in_bytes(unsigned int level); 23 | void set_element_size(int size_in_bytes); 24 | int get_element_size(); 25 | void copy_into_array(PyObject* array); 26 | void copy_from_array(PyObject* array); 27 | void copy_mip_level_from_array(unsigned int level, PyObject* array); 28 | unsigned int get_mip_level_count(); 29 | void set_mip_level_count(unsigned int level_count); 30 | std::vector get_mip_level_size(unsigned int level); 31 | optix::Buffer get_native_buffer(); 32 | static void boost_python_expose(); 33 | }; 34 | -------------------------------------------------------------------------------- /driver/context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "buffer.h" 4 | #include "program.h" 5 | #include "texture_sampler.h" 6 | #include "geometry.h" 7 | #include "material.h" 8 | #include "geometry_instance.h" 9 | #include "group.h" 10 | #include "geometry_group.h" 11 | #include "transform.h" 12 | #include "selector.h" 13 | #include "acceleration.h" 14 | #include "scoped.h" 15 | 16 | 17 | class NativeContextWrapper : public NativeScopedWrapper 18 | { 19 | private: 20 | optix::Context context; 21 | 22 | public: 23 | NativeContextWrapper(); 24 | ~NativeContextWrapper(); 25 | unsigned int get_ray_type_count(); 26 | unsigned int get_entry_point_count(); 27 | void set_ray_type_count(unsigned int ray_type_count); 28 | void set_entry_point_count(unsigned int entry_point_count); 29 | void set_ray_generation_program(unsigned int entry_point_index, NativeProgramWrapper* ray_generation_program); 30 | void set_exception_program(unsigned int entry_point_index, NativeProgramWrapper* exception_program); 31 | void set_miss_program(unsigned int ray_type_index, NativeProgramWrapper* miss_program); 32 | void compile(); 33 | void launch_1d(unsigned int entry_point_index, int width); 34 | void launch_2d(unsigned int entry_point_index, int width, int height); 35 | void launch_3d(unsigned int entry_point_index, int width, int height, int depth); 36 | int get_cpu_num_of_threads(); 37 | void set_cpu_num_of_threads(int threadCount); 38 | int get_stack_size(); 39 | void set_stack_size(int stack_size_bytes); 40 | int get_available_devices_count(); 41 | std::string get_device_name(int device_id); 42 | boost::python::tuple get_device_compute_capability(int device_id); 43 | int get_enabled_device_count(); 44 | std::vector get_enabled_devices(); 45 | void set_devices(std::vector devices); 46 | unsigned long get_used_host_memory(); 47 | unsigned long get_available_device_memory(int device_id); 48 | void set_exception_enabled(RTexception exception, bool enabled); 49 | bool get_exception_enabled(RTexception exception); 50 | void set_print_enabled(bool enabled); 51 | bool get_print_enabled(); 52 | void set_print_buffer_size(int buffer_size_bytes); 53 | int get_print_buffer_size(); 54 | NativeProgramWrapper* create_program_from_file(std::string file_name, std::string function_name); 55 | NativeBufferWrapper* create_buffer(int buffer_type); 56 | NativeTextureSamplerWrapper* create_texture_sampler(); 57 | NativeGeometryWrapper* create_geometry(); 58 | NativeMaterialWrapper* create_material(); 59 | NativeGeometryInstanceWrapper* create_geometry_instance(); 60 | NativeGroupWrapper* create_group(); 61 | NativeGeometryGroupWrapper* create_geometry_group(); 62 | NativeTransformWrapper* create_transform(); 63 | NativeSelectorWrapper* create_selector(); 64 | NativeAccelerationWrapper* create_accelerator(std::string builder, std::string traverser); 65 | static void boost_python_expose(); 66 | }; 67 | -------------------------------------------------------------------------------- /driver/destroyable.cpp: -------------------------------------------------------------------------------- 1 | #include "destroyable.h" 2 | 3 | 4 | NativeDestroyableWrapper::NativeDestroyableWrapper() { 5 | is_destroyed = false; 6 | auto_destroy = true; 7 | object = nullptr; 8 | } 9 | 10 | NativeDestroyableWrapper::~NativeDestroyableWrapper() { 11 | 12 | } 13 | 14 | void NativeDestroyableWrapper::set_destroyable_object(optix::DestroyableObj* object) { 15 | this->object = object; 16 | } 17 | 18 | void NativeDestroyableWrapper::validate() { 19 | object->validate(); 20 | } 21 | 22 | void NativeDestroyableWrapper::mark_destroyed() { 23 | is_destroyed = true; 24 | } 25 | 26 | bool NativeDestroyableWrapper::get_auto_destroy() { 27 | return auto_destroy; 28 | } 29 | 30 | void NativeDestroyableWrapper::set_auto_destroy(bool destroy) { 31 | auto_destroy = destroy; 32 | } 33 | 34 | void NativeDestroyableWrapper::boost_python_expose() { 35 | boost::python::class_( 36 | "NativeDestroyableWrapper", 37 | "Wraps optix::Destroyable class", 38 | boost::python::no_init) 39 | 40 | .add_property("is_destroyed", &NativeDestroyableWrapper::is_destroyed) 41 | .add_property("auto_destroy", &NativeDestroyableWrapper::get_auto_destroy, &NativeDestroyableWrapper::set_auto_destroy) 42 | .def("validate", &NativeDestroyableWrapper::validate) 43 | .def("mark_destroyed", &NativeDestroyableWrapper::mark_destroyed); 44 | } 45 | -------------------------------------------------------------------------------- /driver/destroyable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | 4 | 5 | class NativeDestroyableWrapper 6 | { 7 | private: 8 | optix::DestroyableObj* object; 9 | protected: 10 | bool is_destroyed; 11 | bool auto_destroy; 12 | public: 13 | NativeDestroyableWrapper(); 14 | ~NativeDestroyableWrapper(); 15 | void set_destroyable_object(optix::DestroyableObj* object); 16 | void validate(); 17 | void mark_destroyed(); 18 | bool get_auto_destroy(); 19 | void set_auto_destroy(bool destroy); 20 | static void boost_python_expose(); 21 | }; 22 | -------------------------------------------------------------------------------- /driver/geometry.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry.h" 2 | 3 | 4 | NativeGeometryWrapper::NativeGeometryWrapper(optix::Geometry geometry) { 5 | this->geometry = geometry; 6 | this->set_scoped_object(this->geometry.get()); 7 | } 8 | 9 | NativeGeometryWrapper::~NativeGeometryWrapper() { 10 | if (!is_destroyed) this->geometry->destroy(); 11 | } 12 | 13 | void NativeGeometryWrapper::mark_dirty() { 14 | this->geometry->markDirty(); 15 | } 16 | 17 | bool NativeGeometryWrapper::is_dirty() { 18 | return this->geometry->isDirty(); 19 | } 20 | 21 | void NativeGeometryWrapper::set_primitive_count(unsigned int num_primitives) { 22 | this->geometry->setPrimitiveCount(num_primitives); 23 | } 24 | 25 | unsigned int NativeGeometryWrapper::get_primitive_count() { 26 | return this->geometry->getPrimitiveCount(); 27 | } 28 | 29 | void NativeGeometryWrapper::set_primitive_index_offset(unsigned int index_offset) { 30 | this->geometry->setPrimitiveIndexOffset(index_offset); 31 | } 32 | 33 | unsigned int NativeGeometryWrapper::get_primitive_index_offset() { 34 | return this->geometry->getPrimitiveIndexOffset(); 35 | } 36 | 37 | void NativeGeometryWrapper::set_bounding_box_program(NativeProgramWrapper* program) { 38 | this->geometry->setBoundingBoxProgram(program->get_native()); 39 | } 40 | 41 | void NativeGeometryWrapper::set_intersection_program(NativeProgramWrapper* program) { 42 | this->geometry->setIntersectionProgram(program->get_native()); 43 | } 44 | 45 | optix::Geometry NativeGeometryWrapper::get_native() { 46 | return this->geometry; 47 | } 48 | 49 | void NativeGeometryWrapper::boost_python_expose() { 50 | boost::python::class_ >( 51 | "NativeGeometryWrapper", 52 | "Wraps optix::Geometry class", 53 | boost::python::no_init) 54 | 55 | .def("mark_dirty", &NativeGeometryWrapper::mark_dirty) 56 | .def("is_dirty", &NativeGeometryWrapper::is_dirty) 57 | .def("set_primitive_count", &NativeGeometryWrapper::set_primitive_count) 58 | .def("get_primitive_count", &NativeGeometryWrapper::get_primitive_count) 59 | .def("set_primitive_index_offset", &NativeGeometryWrapper::set_primitive_index_offset) 60 | .def("get_primitive_index_offset", &NativeGeometryWrapper::get_primitive_index_offset) 61 | .def("set_bounding_box_program", &NativeGeometryWrapper::set_bounding_box_program) 62 | .def("set_intersection_program", &NativeGeometryWrapper::set_intersection_program); 63 | } 64 | -------------------------------------------------------------------------------- /driver/geometry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "program.h" 4 | #include "scoped.h" 5 | 6 | 7 | class NativeGeometryWrapper : public NativeScopedWrapper 8 | { 9 | private: 10 | optix::Geometry geometry; 11 | 12 | public: 13 | NativeGeometryWrapper(optix::Geometry geometry); 14 | ~NativeGeometryWrapper(); 15 | void mark_dirty(); 16 | bool is_dirty(); 17 | void set_primitive_count(unsigned int num_primitives); 18 | unsigned int get_primitive_count(); 19 | void set_primitive_index_offset(unsigned int index_offset); 20 | unsigned int get_primitive_index_offset(); 21 | void set_bounding_box_program(NativeProgramWrapper* program); 22 | void set_intersection_program(NativeProgramWrapper* program); 23 | optix::Geometry get_native(); 24 | static void boost_python_expose(); 25 | }; 26 | -------------------------------------------------------------------------------- /driver/geometry_group.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_group.h" 2 | 3 | 4 | NativeGeometryGroupWrapper::NativeGeometryGroupWrapper(optix::GeometryGroup geometry_group) { 5 | this->geometry_group = geometry_group; 6 | this->set_destroyable_object(this->geometry_group.get()); 7 | } 8 | 9 | NativeGeometryGroupWrapper::~NativeGeometryGroupWrapper() { 10 | if (!is_destroyed) this->geometry_group->destroy(); 11 | } 12 | 13 | void NativeGeometryGroupWrapper::set_acceleration(NativeAccelerationWrapper* acceleration) { 14 | this->geometry_group->setAcceleration(acceleration->get_native()); 15 | } 16 | 17 | void NativeGeometryGroupWrapper::set_child_count(unsigned int count) { 18 | this->geometry_group->setChildCount(count); 19 | } 20 | 21 | unsigned int NativeGeometryGroupWrapper::get_child_count() { 22 | return this->geometry_group->getChildCount(); 23 | } 24 | 25 | void NativeGeometryGroupWrapper::set_child_geometry_instance(unsigned int index, NativeGeometryInstanceWrapper* geometry_instance) { 26 | this->geometry_group->setChild(index, geometry_instance->get_native()); 27 | } 28 | 29 | void NativeGeometryGroupWrapper::remove_child(unsigned int index) { 30 | this->geometry_group->removeChild(index); 31 | } 32 | 33 | optix::GeometryGroup NativeGeometryGroupWrapper::get_native() { 34 | return this->geometry_group; 35 | } 36 | 37 | void NativeGeometryGroupWrapper::boost_python_expose() { 38 | boost::python::class_ >( 39 | "NativeGeometryGroupWrapper", 40 | "Wraps optix::GeometryGroup class", 41 | boost::python::no_init) 42 | 43 | .def("set_acceleration", &NativeGeometryGroupWrapper::set_acceleration) 44 | .def("set_child_count", &NativeGeometryGroupWrapper::set_child_count) 45 | .def("get_child_count", &NativeGeometryGroupWrapper::get_child_count) 46 | .def("set_child_geometry_instance", &NativeGeometryGroupWrapper::set_child_geometry_instance) 47 | .def("remove_child", &NativeGeometryGroupWrapper::remove_child); 48 | } 49 | -------------------------------------------------------------------------------- /driver/geometry_group.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "acceleration.h" 4 | #include "geometry_instance.h" 5 | #include "scoped.h" 6 | #include "destroyable.h" 7 | 8 | 9 | class NativeGeometryGroupWrapper : public NativeDestroyableWrapper 10 | { 11 | private: 12 | optix::GeometryGroup geometry_group; 13 | 14 | public: 15 | NativeGeometryGroupWrapper(optix::GeometryGroup geometry_group); 16 | ~NativeGeometryGroupWrapper(); 17 | void set_acceleration(NativeAccelerationWrapper* acceleration); 18 | void set_child_count(unsigned int count); 19 | unsigned int get_child_count(); 20 | void set_child_geometry_instance(unsigned int index, NativeGeometryInstanceWrapper* geometry_instance); 21 | void remove_child(unsigned int index); 22 | optix::GeometryGroup get_native(); 23 | static void boost_python_expose(); 24 | }; 25 | -------------------------------------------------------------------------------- /driver/geometry_instance.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_instance.h" 2 | 3 | 4 | NativeGeometryInstanceWrapper::NativeGeometryInstanceWrapper(optix::GeometryInstance geometry_instance) { 5 | this->geometry_instance = geometry_instance; 6 | this->set_scoped_object(this->geometry_instance.get()); 7 | } 8 | 9 | NativeGeometryInstanceWrapper::~NativeGeometryInstanceWrapper() { 10 | if (!is_destroyed) this->geometry_instance->destroy(); 11 | } 12 | 13 | void NativeGeometryInstanceWrapper::set_geometry(NativeGeometryWrapper* geometry) { 14 | return this->geometry_instance->setGeometry(geometry->get_native()); 15 | } 16 | 17 | void NativeGeometryInstanceWrapper::set_material_count(unsigned int count) { 18 | return this->geometry_instance->setMaterialCount(count); 19 | } 20 | 21 | unsigned int NativeGeometryInstanceWrapper::get_material_count() { 22 | return this->geometry_instance->getMaterialCount(); 23 | } 24 | 25 | void NativeGeometryInstanceWrapper::set_material(unsigned int idx, NativeMaterialWrapper* material) { 26 | this->geometry_instance->setMaterial(idx, material->get_native()); 27 | } 28 | 29 | optix::GeometryInstance NativeGeometryInstanceWrapper::get_native() { 30 | return geometry_instance; 31 | } 32 | 33 | void NativeGeometryInstanceWrapper::boost_python_expose() { 34 | boost::python::class_ >( 35 | "NativeGeometryInstanceWrapper", 36 | "Wraps optix::GeometryInstance class", 37 | boost::python::no_init) 38 | 39 | .def("set_geometry", &NativeGeometryInstanceWrapper::set_geometry) 40 | .def("set_material_count", &NativeGeometryInstanceWrapper::set_material_count) 41 | .def("get_material_count", &NativeGeometryInstanceWrapper::get_material_count) 42 | .def("set_material", &NativeGeometryInstanceWrapper::set_material); 43 | } 44 | -------------------------------------------------------------------------------- /driver/geometry_instance.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "geometry.h" 4 | #include "material.h" 5 | #include "scoped.h" 6 | 7 | 8 | class NativeGeometryInstanceWrapper : public NativeScopedWrapper 9 | { 10 | private: 11 | optix::GeometryInstance geometry_instance; 12 | 13 | public: 14 | NativeGeometryInstanceWrapper(optix::GeometryInstance geometry_instance); 15 | ~NativeGeometryInstanceWrapper(); 16 | void set_geometry(NativeGeometryWrapper* geometry); 17 | void set_material_count(unsigned int count); 18 | unsigned int get_material_count(); 19 | void set_material(unsigned int idx, NativeMaterialWrapper* material); 20 | optix::GeometryInstance get_native(); 21 | static void boost_python_expose(); 22 | }; 23 | -------------------------------------------------------------------------------- /driver/group.cpp: -------------------------------------------------------------------------------- 1 | #include "group.h" 2 | #include "geometry_group.h" 3 | #include "selector.h" 4 | 5 | 6 | NativeGroupWrapper::NativeGroupWrapper(optix::Group group) { 7 | this->group = group; 8 | this->set_destroyable_object(this->group.get()); 9 | } 10 | 11 | NativeGroupWrapper::~NativeGroupWrapper() { 12 | if (!is_destroyed) this->group->destroy(); 13 | } 14 | 15 | void NativeGroupWrapper::set_acceleration(NativeAccelerationWrapper* acceleration) { 16 | this->group->setAcceleration(acceleration->get_native()); 17 | } 18 | 19 | void NativeGroupWrapper::set_child_count(unsigned int count) { 20 | this->group->setChildCount(count); 21 | } 22 | 23 | unsigned int NativeGroupWrapper::get_child_count() { 24 | return this->group->getChildCount(); 25 | } 26 | 27 | void NativeGroupWrapper::set_child_geometry_group(unsigned int index, NativeGeometryGroupWrapper* child) { 28 | this->group->setChild(index, child->get_native()); 29 | } 30 | 31 | void NativeGroupWrapper::set_child_group(unsigned int index, NativeGroupWrapper* child) { 32 | this->group->setChild(index, child->get_native()); 33 | } 34 | 35 | void NativeGroupWrapper::set_child_selector(unsigned int index, NativeSelectorWrapper* child) { 36 | this->group->setChild(index, child->get_native()); 37 | } 38 | 39 | void NativeGroupWrapper::set_child_transform(unsigned int index, NativeTransformWrapper* child) { 40 | this->group->setChild(index, child->get_native()); 41 | } 42 | 43 | void NativeGroupWrapper::set_child_acceleration(unsigned int index, NativeAccelerationWrapper* child) { 44 | this->group->setChild(index, child->get_native()); 45 | } 46 | 47 | void NativeGroupWrapper::remove_child(unsigned int index) { 48 | this->group->removeChild(index); 49 | } 50 | 51 | optix::Group NativeGroupWrapper::get_native() { 52 | return this->group; 53 | } 54 | 55 | void NativeGroupWrapper::boost_python_expose() 56 | { 57 | boost::python::class_ >( 58 | "NativeGroupWrapper", 59 | "Wraps optix::Group class", 60 | boost::python::no_init) 61 | 62 | .def("set_acceleration", &NativeGroupWrapper::set_acceleration) 63 | .def("set_child_count", &NativeGroupWrapper::set_child_count) 64 | .def("get_child_count", &NativeGroupWrapper::get_child_count) 65 | .def("set_child_geometry_group", &NativeGroupWrapper::set_child_geometry_group) 66 | .def("set_child_group", &NativeGroupWrapper::set_child_group) 67 | .def("set_child_selector", &NativeGroupWrapper::set_child_selector) 68 | .def("set_child_transform", &NativeGroupWrapper::set_child_transform) 69 | .def("set_child_acceleration", &NativeGroupWrapper::set_child_acceleration) 70 | .def("remove_child", &NativeGroupWrapper::remove_child); 71 | } 72 | -------------------------------------------------------------------------------- /driver/group.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "acceleration.h" 4 | #include "geometry_instance.h" 5 | #include "transform.h" 6 | #include "scoped.h" 7 | #include "destroyable.h" 8 | 9 | class NativeGeometryGroupWrapper; 10 | class NativeSelectorWrapper; 11 | 12 | class NativeGroupWrapper : public NativeDestroyableWrapper 13 | { 14 | private: 15 | optix::Group group; 16 | 17 | public: 18 | NativeGroupWrapper(optix::Group group); 19 | ~NativeGroupWrapper(); 20 | void set_acceleration(NativeAccelerationWrapper* acceleration); 21 | void set_child_count(unsigned int count); 22 | unsigned int get_child_count(); 23 | void set_child_geometry_group(unsigned int index, NativeGeometryGroupWrapper* child); 24 | void set_child_group(unsigned int index, NativeGroupWrapper* child); 25 | void set_child_selector(unsigned int index, NativeSelectorWrapper* child); 26 | void set_child_transform(unsigned int index, NativeTransformWrapper* child); 27 | void set_child_acceleration(unsigned int index, NativeAccelerationWrapper* child); 28 | void remove_child(unsigned int index); 29 | optix::Group get_native(); 30 | static void boost_python_expose(); 31 | }; 32 | -------------------------------------------------------------------------------- /driver/main.cpp: -------------------------------------------------------------------------------- 1 | #include "shared_includes.h" 2 | #include "destroyable.h" 3 | #include "variable.h" 4 | #include "scoped.h" 5 | #include "program.h" 6 | #include "acceleration.h" 7 | #include "context.h" 8 | #include "buffer.h" 9 | #include "texture_sampler.h" 10 | #include "geometry.h" 11 | #include "material.h" 12 | #include "selector.h" 13 | #include "transform.h" 14 | #include "geometry_group.h" 15 | #include "group.h" 16 | #include "geometry_instance.h" 17 | 18 | 19 | template 20 | struct VectorToList 21 | { 22 | static PyObject* convert(const std::vector& vec) 23 | { 24 | boost::python::list* l = new boost::python::list(); 25 | for(size_t i = 0; i < vec.size(); i++) 26 | (*l).append(vec[i]); 27 | 28 | return l->ptr(); 29 | } 30 | }; 31 | 32 | 33 | BOOST_PYTHON_MODULE(_driver) 34 | { 35 | Py_Initialize(); 36 | 37 | boost::python::to_python_converter >, VectorToList >(); 38 | 39 | /* 40 | * CORE 41 | */ 42 | boost::python::scope().attr("OPTIX_VERSION") = OPTIX_VERSION; 43 | NativeDestroyableWrapper::boost_python_expose(); 44 | NativeVariableWrapper::boost_python_expose(); 45 | NativeScopedWrapper::boost_python_expose(); 46 | NativeProgramWrapper::boost_python_expose(); 47 | NativeContextWrapper::boost_python_expose(); 48 | NativeAccelerationWrapper::boost_python_expose(); 49 | NativeBufferWrapper::boost_python_expose(); 50 | NativeTextureSamplerWrapper::boost_python_expose(); 51 | NativeGeometryWrapper::boost_python_expose(); 52 | NativeMaterialWrapper::boost_python_expose(); 53 | NativeSelectorWrapper::boost_python_expose(); 54 | NativeTransformWrapper::boost_python_expose(); 55 | NativeGeometryGroupWrapper::boost_python_expose(); 56 | NativeGroupWrapper::boost_python_expose(); 57 | NativeGeometryInstanceWrapper::boost_python_expose(); 58 | 59 | /* 60 | * ENUMs 61 | */ 62 | boost::python::enum_("RTformat") 63 | .value("RT_FORMAT_UNKNOWN", RT_FORMAT_UNKNOWN) 64 | .value("RT_FORMAT_FLOAT", RT_FORMAT_FLOAT) 65 | .value("RT_FORMAT_FLOAT2", RT_FORMAT_FLOAT2) 66 | .value("RT_FORMAT_FLOAT3", RT_FORMAT_FLOAT3) 67 | .value("RT_FORMAT_FLOAT4", RT_FORMAT_FLOAT4) 68 | .value("RT_FORMAT_BYTE", RT_FORMAT_BYTE) 69 | .value("RT_FORMAT_BYTE2", RT_FORMAT_BYTE2) 70 | .value("RT_FORMAT_BYTE3", RT_FORMAT_BYTE3) 71 | .value("RT_FORMAT_BYTE4", RT_FORMAT_BYTE4) 72 | .value("RT_FORMAT_UNSIGNED_BYTE", RT_FORMAT_UNSIGNED_BYTE) 73 | .value("RT_FORMAT_UNSIGNED_BYTE2", RT_FORMAT_UNSIGNED_BYTE2) 74 | .value("RT_FORMAT_UNSIGNED_BYTE3", RT_FORMAT_UNSIGNED_BYTE3) 75 | .value("RT_FORMAT_UNSIGNED_BYTE4", RT_FORMAT_UNSIGNED_BYTE4) 76 | .value("RT_FORMAT_SHORT", RT_FORMAT_SHORT) 77 | .value("RT_FORMAT_SHORT2", RT_FORMAT_SHORT2) 78 | .value("RT_FORMAT_SHORT3", RT_FORMAT_SHORT3) 79 | .value("RT_FORMAT_SHORT4", RT_FORMAT_SHORT4) 80 | .value("RT_FORMAT_UNSIGNED_SHORT", RT_FORMAT_UNSIGNED_SHORT) 81 | .value("RT_FORMAT_UNSIGNED_SHORT2", RT_FORMAT_UNSIGNED_SHORT2) 82 | .value("RT_FORMAT_UNSIGNED_SHORT3", RT_FORMAT_UNSIGNED_SHORT3) 83 | .value("RT_FORMAT_UNSIGNED_SHORT4", RT_FORMAT_UNSIGNED_SHORT4) 84 | .value("RT_FORMAT_INT", RT_FORMAT_INT) 85 | .value("RT_FORMAT_INT2", RT_FORMAT_INT2) 86 | .value("RT_FORMAT_INT3", RT_FORMAT_INT3) 87 | .value("RT_FORMAT_INT4", RT_FORMAT_INT4) 88 | .value("RT_FORMAT_UNSIGNED_INT", RT_FORMAT_UNSIGNED_INT) 89 | .value("RT_FORMAT_UNSIGNED_INT2", RT_FORMAT_UNSIGNED_INT2) 90 | .value("RT_FORMAT_UNSIGNED_INT3", RT_FORMAT_UNSIGNED_INT3) 91 | .value("RT_FORMAT_UNSIGNED_INT4", RT_FORMAT_UNSIGNED_INT4) 92 | .value("RT_FORMAT_USER", RT_FORMAT_USER) 93 | .value("RT_FORMAT_BUFFER_ID", RT_FORMAT_BUFFER_ID) 94 | .value("RT_FORMAT_PROGRAM_ID", RT_FORMAT_PROGRAM_ID); 95 | 96 | boost::python::enum_("RTbuffertype") 97 | .value("RT_BUFFER_INPUT", RT_BUFFER_INPUT) 98 | .value("RT_BUFFER_OUTPUT", RT_BUFFER_OUTPUT) 99 | .value("RT_BUFFER_INPUT_OUTPUT", RT_BUFFER_INPUT_OUTPUT); 100 | 101 | boost::python::enum_("RTbufferflag") 102 | .value("RT_BUFFER_GPU_LOCAL", RT_BUFFER_GPU_LOCAL) 103 | .value("RT_BUFFER_COPY_ON_DIRTY", RT_BUFFER_COPY_ON_DIRTY); 104 | 105 | boost::python::enum_("RTwrapmode") 106 | .value("RT_WRAP_REPEAT", RT_WRAP_REPEAT) 107 | .value("RT_WRAP_CLAMP_TO_EDGE", RT_WRAP_CLAMP_TO_EDGE) 108 | .value("RT_WRAP_MIRROR", RT_WRAP_MIRROR) 109 | .value("RT_WRAP_CLAMP_TO_BORDER", RT_WRAP_CLAMP_TO_BORDER); 110 | 111 | boost::python::enum_("RTfiltermode") 112 | .value("RT_FILTER_NEAREST", RT_FILTER_NEAREST) 113 | .value("RT_FILTER_LINEAR", RT_FILTER_LINEAR) 114 | .value("RT_FILTER_NONE", RT_FILTER_NONE); 115 | 116 | boost::python::enum_("RTtexturereadmode") 117 | .value("RT_TEXTURE_READ_ELEMENT_TYPE", RT_TEXTURE_READ_ELEMENT_TYPE) 118 | .value("RT_TEXTURE_READ_NORMALIZED_FLOAT", RT_TEXTURE_READ_NORMALIZED_FLOAT); 119 | 120 | boost::python::enum_("RTtextureindexmode") 121 | .value("RT_TEXTURE_INDEX_NORMALIZED_COORDINATES", RT_TEXTURE_INDEX_NORMALIZED_COORDINATES) 122 | .value("RT_TEXTURE_INDEX_ARRAY_INDEX", RT_TEXTURE_INDEX_ARRAY_INDEX); 123 | 124 | boost::python::enum_("RTexception") 125 | .value("RT_EXCEPTION_PROGRAM_ID_INVALID", RT_EXCEPTION_PROGRAM_ID_INVALID) 126 | .value("RT_EXCEPTION_TEXTURE_ID_INVALID", RT_EXCEPTION_TEXTURE_ID_INVALID) 127 | .value("RT_EXCEPTION_BUFFER_ID_INVALID", RT_EXCEPTION_BUFFER_ID_INVALID) 128 | .value("RT_EXCEPTION_INDEX_OUT_OF_BOUNDS", RT_EXCEPTION_INDEX_OUT_OF_BOUNDS) 129 | .value("RT_EXCEPTION_STACK_OVERFLOW", RT_EXCEPTION_STACK_OVERFLOW) 130 | .value("RT_EXCEPTION_BUFFER_INDEX_OUT_OF_BOUNDS", RT_EXCEPTION_BUFFER_INDEX_OUT_OF_BOUNDS) 131 | .value("RT_EXCEPTION_INVALID_RAY", RT_EXCEPTION_INVALID_RAY) 132 | .value("RT_EXCEPTION_INTERNAL_ERROR", RT_EXCEPTION_INTERNAL_ERROR) 133 | .value("RT_EXCEPTION_USER", RT_EXCEPTION_USER) 134 | .value("RT_EXCEPTION_ALL", RT_EXCEPTION_ALL); 135 | 136 | boost::python::enum_("RTobjecttype") 137 | .value("RT_OBJECTTYPE_UNKNOWN", RT_OBJECTTYPE_UNKNOWN) 138 | .value("RT_OBJECTTYPE_GROUP", RT_OBJECTTYPE_GROUP) 139 | .value("RT_OBJECTTYPE_GEOMETRY_GROUP", RT_OBJECTTYPE_GEOMETRY_GROUP) 140 | .value("RT_OBJECTTYPE_TRANSFORM", RT_OBJECTTYPE_TRANSFORM) 141 | .value("RT_OBJECTTYPE_SELECTOR", RT_OBJECTTYPE_SELECTOR) 142 | .value("RT_OBJECTTYPE_GEOMETRY_INSTANCE", RT_OBJECTTYPE_GEOMETRY_INSTANCE) 143 | .value("RT_OBJECTTYPE_BUFFER", RT_OBJECTTYPE_BUFFER) 144 | .value("RT_OBJECTTYPE_TEXTURE_SAMPLER", RT_OBJECTTYPE_TEXTURE_SAMPLER) 145 | .value("RT_OBJECTTYPE_OBJECT", RT_OBJECTTYPE_OBJECT) 146 | .value("RT_OBJECTTYPE_MATRIX_FLOAT2x2", RT_OBJECTTYPE_MATRIX_FLOAT2x2) 147 | .value("RT_OBJECTTYPE_MATRIX_FLOAT2x3", RT_OBJECTTYPE_MATRIX_FLOAT2x3) 148 | .value("RT_OBJECTTYPE_MATRIX_FLOAT2x4", RT_OBJECTTYPE_MATRIX_FLOAT2x4) 149 | .value("RT_OBJECTTYPE_MATRIX_FLOAT3x2", RT_OBJECTTYPE_MATRIX_FLOAT3x2) 150 | .value("RT_OBJECTTYPE_MATRIX_FLOAT3x3", RT_OBJECTTYPE_MATRIX_FLOAT3x3) 151 | .value("RT_OBJECTTYPE_MATRIX_FLOAT3x4", RT_OBJECTTYPE_MATRIX_FLOAT3x4) 152 | .value("RT_OBJECTTYPE_MATRIX_FLOAT4x2", RT_OBJECTTYPE_MATRIX_FLOAT4x2) 153 | .value("RT_OBJECTTYPE_MATRIX_FLOAT4x3", RT_OBJECTTYPE_MATRIX_FLOAT4x3) 154 | .value("RT_OBJECTTYPE_MATRIX_FLOAT4x4", RT_OBJECTTYPE_MATRIX_FLOAT4x4) 155 | .value("RT_OBJECTTYPE_FLOAT", RT_OBJECTTYPE_FLOAT) 156 | .value("RT_OBJECTTYPE_FLOAT2", RT_OBJECTTYPE_FLOAT2) 157 | .value("RT_OBJECTTYPE_FLOAT3", RT_OBJECTTYPE_FLOAT3) 158 | .value("RT_OBJECTTYPE_FLOAT4", RT_OBJECTTYPE_FLOAT4) 159 | .value("RT_OBJECTTYPE_INT", RT_OBJECTTYPE_INT) 160 | .value("RT_OBJECTTYPE_INT2", RT_OBJECTTYPE_INT2) 161 | .value("RT_OBJECTTYPE_INT3", RT_OBJECTTYPE_INT3) 162 | .value("RT_OBJECTTYPE_INT4", RT_OBJECTTYPE_INT4) 163 | .value("RT_OBJECTTYPE_UNSIGNED_INT", RT_OBJECTTYPE_UNSIGNED_INT) 164 | .value("RT_OBJECTTYPE_UNSIGNED_INT2", RT_OBJECTTYPE_UNSIGNED_INT2) 165 | .value("RT_OBJECTTYPE_UNSIGNED_INT3", RT_OBJECTTYPE_UNSIGNED_INT3) 166 | .value("RT_OBJECTTYPE_UNSIGNED_INT4", RT_OBJECTTYPE_UNSIGNED_INT4) 167 | .value("RT_OBJECTTYPE_USER", RT_OBJECTTYPE_USER) 168 | .value("RT_OBJECTTYPE_PROGRAM", RT_OBJECTTYPE_PROGRAM); 169 | } 170 | -------------------------------------------------------------------------------- /driver/material.cpp: -------------------------------------------------------------------------------- 1 | #include "material.h" 2 | 3 | 4 | NativeMaterialWrapper::NativeMaterialWrapper(optix::Material material) { 5 | this->material = material; 6 | this->set_scoped_object(this->material.get()); 7 | } 8 | 9 | NativeMaterialWrapper::~NativeMaterialWrapper() { 10 | if (!is_destroyed) this->material->destroy(); 11 | } 12 | 13 | void NativeMaterialWrapper::set_closest_hit_program(unsigned int ray_type_index, NativeProgramWrapper* program) { 14 | this->material->setClosestHitProgram(ray_type_index, program->get_native()); 15 | } 16 | 17 | void NativeMaterialWrapper::set_any_hit_program(unsigned int ray_type_index, NativeProgramWrapper* program) { 18 | this->material->setAnyHitProgram(ray_type_index, program->get_native()); 19 | } 20 | 21 | optix::Material NativeMaterialWrapper::get_native() { 22 | return this->material; 23 | } 24 | 25 | void NativeMaterialWrapper::boost_python_expose() { 26 | boost::python::class_ >( 27 | "NativeMaterialWrapper", 28 | "Wraps optix::Material class", 29 | boost::python::no_init) 30 | 31 | .def("set_closest_hit_program", &NativeMaterialWrapper::set_closest_hit_program) 32 | .def("set_any_hit_program", &NativeMaterialWrapper::set_any_hit_program); 33 | } 34 | -------------------------------------------------------------------------------- /driver/material.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "program.h" 4 | #include "scoped.h" 5 | 6 | class NativeMaterialWrapper : public NativeScopedWrapper 7 | { 8 | private: 9 | optix::Material material; 10 | 11 | public: 12 | NativeMaterialWrapper(optix::Material material); 13 | ~NativeMaterialWrapper(); 14 | void set_closest_hit_program(unsigned int ray_type_index, NativeProgramWrapper* program); 15 | void set_any_hit_program(unsigned int ray_type_index, NativeProgramWrapper* program); 16 | optix::Material get_native(); 17 | static void boost_python_expose(); 18 | }; 19 | -------------------------------------------------------------------------------- /driver/program.cpp: -------------------------------------------------------------------------------- 1 | #include "program.h" 2 | 3 | 4 | NativeProgramWrapper::NativeProgramWrapper(optix::Program program) { 5 | this->program = program; 6 | this->set_scoped_object(this->program.get()); 7 | } 8 | 9 | NativeProgramWrapper::~NativeProgramWrapper() { 10 | if (!is_destroyed && auto_destroy) this->program->destroy(); 11 | } 12 | 13 | int NativeProgramWrapper::get_id() { 14 | return this->program->getId(); 15 | } 16 | 17 | optix::Program NativeProgramWrapper::get_native() { 18 | return this->program; 19 | } 20 | 21 | void NativeProgramWrapper::boost_python_expose() { 22 | boost::python::class_ >( 23 | "NativeProgramWrapper", 24 | "Wraps optix::Program class", 25 | boost::python::no_init) 26 | 27 | .def("get_id", &NativeProgramWrapper::get_id); 28 | } 29 | -------------------------------------------------------------------------------- /driver/program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "scoped.h" 4 | 5 | 6 | class NativeProgramWrapper : public NativeScopedWrapper 7 | { 8 | private: 9 | optix::Program program; 10 | 11 | public: 12 | NativeProgramWrapper(optix::Program program); 13 | ~NativeProgramWrapper(); 14 | int get_id(); 15 | optix::Program get_native(); 16 | static void boost_python_expose(); 17 | }; 18 | -------------------------------------------------------------------------------- /driver/scoped.cpp: -------------------------------------------------------------------------------- 1 | #include "scoped.h" 2 | 3 | 4 | void NativeScopedWrapper::set_scoped_object(optix::ScopedObj* scoped_object) { 5 | this->scoped_object = scoped_object; 6 | this->set_destroyable_object(scoped_object); 7 | } 8 | 9 | NativeVariableWrapper* NativeScopedWrapper::query_variable(const std::string& name) { 10 | optix::Variable variable = this->scoped_object->queryVariable(name); 11 | if (variable == 0) 12 | return nullptr; 13 | else 14 | return new NativeVariableWrapper(variable); 15 | } 16 | 17 | NativeVariableWrapper* NativeScopedWrapper::declare_variable(const std::string& name) { 18 | return new NativeVariableWrapper(this->scoped_object->declareVariable(name)); 19 | } 20 | 21 | NativeVariableWrapper* NativeScopedWrapper::get_variable(int index) { 22 | optix::Variable variable = this->scoped_object->getVariable(index); 23 | return new NativeVariableWrapper(variable); 24 | } 25 | 26 | void NativeScopedWrapper::remove_variable(NativeVariableWrapper* variable_wrapper) { 27 | this->scoped_object->removeVariable(variable_wrapper->get_native()); 28 | } 29 | 30 | unsigned int NativeScopedWrapper::get_variable_count() { 31 | return this->scoped_object->getVariableCount(); 32 | } 33 | 34 | void NativeScopedWrapper::boost_python_expose() { 35 | namespace bp = boost::python; 36 | 37 | bp::class_ >( 38 | "NativeScopedWrapper", 39 | "Wraps optix::Scoped class", 40 | bp::no_init) 41 | 42 | .def("declare_variable", &NativeScopedWrapper::declare_variable, bp::return_value_policy()) 43 | .def("query_variable", &NativeScopedWrapper::query_variable, bp::return_value_policy()) 44 | .def("get_variable", &NativeScopedWrapper::get_variable, bp::return_value_policy()) 45 | .def("remove_variable", &NativeScopedWrapper::remove_variable) 46 | .def("get_variable_count", &NativeScopedWrapper::get_variable_count); 47 | } 48 | -------------------------------------------------------------------------------- /driver/scoped.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "variable.h" 4 | #include "destroyable.h" 5 | 6 | class NativeScopedWrapper : public NativeDestroyableWrapper 7 | { 8 | private: 9 | optix::ScopedObj* scoped_object; 10 | 11 | protected: 12 | void set_scoped_object(optix::ScopedObj* scoped_object); 13 | 14 | public: 15 | NativeVariableWrapper* query_variable(const std::string& name); 16 | NativeVariableWrapper* declare_variable(const std::string& name); 17 | NativeVariableWrapper* get_variable(int index); 18 | void remove_variable(NativeVariableWrapper* variable_wrapper); 19 | unsigned int get_variable_count(); 20 | static void boost_python_expose(); 21 | }; 22 | -------------------------------------------------------------------------------- /driver/selector.cpp: -------------------------------------------------------------------------------- 1 | #include "selector.h" 2 | 3 | 4 | NativeSelectorWrapper::NativeSelectorWrapper(optix::Selector selector){ 5 | this->selector = selector; 6 | this->set_destroyable_object(this->selector.get()); 7 | } 8 | 9 | NativeSelectorWrapper::~NativeSelectorWrapper() { 10 | if (!is_destroyed) this->selector->destroy(); 11 | } 12 | 13 | void NativeSelectorWrapper::set_visit_program(NativeProgramWrapper* program) { 14 | this->selector->setVisitProgram(program->get_native()); 15 | } 16 | 17 | void NativeSelectorWrapper::set_child_count(unsigned int count) { 18 | this->selector->setChildCount(count); 19 | } 20 | 21 | unsigned int NativeSelectorWrapper::get_child_count() { 22 | return this->selector->getChildCount(); 23 | } 24 | 25 | void NativeSelectorWrapper::set_child_geometry_group(unsigned int index, NativeGeometryGroupWrapper* child) { 26 | this->selector->setChild(index, child->get_native()); 27 | } 28 | 29 | void NativeSelectorWrapper::set_child_group(unsigned int index, NativeGroupWrapper* child) { 30 | this->selector->setChild(index, child->get_native()); 31 | } 32 | 33 | void NativeSelectorWrapper::set_child_selector(unsigned int index, NativeSelectorWrapper* child) { 34 | this->selector->setChild(index, child->get_native()); 35 | } 36 | 37 | void NativeSelectorWrapper::set_child_transform(unsigned int index, NativeTransformWrapper* child) { 38 | this->selector->setChild(index, child->get_native()); 39 | } 40 | 41 | void NativeSelectorWrapper::remove_child(unsigned int index) { 42 | this->selector->removeChild(index); 43 | } 44 | 45 | optix::Selector NativeSelectorWrapper::get_native() { 46 | return this->selector; 47 | } 48 | 49 | void NativeSelectorWrapper::boost_python_expose() { 50 | boost::python::class_ >( 51 | "NativeSelectorWrapper", 52 | "Wraps optix::Selector class", 53 | boost::python::no_init) 54 | 55 | .def("set_visit_program", &NativeSelectorWrapper::set_visit_program) 56 | .def("set_child_count", &NativeSelectorWrapper::set_child_count) 57 | .def("get_child_count", &NativeSelectorWrapper::get_child_count) 58 | .def("set_child_geometry_group", &NativeSelectorWrapper::set_child_geometry_group) 59 | .def("set_child_group", &NativeSelectorWrapper::set_child_group) 60 | .def("set_child_selector", &NativeSelectorWrapper::set_child_selector) 61 | .def("remove_child", &NativeSelectorWrapper::remove_child); 62 | } 63 | -------------------------------------------------------------------------------- /driver/selector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "geometry_group.h" 4 | #include "group.h" 5 | #include "program.h" 6 | #include "transform.h" 7 | #include "scoped.h" 8 | #include "destroyable.h" 9 | 10 | 11 | class NativeSelectorWrapper : public NativeDestroyableWrapper 12 | { 13 | private: 14 | optix::Selector selector; 15 | 16 | public: 17 | NativeSelectorWrapper(optix::Selector selector); 18 | ~NativeSelectorWrapper(); 19 | void set_visit_program(NativeProgramWrapper* program); 20 | void set_child_count(unsigned int count); 21 | unsigned int get_child_count(); 22 | void set_child_geometry_group(unsigned int index, NativeGeometryGroupWrapper* child); 23 | void set_child_group(unsigned int index, NativeGroupWrapper* child); 24 | void set_child_selector(unsigned int index, NativeSelectorWrapper* child); 25 | void set_child_transform(unsigned int index, NativeTransformWrapper* child); 26 | void remove_child(unsigned int index); 27 | optix::Selector get_native(); 28 | static void boost_python_expose(); 29 | }; 30 | -------------------------------------------------------------------------------- /driver/shared_includes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | -------------------------------------------------------------------------------- /driver/texture_sampler.cpp: -------------------------------------------------------------------------------- 1 | #include "texture_sampler.h" 2 | 3 | 4 | NativeTextureSamplerWrapper::NativeTextureSamplerWrapper(optix::TextureSampler texture_sampler) { 5 | this->texture_sampler = texture_sampler; 6 | this->set_destroyable_object(this->texture_sampler.get()); 7 | } 8 | 9 | NativeTextureSamplerWrapper::~NativeTextureSamplerWrapper() { 10 | if (!is_destroyed && auto_destroy) this->texture_sampler->destroy(); 11 | } 12 | 13 | void NativeTextureSamplerWrapper::set_mip_level_clamp(float min_level, float max_level) { 14 | #if OPTIX_VERSION < 3090 15 | PyErr_SetString(PyExc_NotImplementedError, "OptiX versions before 3.9.0 don't have mipmapping functions"); 16 | boost::python::throw_error_already_set(); 17 | #else 18 | this->texture_sampler->setMipLevelClamp(min_level, max_level); 19 | #endif 20 | } 21 | 22 | std::vector NativeTextureSamplerWrapper::get_mip_level_clamp() { 23 | #if OPTIX_VERSION < 3090 24 | PyErr_SetString(PyExc_NotImplementedError, "OptiX versions before 3.9.0 don't have mipmapping functions"); 25 | boost::python::throw_error_already_set(); 26 | return std::vector(); 27 | #else 28 | std::vector res = std::vector(); 29 | float min_level, max_level; 30 | this->texture_sampler->getMipLevelClamp(min_level, max_level); 31 | res.push_back(float(min_level)); 32 | res.push_back(float(max_level)); 33 | return res; 34 | #endif 35 | } 36 | 37 | void NativeTextureSamplerWrapper::set_mip_level_bias(float bias_value) { 38 | #if OPTIX_VERSION < 3090 39 | PyErr_SetString(PyExc_NotImplementedError, "OptiX versions before 3.9.0 don't have mipmapping functions"); 40 | boost::python::throw_error_already_set(); 41 | #else 42 | this->texture_sampler->setMipLevelBias(bias_value); 43 | #endif 44 | } 45 | 46 | float NativeTextureSamplerWrapper::get_mip_level_bias() { 47 | #if OPTIX_VERSION < 3090 48 | PyErr_SetString(PyExc_NotImplementedError, "OptiX versions before 3.9.0 don't have mipmapping functions"); 49 | boost::python::throw_error_already_set(); 50 | return 0.0; 51 | #else 52 | return this->texture_sampler->getMipLevelBias(); 53 | #endif 54 | } 55 | 56 | void NativeTextureSamplerWrapper::set_mip_level_count(unsigned int num_mip_levels) { 57 | this->texture_sampler->setMipLevelCount(num_mip_levels); 58 | } 59 | 60 | unsigned int NativeTextureSamplerWrapper::get_mip_level_count() { 61 | return this->texture_sampler->getMipLevelCount(); 62 | } 63 | 64 | void NativeTextureSamplerWrapper::set_array_size(unsigned int num_textures_in_array) { 65 | this->texture_sampler->setArraySize(num_textures_in_array); 66 | } 67 | 68 | unsigned int NativeTextureSamplerWrapper::get_array_size() { 69 | return this->texture_sampler->getArraySize(); 70 | } 71 | 72 | void NativeTextureSamplerWrapper::set_wrap_mode(unsigned int dim, RTwrapmode wrapmode) { 73 | this->texture_sampler->setWrapMode(dim, wrapmode); 74 | } 75 | 76 | RTwrapmode NativeTextureSamplerWrapper::get_wrap_mode(unsigned int dim) { 77 | return this->texture_sampler->getWrapMode(dim); 78 | } 79 | 80 | void NativeTextureSamplerWrapper::set_max_anisotropy(float value) { 81 | this->texture_sampler->setMaxAnisotropy(value); 82 | } 83 | 84 | float NativeTextureSamplerWrapper::get_max_anisotropy() { 85 | return this->texture_sampler->getMaxAnisotropy(); 86 | } 87 | 88 | void NativeTextureSamplerWrapper::set_read_mode(RTtexturereadmode readmode) { 89 | this->texture_sampler->setReadMode(readmode); 90 | } 91 | 92 | RTtexturereadmode NativeTextureSamplerWrapper::get_read_mode() { 93 | return this->texture_sampler->getReadMode(); 94 | } 95 | 96 | void NativeTextureSamplerWrapper::set_indexing_mode(RTtextureindexmode indexmode) { 97 | this->texture_sampler->setIndexingMode(indexmode); 98 | } 99 | 100 | RTtextureindexmode NativeTextureSamplerWrapper::get_indexing_mode() { 101 | return this->texture_sampler->getIndexingMode(); 102 | } 103 | 104 | void NativeTextureSamplerWrapper::set_filtering_modes(RTfiltermode minification, RTfiltermode magnification, RTfiltermode mipmapping) { 105 | this->texture_sampler->setFilteringModes(minification, magnification, mipmapping); 106 | } 107 | 108 | int NativeTextureSamplerWrapper::get_id() { 109 | return this->texture_sampler->getId(); 110 | } 111 | 112 | void NativeTextureSamplerWrapper::set_buffer(unsigned int texture_array_idx, unsigned int mip_level, NativeBufferWrapper* buffer) { 113 | this->texture_sampler->setBuffer(texture_array_idx, mip_level, buffer->get_native_buffer()); 114 | } 115 | 116 | optix::TextureSampler NativeTextureSamplerWrapper::get_native() { 117 | return this->texture_sampler; 118 | } 119 | 120 | void NativeTextureSamplerWrapper::boost_python_expose() { 121 | boost::python::class_ >( 122 | "NativeTextureSamplerWrapper", 123 | "Wraps optix::TextureSampler class", 124 | boost::python::no_init) 125 | 126 | .def("get_id", &NativeTextureSamplerWrapper::get_id) 127 | .def("set_mip_level_clamp", &NativeTextureSamplerWrapper::set_mip_level_clamp) 128 | .def("get_mip_level_clamp", &NativeTextureSamplerWrapper::get_mip_level_clamp) 129 | .def("set_mip_level_bias", &NativeTextureSamplerWrapper::set_mip_level_bias) 130 | .def("get_mip_level_bias", &NativeTextureSamplerWrapper::get_mip_level_bias) 131 | .def("set_max_anisotropy", &NativeTextureSamplerWrapper::set_max_anisotropy) 132 | .def("get_max_anisotropy", &NativeTextureSamplerWrapper::get_max_anisotropy) 133 | .def("set_mip_level_count", &NativeTextureSamplerWrapper::set_mip_level_count) 134 | .def("get_mip_level_count", &NativeTextureSamplerWrapper::get_mip_level_count) 135 | .def("set_array_size", &NativeTextureSamplerWrapper::set_array_size) 136 | .def("get_array_size", &NativeTextureSamplerWrapper::get_array_size) 137 | .def("set_wrap_mode", &NativeTextureSamplerWrapper::set_wrap_mode) 138 | .def("get_wrap_mode", &NativeTextureSamplerWrapper::get_wrap_mode) 139 | .def("set_read_mode", &NativeTextureSamplerWrapper::set_read_mode) 140 | .def("get_read_mode", &NativeTextureSamplerWrapper::get_read_mode) 141 | .def("set_indexing_mode", &NativeTextureSamplerWrapper::set_indexing_mode) 142 | .def("get_indexing_mode", &NativeTextureSamplerWrapper::get_indexing_mode) 143 | .def("set_filtering_modes", &NativeTextureSamplerWrapper::set_filtering_modes) 144 | .def("set_buffer", &NativeTextureSamplerWrapper::set_buffer); 145 | } 146 | -------------------------------------------------------------------------------- /driver/texture_sampler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "buffer.h" 4 | #include "destroyable.h" 5 | 6 | 7 | class NativeTextureSamplerWrapper : public NativeDestroyableWrapper 8 | { 9 | private: 10 | optix::TextureSampler texture_sampler; 11 | 12 | public: 13 | NativeTextureSamplerWrapper(optix::TextureSampler texture_sampler); 14 | ~NativeTextureSamplerWrapper(); 15 | int get_id(); 16 | void set_mip_level_clamp(float min_level, float max_level); 17 | std::vector get_mip_level_clamp(); 18 | void set_mip_level_bias(float bias_value); 19 | float get_mip_level_bias(); 20 | void set_mip_level_count(unsigned int num_mip_levels); 21 | unsigned int get_mip_level_count(); 22 | void set_array_size(unsigned int num_textures_in_array); 23 | unsigned int get_array_size(); 24 | void set_wrap_mode(unsigned int dim, RTwrapmode wrapmode); 25 | RTwrapmode get_wrap_mode(unsigned int dim); 26 | void set_max_anisotropy(float value); 27 | float get_max_anisotropy(); 28 | void set_read_mode(RTtexturereadmode readmode); 29 | RTtexturereadmode get_read_mode(); 30 | void set_indexing_mode(RTtextureindexmode indexmode); 31 | RTtextureindexmode get_indexing_mode(); 32 | void set_filtering_modes(RTfiltermode minification, RTfiltermode magnification, RTfiltermode mipmapping); 33 | void set_buffer(unsigned int texture_array_idx, unsigned int mip_level, NativeBufferWrapper* buffer); 34 | optix::TextureSampler get_native(); 35 | static void boost_python_expose(); 36 | }; 37 | -------------------------------------------------------------------------------- /driver/transform.cpp: -------------------------------------------------------------------------------- 1 | #include "transform.h" 2 | #include "selector.h" 3 | #include "group.h" 4 | #include "geometry_group.h" 5 | 6 | 7 | NativeTransformWrapper::NativeTransformWrapper(optix::Transform transform) { 8 | this->transform = transform; 9 | this->set_destroyable_object(this->transform.get()); 10 | } 11 | 12 | NativeTransformWrapper::~NativeTransformWrapper() { 13 | if (!is_destroyed) this->transform->destroy(); 14 | } 15 | 16 | void NativeTransformWrapper::set_matrix(bool transpose, boost::python::list& matrix) { 17 | float flat_matrix[16]; 18 | int i, j; 19 | 20 | for (i=0; i<4; i++) { 21 | for (j=0; j<4; j++) { 22 | flat_matrix[4*i+j] = boost::python::extract(matrix[i][j]); 23 | } 24 | } 25 | 26 | this->transform->setMatrix(transpose, flat_matrix, NULL); 27 | } 28 | 29 | boost::python::list NativeTransformWrapper::get_matrix(bool transpose) { 30 | float flat_matrix[16]; 31 | this->transform->getMatrix(transpose, flat_matrix, NULL); 32 | boost::python::list matrix; 33 | int i, j; 34 | 35 | for (i=0; i<4; i++) { 36 | boost::python::list row; 37 | for (j=0; j<4; j++) { 38 | row.append(flat_matrix[4*i+j]); 39 | } 40 | matrix.append(row); 41 | } 42 | 43 | return matrix; 44 | } 45 | 46 | void NativeTransformWrapper::set_child_geometry_group(unsigned int index, NativeGeometryGroupWrapper* child) { 47 | this->transform->setChild(child->get_native()); 48 | } 49 | 50 | void NativeTransformWrapper::set_child_group(unsigned int index, NativeGroupWrapper* child) { 51 | this->transform->setChild(child->get_native()); 52 | } 53 | 54 | void NativeTransformWrapper::set_child_selector(unsigned int index, NativeSelectorWrapper* child) { 55 | this->transform->setChild(child->get_native()); 56 | } 57 | 58 | void NativeTransformWrapper::set_child_transform(unsigned int index, NativeGeometryGroupWrapper* child) { 59 | this->transform->setChild(child->get_native()); 60 | } 61 | 62 | optix::Transform NativeTransformWrapper::get_native() { 63 | return this->transform; 64 | } 65 | 66 | void NativeTransformWrapper::boost_python_expose() { 67 | boost::python::class_ >( 68 | "NativeTransformWrapper", 69 | "Wraps optix::Transform class", 70 | boost::python::no_init) 71 | 72 | .def("set_matrix", &NativeTransformWrapper::set_matrix) 73 | .def("get_matrix", &NativeTransformWrapper::get_matrix) 74 | .def("set_child_geometry_group", &NativeTransformWrapper::set_child_geometry_group) 75 | .def("set_child_group", &NativeTransformWrapper::set_child_group) 76 | .def("set_child_selector", &NativeTransformWrapper::set_child_selector) 77 | .def("set_child_transform", &NativeTransformWrapper::set_child_transform); 78 | } 79 | -------------------------------------------------------------------------------- /driver/transform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | #include "program.h" 4 | #include "destroyable.h" 5 | 6 | class NativeSelectorWrapper; 7 | class NativeGroupWrapper; 8 | class NativeGeometryGroupWrapper; 9 | 10 | class NativeTransformWrapper : public NativeDestroyableWrapper 11 | { 12 | private: 13 | optix::Transform transform; 14 | 15 | public: 16 | NativeTransformWrapper(optix::Transform transform); 17 | ~NativeTransformWrapper(); 18 | void set_matrix(bool transpose, boost::python::list &matrix); 19 | boost::python::list get_matrix(bool transpose); 20 | void set_child_geometry_group(unsigned int index, NativeGeometryGroupWrapper* child); 21 | void set_child_group(unsigned int index, NativeGroupWrapper* child); 22 | void set_child_selector(unsigned int index, NativeSelectorWrapper* child); 23 | void set_child_transform(unsigned int index, NativeGeometryGroupWrapper* child); 24 | optix::Transform get_native(); 25 | static void boost_python_expose(); 26 | }; 27 | -------------------------------------------------------------------------------- /driver/variable.cpp: -------------------------------------------------------------------------------- 1 | #include "variable.h" 2 | #include "buffer.h" 3 | #include "texture_sampler.h" 4 | #include "group.h" 5 | #include "geometry_group.h" 6 | #include "transform.h" 7 | #include "selector.h" 8 | #include "program.h" 9 | 10 | 11 | NativeVariableWrapper::NativeVariableWrapper(optix::Variable variable) { 12 | this->variable = variable; 13 | } 14 | 15 | NativeVariableWrapper::~NativeVariableWrapper() { 16 | } 17 | 18 | bool NativeVariableWrapper::is_valid() { 19 | if (this->variable == 0) 20 | return false; 21 | else 22 | return true; 23 | } 24 | 25 | std::string NativeVariableWrapper::get_name() { 26 | return this->variable->getName(); 27 | } 28 | 29 | std::string NativeVariableWrapper::get_annotation() { 30 | return this->variable->getAnnotation(); 31 | } 32 | 33 | RTobjecttype NativeVariableWrapper::get_type() { 34 | return this->variable->getType(); 35 | } 36 | 37 | unsigned long NativeVariableWrapper::get_size_in_bytes() { 38 | return this->variable->getSize(); 39 | } 40 | 41 | void NativeVariableWrapper::set_buffer(NativeBufferWrapper* buffer_wrapper) { 42 | this->variable->setBuffer(buffer_wrapper->get_native_buffer()); 43 | } 44 | 45 | void NativeVariableWrapper::set_texture(NativeTextureSamplerWrapper* texture_wrapper) { 46 | this->variable->setTextureSampler(texture_wrapper->get_native()); 47 | } 48 | 49 | void NativeVariableWrapper::set_group(NativeGroupWrapper* group_wrapper) { 50 | this->variable->set(group_wrapper->get_native()); 51 | } 52 | 53 | void NativeVariableWrapper::set_geometry_group(NativeGeometryGroupWrapper* geometry_group_wrapper) { 54 | this->variable->set(geometry_group_wrapper->get_native()); 55 | } 56 | 57 | void NativeVariableWrapper::set_transform(NativeTransformWrapper* transform_wrapper) { 58 | this->variable->set(transform_wrapper->get_native()); 59 | } 60 | 61 | void NativeVariableWrapper::set_selector(NativeSelectorWrapper* selector_wrapper) { 62 | this->variable->set(selector_wrapper->get_native()); 63 | } 64 | 65 | void NativeVariableWrapper::set_program_id_with_program(NativeProgramWrapper* program_wrapper) { 66 | this->variable->setProgramId(program_wrapper->get_native()); 67 | } 68 | 69 | void NativeVariableWrapper::set_from_array(PyObject* array, RTobjecttype object_type) { 70 | Py_buffer pb; 71 | PyObject_GetBuffer(array, &pb, PyBUF_SIMPLE); 72 | 73 | switch(object_type) 74 | { 75 | case RT_OBJECTTYPE_FLOAT: 76 | this->variable->setFloat(((float*)pb.buf)[0]); 77 | break; 78 | case RT_OBJECTTYPE_FLOAT2: 79 | this->variable->setFloat(((optix::float2*)pb.buf)[0]); 80 | break; 81 | case RT_OBJECTTYPE_FLOAT3: 82 | this->variable->setFloat(((optix::float3*)pb.buf)[0]); 83 | break; 84 | case RT_OBJECTTYPE_FLOAT4: 85 | this->variable->setFloat(((optix::float4*)pb.buf)[0]); 86 | break; 87 | case RT_OBJECTTYPE_INT: 88 | this->variable->setInt(((int*)pb.buf)[0]); 89 | break; 90 | case RT_OBJECTTYPE_INT2: 91 | this->variable->setInt(((optix::int2*)pb.buf)[0]); 92 | break; 93 | case RT_OBJECTTYPE_INT3: 94 | this->variable->setInt(((optix::int3*)pb.buf)[0]); 95 | break; 96 | case RT_OBJECTTYPE_INT4: 97 | this->variable->setInt(((optix::int4*)pb.buf)[0]); 98 | break; 99 | case RT_OBJECTTYPE_UNSIGNED_INT: 100 | this->variable->setUint(((unsigned int*)pb.buf)[0]); 101 | break; 102 | case RT_OBJECTTYPE_UNSIGNED_INT2: 103 | this->variable->setUint(((optix::uint2*)pb.buf)[0]); 104 | break; 105 | case RT_OBJECTTYPE_UNSIGNED_INT3: 106 | this->variable->setUint(((optix::uint3*)pb.buf)[0]); 107 | break; 108 | case RT_OBJECTTYPE_UNSIGNED_INT4: 109 | this->variable->setUint(((optix::uint4*)pb.buf)[0]); 110 | break; 111 | case RT_OBJECTTYPE_MATRIX_FLOAT2x2: 112 | this->variable->setMatrix2x2fv(false, (float*) pb.buf); 113 | break; 114 | case RT_OBJECTTYPE_MATRIX_FLOAT2x3: 115 | this->variable->setMatrix2x3fv(false, (float*) pb.buf); 116 | break; 117 | case RT_OBJECTTYPE_MATRIX_FLOAT2x4: 118 | this->variable->setMatrix2x4fv(false, (float*) pb.buf); 119 | break; 120 | case RT_OBJECTTYPE_MATRIX_FLOAT3x2: 121 | this->variable->setMatrix3x2fv(false, (float*) pb.buf); 122 | break; 123 | case RT_OBJECTTYPE_MATRIX_FLOAT3x3: 124 | this->variable->setMatrix3x3fv(false, (float*) pb.buf); 125 | break; 126 | case RT_OBJECTTYPE_MATRIX_FLOAT3x4: 127 | this->variable->setMatrix3x4fv(false, (float*) pb.buf); 128 | break; 129 | case RT_OBJECTTYPE_MATRIX_FLOAT4x2: 130 | this->variable->setMatrix4x2fv(false, (float*) pb.buf); 131 | break; 132 | case RT_OBJECTTYPE_MATRIX_FLOAT4x3: 133 | this->variable->setMatrix4x3fv(false, (float*) pb.buf); 134 | break; 135 | case RT_OBJECTTYPE_MATRIX_FLOAT4x4: 136 | this->variable->setMatrix4x4fv(false, (float*) pb.buf); 137 | break; 138 | case RT_OBJECTTYPE_USER: 139 | this->variable->setUserData(pb.len, pb.buf); 140 | break; 141 | default: 142 | PyErr_SetString(PyExc_RuntimeError, "Cannot assign variable"); 143 | boost::python::throw_error_already_set(); 144 | }; 145 | 146 | PyBuffer_Release(&pb); 147 | } 148 | 149 | optix::Variable NativeVariableWrapper::get_native() { 150 | return variable; 151 | } 152 | 153 | void NativeVariableWrapper::boost_python_expose() { 154 | boost::python::class_( 155 | "NativeVariableWrapper", 156 | "Wraps optix::Variable class", 157 | boost::python::no_init) 158 | 159 | .add_property("name", &NativeVariableWrapper::get_name) 160 | .add_property("annotation", &NativeVariableWrapper::get_annotation) 161 | .add_property("type", &NativeVariableWrapper::get_type) 162 | .add_property("nbytes", &NativeVariableWrapper::get_size_in_bytes) 163 | .add_property("_native", &NativeVariableWrapper::get_native) 164 | .def("is_valid", &NativeVariableWrapper::is_valid) 165 | .def("set_buffer", &NativeVariableWrapper::set_buffer) 166 | .def("set_texture", &NativeVariableWrapper::set_texture) 167 | .def("set_program_id_with_program", &NativeVariableWrapper::set_program_id_with_program) 168 | .def("set_group", &NativeVariableWrapper::set_group) 169 | .def("set_geometry_group", &NativeVariableWrapper::set_geometry_group) 170 | .def("set_transform", &NativeVariableWrapper::set_transform) 171 | .def("set_selector", &NativeVariableWrapper::set_selector) 172 | .def("set_from_array", &NativeVariableWrapper::set_from_array); 173 | } 174 | -------------------------------------------------------------------------------- /driver/variable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "shared_includes.h" 3 | 4 | class NativeBufferWrapper; 5 | class NativeTextureSamplerWrapper; 6 | class NativeProgramWrapper; 7 | class NativeGroupWrapper; 8 | class NativeGeometryGroupWrapper; 9 | class NativeTransformWrapper; 10 | class NativeSelectorWrapper; 11 | 12 | 13 | class NativeVariableWrapper 14 | { 15 | private: 16 | optix::Variable variable; 17 | 18 | public: 19 | NativeVariableWrapper(optix::Variable variable); 20 | ~NativeVariableWrapper(); 21 | bool is_valid(); 22 | std::string get_name(); 23 | std::string get_annotation(); 24 | RTobjecttype get_type(); 25 | unsigned long get_size_in_bytes(); 26 | void set_buffer(NativeBufferWrapper* buffer_wrapper); 27 | void set_texture(NativeTextureSamplerWrapper* texture_wrapper); 28 | void set_program_id_with_program(NativeProgramWrapper* program_wrapper); 29 | void set_group(NativeGroupWrapper* group_wrapper); 30 | void set_geometry_group(NativeGeometryGroupWrapper* geometry_group_wrapper); 31 | void set_transform(NativeTransformWrapper* transform_wrapper); 32 | void set_selector(NativeSelectorWrapper* selector_wrapper); 33 | void set_from_array(PyObject* array, RTobjecttype object_type); 34 | optix::Variable get_native(); 35 | static void boost_python_expose(); 36 | }; 37 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozen/PyOptiX/c7510ee9d967fe6c22fddcdcdd3b0127e075c8ba/examples/__init__.py -------------------------------------------------------------------------------- /examples/buffers_of_buffers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozen/PyOptiX/c7510ee9d967fe6c22fddcdcdd3b0127e075c8ba/examples/buffers_of_buffers/__init__.py -------------------------------------------------------------------------------- /examples/buffers_of_buffers/buffers_of_buffers.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from os.path import dirname 3 | sys.path.append(dirname(dirname(dirname(__file__)))) 4 | 5 | from random import random as randf 6 | import numpy as np 7 | from PIL import Image 8 | from pyoptix import Context, Buffer, Program, EntryPoint, Geometry, Material, GeometryInstance, GeometryGroup, \ 9 | Acceleration, Compiler 10 | from examples.common import ImageWindow, calculate_camera_variables 11 | from examples.buffers_of_buffers.common_structs import BasicLight 12 | 13 | 14 | width = 512 15 | height = 512 16 | 17 | MAX_BUFFER_WIDTH = 64 18 | MAX_BUFFER_HEIGHT = 32 19 | 20 | Compiler.add_program_directory(dirname(__file__)) 21 | 22 | 23 | def create_random_buffer(max_width, max_height): 24 | scale = randf() 25 | w = int(max(max_width * scale, 1)) 26 | h = int(max(max_height * scale, 1)) 27 | 28 | arr = [] 29 | red, green, blue = randf(), randf(), randf() 30 | 31 | for y in range(h): 32 | arr.append([]) 33 | for x in range(w): 34 | if randf() < 0.1: 35 | arr[y].append([red * 255.0, green * 255.0, blue * 255.0, 255]) 36 | else: 37 | arr[y].append([255, 255, 255, 0]) 38 | 39 | return Buffer.from_array(np.array(arr, dtype=np.uint8), buffer_type='i', drop_last_dim=True) 40 | 41 | 42 | def create_context(): 43 | context = Context() 44 | 45 | context.set_ray_type_count(2) 46 | context.set_stack_size(1200) 47 | context.set_print_enabled(True) 48 | context.set_all_exceptions_enabled(True) 49 | 50 | # here pyoptix won't be able to deduce types of these variables, 51 | # so we must put them inside numpy arrays with proper dtypes 52 | context['max_depth'] = np.array(5, dtype=np.int32) 53 | context['radiance_ray_type'] = np.array(0, dtype=np.uint32) 54 | context['shadow_ray_type'] = np.array(1, dtype=np.uint32) 55 | context['scene_epsilon'] = np.array(1e-4, dtype=np.float32) 56 | 57 | context['output_buffer'] = Buffer.empty((height, width, 4), dtype=np.uint8, buffer_type='o', drop_last_dim=True) 58 | 59 | cam_eye = [2.0, 1.5, -2.0] 60 | lookat = [0.0, 1.2, 0.0] 61 | up = [0.0, 1.0, 0.0] 62 | hfov = 60.0 63 | aspect_ratio = width / height 64 | camera_u, camera_v, camera_w = calculate_camera_variables(cam_eye, lookat, up, hfov, aspect_ratio) 65 | 66 | context['eye'] = np.array(cam_eye, dtype=np.float32) 67 | context['U'] = np.array(camera_u, dtype=np.float32) 68 | context['V'] = np.array(camera_v, dtype=np.float32) 69 | context['W'] = np.array(camera_w, dtype=np.float32) 70 | 71 | ray_gen_program = Program('pinhole_camera.cu', 'pinhole_camera') 72 | exception_program = Program('pinhole_camera.cu', 'exception') 73 | entry_point = EntryPoint(ray_gen_program, exception_program) 74 | 75 | context['bad_color'] = np.array([0, 1, 1], dtype=np.float32) 76 | 77 | context.set_miss_program(0, Program('constantbg.cu', 'miss')) 78 | context['bg_color'] = np.array([0.4, 0.33, 0.21], dtype=np.float32) 79 | 80 | return context, entry_point 81 | 82 | 83 | def create_scene(context, num_buffers): 84 | # Sphere 85 | sphere = Geometry(Program('sphere_texcoord.cu', 'bounds'), Program('sphere_texcoord.cu', 'intersect')) 86 | sphere.set_primitive_count(1) 87 | sphere['sphere'] = np.array([0.0, 1.2, 0.0, 1.0], dtype=np.float32) 88 | sphere['matrix_row_0'] = np.array([1.0, 0.0, 0.0], dtype=np.float32) 89 | sphere['matrix_row_1'] = np.array([0.0, 1.0, 0.0], dtype=np.float32) 90 | sphere['matrix_row_2'] = np.array([0.0, 0.0, 1.0], dtype=np.float32) 91 | 92 | # Floor 93 | parallelogram = Geometry(Program('parallelogram.cu', 'bounds'), Program('parallelogram.cu', 'intersect')) 94 | parallelogram.set_primitive_count(1) 95 | anchor = np.array([-20.0, 0.01, 20.0], dtype=np.float32) 96 | v1 = np.array([40.0, 0.0, 0.0], dtype=np.float32) 97 | v2 = np.array([0.0, 0.0, -40.0], dtype=np.float32) 98 | normal = np.cross(v1, v2) 99 | normal /= np.linalg.norm(normal) 100 | d = np.dot(normal, anchor) 101 | v1 *= 1 / np.dot(v1, v1) 102 | v2 *= 1 / np.dot(v2, v2) 103 | plane = np.append(normal, d) 104 | parallelogram['plane'] = plane 105 | parallelogram['v1'] = v1 106 | parallelogram['v2'] = v2 107 | parallelogram['anchor'] = anchor 108 | 109 | # Sphere material 110 | sphere_matl = Material( 111 | closest_hit={ 112 | 0: Program('optixBuffersOfBuffers.cu', 'closest_hit_radiance') 113 | }, 114 | any_hit={ 115 | 1: Program('optixBuffersOfBuffers.cu', 'any_hit_shadow') 116 | } 117 | ) 118 | 119 | buffers = [create_random_buffer(MAX_BUFFER_WIDTH, MAX_BUFFER_HEIGHT) for _ in range(num_buffers)] 120 | 121 | # mark buffers as bindless so that they won't be destroyed when `buffers` list is garbage-collected 122 | for buffer in buffers: 123 | buffer.bindless = True 124 | 125 | sphere_matl['Kd_layers'] = Buffer.from_array([buf.get_id() for buf in buffers], dtype=np.int32, buffer_type='i') 126 | 127 | # Floor material 128 | floor_matl = Material( 129 | closest_hit={ 130 | 0: Program('phong.cu', 'closest_hit_radiance') 131 | }, 132 | any_hit={ 133 | 1: Program('phong.cu', 'any_hit_shadow') 134 | } 135 | ) 136 | floor_matl['Kd'] = np.array([0.7, 0.7, 0.7], dtype=np.float32) 137 | floor_matl['Ka'] = np.array([1.0, 1.0, 1.0], dtype=np.float32) 138 | floor_matl['Kr'] = np.array([0.0, 0.0, 0.0], dtype=np.float32) 139 | floor_matl['phong_exp'] = np.array(1.0, dtype=np.float32) 140 | 141 | # Place geometry into hierarchy 142 | geometrygroup = GeometryGroup() 143 | geometrygroup.add_child(GeometryInstance(sphere, sphere_matl)) 144 | geometrygroup.add_child(GeometryInstance(parallelogram, floor_matl)) 145 | acc = Acceleration('Sbvh', 'Bvh') 146 | geometrygroup.set_acceleration(acc) 147 | 148 | context['top_object'] = geometrygroup 149 | context['top_shadower'] = geometrygroup 150 | 151 | # Lights 152 | context['ambient_light_color'] = np.array([0.1, 0.1, 0.1], dtype=np.float32) 153 | lights = [ 154 | np.array(BasicLight([0.0, 8.0, -5.0], [0.4, 0.4, 0.4], True)), 155 | np.array(BasicLight([5.0, 8.0, 0.0], [0.4, 0.4, 0.4], True)), 156 | ] 157 | context["lights"] = Buffer.from_array(np.array(lights), buffer_type='i', drop_last_dim=True) 158 | 159 | 160 | def main(): 161 | num_buffers = 4 162 | context, entry_point = create_context() 163 | create_scene(context, num_buffers) 164 | entry_point.launch((width, height)) 165 | 166 | result_array = context['output_buffer'].to_array() 167 | result_image = Image.fromarray(result_array) 168 | ImageWindow(result_image.rotate(180)) 169 | 170 | 171 | if __name__ == '__main__': 172 | main() 173 | -------------------------------------------------------------------------------- /examples/buffers_of_buffers/commonStructs.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 | #pragma once 30 | 31 | #include 32 | 33 | struct BasicLight 34 | { 35 | #if defined(__cplusplus) 36 | typedef optix::float3 float3; 37 | #endif 38 | float3 pos; 39 | float3 color; 40 | int casts_shadow; 41 | int padding; // make this structure 32 bytes -- powers of two are your friend! 42 | }; 43 | 44 | 45 | -------------------------------------------------------------------------------- /examples/buffers_of_buffers/common_structs.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class BasicLight(object): 5 | dtype = np.dtype([ 6 | ('pos', np.float32, 3), 7 | ('color', np.float32, 3), 8 | ('casts_shadow', np.int32), 9 | ('padding', np.int32), 10 | ]) 11 | 12 | """ 13 | __array__ is called when a BasicLight is being converted to a numpy array. 14 | Then, one can assign that numpy array to an optix variable/buffer. The format will be user format. 15 | Memory layout (dtype) must match with the corresponding C struct in the device code. 16 | """ 17 | def __array__(self): 18 | np_array = np.zeros(1, dtype=BasicLight.dtype) 19 | np_array['pos'] = self._pos 20 | np_array['color'] = self._color 21 | np_array['casts_shadow'] = 1 if self._casts_shadow else 0 22 | np_array['padding'] = 0 23 | return np_array 24 | 25 | def __init__(self, pos, color, casts_shadow): 26 | self._pos = pos 27 | self._color = color 28 | self._casts_shadow = casts_shadow 29 | -------------------------------------------------------------------------------- /examples/buffers_of_buffers/constantbg.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 | 31 | rtDeclareVariable(float3, bg_color, , ); 32 | 33 | struct PerRayData_radiance 34 | { 35 | float3 result; 36 | float importance; 37 | int depth; 38 | }; 39 | 40 | rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, ); 41 | 42 | RT_PROGRAM void miss() 43 | { 44 | prd_radiance.result = bg_color; 45 | } 46 | -------------------------------------------------------------------------------- /examples/buffers_of_buffers/optixBuffersOfBuffers.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 "commonStructs.h" 31 | #include "helpers.h" 32 | 33 | struct PerRayData_radiance 34 | { 35 | float3 result; 36 | float importance; 37 | int depth; 38 | }; 39 | 40 | struct PerRayData_shadow 41 | { 42 | float3 attenuation; 43 | }; 44 | 45 | 46 | // 47 | // Declaration of our Buffer of Buffers 48 | // 49 | rtBuffer > Kd_layers; 50 | 51 | rtBuffer lights; 52 | rtDeclareVariable(float3, ambient_light_color, , ); 53 | rtDeclareVariable(unsigned int, radiance_ray_type, , ); 54 | rtDeclareVariable(unsigned int, shadow_ray_type, , ); 55 | rtDeclareVariable(rtObject, top_object, , ); 56 | rtDeclareVariable(rtObject, top_shadower, , ); 57 | rtDeclareVariable(float, scene_epsilon, , ); 58 | 59 | rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, ); 60 | rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 61 | rtDeclareVariable(float3, texcoord, attribute texcoord, ); 62 | 63 | rtDeclareVariable(optix::Ray, ray, rtCurrentRay, ); 64 | rtDeclareVariable(float, t_hit, rtIntersectionDistance, ); 65 | rtDeclareVariable(PerRayData_radiance, prd, rtPayload, ); 66 | rtDeclareVariable(PerRayData_shadow, prd_shadow, rtPayload, ); 67 | 68 | RT_PROGRAM void any_hit_shadow() 69 | { 70 | // this material is opaque, so it fully attenuates all shadow rays 71 | prd_shadow.attenuation = optix::make_float3(0.0f); 72 | rtTerminateRay(); 73 | } 74 | 75 | 76 | RT_PROGRAM void closest_hit_radiance() 77 | { 78 | float3 world_shading_normal = optix::normalize( 79 | rtTransformNormal( RT_OBJECT_TO_WORLD, shading_normal ) ); 80 | float3 world_geometric_normal = optix::normalize( 81 | rtTransformNormal( RT_OBJECT_TO_WORLD, geometric_normal ) ); 82 | float3 normal = optix::faceforward( 83 | world_shading_normal, -ray.direction, world_geometric_normal ); 84 | 85 | float3 hit_point = ray.origin + t_hit * ray.direction; 86 | 87 | // 88 | // Calculate Kd - loop over all nested buffers, accumulating color 89 | // 90 | float3 Kd = make_float3( 1.0f ); 91 | for( int i = 0; i < Kd_layers.size(); ++i ) 92 | { 93 | // Grab a refernce to the nested buffer so we dont need to perform 94 | // the buffer lookup multiple times 95 | rtBufferId& layer = Kd_layers[i]; 96 | 97 | optix::size_t2 size = layer.size(); 98 | uint2 idx = make_uint2( min( texcoord.x*size.x, size.x-1.0f ), 99 | min( texcoord.y*size.y, size.y-1.0f ) ); 100 | uchar4 val = layer[ idx ]; 101 | float4 fval = make_float4( val.x / 256.0f, 102 | val.y / 256.0f, 103 | val.z / 256.0f, 104 | val.w / 256.0f ); 105 | Kd = make_float3( fval )*fval.w + Kd*(1.0f - fval.w ); 106 | } 107 | 108 | // ambient contribution 109 | float3 result = Kd * ambient_light_color; 110 | 111 | // compute direct lighting 112 | unsigned int num_lights = lights.size(); 113 | for(int i = 0; i < num_lights; ++i) { 114 | BasicLight light = lights[i]; 115 | float Ldist = optix::length(light.pos - hit_point); 116 | float3 L = optix::normalize(light.pos - hit_point); 117 | float nDl = optix::dot( normal, L); 118 | 119 | // cast shadow ray 120 | float3 light_attenuation = make_float3(static_cast( nDl > 0.0f )); 121 | if ( nDl > 0.0f && light.casts_shadow ) { 122 | PerRayData_shadow shadow_prd; 123 | shadow_prd.attenuation = make_float3(1.0f); 124 | optix::Ray shadow_ray = optix::make_Ray( 125 | hit_point, L, shadow_ray_type, scene_epsilon, Ldist ); 126 | rtTrace(top_shadower, shadow_ray, shadow_prd); 127 | light_attenuation = shadow_prd.attenuation; 128 | } 129 | 130 | // If not completely shadowed, light the hit point 131 | if( fmaxf(light_attenuation) > 0.0f ) { 132 | float3 Lc = light.color * light_attenuation; 133 | result += Kd * nDl * Lc; 134 | } 135 | } 136 | 137 | // pass the color back up the tree 138 | prd.result = result; 139 | } 140 | -------------------------------------------------------------------------------- /examples/buffers_of_buffers/parallelogram.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 | 31 | using namespace optix; 32 | 33 | rtDeclareVariable(float4, plane, , ); 34 | rtDeclareVariable(float3, v1, , ); 35 | rtDeclareVariable(float3, v2, , ); 36 | rtDeclareVariable(float3, anchor, , ); 37 | rtDeclareVariable(int, lgt_instance, , ) = {0}; 38 | 39 | rtDeclareVariable(float3, texcoord, attribute texcoord, ); 40 | rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, ); 41 | rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 42 | rtDeclareVariable(int, lgt_idx, attribute lgt_idx, ); 43 | rtDeclareVariable(optix::Ray, ray, rtCurrentRay, ); 44 | 45 | RT_PROGRAM void intersect(int primIdx) 46 | { 47 | float3 n = make_float3( plane ); 48 | float dt = dot(ray.direction, n ); 49 | float t = (plane.w - dot(n, ray.origin))/dt; 50 | if( t > ray.tmin && t < ray.tmax ) { 51 | float3 p = ray.origin + ray.direction * t; 52 | float3 vi = p - anchor; 53 | float a1 = dot(v1, vi); 54 | if(a1 >= 0 && a1 <= 1){ 55 | float a2 = dot(v2, vi); 56 | if(a2 >= 0 && a2 <= 1){ 57 | if( rtPotentialIntersection( t ) ) { 58 | shading_normal = geometric_normal = n; 59 | texcoord = make_float3(a1,a2,0); 60 | lgt_idx = lgt_instance; 61 | rtReportIntersection( 0 ); 62 | } 63 | } 64 | } 65 | } 66 | } 67 | 68 | RT_PROGRAM void bounds (int, float result[6]) 69 | { 70 | // v1 and v2 are scaled by 1./length^2. Rescale back to normal for the bounds computation. 71 | const float3 tv1 = v1 / dot( v1, v1 ); 72 | const float3 tv2 = v2 / dot( v2, v2 ); 73 | const float3 p00 = anchor; 74 | const float3 p01 = anchor + tv1; 75 | const float3 p10 = anchor + tv2; 76 | const float3 p11 = anchor + tv1 + tv2; 77 | const float area = length(cross(tv1, tv2)); 78 | 79 | optix::Aabb* aabb = (optix::Aabb*)result; 80 | 81 | if(area > 0.0f && !isinf(area)) { 82 | aabb->m_min = fminf( fminf( p00, p01 ), fminf( p10, p11 ) ); 83 | aabb->m_max = fmaxf( fmaxf( p00, p01 ), fmaxf( p10, p11 ) ); 84 | } else { 85 | aabb->invalidate(); 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /examples/buffers_of_buffers/phong.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 "phong.h" 32 | 33 | using namespace optix; 34 | 35 | rtDeclareVariable(float3, Ka, , ); 36 | rtDeclareVariable(float3, Kd, , ); 37 | rtDeclareVariable(float3, Ks, , ); 38 | rtDeclareVariable(float3, Kr, , ); 39 | rtDeclareVariable(float, phong_exp, , ); 40 | 41 | rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, ); 42 | rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 43 | 44 | 45 | RT_PROGRAM void any_hit_shadow() 46 | { 47 | phongShadowed(); 48 | } 49 | 50 | 51 | RT_PROGRAM void closest_hit_radiance() 52 | { 53 | float3 world_shading_normal = normalize( rtTransformNormal( RT_OBJECT_TO_WORLD, shading_normal ) ); 54 | float3 world_geometric_normal = normalize( rtTransformNormal( RT_OBJECT_TO_WORLD, geometric_normal ) ); 55 | 56 | float3 ffnormal = faceforward( world_shading_normal, -ray.direction, world_geometric_normal ); 57 | phongShade( Kd, Ka, Ks, Kr, phong_exp, ffnormal ); 58 | } 59 | 60 | 61 | rtTextureSampler Kd_map; 62 | rtDeclareVariable(float3, texcoord, attribute texcoord, ); 63 | 64 | RT_PROGRAM void closest_hit_radiance_textured() 65 | { 66 | float3 world_shading_normal = normalize( rtTransformNormal( RT_OBJECT_TO_WORLD, shading_normal ) ); 67 | float3 world_geometric_normal = normalize( rtTransformNormal( RT_OBJECT_TO_WORLD, geometric_normal ) ); 68 | 69 | float3 ffnormal = faceforward( world_shading_normal, -ray.direction, world_geometric_normal ); 70 | 71 | const float3 Kd_val = make_float3( tex2D( Kd_map, texcoord.x, texcoord.y ) ); 72 | phongShade( Kd_val, Ka, Ks, Kr, phong_exp, ffnormal ); 73 | } 74 | -------------------------------------------------------------------------------- /examples/buffers_of_buffers/phong.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 | #include 30 | #include "commonStructs.h" 31 | #include "helpers.h" 32 | 33 | struct PerRayData_radiance 34 | { 35 | float3 result; 36 | float importance; 37 | int depth; 38 | }; 39 | 40 | struct PerRayData_shadow 41 | { 42 | float3 attenuation; 43 | }; 44 | 45 | 46 | rtDeclareVariable(int, max_depth, , ); 47 | rtBuffer lights; 48 | rtDeclareVariable(float3, ambient_light_color, , ); 49 | rtDeclareVariable(unsigned int, radiance_ray_type, , ); 50 | rtDeclareVariable(unsigned int, shadow_ray_type, , ); 51 | rtDeclareVariable(float, scene_epsilon, , ); 52 | rtDeclareVariable(rtObject, top_object, , ); 53 | rtDeclareVariable(rtObject, top_shadower, , ); 54 | 55 | rtDeclareVariable(optix::Ray, ray, rtCurrentRay, ); 56 | rtDeclareVariable(float, t_hit, rtIntersectionDistance, ); 57 | rtDeclareVariable(PerRayData_radiance, prd, rtPayload, ); 58 | rtDeclareVariable(PerRayData_shadow, prd_shadow, rtPayload, ); 59 | 60 | static __device__ void phongShadowed() 61 | { 62 | // this material is opaque, so it fully attenuates all shadow rays 63 | prd_shadow.attenuation = optix::make_float3(0.0f); 64 | rtTerminateRay(); 65 | } 66 | 67 | static 68 | __device__ void phongShade( float3 p_Kd, 69 | float3 p_Ka, 70 | float3 p_Ks, 71 | float3 p_Kr, 72 | float p_phong_exp, 73 | float3 p_normal ) 74 | { 75 | float3 hit_point = ray.origin + t_hit * ray.direction; 76 | 77 | // ambient contribution 78 | 79 | float3 result = p_Ka * ambient_light_color; 80 | 81 | // compute direct lighting 82 | unsigned int num_lights = lights.size(); 83 | for(int i = 0; i < num_lights; ++i) { 84 | BasicLight light = lights[i]; 85 | float Ldist = optix::length(light.pos - hit_point); 86 | float3 L = optix::normalize(light.pos - hit_point); 87 | float nDl = optix::dot( p_normal, L); 88 | 89 | // cast shadow ray 90 | float3 light_attenuation = make_float3(static_cast( nDl > 0.0f )); 91 | if ( nDl > 0.0f && light.casts_shadow ) { 92 | PerRayData_shadow shadow_prd; 93 | shadow_prd.attenuation = make_float3(1.0f); 94 | optix::Ray shadow_ray = optix::make_Ray( hit_point, L, shadow_ray_type, scene_epsilon, Ldist ); 95 | rtTrace(top_shadower, shadow_ray, shadow_prd); 96 | light_attenuation = shadow_prd.attenuation; 97 | } 98 | 99 | // If not completely shadowed, light the hit point 100 | if( fmaxf(light_attenuation) > 0.0f ) { 101 | float3 Lc = light.color * light_attenuation; 102 | 103 | result += p_Kd * nDl * Lc; 104 | 105 | float3 H = optix::normalize(L - ray.direction); 106 | float nDh = optix::dot( p_normal, H ); 107 | if(nDh > 0) { 108 | float power = pow(nDh, p_phong_exp); 109 | result += p_Ks * power * Lc; 110 | } 111 | } 112 | } 113 | 114 | if( fmaxf( p_Kr ) > 0 ) { 115 | 116 | // ray tree attenuation 117 | PerRayData_radiance new_prd; 118 | new_prd.importance = prd.importance * optix::luminance( p_Kr ); 119 | new_prd.depth = prd.depth + 1; 120 | 121 | // reflection ray 122 | if( new_prd.importance >= 0.01f && new_prd.depth <= max_depth) { 123 | float3 R = optix::reflect( ray.direction, p_normal ); 124 | optix::Ray refl_ray = optix::make_Ray( hit_point, R, radiance_ray_type, scene_epsilon, RT_DEFAULT_MAX ); 125 | rtTrace(top_object, refl_ray, new_prd); 126 | result += p_Kr * new_prd.result; 127 | } 128 | } 129 | 130 | // pass the color back up the tree 131 | prd.result = result; 132 | } 133 | -------------------------------------------------------------------------------- /examples/buffers_of_buffers/pinhole_camera.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 "helpers.h" 31 | 32 | using namespace optix; 33 | 34 | struct PerRayData_radiance 35 | { 36 | float3 result; 37 | float importance; 38 | int depth; 39 | }; 40 | 41 | rtDeclareVariable(float3, eye, , ); 42 | rtDeclareVariable(float3, U, , ); 43 | rtDeclareVariable(float3, V, , ); 44 | rtDeclareVariable(float3, W, , ); 45 | rtDeclareVariable(float3, bad_color, , ); 46 | rtDeclareVariable(float, scene_epsilon, , ); 47 | rtBuffer output_buffer; 48 | rtDeclareVariable(rtObject, top_object, , ); 49 | rtDeclareVariable(unsigned int, radiance_ray_type, , ); 50 | 51 | rtDeclareVariable(uint2, launch_index, rtLaunchIndex, ); 52 | rtDeclareVariable(uint2, launch_dim, rtLaunchDim, ); 53 | rtDeclareVariable(float, time_view_scale, , ) = 1e-6f; 54 | 55 | //#define TIME_VIEW 56 | 57 | RT_PROGRAM void pinhole_camera() 58 | { 59 | #ifdef TIME_VIEW 60 | clock_t t0 = clock(); 61 | #endif 62 | float2 d = make_float2(launch_index) / make_float2(launch_dim) * 2.f - 1.f; 63 | float3 ray_origin = eye; 64 | float3 ray_direction = normalize(d.x*U + d.y*V + W); 65 | 66 | optix::Ray ray = optix::make_Ray(ray_origin, ray_direction, radiance_ray_type, scene_epsilon, RT_DEFAULT_MAX); 67 | 68 | PerRayData_radiance prd; 69 | prd.importance = 1.f; 70 | prd.depth = 0; 71 | 72 | rtTrace(top_object, ray, prd); 73 | 74 | #ifdef TIME_VIEW 75 | clock_t t1 = clock(); 76 | 77 | float expected_fps = 1.0f; 78 | float pixel_time = ( t1 - t0 ) * time_view_scale * expected_fps; 79 | output_buffer[launch_index] = make_color( make_float3( pixel_time ) ); 80 | #else 81 | output_buffer[launch_index] = make_color( prd.result ); 82 | #endif 83 | } 84 | 85 | RT_PROGRAM void exception() 86 | { 87 | const unsigned int code = rtGetExceptionCode(); 88 | rtPrintf( "Caught exception 0x%X at launch index (%d,%d)\n", code, launch_index.x, launch_index.y ); 89 | output_buffer[launch_index] = make_color( bad_color ); 90 | } 91 | -------------------------------------------------------------------------------- /examples/buffers_of_buffers/sphere_texcoord.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 | #include "helpers.h" 35 | 36 | using namespace optix; 37 | 38 | rtDeclareVariable(float4, sphere, , ); 39 | rtDeclareVariable(float3, rotation, , ); 40 | 41 | rtDeclareVariable(float3, matrix_row_0, , ); 42 | rtDeclareVariable(float3, matrix_row_1, , ); 43 | rtDeclareVariable(float3, matrix_row_2, , ); 44 | 45 | rtDeclareVariable(optix::Ray, ray, rtCurrentRay, ); 46 | 47 | rtDeclareVariable(float3, texcoord, attribute texcoord, ); 48 | rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, ); 49 | rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 50 | 51 | RT_PROGRAM void intersect(int primIdx) 52 | { 53 | float3 center = make_float3(sphere); 54 | float3 O = ray.origin - center; 55 | float3 D = ray.direction; 56 | float radius = sphere.w; 57 | 58 | float b = dot(O, D); 59 | float c = dot(O, O)-radius*radius; 60 | float disc = b*b-c; 61 | if(disc > 0.0f){ 62 | float sdisc = sqrtf(disc); 63 | float root1 = (-b - sdisc); 64 | bool check_second = true; 65 | if( rtPotentialIntersection( root1 ) ) { 66 | shading_normal = geometric_normal = (O + root1*D)/radius; 67 | 68 | float3 polar; 69 | polar.x = dot(matrix_row_0, geometric_normal); 70 | polar.y = dot(matrix_row_1, geometric_normal); 71 | polar.z = dot(matrix_row_2, geometric_normal); 72 | polar = optix::cart_to_pol(polar); 73 | 74 | texcoord = make_float3( polar.x*0.5f*M_1_PIf, (polar.y+M_PI_2f)*M_1_PIf, polar.z/radius ); 75 | 76 | if(rtReportIntersection(0)) 77 | check_second = false; 78 | } 79 | if(check_second) { 80 | float root2 = (-b + sdisc); 81 | if( rtPotentialIntersection( root2 ) ) { 82 | shading_normal = geometric_normal = (O + root2*D)/radius; 83 | 84 | float3 polar; 85 | polar.x = dot(matrix_row_0, geometric_normal); 86 | polar.y = dot(matrix_row_1, geometric_normal); 87 | polar.z = dot(matrix_row_2, geometric_normal); 88 | polar = optix::cart_to_pol(polar); 89 | 90 | texcoord = make_float3( polar.x*0.5f*M_1_PIf, (polar.y+M_PI_2f)*M_1_PIf, polar.z/radius ); 91 | 92 | rtReportIntersection(0); 93 | } 94 | } 95 | } 96 | } 97 | 98 | RT_PROGRAM void bounds (int, optix::Aabb* aabb) 99 | { 100 | const float3 cen = make_float3( sphere ); 101 | const float3 rad = make_float3( sphere.w ); 102 | 103 | if( rad.x > 0.0f && !isinf(rad.x) ) { 104 | aabb->m_min = cen - rad; 105 | aabb->m_max = cen + rad; 106 | } else { 107 | aabb->invalidate(); 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /examples/common.py: -------------------------------------------------------------------------------- 1 | from PIL import ImageTk 2 | from tkinter import Tk, Label, BOTH 3 | from tkinter.ttk import Frame 4 | 5 | 6 | class ImageWindow(Frame): 7 | def __init__(self, img): 8 | parent = Tk() 9 | Frame.__init__(self, parent) 10 | self.pack(fill=BOTH, expand=1) 11 | label1 = Label(self) 12 | label1.photo = ImageTk.PhotoImage(img) 13 | label1.config(image=label1.photo) 14 | label1.pack(fill=BOTH, expand=1) 15 | parent.mainloop() 16 | 17 | 18 | def calculate_camera_variables(eye, lookat, up, fov, aspect_ratio, fov_is_vertical=False): 19 | import numpy as np 20 | import math 21 | 22 | W = np.array(lookat) - np.array(eye) 23 | wlen = np.linalg.norm(W) 24 | U = np.cross(W, np.array(up)) 25 | U /= np.linalg.norm(U) 26 | V = np.cross(U, W) 27 | V /= np.linalg.norm(V) 28 | 29 | if fov_is_vertical: 30 | vlen = wlen * math.tan(0.5 * fov * math.pi / 180.0) 31 | V *= vlen 32 | ulen = vlen * aspect_ratio 33 | U *= ulen 34 | else: 35 | ulen = wlen * math.tan(0.5 * fov * math.pi / 180.0) 36 | U *= ulen 37 | vlen = ulen * aspect_ratio 38 | V *= vlen 39 | 40 | return U, V, W 41 | -------------------------------------------------------------------------------- /examples/hello/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozen/PyOptiX/c7510ee9d967fe6c22fddcdcdd3b0127e075c8ba/examples/hello/__init__.py -------------------------------------------------------------------------------- /examples/hello/draw_color.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 | 32 | using namespace optix; 33 | 34 | rtDeclareVariable(uint2, launch_index, rtLaunchIndex, ); 35 | rtBuffer result_buffer; 36 | 37 | rtDeclareVariable(float3, draw_color, , ); 38 | 39 | RT_PROGRAM void draw_solid_color() 40 | { 41 | result_buffer[launch_index] = make_float4(draw_color, 0.f); 42 | } 43 | -------------------------------------------------------------------------------- /examples/hello/hello.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from os.path import dirname 3 | sys.path.append(dirname(dirname(dirname(__file__)))) 4 | 5 | import numpy as np 6 | from PIL import Image 7 | from pyoptix import Context, Buffer, Program, EntryPoint, Compiler 8 | from examples.common import ImageWindow 9 | 10 | 11 | Compiler.add_program_directory(dirname(__file__)) 12 | 13 | 14 | def main(): 15 | width = 512 16 | height = 384 17 | 18 | context = Context() 19 | 20 | context.set_ray_type_count(1) 21 | 22 | context['result_buffer'] = Buffer.empty((height, width, 4), buffer_type='o', dtype=np.float32, drop_last_dim=True) 23 | 24 | ray_gen_program = Program('draw_color.cu', 'draw_solid_color') 25 | 26 | ray_gen_program['draw_color'] = np.array([0.462, 0.725, 0.0], dtype=np.float32) 27 | 28 | entry_point = EntryPoint(ray_gen_program) 29 | entry_point.launch(size=(width, height)) 30 | 31 | result_array = context['result_buffer'].to_array() 32 | result_array *= 255 33 | result_image = Image.fromarray(result_array.astype(np.uint8)[:, :, :3]) 34 | 35 | ImageWindow(result_image) 36 | 37 | if __name__ == '__main__': 38 | main() 39 | -------------------------------------------------------------------------------- /examples/sphere/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozen/PyOptiX/c7510ee9d967fe6c22fddcdcdd3b0127e075c8ba/examples/sphere/__init__.py -------------------------------------------------------------------------------- /examples/sphere/constantbg.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 | 31 | rtDeclareVariable(float3, bg_color, , ); 32 | 33 | struct PerRayData_radiance 34 | { 35 | float3 result; 36 | float importance; 37 | int depth; 38 | }; 39 | 40 | rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, ); 41 | 42 | RT_PROGRAM void miss() 43 | { 44 | prd_radiance.result = bg_color; 45 | } 46 | -------------------------------------------------------------------------------- /examples/sphere/helpers.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 | #pragma once 30 | 31 | #include 32 | 33 | // Convert a float3 in [0,1)^3 to a uchar4 in [0,255]^4 -- 4th channel is set to 255 34 | #ifdef __CUDACC__ 35 | static __device__ __inline__ optix::uchar4 make_color(const optix::float3& c) 36 | { 37 | return optix::make_uchar4( static_cast(__saturatef(c.z)*255.99f), /* B */ 38 | static_cast(__saturatef(c.y)*255.99f), /* G */ 39 | static_cast(__saturatef(c.x)*255.99f), /* R */ 40 | 255u); /* A */ 41 | } 42 | #endif 43 | 44 | // Sample Phong lobe relative to U, V, W frame 45 | static 46 | __host__ __device__ __inline__ optix::float3 sample_phong_lobe( optix::float2 sample, float exponent, 47 | optix::float3 U, optix::float3 V, optix::float3 W ) 48 | { 49 | const float power = expf( logf(sample.y)/(exponent+1.0f) ); 50 | const float phi = sample.x * 2.0f * (float)M_PIf; 51 | const float scale = sqrtf(1.0f - power*power); 52 | 53 | const float x = cosf(phi)*scale; 54 | const float y = sinf(phi)*scale; 55 | const float z = power; 56 | 57 | return x*U + y*V + z*W; 58 | } 59 | 60 | // Sample Phong lobe relative to U, V, W frame 61 | static 62 | __host__ __device__ __inline__ optix::float3 sample_phong_lobe( const optix::float2 &sample, float exponent, 63 | const optix::float3 &U, const optix::float3 &V, const optix::float3 &W, 64 | float &pdf, float &bdf_val ) 65 | { 66 | const float cos_theta = powf(sample.y, 1.0f/(exponent+1.0f) ); 67 | 68 | const float phi = sample.x * 2.0f * M_PIf; 69 | const float sin_theta = sqrtf(1.0f - cos_theta*cos_theta); 70 | 71 | const float x = cosf(phi)*sin_theta; 72 | const float y = sinf(phi)*sin_theta; 73 | const float z = cos_theta; 74 | 75 | const float powered_cos = powf( cos_theta, exponent ); 76 | pdf = (exponent+1.0f) / (2.0f*M_PIf) * powered_cos; 77 | bdf_val = (exponent+2.0f) / (2.0f*M_PIf) * powered_cos; 78 | 79 | return x*U + y*V + z*W; 80 | } 81 | 82 | // Get Phong lobe PDF for local frame 83 | static 84 | __host__ __device__ __inline__ float get_phong_lobe_pdf( float exponent, const optix::float3 &normal, const optix::float3 &dir_out, 85 | const optix::float3 &dir_in, float &bdf_val) 86 | { 87 | using namespace optix; 88 | 89 | float3 r = -reflect(dir_out, normal); 90 | const float cos_theta = fabs(dot(r, dir_in)); 91 | const float powered_cos = powf(cos_theta, exponent ); 92 | 93 | bdf_val = (exponent+2.0f) / (2.0f*M_PIf) * powered_cos; 94 | return (exponent+1.0f) / (2.0f*M_PIf) * powered_cos; 95 | } 96 | 97 | // Create ONB from normal. Resulting W is parallel to normal 98 | static 99 | __host__ __device__ __inline__ void create_onb( const optix::float3& n, optix::float3& U, optix::float3& V, optix::float3& W ) 100 | { 101 | using namespace optix; 102 | 103 | W = normalize( n ); 104 | U = cross( W, optix::make_float3( 0.0f, 1.0f, 0.0f ) ); 105 | 106 | if ( fabs( U.x ) < 0.001f && fabs( U.y ) < 0.001f && fabs( U.z ) < 0.001f ) 107 | U = cross( W, make_float3( 1.0f, 0.0f, 0.0f ) ); 108 | 109 | U = normalize( U ); 110 | V = cross( W, U ); 111 | } 112 | 113 | // Create ONB from normalized vector 114 | static 115 | __device__ __inline__ void create_onb( const optix::float3& n, optix::float3& U, optix::float3& V) 116 | { 117 | using namespace optix; 118 | 119 | U = cross( n, make_float3( 0.0f, 1.0f, 0.0f ) ); 120 | 121 | if ( dot( U, U ) < 1e-3f ) 122 | U = cross( n, make_float3( 1.0f, 0.0f, 0.0f ) ); 123 | 124 | U = normalize( U ); 125 | V = cross( n, U ); 126 | } 127 | 128 | // Compute the origin ray differential for transfer 129 | static 130 | __host__ __device__ __inline__ optix::float3 differential_transfer_origin(optix::float3 dPdx, optix::float3 dDdx, float t, optix::float3 direction, optix::float3 normal) 131 | { 132 | float dtdx = -optix::dot((dPdx + t*dDdx), normal)/optix::dot(direction, normal); 133 | return (dPdx + t*dDdx)+dtdx*direction; 134 | } 135 | 136 | // Compute the direction ray differential for a pinhole camera 137 | static 138 | __host__ __device__ __inline__ optix::float3 differential_generation_direction(optix::float3 d, optix::float3 basis) 139 | { 140 | float dd = optix::dot(d,d); 141 | return (dd*basis-optix::dot(d,basis)*d)/(dd*sqrtf(dd)); 142 | } 143 | 144 | // Compute the direction ray differential for reflection 145 | static 146 | __host__ __device__ __inline__ 147 | optix::float3 differential_reflect_direction(optix::float3 dPdx, optix::float3 dDdx, optix::float3 dNdP, 148 | optix::float3 D, optix::float3 N) 149 | { 150 | using namespace optix; 151 | 152 | float3 dNdx = dNdP*dPdx; 153 | float dDNdx = dot(dDdx,N) + dot(D,dNdx); 154 | return dDdx - 2*(dot(D,N)*dNdx + dDNdx*N); 155 | } 156 | 157 | // Compute the direction ray differential for refraction 158 | static __host__ __device__ __inline__ 159 | optix::float3 differential_refract_direction(optix::float3 dPdx, optix::float3 dDdx, optix::float3 dNdP, 160 | optix::float3 D, optix::float3 N, float ior, optix::float3 T) 161 | { 162 | using namespace optix; 163 | 164 | float eta; 165 | if(dot(D,N) > 0.f) { 166 | eta = ior; 167 | N = -N; 168 | } else { 169 | eta = 1.f / ior; 170 | } 171 | 172 | float3 dNdx = dNdP*dPdx; 173 | float mu = eta*dot(D,N)-dot(T,N); 174 | float TN = -sqrtf(1-eta*eta*(1-dot(D,N)*dot(D,N))); 175 | float dDNdx = dot(dDdx,N) + dot(D,dNdx); 176 | float dmudx = (eta - (eta*eta*dot(D,N))/TN)*dDNdx; 177 | return eta*dDdx - (mu*dNdx+dmudx*N); 178 | } 179 | 180 | // Color space conversions 181 | static __host__ __device__ __inline__ optix::float3 Yxy2XYZ( const optix::float3& Yxy ) 182 | { 183 | // avoid division by zero 184 | if( Yxy.z < 1e-4 ) 185 | return optix::make_float3( 0.0f, 0.0f, 0.0f ); 186 | 187 | return optix::make_float3( Yxy.y * ( Yxy.x / Yxy.z ), 188 | Yxy.x, 189 | ( 1.0f - Yxy.y - Yxy.z ) * ( Yxy.x / Yxy.z ) ); 190 | } 191 | 192 | static __host__ __device__ __inline__ optix::float3 XYZ2rgb( const optix::float3& xyz) 193 | { 194 | const float R = optix::dot( xyz, optix::make_float3( 3.2410f, -1.5374f, -0.4986f ) ); 195 | const float G = optix::dot( xyz, optix::make_float3( -0.9692f, 1.8760f, 0.0416f ) ); 196 | const float B = optix::dot( xyz, optix::make_float3( 0.0556f, -0.2040f, 1.0570f ) ); 197 | return optix::make_float3( R, G, B ); 198 | } 199 | 200 | static __host__ __device__ __inline__ optix::float3 Yxy2rgb( optix::float3 Yxy ) 201 | { 202 | using namespace optix; 203 | 204 | // avoid division by zero 205 | if( Yxy.z < 1e-4 ) 206 | return make_float3( 0.0f, 0.0f, 0.0f ); 207 | 208 | // First convert to xyz 209 | float3 xyz = make_float3( Yxy.y * ( Yxy.x / Yxy.z ), 210 | Yxy.x, 211 | ( 1.0f - Yxy.y - Yxy.z ) * ( Yxy.x / Yxy.z ) ); 212 | 213 | const float R = dot( xyz, make_float3( 3.2410f, -1.5374f, -0.4986f ) ); 214 | const float G = dot( xyz, make_float3( -0.9692f, 1.8760f, 0.0416f ) ); 215 | const float B = dot( xyz, make_float3( 0.0556f, -0.2040f, 1.0570f ) ); 216 | return make_float3( R, G, B ); 217 | } 218 | 219 | static __host__ __device__ __inline__ optix::float3 rgb2Yxy( optix::float3 rgb) 220 | { 221 | using namespace optix; 222 | 223 | // convert to xyz 224 | const float X = dot( rgb, make_float3( 0.4124f, 0.3576f, 0.1805f ) ); 225 | const float Y = dot( rgb, make_float3( 0.2126f, 0.7152f, 0.0722f ) ); 226 | const float Z = dot( rgb, make_float3( 0.0193f, 0.1192f, 0.9505f ) ); 227 | 228 | // avoid division by zero 229 | // here we make the simplifying assumption that X, Y, Z are positive 230 | float denominator = X + Y + Z; 231 | if ( denominator < 1e-4 ) 232 | return make_float3( 0.0f, 0.0f, 0.0f ); 233 | 234 | // convert xyz to Yxy 235 | return make_float3( Y, 236 | X / ( denominator ), 237 | Y / ( denominator ) ); 238 | } 239 | 240 | static __host__ __device__ __inline__ optix::float3 tonemap( const optix::float3 &hdr_value, float Y_log_av, float Y_max) 241 | { 242 | using namespace optix; 243 | 244 | float3 val_Yxy = rgb2Yxy( hdr_value ); 245 | 246 | float Y = val_Yxy.x; // Y channel is luminance 247 | const float a = 0.04f; 248 | float Y_rel = a * Y / Y_log_av; 249 | float mapped_Y = Y_rel * (1.0f + Y_rel / (Y_max * Y_max)) / (1.0f + Y_rel); 250 | 251 | float3 mapped_Yxy = make_float3( mapped_Y, val_Yxy.y, val_Yxy.z ); 252 | float3 mapped_rgb = Yxy2rgb( mapped_Yxy ); 253 | 254 | return mapped_rgb; 255 | } 256 | 257 | -------------------------------------------------------------------------------- /examples/sphere/normal_shader.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 | 32 | using namespace optix; 33 | 34 | rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 35 | 36 | struct PerRayData_radiance 37 | { 38 | float3 result; 39 | float importance; 40 | int depth; 41 | }; 42 | 43 | struct PerRayData_shadow 44 | { 45 | float3 attenuation; 46 | }; 47 | 48 | rtDeclareVariable(PerRayData_radiance, prd_radiance, rtPayload, ); 49 | rtDeclareVariable(PerRayData_shadow, prd_shadow, rtPayload, ); 50 | 51 | 52 | RT_PROGRAM void any_hit_shadow() 53 | { 54 | // this material is opaque, so it fully attenuates all shadow rays 55 | prd_shadow.attenuation = make_float3(0); 56 | 57 | rtTerminateRay(); 58 | } 59 | 60 | RT_PROGRAM void closest_hit_radiance() 61 | { 62 | prd_radiance.result = normalize(rtTransformNormal(RT_OBJECT_TO_WORLD, shading_normal))*0.5f + 0.5f; 63 | } 64 | -------------------------------------------------------------------------------- /examples/sphere/pinhole_camera.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 "helpers.h" 31 | 32 | using namespace optix; 33 | 34 | struct PerRayData_radiance 35 | { 36 | float3 result; 37 | float importance; 38 | int depth; 39 | }; 40 | 41 | rtDeclareVariable(float3, eye, , ); 42 | rtDeclareVariable(float3, U, , ); 43 | rtDeclareVariable(float3, V, , ); 44 | rtDeclareVariable(float3, W, , ); 45 | rtDeclareVariable(float3, bad_color, , ); 46 | rtDeclareVariable(float, scene_epsilon, , ); 47 | rtBuffer output_buffer; 48 | rtDeclareVariable(rtObject, top_object, , ); 49 | rtDeclareVariable(unsigned int, radiance_ray_type, , ); 50 | 51 | rtDeclareVariable(uint2, launch_index, rtLaunchIndex, ); 52 | rtDeclareVariable(uint2, launch_dim, rtLaunchDim, ); 53 | rtDeclareVariable(float, time_view_scale, , ) = 1e-6f; 54 | 55 | //#define TIME_VIEW 56 | 57 | RT_PROGRAM void pinhole_camera() 58 | { 59 | #ifdef TIME_VIEW 60 | clock_t t0 = clock(); 61 | #endif 62 | float2 d = make_float2(launch_index) / make_float2(launch_dim) * 2.f - 1.f; 63 | float3 ray_origin = eye; 64 | float3 ray_direction = normalize(d.x*U + d.y*V + W); 65 | 66 | optix::Ray ray = optix::make_Ray(ray_origin, ray_direction, radiance_ray_type, scene_epsilon, RT_DEFAULT_MAX); 67 | 68 | PerRayData_radiance prd; 69 | prd.importance = 1.f; 70 | prd.depth = 0; 71 | 72 | rtTrace(top_object, ray, prd); 73 | 74 | #ifdef TIME_VIEW 75 | clock_t t1 = clock(); 76 | 77 | float expected_fps = 1.0f; 78 | float pixel_time = ( t1 - t0 ) * time_view_scale * expected_fps; 79 | output_buffer[launch_index] = make_color( make_float3( pixel_time ) ); 80 | #else 81 | output_buffer[launch_index] = make_color( prd.result ); 82 | #endif 83 | } 84 | 85 | RT_PROGRAM void exception() 86 | { 87 | const unsigned int code = rtGetExceptionCode(); 88 | rtPrintf( "Caught exception 0x%X at launch index (%d,%d)\n", code, launch_index.x, launch_index.y ); 89 | output_buffer[launch_index] = make_color( bad_color ); 90 | } 91 | -------------------------------------------------------------------------------- /examples/sphere/sphere.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 | 31 | using namespace optix; 32 | 33 | rtDeclareVariable(float4, sphere, , ); 34 | 35 | rtDeclareVariable(float3, geometric_normal, attribute geometric_normal, ); 36 | rtDeclareVariable(float3, shading_normal, attribute shading_normal, ); 37 | rtDeclareVariable(optix::Ray, ray, rtCurrentRay, ); 38 | 39 | template 40 | static __device__ 41 | void intersect_sphere(void) 42 | { 43 | float3 center = make_float3(sphere); 44 | float3 O = ray.origin - center; 45 | float3 D = ray.direction; 46 | float radius = sphere.w; 47 | 48 | float b = dot(O, D); 49 | float c = dot(O, O)-radius*radius; 50 | float disc = b*b-c; 51 | if(disc > 0.0f){ 52 | float sdisc = sqrtf(disc); 53 | float root1 = (-b - sdisc); 54 | 55 | bool do_refine = false; 56 | 57 | float root11 = 0.0f; 58 | 59 | if(use_robust_method && fabsf(root1) > 10.f * radius) { 60 | do_refine = true; 61 | } 62 | 63 | if(do_refine) { 64 | // refine root1 65 | float3 O1 = O + root1 * ray.direction; 66 | b = dot(O1, D); 67 | c = dot(O1, O1) - radius*radius; 68 | disc = b*b - c; 69 | 70 | if(disc > 0.0f) { 71 | sdisc = sqrtf(disc); 72 | root11 = (-b - sdisc); 73 | } 74 | } 75 | 76 | bool check_second = true; 77 | if( rtPotentialIntersection( root1 + root11 ) ) { 78 | shading_normal = geometric_normal = (O + (root1 + root11)*D)/radius; 79 | if(rtReportIntersection(0)) 80 | check_second = false; 81 | } 82 | if(check_second) { 83 | float root2 = (-b + sdisc) + (do_refine ? root1 : 0); 84 | if( rtPotentialIntersection( root2 ) ) { 85 | shading_normal = geometric_normal = (O + root2*D)/radius; 86 | rtReportIntersection(0); 87 | } 88 | } 89 | } 90 | } 91 | 92 | 93 | RT_PROGRAM void intersect(int primIdx) 94 | { 95 | intersect_sphere(); 96 | } 97 | 98 | 99 | RT_PROGRAM void robust_intersect(int primIdx) 100 | { 101 | intersect_sphere(); 102 | } 103 | 104 | 105 | RT_PROGRAM void bounds (int, float result[6]) 106 | { 107 | const float3 cen = make_float3( sphere ); 108 | const float3 rad = make_float3( sphere.w ); 109 | 110 | optix::Aabb* aabb = (optix::Aabb*)result; 111 | 112 | if( rad.x > 0.0f && !isinf(rad.x) ) { 113 | aabb->m_min = cen - rad; 114 | aabb->m_max = cen + rad; 115 | } else { 116 | aabb->invalidate(); 117 | } 118 | } 119 | 120 | -------------------------------------------------------------------------------- /examples/sphere/sphere.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from os.path import dirname 3 | sys.path.append(dirname(dirname(dirname(__file__)))) 4 | 5 | import numpy as np 6 | from PIL import Image 7 | from pyoptix import Context, Compiler, Buffer, Program, Geometry, Material, GeometryInstance, EntryPoint, \ 8 | GeometryGroup, Acceleration 9 | from examples.common import ImageWindow, calculate_camera_variables 10 | 11 | width = 1024 12 | height = 768 13 | 14 | Compiler.add_program_directory(dirname(__file__)) 15 | 16 | 17 | def main(): 18 | context, entry_point = create_context() 19 | sphere = create_geometry() 20 | material = create_material() 21 | create_instance(context, sphere, material) 22 | 23 | entry_point.launch((width, height)) 24 | result_array = context['output_buffer'].to_array() 25 | result_image = Image.fromarray(result_array) 26 | ImageWindow(result_image) 27 | 28 | context.pop() 29 | 30 | 31 | def create_context(): 32 | context = Context() 33 | 34 | context.set_ray_type_count(1) 35 | context['radiance_ray_type'] = np.array(0, dtype=np.uint32) 36 | context['scene_epsilon'] = np.array(1e-4, dtype=np.float32) 37 | context['output_buffer'] = Buffer.empty((height, width, 4), dtype=np.uint8, buffer_type='o', drop_last_dim=True) 38 | entry_point = EntryPoint(Program('pinhole_camera.cu', 'pinhole_camera'), 39 | Program('pinhole_camera.cu', 'exception')) 40 | 41 | cam_eye = [0.0, 0.0, 5.0] 42 | lookat = [0.0, 0.0, 0.0] 43 | up = [0.0, 1.0, 0.0] 44 | hfov = 60.0 45 | aspect_ratio = width / height 46 | camera_u, camera_v, camera_w = calculate_camera_variables(cam_eye, lookat, up, hfov, aspect_ratio, True) 47 | 48 | context['eye'] = np.array(cam_eye, dtype=np.float32) 49 | context['U'] = np.array(camera_u, dtype=np.float32) 50 | context['V'] = np.array(camera_v, dtype=np.float32) 51 | context['W'] = np.array(camera_w, dtype=np.float32) 52 | 53 | context['bad_color'] = np.array([1.0, 0.0, 1.0], dtype=np.float32) 54 | context.set_miss_program(0, Program('constantbg.cu', 'miss')) 55 | context['bg_color'] = np.array([0.2, 0.1, 0.3], dtype=np.float32) 56 | 57 | return context, entry_point 58 | 59 | 60 | def create_geometry(): 61 | sphere = Geometry(Program('sphere.cu', 'bounds'), Program('sphere.cu', 'intersect')) 62 | sphere.set_primitive_count(1) 63 | sphere['sphere'] = np.array([0, 0, 0, 1.5], dtype=np.float32) 64 | return sphere 65 | 66 | 67 | def create_material(): 68 | return Material(closest_hit={ 69 | 0: Program('normal_shader.cu', 'closest_hit_radiance') 70 | }) 71 | 72 | 73 | def create_instance(context, sphere, material): 74 | instance = GeometryInstance(sphere, material) 75 | group = GeometryGroup(children=[instance]) 76 | group.set_acceleration(Acceleration()) 77 | context['top_object'] = group 78 | 79 | 80 | if __name__ == '__main__': 81 | main() 82 | -------------------------------------------------------------------------------- /examples/texture_sampler/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozen/PyOptiX/c7510ee9d967fe6c22fddcdcdd3b0127e075c8ba/examples/texture_sampler/__init__.py -------------------------------------------------------------------------------- /examples/texture_sampler/draw_texture.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 | 32 | using namespace optix; 33 | 34 | rtBuffer result_buffer; 35 | rtTextureSampler input_texture; 36 | // This line would also implicitly cast up to floats: 37 | // rtTextureSampler input_texture; 38 | rtDeclareVariable(uint2, launch_index, rtLaunchIndex, ); 39 | 40 | RT_PROGRAM void draw_texture() 41 | { 42 | size_t2 screen = result_buffer.size(); 43 | float2 uv = make_float2(launch_index) / make_float2(screen); 44 | 45 | result_buffer[launch_index] = tex2D(input_texture, uv.x, uv.y); 46 | } 47 | 48 | RT_PROGRAM void exception() 49 | { 50 | const unsigned int code = rtGetExceptionCode(); 51 | rtPrintf( "Caught exception 0x%X at launch index (%d,%d)\n", code, launch_index.x, launch_index.y ); 52 | result_buffer[launch_index] = make_float4(0, 1, 0, 0); 53 | } 54 | -------------------------------------------------------------------------------- /examples/texture_sampler/texture_sampler.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from os.path import dirname 3 | sys.path.append(dirname(dirname(dirname(__file__)))) 4 | 5 | import numpy as np 6 | from PIL import Image 7 | from pyoptix import Context, Compiler, Buffer, Program, EntryPoint, TextureSampler 8 | from examples.common import ImageWindow 9 | 10 | 11 | Compiler.add_program_directory(dirname(__file__)) 12 | 13 | 14 | def main(): 15 | tex_width = 64 16 | tex_height = 64 17 | 18 | trace_width = 512 19 | trace_height = 384 20 | 21 | context = Context() 22 | 23 | tex_data = [] 24 | for j in range(tex_height): 25 | tex_data.append([]) 26 | for i in range(tex_width): 27 | tex_data[j].append([ 28 | (i + j) / (tex_width + tex_height) * 255, 29 | i / tex_width * 255, 30 | j / tex_height * 255, 31 | 255 32 | ]) 33 | 34 | tex_buffer = Buffer.from_array(np.array(tex_data, dtype=np.uint8), buffer_type='i', drop_last_dim=True) 35 | tex_sampler = TextureSampler(tex_buffer, wrap_mode='clamp_to_edge', indexing_mode='normalized_coordinates', 36 | read_mode='normalized_float', filter_mode='linear') 37 | 38 | context['input_texture'] = tex_sampler 39 | 40 | context['result_buffer'] = Buffer.empty((trace_height, trace_width, 4), dtype=np.float32, 41 | buffer_type='o', drop_last_dim=True) 42 | 43 | entry_point = EntryPoint(Program('draw_texture.cu', 'draw_texture'), 44 | Program('draw_texture.cu', 'exception')) 45 | 46 | entry_point.launch((trace_width, trace_height)) 47 | 48 | result_array = context['result_buffer'].to_array() 49 | result_array *= 255 50 | result_array = result_array.astype(np.uint8) 51 | result_image = Image.fromarray(result_array) 52 | ImageWindow(result_image) 53 | 54 | 55 | if __name__ == '__main__': 56 | main() 57 | -------------------------------------------------------------------------------- /pyoptix/__init__.py: -------------------------------------------------------------------------------- 1 | from .acceleration import Acceleration 2 | from .buffer import Buffer 3 | from .compiler import Compiler 4 | from .context import Context, current_context 5 | from .entry_point import EntryPoint 6 | from .geometry import Geometry 7 | from .geometry_group import GeometryGroup 8 | from .geometry_instance import GeometryInstance 9 | from .group import Group 10 | from .material import Material 11 | from .program import Program 12 | from .selector import Selector 13 | from .texture_sampler import TextureSampler 14 | from .transform import Transform 15 | from ._driver import OPTIX_VERSION 16 | -------------------------------------------------------------------------------- /pyoptix/acceleration.py: -------------------------------------------------------------------------------- 1 | import six 2 | from pyoptix.context import current_context 3 | from pyoptix.mixins.destroyable import DestroyableObject 4 | from pyoptix.mixins.graphnode import GraphNodeMixin 5 | from pyoptix.mixins.hascontext import HasContextMixin 6 | 7 | 8 | class Acceleration(GraphNodeMixin, HasContextMixin, DestroyableObject): 9 | def __init__(self, builder="NoAccel", traverser="NoAccel", **kwargs): 10 | HasContextMixin.__init__(self, current_context()) 11 | DestroyableObject.__init__(self, self._safe_context._create_accelerator(builder, traverser)) 12 | GraphNodeMixin.__init__(self) 13 | 14 | for key, value in six.iteritems(kwargs): 15 | self._safe_native.set_property(key, value) 16 | 17 | def set_property(self, key, value): 18 | self._safe_native.set_property(key, value) 19 | 20 | def get_property(self, key): 21 | return self._safe_native.get_property(key) 22 | 23 | def mark_dirty(self): 24 | self._safe_native.mark_dirty() 25 | 26 | def is_dirty(self): 27 | return self._safe_native.is_dirty() 28 | 29 | def validate(self): 30 | self._safe_native.validate() 31 | -------------------------------------------------------------------------------- /pyoptix/buffer.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | from pyoptix.enums import Format, convert_buffer_type, get_format_from_dtype 3 | from pyoptix.context import current_context 4 | from pyoptix.mixins.bindless import BindlessMixin 5 | from pyoptix.mixins.destroyable import DestroyableObject 6 | from pyoptix.mixins.hascontext import HasContextMixin 7 | 8 | 9 | class Buffer(HasContextMixin, DestroyableObject, BindlessMixin): 10 | def __init__(self, buffer_type='io'): 11 | HasContextMixin.__init__(self, current_context()) 12 | DestroyableObject.__init__(self, self._safe_context._create_buffer(convert_buffer_type(buffer_type))) 13 | BindlessMixin.__init__(self) 14 | 15 | self._numpy_dtype = None 16 | self._numpy_shape = None 17 | self._last_dim_dropped = False 18 | 19 | @property 20 | def id(self): 21 | return self.get_id() 22 | 23 | @property 24 | def numpy_shape(self): 25 | return self._numpy_shape 26 | 27 | @property 28 | def shape(self): 29 | return self._safe_native.get_size() 30 | 31 | @property 32 | def dtype(self): 33 | return numpy.dtype(self._numpy_dtype) 34 | 35 | @property 36 | def size(self): 37 | return self._safe_native.get_size_in_bytes() 38 | 39 | @property 40 | def element_size(self): 41 | return self._safe_native.get_element_size() 42 | 43 | @classmethod 44 | def empty(cls, shape, dtype=numpy.float32, buffer_type='io', drop_last_dim=False): 45 | instance = cls(buffer_type=buffer_type) 46 | instance._reset_buffer(shape, dtype, drop_last_dim) 47 | return instance 48 | 49 | @classmethod 50 | def from_array(cls, array, dtype=None, buffer_type='io', drop_last_dim=False): 51 | if not isinstance(array, numpy.ndarray): 52 | try: 53 | array = numpy.array(array, dtype=dtype) 54 | except Exception as e: 55 | raise TypeError('array parameter must be a numpy array or castable to numpy array') 56 | 57 | instance = cls(buffer_type=buffer_type) 58 | instance._restructure_and_copy_from_numpy_array(array, drop_last_dim) 59 | return instance 60 | 61 | def get_id(self): 62 | return self._safe_native.get_id() 63 | 64 | def mark_dirty(self): 65 | self._safe_native.mark_dirty() 66 | 67 | def get_element_size(self): 68 | return self._safe_native.get_element_size() 69 | 70 | def get_size(self): 71 | return self._safe_native.get_size() 72 | 73 | def get_size_in_bytes(self): 74 | return self._safe_native.get_size_in_bytes() 75 | 76 | def set_format(self, format=None, dtype=None, type_size=1): 77 | _format = None 78 | 79 | if format is not None: 80 | if isinstance(format, Format): 81 | _format = format 82 | else: 83 | raise ValueError('Invalid buffer format') 84 | elif dtype is not None: 85 | try: 86 | dtype = numpy.dtype(dtype) 87 | _format = get_format_from_dtype(dtype, type_size) 88 | except TypeError: 89 | raise ValueError('Invalid dtype argument') 90 | 91 | self._safe_native.set_format(_format) 92 | 93 | def _reset_buffer(self, numpy_shape, dtype=numpy.float32, drop_last_dim=False): 94 | self._numpy_dtype = numpy.dtype(dtype) 95 | self._numpy_shape = numpy_shape 96 | 97 | item_size = self._numpy_dtype.itemsize 98 | temp_shape = numpy_shape 99 | type_size = 1 100 | 101 | if drop_last_dim: 102 | item_size = numpy_shape[-1] * self._numpy_dtype.itemsize 103 | temp_shape = numpy_shape[0:-1] 104 | type_size = numpy_shape[-1] 105 | self._last_dim_dropped = True 106 | 107 | self.set_format(dtype=dtype, type_size=type_size) 108 | if self._safe_native.get_format() == Format.user: 109 | self._safe_native.set_element_size(item_size) 110 | 111 | # convert numpy dim to optix dim (inverting shape) 112 | temp_shape = temp_shape[::-1] 113 | self._safe_native.set_size(list(temp_shape)) 114 | 115 | def _restructure_according_to_numpy_array(self, numpy_array, drop_last_dim=False): 116 | self._reset_buffer(numpy_shape=numpy_array.shape, dtype=numpy_array.dtype, drop_last_dim=drop_last_dim) 117 | 118 | def _restructure_and_copy_from_numpy_array(self, numpy_array, drop_last_dim=False): 119 | self._restructure_according_to_numpy_array(numpy_array, drop_last_dim) 120 | self.copy_from_array(numpy_array) 121 | 122 | def to_array(self): 123 | numpy_array = numpy.empty(self._numpy_shape, dtype=self.dtype) 124 | self.copy_to_array(numpy_array) 125 | return numpy_array 126 | 127 | def copy_to_array(self, numpy_array): 128 | if numpy_array.nbytes != self._safe_native.get_size_in_bytes(): 129 | raise BufferError("Arrays size must be equal!") 130 | 131 | self._safe_native.copy_into_array(numpy_array) 132 | 133 | def copy_from_array(self, numpy_array): 134 | if numpy_array.nbytes != self._safe_native.get_size_in_bytes(): 135 | raise BufferError("Arrays size must be equal!") 136 | 137 | self._safe_native.copy_from_array(numpy_array) 138 | 139 | def set_mip_level_count(self, level_count): 140 | self._safe_native.set_mip_level_count(level_count) 141 | 142 | def get_mip_level_count(self): 143 | return self._safe_native.get_mip_level_count() 144 | 145 | def get_mip_level_size(self): 146 | return self._safe_native.get_mip_level_size() 147 | 148 | def get_mip_level_size_in_bytes(self): 149 | return self._safe_native.get_mip_level_size_in_bytes() 150 | 151 | def copy_level_from_array(self, level, numpy_array): 152 | if numpy_array.nbytes != self._safe_native.get_mip_level_size_in_bytes(level): 153 | raise BufferError("Arrays size must be equal!") 154 | 155 | self._safe_native.copy_mip_level_from_array(level, numpy_array) 156 | 157 | def copy_level_from_buffer(self, level, buffer): 158 | if not isinstance(buffer, Buffer): 159 | raise TypeError('buffer is not of type Buffer') 160 | self.copy_level_from_array(self, level, buffer.to_array()) 161 | 162 | def validate(self): 163 | self._safe_native.validate() 164 | -------------------------------------------------------------------------------- /pyoptix/compiler.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import re 3 | import os 4 | import sys 5 | import shlex 6 | import fnmatch 7 | from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, S_IWOTH, S_IXUSR, S_IXGRP, S_IXOTH 8 | from subprocess import check_call, CalledProcessError 9 | from pyoptix.utils import glob_recursive, find_sub_path 10 | 11 | try: 12 | from configparser import ConfigParser 13 | except ImportError: 14 | from ConfigParser import SafeConfigParser as ConfigParser 15 | 16 | logger = logging.getLogger(__name__) 17 | 18 | 19 | class Compiler: 20 | nvcc_path = 'nvcc' 21 | extra_compile_args = [] 22 | output_path = '/tmp/pyoptix/ptx' 23 | use_fast_math = True 24 | _compile_args = [] 25 | _program_directories = [] 26 | 27 | @classmethod 28 | def add_program_directory(cls, directory): 29 | if directory not in cls._program_directories: 30 | cls._program_directories.append(directory) 31 | 32 | @classmethod 33 | def remove_program_directory(cls, directory): 34 | if directory in cls._program_directories: 35 | cls._program_directories.remove(directory) 36 | 37 | @classmethod 38 | def is_compile_required(cls, source_path, ptx_path): 39 | if os.path.isfile(ptx_path): 40 | ptx_mtime = os.path.getmtime(ptx_path) 41 | source_mtime = os.path.getmtime(source_path) 42 | 43 | if source_mtime > ptx_mtime: 44 | return True 45 | elif cls._has_modified_includes(source_path, ptx_mtime): 46 | return True 47 | else: 48 | return False 49 | 50 | else: 51 | return True 52 | 53 | @classmethod 54 | def _has_modified_includes(cls, file_path, modified_after, depth=4): 55 | if depth == 0: 56 | return False 57 | 58 | include_pattern = '#include\s*"(.*)"' 59 | 60 | with open(file_path) as f: 61 | content = f.read() 62 | for included_path in re.findall(include_pattern, content): 63 | for compiler_include_path in cls._program_directories: 64 | included_file_path = os.path.join(compiler_include_path, included_path) 65 | if not os.path.exists(included_file_path): 66 | continue 67 | 68 | included_file_mtime = os.path.getmtime(included_file_path) 69 | 70 | if included_file_mtime > modified_after: 71 | return True 72 | elif cls._has_modified_includes(included_file_path, modified_after, depth=depth - 1): 73 | return True 74 | 75 | return False 76 | 77 | @classmethod 78 | def compile(cls, source_path, output_ptx_name=None): 79 | if output_ptx_name is None: 80 | output_ptx_name = cls.get_ptx_name(source_path) 81 | 82 | if not os.path.isdir(cls.output_path): 83 | raise RuntimeError('Compiler.output_path is not a directory.') 84 | 85 | output_ptx_path = os.path.join(cls.output_path, output_ptx_name) 86 | is_compiled = True 87 | 88 | if cls.is_compile_required(source_path, output_ptx_path): 89 | if os.path.exists(output_ptx_path): 90 | os.remove(output_ptx_path) 91 | 92 | logger.info("Compiling {0}".format(source_path)) 93 | bash_command = cls.nvcc_path + " " 94 | bash_command += " ".join(cls._compile_args) 95 | bash_command += " ".join(cls.extra_compile_args) 96 | bash_command += " -ptx" 97 | if cls.use_fast_math: 98 | bash_command += " --use_fast_math" 99 | for include_path in cls._program_directories: 100 | if os.path.exists(include_path): 101 | bash_command += " -I=" + include_path 102 | bash_command += " " + source_path 103 | bash_command += " -o=" + output_ptx_path 104 | logger.debug("Executing: {0}".format(bash_command)) 105 | try: 106 | check_call(shlex.split(bash_command)) 107 | except CalledProcessError as e: 108 | logger.error(e) 109 | 110 | if not os.path.exists(output_ptx_path): 111 | logger.error("Could not compile {0}".format(source_path)) 112 | raise RuntimeError("Could not compile {0}".format(source_path)) 113 | else: 114 | os.chmod(output_ptx_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) 115 | 116 | else: 117 | logger.debug("No compiling required for {0}".format(source_path)) 118 | is_compiled = False 119 | 120 | return output_ptx_path, is_compiled 121 | 122 | @classmethod 123 | def compile_all_directories(cls, source_extension='.cu'): 124 | for program_dir in cls._program_directories: 125 | for program_path in glob_recursive(program_dir, '*' + source_extension): 126 | Compiler.compile(os.path.abspath(program_path)) 127 | 128 | @classmethod 129 | def clean(cls): 130 | if os.path.exists(cls.output_path): 131 | for dirpath, dirnames, filenames in os.walk(cls.output_path): 132 | for filename in fnmatch.filter(filenames, '*.ptx'): 133 | os.remove(os.path.join(dirpath, filename)) 134 | 135 | @staticmethod 136 | def is_ptx(file_path): 137 | return os.path.splitext(file_path)[1].lower() == '.ptx' 138 | 139 | @staticmethod 140 | def get_ptx_name(file_path): 141 | return '%s.ptx' % file_path.replace(os.sep, '_') 142 | 143 | @classmethod 144 | def get_abs_program_path(cls, file_path): 145 | if os.path.exists(file_path): 146 | return file_path 147 | else: 148 | abs_path = find_sub_path(file_path, cls._program_directories) 149 | if os.path.exists(abs_path): 150 | return abs_path 151 | else: 152 | raise ValueError('File not found') 153 | 154 | 155 | try: 156 | config_path = os.path.join(os.path.dirname(sys.executable), 'pyoptix.conf') 157 | 158 | if not os.path.exists(config_path): 159 | config_path = '/etc/pyoptix.conf' 160 | 161 | config = ConfigParser() 162 | config.read(config_path) 163 | nvcc_path = config.get('pyoptix', 'nvcc_path') 164 | compile_args = config.get('pyoptix', 'compile_args') 165 | 166 | if nvcc_path is not None: 167 | Compiler.nvcc_path = nvcc_path 168 | if compile_args is not None: 169 | Compiler._compile_args = [arg for arg in compile_args.split(os.pathsep)] 170 | 171 | except Exception as e: 172 | logger.warning("Could not load pyoptix.conf") 173 | 174 | if not os.path.exists(Compiler.output_path): 175 | os.makedirs(Compiler.output_path) 176 | os.chmod(Compiler.output_path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH) 177 | -------------------------------------------------------------------------------- /pyoptix/context.py: -------------------------------------------------------------------------------- 1 | import weakref 2 | import atexit 3 | from pyoptix._driver import NativeContextWrapper 4 | from pyoptix.enums import ExceptionType 5 | from pyoptix.mixins.scoped import ScopedObject 6 | 7 | 8 | class Context(ScopedObject): 9 | def __init__(self): 10 | self._program_cache = {} 11 | self._ray_gen_programs = {} 12 | self._exception_programs = {} 13 | self._miss_programs = {} 14 | self._destroyables = [] 15 | 16 | self._native = NativeContextWrapper() 17 | ScopedObject.__init__(self, self._native) 18 | 19 | push_context(self) 20 | 21 | def __del__(self): 22 | self._mark_all_objects_destroyed() 23 | 24 | def _mark_all_objects_destroyed(self): 25 | for destroyable in self._destroyables: 26 | if destroyable() is not None: 27 | destroyable().mark_destroyed() 28 | 29 | @property 30 | def program_cache(self): 31 | return self._program_cache 32 | 33 | def push(self): 34 | if current_context() == self: 35 | raise RuntimeError("Cannot push: Context is already at the top of the stack") 36 | else: 37 | push_context(self) 38 | 39 | def pop(self): 40 | if current_context() == self: 41 | pop_context() 42 | else: 43 | raise RuntimeError("Cannot pop: Context is not at the top of the stack") 44 | 45 | def launch(self, entry_point_index, width, height=None, depth=None): 46 | if not height: 47 | self._native.launch_1d(entry_point_index, width) 48 | elif not depth: 49 | self._native.launch_2d(entry_point_index, width, height) 50 | else: 51 | self._native.launch_3d(entry_point_index, width, height, depth) 52 | 53 | def _create_accelerator(self, builder, traverser): 54 | obj = self._native.create_accelerator(builder, traverser) 55 | self._destroyables.append(weakref.ref(obj)) 56 | return obj 57 | 58 | def _create_geometry(self): 59 | obj = self._native.create_geometry() 60 | self._destroyables.append(weakref.ref(obj)) 61 | return obj 62 | 63 | def _create_buffer(self, buffer_type): 64 | obj = self._native.create_buffer(buffer_type) 65 | self._destroyables.append(weakref.ref(obj)) 66 | return obj 67 | 68 | def _create_geometry_group(self): 69 | obj = self._native.create_geometry_group() 70 | self._destroyables.append(weakref.ref(obj)) 71 | return obj 72 | 73 | def _create_geometry_instance(self): 74 | obj = self._native.create_geometry_instance() 75 | self._destroyables.append(weakref.ref(obj)) 76 | return obj 77 | 78 | def _create_group(self): 79 | obj = self._native.create_group() 80 | self._destroyables.append(weakref.ref(obj)) 81 | return obj 82 | 83 | def _create_material(self): 84 | obj = self._native.create_material() 85 | self._destroyables.append(weakref.ref(obj)) 86 | return obj 87 | 88 | def _create_program_from_file(self, file_name, function_name): 89 | obj = self._native.create_program_from_file(file_name, function_name) 90 | self._destroyables.append(weakref.ref(obj)) 91 | return obj 92 | 93 | def _create_selector(self): 94 | obj = self._native.create_selector() 95 | self._destroyables.append(weakref.ref(obj)) 96 | return obj 97 | 98 | def _create_texture_sampler(self): 99 | obj = self._native.create_texture_sampler() 100 | self._destroyables.append(weakref.ref(obj)) 101 | return obj 102 | 103 | def _create_transform(self): 104 | obj = self._native.create_transform() 105 | self._destroyables.append(weakref.ref(obj)) 106 | return obj 107 | 108 | def get_ray_type_count(self): 109 | return self._native.get_ray_type_count() 110 | 111 | def set_ray_type_count(self, ray_type_count): 112 | if not isinstance(ray_type_count, int) or ray_type_count < 0: 113 | raise TypeError('Index offset must be a positive integer') 114 | 115 | self._native.set_ray_type_count(ray_type_count) 116 | 117 | def get_entry_point_count(self): 118 | return self._native.get_entry_point_count() 119 | 120 | def set_entry_point_count(self, entry_point_count): 121 | if not isinstance(entry_point_count, int) or entry_point_count < 0: 122 | raise TypeError('Entry point count must be a positive integer') 123 | 124 | self._native.set_entry_point_count(entry_point_count) 125 | 126 | def get_cpu_num_of_threads(self): 127 | return self._native.get_cpu_num_of_threads() 128 | 129 | def set_cpu_num_of_threads(self, cpu_num_of_threads): 130 | if not isinstance(cpu_num_of_threads, int) or cpu_num_of_threads < 0: 131 | raise TypeError('Number of threads must be a positive integer') 132 | 133 | self._native.set_cpu_num_of_threads(cpu_num_of_threads) 134 | 135 | def get_stack_size(self): 136 | return self._native.get_stack_size() 137 | 138 | def set_stack_size(self, stack_size_bytes): 139 | if not isinstance(stack_size_bytes, int) or stack_size_bytes < 0: 140 | raise TypeError('Stack size is the number of bytes that must be a positive integer') 141 | 142 | self._native.set_stack_size(stack_size_bytes) 143 | 144 | def get_available_devices_count(self): 145 | return self._native.get_available_devices_count() 146 | 147 | def get_device_name(self, device_id): 148 | return self._native.get_device_name(device_id) 149 | 150 | def get_device_compute_capability(self, device_id): 151 | return self._native.get_device_compute_capability(device_id) 152 | 153 | def get_enabled_device_count(self): 154 | return self._native.get_enabled_device_count() 155 | 156 | def get_enabled_devices(self): 157 | return self._native.get_enabled_devices() 158 | 159 | def set_devices(self, devices): 160 | self._native.set_devices(devices) 161 | 162 | def get_used_host_memory(self): 163 | return self._native.get_used_host_memory() 164 | 165 | def get_available_device_memory(self, device_id): 166 | return self._native.get_available_device_memory(device_id) 167 | 168 | def get_exception_enabled(self, exception_type): 169 | if not isinstance(exception_type, ExceptionType): 170 | return TypeError('exception_type is not of type pyoptix.enums.ExceptionType') 171 | 172 | return self._native.get_exception_enabled(exception_type) 173 | 174 | def set_exception_enabled(self, exception_type, enabled=True): 175 | if not isinstance(exception_type, ExceptionType): 176 | return TypeError('exception_type is not of type pyoptix.enums.ExceptionType') 177 | 178 | self._native.set_exception_enabled(exception_type, enabled) 179 | 180 | def get_print_enabled(self): 181 | return self._native.get_print_enabled() 182 | 183 | def set_print_enabled(self, enabled=True): 184 | self._native.set_print_enabled(enabled) 185 | 186 | def get_print_buffer_size(self): 187 | return self._native.get_print_buffer_size() 188 | 189 | def set_print_buffer_size(self, print_buffer_size): 190 | if not isinstance(print_buffer_size, int) or print_buffer_size < 0: 191 | raise TypeError('Print buffer size is the number of bytes that must be a positive integer') 192 | 193 | self._native.set_print_buffer_size(print_buffer_size) 194 | 195 | def set_ray_generation_program(self, entry_point_index, program): 196 | self._native.set_ray_generation_program(entry_point_index, program._native) 197 | self._ray_gen_programs[entry_point_index] = program 198 | 199 | def get_ray_generation_program(self, entry_point_index): 200 | return self._ray_gen_programs[entry_point_index] 201 | 202 | def set_exception_program(self, entry_point_index, program): 203 | self._native.set_exception_program(entry_point_index, program._native) 204 | self._ray_gen_programs[entry_point_index] = program 205 | 206 | def get_exception_program(self, entry_point_index): 207 | return self._exception_programs[entry_point_index] 208 | 209 | def set_miss_program(self, ray_type_index, program): 210 | self._native.set_miss_program(ray_type_index, program._native) 211 | self._miss_programs[ray_type_index] = program 212 | 213 | def get_miss_program(self, ray_type_index): 214 | return self._miss_programs[ray_type_index] 215 | 216 | def set_all_exceptions_enabled(self, is_enabled): 217 | self._native.set_exception_enabled(ExceptionType.all, is_enabled) 218 | 219 | def validate(self): 220 | self._native.validate() 221 | 222 | def compile(self): 223 | self._native.compile() 224 | 225 | 226 | _context_stack = [] 227 | 228 | 229 | def current_context(): 230 | return _context_stack[-1] 231 | 232 | 233 | def push_context(ctx): 234 | if not isinstance(ctx, Context): 235 | raise TypeError('ctx must be an instance of Context') 236 | _context_stack.append(ctx) 237 | 238 | 239 | def pop_context(): 240 | return _context_stack.pop() 241 | 242 | 243 | def _clear_context_stack(): 244 | while len(_context_stack) > 0: 245 | ctx = _context_stack.pop() 246 | ctx._mark_all_objects_destroyed() 247 | 248 | 249 | atexit.register(_clear_context_stack) 250 | 251 | # Create a context automatically 252 | Context() 253 | -------------------------------------------------------------------------------- /pyoptix/entry_point.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from pyoptix.context import current_context 3 | from pyoptix.program import Program 4 | from pyoptix.utils import is_2_string_tuple 5 | from pyoptix.mixins.hascontext import HasContextMixin 6 | 7 | logger = logging.getLogger(__name__) 8 | 9 | 10 | class EntryPoint(HasContextMixin): 11 | __default_exception_program = None 12 | 13 | @classmethod 14 | def set_default_exception_program(cls, file_path, function_name): 15 | cls.__default_exception_program = (file_path, function_name) 16 | 17 | def __init__(self, ray_generation_program, exception_program=None, size=None): 18 | HasContextMixin.__init__(self, current_context()) 19 | 20 | if is_2_string_tuple(ray_generation_program): 21 | self.ray_generation_program = Program(*ray_generation_program) 22 | elif isinstance(ray_generation_program, Program): 23 | self.ray_generation_program = ray_generation_program 24 | else: 25 | raise ValueError('Invalid ray generation program given') 26 | 27 | if is_2_string_tuple(exception_program): 28 | self.exception_program = Program(*exception_program) 29 | elif isinstance(exception_program, Program) or exception_program is None: 30 | self.exception_program = exception_program 31 | else: 32 | raise ValueError('Invalid exception program given') 33 | 34 | self.size = size 35 | 36 | def __call__(self): 37 | self.launch() 38 | 39 | def __getitem__(self, item): 40 | return self.ray_generation_program[item] 41 | 42 | def __setitem__(self, key, value): 43 | if value is not None: 44 | self.ray_generation_program[key] = value 45 | 46 | def __delitem__(self, key): 47 | del self.ray_generation_program[key] 48 | 49 | def __contains__(self, item): 50 | return item in self.ray_generation_program 51 | 52 | def launch(self, size=None, context=None): 53 | if self.size is None and size is None: 54 | raise ValueError("Launch size must be set before or while launching") 55 | elif size is None: 56 | size = self.size 57 | 58 | if context is None: 59 | context = self._safe_context 60 | 61 | context.set_entry_point_count(1) 62 | context.set_ray_generation_program(0, self.ray_generation_program) 63 | 64 | if self.exception_program is not None: 65 | context.set_exception_program(0, self.exception_program) 66 | elif self.__default_exception_program is not None: 67 | context.set_exception_program(0, Program.get_or_create(*self.__default_exception_program)) 68 | 69 | # launch 70 | context.validate() 71 | context.compile() 72 | logger.debug("Launching {0} with {1} threads".format(self.ray_generation_program.name, size)) 73 | context.launch(0, *size) 74 | -------------------------------------------------------------------------------- /pyoptix/geometry.py: -------------------------------------------------------------------------------- 1 | from pyoptix.context import current_context 2 | from pyoptix.mixins.graphnode import GraphNodeMixin 3 | from pyoptix.mixins.scoped import ScopedObject 4 | from pyoptix.mixins.hascontext import HasContextMixin 5 | 6 | 7 | class Geometry(GraphNodeMixin, ScopedObject, HasContextMixin): 8 | def __init__(self, bounding_box_program, intersection_program): 9 | HasContextMixin.__init__(self, current_context()) 10 | ScopedObject.__init__(self, self._safe_context._create_geometry()) 11 | GraphNodeMixin.__init__(self) 12 | 13 | self._bounding_box_program = None 14 | self._intersection_program = None 15 | 16 | self.set_bounding_box_program(bounding_box_program) 17 | self.set_intersection_program(intersection_program) 18 | 19 | def mark_dirty(self): 20 | self._native.mark_dirty() 21 | 22 | def is_dirty(self): 23 | return self._native.is_dirty() 24 | 25 | def set_primitive_count(self, num_primitives): 26 | if not isinstance(num_primitives, int) or num_primitives < 0: 27 | raise TypeError('Primitive count must be an unsigned integer') 28 | 29 | self._native.set_primitive_count(num_primitives) 30 | 31 | def get_primitive_count(self): 32 | return self._native.get_primitive_count() 33 | 34 | def set_primitive_index_offset(self, index_offset): 35 | if not isinstance(index_offset, int) or index_offset < 0: 36 | raise TypeError('Index offset must be an unsigned integer') 37 | 38 | self._native.set_primitive_index_offset(index_offset) 39 | 40 | def get_primitive_index_offset(self): 41 | return self._native.get_primitive_index_offset() 42 | 43 | def set_bounding_box_program(self, program): 44 | self._bounding_box_program = program 45 | self._native.set_bounding_box_program(program._native) 46 | 47 | def get_bounding_box_program(self): 48 | return self._bounding_box_program 49 | 50 | def set_intersection_program(self, program): 51 | self._intersection_program = program 52 | self._native.set_intersection_program(program._native) 53 | 54 | def get_intersection_program(self): 55 | return self._intersection_program 56 | 57 | def validate(self): 58 | self._native.validate() 59 | -------------------------------------------------------------------------------- /pyoptix/geometry_group.py: -------------------------------------------------------------------------------- 1 | from pyoptix.context import current_context 2 | from pyoptix.mixins.destroyable import DestroyableObject 3 | from pyoptix.mixins.graphnode import GraphNodeMixin 4 | from pyoptix.mixins.parent import ParentMixin 5 | from pyoptix.mixins.hascontext import HasContextMixin 6 | 7 | 8 | class GeometryGroup(GraphNodeMixin, ParentMixin, HasContextMixin, DestroyableObject): 9 | def __init__(self, children=None): 10 | from pyoptix.acceleration import Acceleration 11 | from pyoptix.geometry_instance import GeometryInstance 12 | 13 | HasContextMixin.__init__(self, current_context()) 14 | DestroyableObject.__init__(self, self._safe_context._create_geometry_group()) 15 | GraphNodeMixin.__init__(self) 16 | ParentMixin.__init__(self, [Acceleration, GeometryInstance], children) 17 | 18 | self._acceleration = None 19 | 20 | def set_acceleration(self, acceleration): 21 | try: 22 | acceleration.validate() 23 | except Exception as e: 24 | raise RuntimeError('Acceleration could not be validated') 25 | 26 | self._safe_native.set_acceleration(acceleration._safe_native) 27 | self._acceleration = acceleration 28 | 29 | def get_acceleration(self): 30 | return self._acceleration 31 | 32 | def validate(self): 33 | self._safe_native.validate() 34 | 35 | """ 36 | Use Context scope when a variable is assigned to GeometryGroup 37 | """ 38 | def __getitem__(self, item): 39 | return self._safe_context[item] 40 | 41 | def __setitem__(self, key, value): 42 | if value is not None: 43 | self._safe_context[key] = value 44 | 45 | def __delitem__(self, key): 46 | del self._safe_context[key] 47 | 48 | def __contains__(self, item): 49 | return item in self._safe_context 50 | 51 | """ 52 | Override get children methods because GeometryGroup's children must be of type GeometryInstance 53 | """ 54 | def get_geometry_instances(self): 55 | return self._children 56 | 57 | def get_materials(self): 58 | materials = set() 59 | for geometry_instance in self._children: 60 | materials = materials | set(geometry_instance.get_materials()) 61 | return list(materials) 62 | 63 | def get_geometries(self): 64 | geometries = set() 65 | for geometry_instance in self._children: 66 | geometries.add(geometry_instance.get_geometry()) 67 | return list(geometries) 68 | -------------------------------------------------------------------------------- /pyoptix/geometry_instance.py: -------------------------------------------------------------------------------- 1 | from pyoptix.context import current_context 2 | from pyoptix.geometry import Geometry 3 | from pyoptix.material import Material 4 | from pyoptix.mixins.graphnode import GraphNodeMixin 5 | from pyoptix.mixins.scoped import ScopedObject 6 | from pyoptix.mixins.hascontext import HasContextMixin 7 | 8 | 9 | class GeometryInstance(GraphNodeMixin, ScopedObject, HasContextMixin): 10 | def __init__(self, geometry=None, materials=None): 11 | HasContextMixin.__init__(self, current_context()) 12 | ScopedObject.__init__(self, self._safe_context._create_geometry_instance()) 13 | GraphNodeMixin.__init__(self) 14 | 15 | self._geometry = None 16 | self._materials = [] 17 | 18 | if geometry is not None and isinstance(geometry, Geometry): 19 | self.set_geometry(geometry) 20 | 21 | if materials is not None: 22 | # allow single material parameter 23 | if isinstance(materials, Material): 24 | materials = [materials] 25 | 26 | if not isinstance(materials, list): 27 | raise TypeError('materials parameter must be a list') 28 | 29 | self._safe_native.set_material_count(len(materials)) 30 | for idx, material in enumerate(materials): 31 | self.set_material(idx, material) 32 | 33 | def validate(self): 34 | self._safe_native.validate() 35 | 36 | def add_material(self, material): 37 | self._safe_native.set_material_count(len(self._materials)) 38 | self._safe_native.set_material(len(self._materials), material._safe_native) 39 | 40 | def set_material(self, idx, material): 41 | if not isinstance(material, Material): 42 | raise TypeError('Parameter material is not of type Material') 43 | 44 | if idx > len(self._materials): 45 | raise IndexError('Material index is out of range') 46 | 47 | if idx == len(self._materials): 48 | self._materials.append(material) 49 | else: 50 | self._materials[idx] = material 51 | 52 | self._safe_native.set_material_count(len(self._materials)) 53 | self._safe_native.set_material(idx, material._safe_native) 54 | 55 | def get_material(self, idx=0): 56 | if idx < len(self._materials): 57 | return self._materials[idx] 58 | else: 59 | raise IndexError('Material index is out of range') 60 | 61 | def get_materials(self): 62 | return self._materials 63 | 64 | def get_material_count(self): 65 | return len(self._materials) 66 | 67 | def set_geometry(self, geometry): 68 | if not isinstance(geometry, Geometry): 69 | raise TypeError('Parameter geometry is not of type Geometry') 70 | 71 | self._geometry = geometry 72 | self._safe_native.set_geometry(geometry._safe_native) 73 | 74 | def get_geometry(self): 75 | return self._geometry 76 | -------------------------------------------------------------------------------- /pyoptix/group.py: -------------------------------------------------------------------------------- 1 | from pyoptix.context import current_context 2 | from pyoptix.mixins.destroyable import DestroyableObject 3 | from pyoptix.mixins.graphnode import GraphNodeMixin 4 | from pyoptix.mixins.parent import ParentMixin 5 | from pyoptix.mixins.hascontext import HasContextMixin 6 | 7 | 8 | class Group(GraphNodeMixin, ParentMixin, HasContextMixin, DestroyableObject): 9 | def __init__(self, children=None): 10 | from pyoptix.acceleration import Acceleration 11 | from pyoptix.geometry_group import GeometryGroup 12 | from pyoptix.selector import Selector 13 | from pyoptix.transform import Transform 14 | 15 | HasContextMixin.__init__(self, current_context()) 16 | DestroyableObject.__init__(self, self._safe_context._create_group()) 17 | GraphNodeMixin.__init__(self) 18 | ParentMixin.__init__(self, [GeometryGroup, Group, Selector, Transform, Acceleration], children) 19 | 20 | self._acceleration = None 21 | 22 | def set_acceleration(self, acceleration): 23 | try: 24 | acceleration.validate() 25 | except Exception as e: 26 | raise RuntimeError('Acceleration could not be validated') 27 | 28 | self._safe_native.set_acceleration(acceleration._safe_native) 29 | self._acceleration = acceleration 30 | 31 | def get_acceleration(self): 32 | return self._acceleration 33 | 34 | def validate(self): 35 | self._safe_native.validate() 36 | 37 | """ 38 | Use Context scope when a variable is assigned to GeometryGroup 39 | """ 40 | def __getitem__(self, item): 41 | return self._safe_context[item] 42 | 43 | def __setitem__(self, key, value): 44 | if value is not None: 45 | self._safe_context[key] = value 46 | 47 | def __delitem__(self, key): 48 | del self._safe_context[key] 49 | 50 | def __contains__(self, item): 51 | return item in self._safe_context 52 | -------------------------------------------------------------------------------- /pyoptix/material.py: -------------------------------------------------------------------------------- 1 | import six 2 | from pyoptix.context import current_context 3 | from pyoptix.mixins.graphnode import GraphNodeMixin 4 | from pyoptix.mixins.scoped import ScopedObject 5 | from pyoptix.mixins.hascontext import HasContextMixin 6 | 7 | 8 | class Material(GraphNodeMixin, ScopedObject, HasContextMixin): 9 | def __init__(self, closest_hit=None, any_hit=None): 10 | HasContextMixin.__init__(self, current_context()) 11 | ScopedObject.__init__(self, self._safe_context._create_material()) 12 | GraphNodeMixin.__init__(self) 13 | 14 | self._closest_hit_programs = {} 15 | self._any_hit_programs = {} 16 | 17 | if closest_hit is None: 18 | closest_hit = {} 19 | if any_hit is None: 20 | any_hit = {} 21 | 22 | for index, program in six.iteritems(closest_hit): 23 | self.set_closest_hit_program(index, program) 24 | 25 | for index, program in six.iteritems(any_hit): 26 | self.set_any_hit_program(index, program) 27 | 28 | def set_closest_hit_program(self, ray_type_index, program): 29 | self._closest_hit_programs[ray_type_index] = program 30 | self._safe_native.set_closest_hit_program(ray_type_index, program._safe_native) 31 | 32 | def get_closest_hit_program(self, ray_type_index): 33 | return self._closest_hit_programs[ray_type_index] 34 | 35 | def set_any_hit_program(self, ray_type_index, program): 36 | self._any_hit_programs[ray_type_index] = program 37 | self._safe_native.set_any_hit_program(ray_type_index, program._safe_native) 38 | 39 | def get_any_hit_program(self, ray_type_index): 40 | return self._any_hit_programs[ray_type_index] 41 | 42 | def validate(self): 43 | self._safe_native.validate() 44 | -------------------------------------------------------------------------------- /pyoptix/mixins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ozen/PyOptiX/c7510ee9d967fe6c22fddcdcdd3b0127e075c8ba/pyoptix/mixins/__init__.py -------------------------------------------------------------------------------- /pyoptix/mixins/bindless.py: -------------------------------------------------------------------------------- 1 | class BindlessMixin(object): 2 | def __init__(self): 3 | self._bindless = False 4 | 5 | @property 6 | def bindless(self): 7 | return self._bindless 8 | 9 | @bindless.setter 10 | def bindless(self, value): 11 | value = bool(value) 12 | self._safe_native.auto_destroy = not value 13 | self._bindless = value 14 | -------------------------------------------------------------------------------- /pyoptix/mixins/destroyable.py: -------------------------------------------------------------------------------- 1 | class DestroyableObject(object): 2 | def __init__(self, native): 3 | self._native = native 4 | 5 | @property 6 | def _safe_native(self): 7 | if not self._native.is_destroyed: 8 | return self._native 9 | else: 10 | raise RuntimeError('Underlying OptiX object was destroyed before.') 11 | -------------------------------------------------------------------------------- /pyoptix/mixins/graphnode.py: -------------------------------------------------------------------------------- 1 | class GraphNodeMixin(object): 2 | def __init__(self): 3 | self._parents = [] 4 | 5 | def _add_parent(self, parent): 6 | self._parents.append(parent) 7 | 8 | def _remove_parent(self, parent): 9 | self._parents.remove(parent) 10 | -------------------------------------------------------------------------------- /pyoptix/mixins/hascontext.py: -------------------------------------------------------------------------------- 1 | import weakref 2 | 3 | 4 | class HasContextMixin(object): 5 | def __init__(self, context): 6 | self._context_ref = weakref.ref(context) 7 | 8 | @property 9 | def _safe_context(self): 10 | ctx = self._context_ref() 11 | if ctx is not None: 12 | return ctx 13 | else: 14 | raise RuntimeError('Context of this object is no longer valid') 15 | -------------------------------------------------------------------------------- /pyoptix/mixins/parent.py: -------------------------------------------------------------------------------- 1 | class ParentMixin(object): 2 | def __init__(self, allowed_children, children=None): 3 | self._children = [] 4 | self._allowed_children = allowed_children 5 | 6 | if children is not None: 7 | if not isinstance(children, list): 8 | raise TypeError('children parameter must be a list') 9 | 10 | for child in children: 11 | self.add_child(child) 12 | 13 | def add_child(self, child): 14 | if not any([isinstance(child, allowed) for allowed in self._allowed_children]): 15 | raise TypeError( 16 | "You can not add {0} to {1} as a child".format(child.__class__.__name__, self.__class__.__name__)) 17 | 18 | total_child_count = self._safe_native.get_child_count() 19 | self._safe_native.set_child_count(total_child_count + 1) 20 | 21 | try: 22 | self._set_optix_child(total_child_count, child) 23 | except Exception as e: 24 | total_child_count = self._safe_native.get_child_count() 25 | self._safe_native.set_child_count(total_child_count - 1) 26 | raise e 27 | 28 | child._add_parent(self) 29 | self._children.append(child) 30 | return total_child_count 31 | 32 | def _set_optix_child(self, index, child): 33 | from pyoptix.acceleration import Acceleration 34 | from pyoptix.geometry import Geometry 35 | from pyoptix.geometry_group import GeometryGroup 36 | from pyoptix.geometry_instance import GeometryInstance 37 | from pyoptix.group import Group 38 | from pyoptix.material import Material 39 | from pyoptix.selector import Selector 40 | from pyoptix.transform import Transform 41 | 42 | if isinstance(child, Acceleration): 43 | self._safe_native.set_child_acceleration(index, child._safe_native) 44 | elif isinstance(child, Transform): 45 | self._safe_native.set_child_transform(index, child._safe_native) 46 | elif isinstance(child, GeometryGroup): 47 | self._safe_native.set_child_geometry_group(index, child._safe_native) 48 | elif isinstance(child, Selector): 49 | self._safe_native.set_child_selector(index, child._safe_native) 50 | elif isinstance(child, Group): 51 | self._safe_native.set_child_group(index, child._safe_native) 52 | elif isinstance(child, GeometryInstance): 53 | self._safe_native.set_child_geometry_instance(index, child._safe_native) 54 | elif isinstance(child, Geometry): 55 | self._safe_native.set_child_geometry(index, child._safe_native) 56 | elif isinstance(child, Material): 57 | self._safe_native.set_child_material(index, child._safe_native) 58 | else: 59 | raise TypeError( 60 | "You can not add {0} to {1} as a child".format(child.__class__.__name__, self.__class__.__name__)) 61 | 62 | def remove_child(self, child): 63 | index = self._children.index(child) 64 | 65 | if index != len(self._children) - 1: 66 | # swap with the last child 67 | self._set_optix_child(index, self._children[-1]) 68 | self._children[index], self._children[-1] = self._children[-1], self._children[index] 69 | 70 | self._remove_last_child() 71 | 72 | def _remove_last_child(self): 73 | self._children[-1]._remove_parent(self) 74 | self._safe_native.remove_child(len(self._children)-1) 75 | self._children.pop() 76 | 77 | def get_children(self): 78 | return self._children 79 | 80 | def get_geometry_instances(self): 81 | geometry_instances = set() 82 | for child in self._children: 83 | geometry_instances = geometry_instances | set(child.get_geometry_instances()) 84 | return list(geometry_instances) 85 | 86 | def get_materials(self): 87 | materials = set() 88 | for child in self._children: 89 | materials = materials | set(child.get_materials()) 90 | return list(materials) 91 | 92 | def get_geometries(self): 93 | geometries = set() 94 | for child in self._children: 95 | geometries = geometries | set(child.get_geometries()) 96 | return list(geometries) 97 | -------------------------------------------------------------------------------- /pyoptix/mixins/scoped.py: -------------------------------------------------------------------------------- 1 | from pyoptix.mixins.destroyable import DestroyableObject 2 | 3 | 4 | class ScopedObject(DestroyableObject): 5 | def __init__(self, native): 6 | DestroyableObject.__init__(self, native) 7 | self._variables = {} 8 | 9 | def __setitem__(self, key, value): 10 | from pyoptix.variable import Variable 11 | 12 | variable_wrapper = self._safe_native.query_variable(key) 13 | declared = False 14 | 15 | if variable_wrapper is None: 16 | variable_wrapper = self._safe_native.declare_variable(key) 17 | declared = True 18 | 19 | try: 20 | optix_variable = Variable(variable_wrapper) 21 | optix_variable.value = value 22 | self._variables[key] = optix_variable 23 | except Exception as e: 24 | if declared: 25 | self._safe_native.remove_variable(variable_wrapper) 26 | raise e 27 | 28 | def __getitem__(self, key): 29 | return self._variables[key].value 30 | 31 | def __len__(self): 32 | return len(self._variables) 33 | 34 | def __delitem__(self, key): 35 | wrapped_variable = self._safe_native.query_variable(key) 36 | if not wrapped_variable.is_valid(): 37 | raise ValueError("Variable not found") 38 | 39 | self._safe_native.remove_variable(wrapped_variable) 40 | del self._variables[key] 41 | 42 | def __contains__(self, item): 43 | return item in self._variables 44 | -------------------------------------------------------------------------------- /pyoptix/program.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyoptix.compiler import Compiler 3 | from pyoptix.context import current_context 4 | from pyoptix.mixins.bindless import BindlessMixin 5 | from pyoptix.mixins.scoped import ScopedObject 6 | from pyoptix.mixins.hascontext import HasContextMixin 7 | 8 | 9 | class Program(ScopedObject, HasContextMixin, BindlessMixin): 10 | dynamic_programs = False 11 | 12 | def __init__(self, file_path, function_name, output_ptx_name=None): 13 | HasContextMixin.__init__(self, current_context()) 14 | self._function_name = function_name 15 | 16 | file_path = Compiler.get_abs_program_path(file_path) 17 | 18 | if Compiler.is_ptx(file_path): 19 | self._ptx_path = file_path 20 | else: 21 | # if not ptx, compile to ptx 22 | self._ptx_path, _ = Compiler.compile(file_path, output_ptx_name) 23 | 24 | # Create program object from compiled file 25 | ScopedObject.__init__(self, self._safe_context._create_program_from_file(self._ptx_path, self._function_name)) 26 | BindlessMixin.__init__(self) 27 | 28 | self._safe_context.program_cache[(file_path, function_name)] = self 29 | 30 | @property 31 | def id(self): 32 | return self.get_id() 33 | 34 | @property 35 | def name(self): 36 | return "({0}, {1})".format(os.path.basename(self._ptx_path), self._function_name) 37 | 38 | @property 39 | def file_path(self): 40 | return self._ptx_path 41 | 42 | @property 43 | def function_name(self): 44 | return self._function_name 45 | 46 | def get_id(self): 47 | return self._safe_native.get_id() 48 | 49 | def validate(self): 50 | self._safe_native.validate() 51 | 52 | @classmethod 53 | def get_or_create(cls, file_path, function_name): 54 | file_path = Compiler.get_abs_program_path(file_path) 55 | cache_key = (file_path, function_name) 56 | context = current_context() 57 | 58 | if cache_key not in context.program_cache: 59 | # create new if it does not exist in cache 60 | context.program_cache[cache_key] = cls(file_path, function_name) 61 | elif not Compiler.is_ptx(file_path) and Program.dynamic_programs: 62 | # check if the source file was changed. it is compiled if it was changed 63 | ptx_path, is_compiled = Compiler.compile(file_path) 64 | 65 | # recreate program object if it was changed 66 | if is_compiled: 67 | context.program_cache[cache_key] = cls(ptx_path, function_name) 68 | 69 | return context.program_cache[cache_key] 70 | -------------------------------------------------------------------------------- /pyoptix/selector.py: -------------------------------------------------------------------------------- 1 | from pyoptix.context import current_context 2 | from pyoptix.mixins.destroyable import DestroyableObject 3 | from pyoptix.mixins.graphnode import GraphNodeMixin 4 | from pyoptix.mixins.parent import ParentMixin 5 | from pyoptix.mixins.hascontext import HasContextMixin 6 | 7 | 8 | class Selector(GraphNodeMixin, ParentMixin, HasContextMixin, DestroyableObject): 9 | def __init__(self, children=None): 10 | from pyoptix.geometry_group import GeometryGroup 11 | from pyoptix.group import Group 12 | from pyoptix.transform import Transform 13 | 14 | HasContextMixin.__init__(self, current_context()) 15 | DestroyableObject.__init__(self, self._safe_context._create_selector()) 16 | GraphNodeMixin.__init__(self) 17 | ParentMixin.__init__(self, [GeometryGroup, Group, Selector, Transform], children) 18 | 19 | self._visit_program = None 20 | 21 | def set_visit_program(self, program): 22 | self._safe_native.set_visit_program(program._safe_native) 23 | self._visit_program = program 24 | 25 | def get_visit_program(self): 26 | return self._visit_program 27 | 28 | def validate(self): 29 | self._safe_native.validate() 30 | -------------------------------------------------------------------------------- /pyoptix/texture_sampler.py: -------------------------------------------------------------------------------- 1 | from pyoptix._driver import OPTIX_VERSION 2 | from pyoptix.enums import FilterMode, convert_filtering_mode, convert_wrap_mode, convert_read_mode, \ 3 | convert_indexing_mode 4 | from pyoptix.context import current_context 5 | from pyoptix.mixins.bindless import BindlessMixin 6 | from pyoptix.mixins.destroyable import DestroyableObject 7 | from pyoptix.mixins.hascontext import HasContextMixin 8 | 9 | 10 | class TextureSampler(HasContextMixin, DestroyableObject, BindlessMixin): 11 | def __init__(self, buffer, wrap_mode=None, indexing_mode=None, 12 | read_mode=None, filter_mode=None, max_anisotropy=1): 13 | HasContextMixin.__init__(self, current_context()) 14 | DestroyableObject.__init__(self, self._safe_context._create_texture_sampler()) 15 | BindlessMixin.__init__(self) 16 | 17 | self._buffer = None 18 | self._filtering_mode_minification = None 19 | self._filtering_mode_magnification = None 20 | self._filtering_mode_mipmapping = None 21 | 22 | if indexing_mode is not None: 23 | self.set_indexing_mode(indexing_mode) 24 | 25 | if wrap_mode is not None: 26 | self.set_wrap_mode(0, wrap_mode) 27 | self.set_wrap_mode(1, wrap_mode) 28 | self.set_wrap_mode(2, wrap_mode) 29 | 30 | if read_mode is not None: 31 | self.set_read_mode(read_mode) 32 | 33 | if filter_mode is not None: 34 | if OPTIX_VERSION >= 3090 and buffer.get_mip_level_count() > 1: 35 | self.set_filtering_modes(filter_mode, filter_mode, filter_mode) 36 | else: 37 | self.set_filtering_modes(filter_mode, filter_mode, FilterMode.none) 38 | 39 | self._safe_native.set_max_anisotropy(max_anisotropy) 40 | 41 | if OPTIX_VERSION < 3090: 42 | # required with OptiX < 3.9.0 43 | self._safe_native.set_mip_level_count(1) 44 | self._safe_native.set_array_size(1) 45 | 46 | self.set_buffer(0, 0, buffer) 47 | 48 | @property 49 | def id(self): 50 | return self.get_id() 51 | 52 | def get_id(self): 53 | return self._safe_native.get_id() 54 | 55 | def set_buffer(self, texture_array_idx, mip_level, buffer): 56 | self._buffer = buffer 57 | self._safe_native.set_buffer(texture_array_idx, mip_level, buffer._safe_native) 58 | 59 | def get_buffer(self): 60 | return self._buffer 61 | 62 | def set_filtering_modes(self, minification=None, magnification=None, mipmapping=None): 63 | minification = convert_filtering_mode(minification) 64 | magnification = convert_filtering_mode(magnification) 65 | mipmapping = convert_filtering_mode(mipmapping) 66 | 67 | if minification is None: 68 | minification = FilterMode.none 69 | 70 | if magnification is None: 71 | magnification = FilterMode.none 72 | 73 | if mipmapping is None: 74 | mipmapping = FilterMode.none 75 | 76 | self._filtering_mode_minification = minification 77 | self._filtering_mode_magnification = magnification 78 | self._filtering_mode_mipmapping = mipmapping 79 | 80 | self._safe_native.set_filtering_modes(minification, magnification, mipmapping) 81 | 82 | def get_filtering_modes(self): 83 | return self._filtering_mode_minification, self._filtering_mode_magnification, self._filtering_mode_mipmapping 84 | 85 | def set_wrap_mode(self, dim, mode): 86 | mode = convert_wrap_mode(mode) 87 | self._safe_native.set_wrap_mode(dim, mode) 88 | 89 | def get_wrap_mode(self): 90 | return self._safe_native.get_wrap_mode() 91 | 92 | def set_read_mode(self, mode): 93 | mode = convert_read_mode(mode) 94 | self._safe_native.set_read_mode(mode) 95 | 96 | def get_read_mode(self): 97 | return self._safe_native.get_read_mode() 98 | 99 | def set_indexing_mode(self, mode): 100 | mode = convert_indexing_mode(mode) 101 | self._safe_native.set_indexing_mode(mode) 102 | 103 | def get_indexing_mode(self): 104 | return self._safe_native.get_indexing_mode() 105 | 106 | def set_max_anisotropy(self, max_anisotropy): 107 | self._safe_native.set_max_anisotropy(max_anisotropy) 108 | 109 | def get_max_anisotropy(self): 110 | return self._safe_native.get_max_anisotropy() 111 | 112 | def set_mip_level_clamp(self, mip_level_clamp): 113 | self._safe_native.set_mip_level_clamp(mip_level_clamp) 114 | 115 | def get_mip_level_clamp(self): 116 | return self._safe_native.get_mip_level_clamp() 117 | 118 | def set_mip_level_bias(self, mip_level_bias): 119 | self._safe_native.set_mip_level_bias(mip_level_bias) 120 | 121 | def get_mip_level_bias(self): 122 | return self._safe_native.get_mip_level_bias() 123 | 124 | def validate(self): 125 | self._safe_native.validate() 126 | -------------------------------------------------------------------------------- /pyoptix/transform.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | from pyoptix.context import current_context 3 | from pyoptix.mixins.destroyable import DestroyableObject 4 | from pyoptix.mixins.graphnode import GraphNodeMixin 5 | from pyoptix.mixins.parent import ParentMixin 6 | from pyoptix.mixins.hascontext import HasContextMixin 7 | 8 | 9 | class Transform(GraphNodeMixin, ParentMixin, HasContextMixin, DestroyableObject): 10 | def __init__(self, children=None): 11 | from pyoptix.geometry_group import GeometryGroup 12 | from pyoptix.group import Group 13 | from pyoptix.selector import Selector 14 | 15 | HasContextMixin.__init__(self, current_context()) 16 | DestroyableObject.__init__(self, self._safe_context._create_transform()) 17 | GraphNodeMixin.__init__(self) 18 | ParentMixin.__init__(self, [GeometryGroup, Group, Selector, Transform], children) 19 | 20 | self._transpose = False 21 | 22 | def set(self, matrix, column_major=False): 23 | self._transpose = column_major 24 | 25 | if isinstance(matrix, numpy.ndarray) and isinstance(matrix.dtype, numpy.float32): 26 | self.set_matrix(self._transpose, matrix) 27 | else: 28 | self.set_matrix(self._transpose, numpy.matrix(matrix, dtype=numpy.float32)) 29 | 30 | def get(self, column_major=None): 31 | transpose = column_major if column_major is not None else self._transpose 32 | return self.get_matrix(transpose) 33 | 34 | def get_child_count(self): 35 | return 1 36 | 37 | def _set_child_count(self, count): 38 | pass 39 | 40 | def set_matrix(self, transpose, matrix): 41 | matrix = numpy.array(matrix, dtype=numpy.float32) 42 | 43 | if matrix.shape != (4, 4): 44 | raise ValueError('Transformation matrix must be 4 by 4') 45 | 46 | self._safe_native.set_matrix(transpose, matrix.tolist()) 47 | 48 | def get_matrix(self, transpose): 49 | return numpy.array(self._safe_native.get_matrix(transpose), dtype=numpy.float32) 50 | 51 | def validate(self): 52 | self._safe_native.validate() 53 | -------------------------------------------------------------------------------- /pyoptix/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import fnmatch 3 | 4 | 5 | def find_sub_path(sub_path, search_paths): 6 | import os.path 7 | 8 | for search_path in search_paths: 9 | path = os.path.join(search_path, sub_path) 10 | if os.path.exists(path): 11 | return path 12 | 13 | raise ValueError('Sub-path not found in searched paths: {0}'.format(sub_path)) 14 | 15 | 16 | def is_2_string_tuple(obj): 17 | return isinstance(obj, tuple) and len(obj) == 2 \ 18 | and isinstance(obj[0], str) and isinstance(obj[1], str) 19 | 20 | 21 | def is_4_string_tuple(obj): 22 | return isinstance(obj, tuple) and len(obj) == 4 \ 23 | and isinstance(obj[0], str) and isinstance(obj[1], str) \ 24 | and isinstance(obj[2], str) and isinstance(obj[4], str) 25 | 26 | 27 | def glob_recursive(path, pattern): 28 | matches = [] 29 | for dirpath, dirnames, filenames in os.walk(path): 30 | for filename in fnmatch.filter(filenames, pattern): 31 | matches.append(os.path.join(dirpath, filename)) 32 | return matches 33 | -------------------------------------------------------------------------------- /pyoptix/variable.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | from pyoptix.enums import ObjectType, get_object_type_from_dtype, get_dtype_from_object_type, \ 3 | get_object_type_from_pyoptix_class 4 | 5 | OBJECT_TYPE_TO_SET_FUNCTION = { 6 | ObjectType.buffer: 'set_buffer', 7 | ObjectType.texture_sampler: 'set_texture', 8 | ObjectType.program: 'set_program_id_with_program', 9 | ObjectType.group: 'set_group', 10 | ObjectType.geometry_group: 'set_geometry_group', 11 | ObjectType.selector: 'set_selector', 12 | ObjectType.transform: 'set_transform', 13 | } 14 | 15 | 16 | class Variable(object): 17 | def __init__(self, wrapped_variable): 18 | self._native = wrapped_variable 19 | self._value = None 20 | 21 | @property 22 | def name(self): 23 | return self._native.name 24 | 25 | @property 26 | def type(self): 27 | return self._native.type 28 | 29 | @property 30 | def annotation(self): 31 | return self._native.annotation 32 | 33 | @property 34 | def nbytes(self): 35 | return self._native.nbytes 36 | 37 | @property 38 | def value(self): 39 | return self._value 40 | 41 | @value.setter 42 | def value(self, value): 43 | optix_has_type = self.type != ObjectType.unknown and self.type != ObjectType.user 44 | class_object_type = get_object_type_from_pyoptix_class(value) 45 | 46 | if class_object_type: 47 | # OPTION 1: value is a known OptiX object like GeometryGroup, Buffer etc. 48 | # do a preliminary check on type right now so it won't fail in device-compile time 49 | if optix_has_type and self.type != class_object_type and self.type != ObjectType.object: 50 | raise TypeError("Variable type is {0}, but {1} was given".format(self.type, type(value))) 51 | 52 | # call the respective set function of the optix type of the variable 53 | getattr(self._native, OBJECT_TYPE_TO_SET_FUNCTION[class_object_type])(value._native) 54 | self._value = value 55 | 56 | elif optix_has_type: 57 | # OPTION 2: OptiX variable has a type but value is not a known OptiX object. 58 | # Try to form a numpy array from value that is compatible with the variable type. 59 | try: 60 | dtype, shape = get_dtype_from_object_type(self.type) 61 | 62 | if dtype is None or shape is None: 63 | raise ValueError() 64 | 65 | value = numpy.array(value, dtype=dtype) 66 | 67 | if len(value.shape) == 0: 68 | value = value.reshape(1) 69 | 70 | if value.shape != shape: 71 | raise TypeError("Array shape does not match to the shape of {0}.".format(self.type)) 72 | 73 | self._native.set_from_array(value, self.type) 74 | self._value = value 75 | 76 | except (ValueError, AttributeError): 77 | raise TypeError("Variable type is {0}, but {1} was given".format(self.type, type(value))) 78 | 79 | elif isinstance(value, numpy.ndarray) and not optix_has_type: 80 | # OPTION 3: OptiX variable type is unknown or it is user-type, but the value is a numpy array. 81 | # Use ndarray's dtype to determine variable type 82 | if len(value.shape) == 0: 83 | value = value.reshape(1) 84 | 85 | object_type = get_object_type_from_dtype(value.dtype, value.shape) 86 | self._native.set_from_array(value, object_type) 87 | self._value = value 88 | 89 | else: 90 | # Unknown and user-typed variables can only be assigned an ndarray 91 | raise TypeError("Cannot recognize the variable type or it's user-type. You can assign a numpy array.") 92 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | six 2 | numpy 3 | Pillow 4 | PyYAML 5 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import fnmatch 4 | from subprocess import check_call, check_output, CalledProcessError 5 | from tempfile import NamedTemporaryFile 6 | from setuptools import setup, Extension 7 | 8 | try: 9 | from configparser import ConfigParser 10 | except ImportError: 11 | from ConfigParser import SafeConfigParser as ConfigParser 12 | 13 | BOOST_PYTHON_LIBNAMES = [ 14 | 'boost_python-py%s%s' % (sys.version_info.major, sys.version_info.minor), 15 | 'boost_python%s' % sys.version_info.major, 16 | ] 17 | 18 | BOOST_PYTHON_FILENAMES = {'lib%s.so' % libname: libname for libname in BOOST_PYTHON_LIBNAMES} 19 | 20 | ld_paths = None 21 | 22 | 23 | def check_call_sudo_if_fails(cmd): 24 | try: 25 | return check_call(cmd) 26 | except CalledProcessError as e: 27 | return check_call(['sudo'] + cmd) 28 | 29 | 30 | def check_output_sudo_if_fails(cmd): 31 | try: 32 | return check_output(cmd) 33 | except CalledProcessError as e: 34 | return check_output(['sudo'] + cmd) 35 | 36 | 37 | def populate_ld_paths(): 38 | global ld_paths 39 | ld_paths = [] 40 | for line in check_output_sudo_if_fails(['ldconfig', '-vNX']).decode('utf8').splitlines(): 41 | if line.startswith('/'): 42 | ld_paths.append(line[:line.find(':')]) 43 | if "LD_LIBRARY_PATH" in os.environ: 44 | ld_paths.extend(os.environ["LD_LIBRARY_PATH"].split(os.pathsep)) 45 | 46 | 47 | def glob_recursive(path, pattern): 48 | matches = [] 49 | for dirpath, dirnames, filenames in os.walk(path): 50 | for filename in fnmatch.filter(filenames, pattern): 51 | matches.append(os.path.join(dirpath, filename)) 52 | return matches 53 | 54 | 55 | def search_library(filenames): 56 | filenames = list(filenames) 57 | 58 | if ld_paths is None: 59 | populate_ld_paths() 60 | 61 | for path in ld_paths: 62 | for filename in filenames: 63 | print(os.path.join(path, filename)) 64 | if os.path.exists(os.path.join(path, filename)): 65 | return os.path.abspath(os.path.join(path, filename)) 66 | 67 | 68 | def search_on_path(filenames): 69 | filenames = list(filenames) 70 | 71 | for path in os.environ["PATH"].split(os.pathsep): 72 | for filename in filenames: 73 | if os.path.exists(os.path.join(path, filename)): 74 | return os.path.abspath(os.path.join(path, filename)) 75 | 76 | 77 | def save_pyoptix_conf(nvcc_path, compile_args, include_dirs, library_dirs, libraries): 78 | try: 79 | config = ConfigParser() 80 | config.add_section('pyoptix') 81 | 82 | config.set('pyoptix', 'nvcc_path', nvcc_path) 83 | config.set('pyoptix', 'compile_args', os.pathsep.join(compile_args)) 84 | config.set('pyoptix', 'include_dirs', os.pathsep.join(include_dirs)) 85 | config.set('pyoptix', 'library_dirs', os.pathsep.join(library_dirs)) 86 | config.set('pyoptix', 'libraries', os.pathsep.join(libraries)) 87 | 88 | tmp = NamedTemporaryFile(mode='w+', delete=False) 89 | config.write(tmp) 90 | tmp.close() 91 | config_path = os.path.join(os.path.dirname(sys.executable), 'pyoptix.conf') 92 | check_call_sudo_if_fails(['cp', tmp.name, config_path]) 93 | check_call_sudo_if_fails(['cp', tmp.name, '/etc/pyoptix.conf']) 94 | check_call_sudo_if_fails(['chmod', '644', config_path]) 95 | check_call_sudo_if_fails(['chmod', '644', '/etc/pyoptix.conf']) 96 | except Exception as e: 97 | print("PyOptiX configuration could not be saved. When you use pyoptix.Compiler, " 98 | "nvcc path must be in PATH, OptiX library paths must be in LD_LIBRARY_PATH, and pyoptix.Compiler " 99 | "attributes should be set manually.") 100 | 101 | 102 | def extension_prebuild(): 103 | nvcc_path = search_on_path(['nvcc', 'nvcc.exe']) 104 | if nvcc_path is None: 105 | raise OSError('nvcc is not in PATH') 106 | 107 | cuda_root = os.path.dirname(os.path.dirname(nvcc_path)) 108 | cuda_include = os.path.join(cuda_root, 'include') 109 | cuda_lib_dirs = [ 110 | os.path.join(cuda_root, 'lib64'), 111 | os.path.join(cuda_root, 'bin'), 112 | ] 113 | 114 | optix_lib_path = search_library(['liboptix.so']) 115 | 116 | if optix_lib_path is None: 117 | raise OSError('OptiX Library not found. Add its path to ldconfig or LD_LIBRARY_PATH.') 118 | 119 | optix_root = os.path.dirname(os.path.dirname(optix_lib_path)) 120 | optix_include = os.path.join(optix_root, 'include') 121 | optix_lib_dirs = [ 122 | os.path.join(optix_root, 'lib64'), 123 | os.path.join(optix_root, 'bin'), 124 | ] 125 | 126 | boost_python_lib_file = search_library(BOOST_PYTHON_FILENAMES) 127 | 128 | if boost_python_lib_file is None: 129 | raise OSError('Boost.Python library not found. Add its path to ldconfig or LD_LIBRARY_PATH.') 130 | 131 | boost_python_lib_dir, boost_python_lib_name = os.path.split(boost_python_lib_file) 132 | 133 | sources = glob_recursive('driver', '*.cpp') 134 | include_dirs = [x[0] for x in os.walk('driver')] + [cuda_include, optix_include] 135 | library_dirs = cuda_lib_dirs + optix_lib_dirs + [boost_python_lib_dir] 136 | libraries = ['optix', 'optixu', 'cudart', BOOST_PYTHON_FILENAMES[boost_python_lib_name]] 137 | 138 | compile_args = [ 139 | '-I%s' % cuda_include, '-I%s' % optix_include, '-I%s' % optix_include, '-loptix', '-loptixu', 140 | '-lcudart', 141 | ] + ['-L%s' % lib for lib in cuda_lib_dirs + optix_lib_dirs] 142 | 143 | save_pyoptix_conf(nvcc_path, compile_args, include_dirs, library_dirs, libraries) 144 | 145 | return sources, include_dirs, library_dirs, libraries 146 | 147 | 148 | def main(): 149 | building_extension = False 150 | 151 | for arg in sys.argv: 152 | if arg in ['build', 'build_ext', 'install', 'install_lib']: 153 | building_extension = True 154 | 155 | if building_extension: 156 | sources, include_dirs, library_dirs, libraries = extension_prebuild() 157 | else: 158 | sources = include_dirs = library_dirs = libraries = [] 159 | 160 | setup( 161 | name='pyoptix', 162 | version='0.10.1', 163 | description='Python wrapper for NVIDIA OptiX', 164 | author='Yigit Ozen', 165 | author_email='ozen@computer.org', 166 | license="MIT", 167 | url='http://github.com/ozen/pyoptix', 168 | packages=['pyoptix', 'pyoptix.mixins'], 169 | ext_modules=[Extension(name='pyoptix._driver', sources=sources, include_dirs=include_dirs, 170 | library_dirs=library_dirs, runtime_library_dirs=library_dirs, libraries=libraries, 171 | language='c++', extra_compile_args=['-std=c++11'])], 172 | install_requires=['six', 'numpy'], 173 | classifiers=[ 174 | 'Development Status :: 5 - Production/Stable', 175 | 'Intended Audience :: Developers', 176 | 'Topic :: Multimedia :: Graphics :: 3D Rendering', 177 | 'Topic :: Software Development :: Libraries :: Python Modules', 178 | 'Operating System :: POSIX :: Linux', 179 | 'Programming Language :: Python', 180 | 'Programming Language :: Python :: 2', 181 | 'Programming Language :: Python :: 2.7', 182 | 'Programming Language :: Python :: 3', 183 | 'Programming Language :: Python :: 3.2', 184 | 'Programming Language :: Python :: 3.3', 185 | 'Programming Language :: Python :: 3.4', 186 | 'Programming Language :: Python :: 3.5', 187 | 'Programming Language :: Python :: 3.6', 188 | ], 189 | ) 190 | 191 | 192 | if __name__ == '__main__': 193 | main() 194 | --------------------------------------------------------------------------------