├── gallery ├── sponza.png └── breakfast_room.png ├── python ├── FeiRays │ ├── __init__.py │ ├── PyFeiRays.dll │ ├── libPyFeiRays.so │ ├── utils.py │ ├── Native.py │ └── Scene.py ├── README.md ├── setup.py └── test.py ├── shaders ├── common │ ├── miss.spv │ ├── frag_srgb.spv │ ├── rand_init.spv │ ├── vert_srgb.spv │ ├── miss_tex_sky.spv │ ├── light_source_dist.shinc │ ├── image.shinc │ ├── vert_srgb.vert │ ├── bindings.h │ ├── frag_srgb.frag │ ├── sunlight.shinc │ ├── payload.shinc │ ├── rand_init.comp │ ├── miss.rmiss │ ├── miss_tex_sky.rmiss │ └── rand_xorwow.shinc ├── glslangValidator.exe ├── path_tracer │ ├── final.spv │ ├── raygen.spv │ ├── raygen_params.shinc │ ├── final.comp │ └── raygen.rgen ├── geometry │ ├── closesthit_sphere_lights.spv │ ├── intersection_unit_spheres.spv │ ├── closesthit_colored_unit_spheres.spv │ ├── closesthit_textured_triangle_lists.spv │ ├── closesthit_textured_unit_spheres.spv │ ├── closesthit_unit_spheres_checker_tex.spv │ ├── closesthit_colored_indexed_triangle_lists.spv │ ├── closesthit_wavefront_indexed_triangle_lists.spv │ ├── closesthit_sphere_lights.rchit │ ├── intersection_unit_spheres.rint │ ├── closesthit_unit_spheres_checker_tex.rchit │ ├── closesthit_textured_unit_spheres.rchit │ ├── closesthit_colored_unit_spheres.rchit │ ├── closesthit_colored_indexed_triangle_lists.rchit │ ├── closesthit_textured_triangle_lists.rchit │ └── closesthit_wavefront_indexed_triangle_lists.rchit ├── build.bat └── build.sh ├── RNGState_xorwow.h ├── PyFeiRays ├── CMakeLists.txt ├── texture_map.h ├── api_utils.cpp ├── Scene.h ├── texture_map.cpp ├── dds_reader.hpp ├── api.h ├── api_scene.cpp └── Scene.cpp ├── .gitmodules ├── Material.h ├── ColoredUnitSphere.h ├── TexturedUnitSphere.h ├── tests ├── lambertian_obj.h ├── texture_map.h ├── wavefront_obj.h ├── test_rng.cpp ├── texture_map.cpp ├── test7.cpp ├── dds_reader.hpp ├── lambertian_obj.cpp ├── test3.cpp ├── rt_weekend.cpp ├── test2.cpp ├── test4.cpp ├── test6.cpp ├── test1.cpp ├── test5.cpp └── wavefront_obj.cpp ├── UnitSphereCheckerTex.h ├── SRGBConverter.h ├── RNGInitializer.h ├── ColoredIndexedTriangleList.h ├── TexturedTriangleList.h ├── Timing.h ├── WavefrontIndexedTriangleList.h ├── TexturedUnitSphere.cpp ├── ColoredUnitSphere.cpp ├── UnitSphereCheckerTex.cpp ├── pack_shaders.cpp ├── ColoredIndexedTriangleList.cpp ├── LICENSE ├── rand_state_init_xorwow.hpp ├── CMakeLists.txt ├── TexturedTriangleList.cpp ├── rand_state_init_xorwow.cu ├── README.md ├── WavefrontIndexedTriangleList.cpp ├── PathTracer.h ├── RNGInitializer.cpp ├── context.h └── SRGBConverter.cpp /gallery/sponza.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/gallery/sponza.png -------------------------------------------------------------------------------- /python/FeiRays/__init__.py: -------------------------------------------------------------------------------- 1 | from .utils import Transform 2 | from .Scene import * 3 | -------------------------------------------------------------------------------- /shaders/common/miss.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/common/miss.spv -------------------------------------------------------------------------------- /gallery/breakfast_room.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/gallery/breakfast_room.png -------------------------------------------------------------------------------- /python/FeiRays/PyFeiRays.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/python/FeiRays/PyFeiRays.dll -------------------------------------------------------------------------------- /python/FeiRays/libPyFeiRays.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/python/FeiRays/libPyFeiRays.so -------------------------------------------------------------------------------- /shaders/common/frag_srgb.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/common/frag_srgb.spv -------------------------------------------------------------------------------- /shaders/common/rand_init.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/common/rand_init.spv -------------------------------------------------------------------------------- /shaders/common/vert_srgb.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/common/vert_srgb.spv -------------------------------------------------------------------------------- /shaders/glslangValidator.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/glslangValidator.exe -------------------------------------------------------------------------------- /shaders/path_tracer/final.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/path_tracer/final.spv -------------------------------------------------------------------------------- /shaders/path_tracer/raygen.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/path_tracer/raygen.spv -------------------------------------------------------------------------------- /shaders/common/miss_tex_sky.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/common/miss_tex_sky.spv -------------------------------------------------------------------------------- /shaders/geometry/closesthit_sphere_lights.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/geometry/closesthit_sphere_lights.spv -------------------------------------------------------------------------------- /shaders/geometry/intersection_unit_spheres.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/geometry/intersection_unit_spheres.spv -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | FeiRays 2 | ================ 3 | Vulkan based Monte-Carol Ray-tracing. 4 | [FeiRays](https://github.com/fynv/FeiRays) 5 | 6 | 7 | -------------------------------------------------------------------------------- /shaders/geometry/closesthit_colored_unit_spheres.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/geometry/closesthit_colored_unit_spheres.spv -------------------------------------------------------------------------------- /shaders/geometry/closesthit_textured_triangle_lists.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/geometry/closesthit_textured_triangle_lists.spv -------------------------------------------------------------------------------- /shaders/geometry/closesthit_textured_unit_spheres.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/geometry/closesthit_textured_unit_spheres.spv -------------------------------------------------------------------------------- /shaders/geometry/closesthit_unit_spheres_checker_tex.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/geometry/closesthit_unit_spheres_checker_tex.spv -------------------------------------------------------------------------------- /shaders/geometry/closesthit_colored_indexed_triangle_lists.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/geometry/closesthit_colored_indexed_triangle_lists.spv -------------------------------------------------------------------------------- /shaders/geometry/closesthit_wavefront_indexed_triangle_lists.spv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fynv/FeiRays/HEAD/shaders/geometry/closesthit_wavefront_indexed_triangle_lists.spv -------------------------------------------------------------------------------- /RNGState_xorwow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct V5 4 | { 5 | unsigned v0; 6 | unsigned v1; 7 | unsigned v2; 8 | unsigned v3; 9 | unsigned v4; 10 | }; 11 | 12 | struct RNGState 13 | { 14 | V5 v; 15 | unsigned d; 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /shaders/path_tracer/raygen_params.shinc: -------------------------------------------------------------------------------- 1 | 2 | layout(std140, binding = 1) uniform RayGenParams 3 | { 4 | vec4 origin; 5 | vec4 upper_left; 6 | vec4 ux; 7 | vec4 uy; 8 | Image target; 9 | float lens_radius; 10 | int num_iter; 11 | }; 12 | 13 | -------------------------------------------------------------------------------- /PyFeiRays/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | 3 | project(PyFeiRays) 4 | 5 | add_library(PyFeiRays SHARED dds_reader.hpp Scene.cpp Scene.h texture_map.cpp texture_map.h api.h api_utils.cpp api_scene.cpp) 6 | target_link_libraries(PyFeiRays FeiRays volk) 7 | 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/glm"] 2 | path = thirdparty/glm 3 | url = https://github.com/g-truc/glm.git 4 | [submodule "thirdparty/volk"] 5 | path = thirdparty/volk 6 | url = https://github.com/zeux/volk.git 7 | [submodule "thirdparty/Vulkan-Headers"] 8 | path = thirdparty/Vulkan-Headers 9 | url = https://github.com/KhronosGroup/Vulkan-Headers.git 10 | -------------------------------------------------------------------------------- /Material.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | enum MaterialType 6 | { 7 | lambertian, 8 | metal, 9 | dielectric, 10 | emissive, 11 | foggy 12 | }; 13 | 14 | struct Material 15 | { 16 | MaterialType type = lambertian; 17 | glm::vec3 color = { 1.0f, 1.0f, 1.0f }; 18 | float fuzz = 0.0f; 19 | float ref_idx = 0.0f; 20 | float density = 0.0f; 21 | }; 22 | 23 | -------------------------------------------------------------------------------- /shaders/common/light_source_dist.shinc: -------------------------------------------------------------------------------- 1 | #ifndef LIGHT_SOURCE_DIST_H 2 | #define LIGHT_SOURCE_DIST_H 3 | 4 | layout(buffer_reference, std430, buffer_reference_align = 4) buffer LightSourceDistBuf 5 | { 6 | float d; 7 | }; 8 | 9 | layout(std140, binding = 6) uniform LightSourcesDist 10 | { 11 | LightSourceDistBuf buf_lightSourceDist; 12 | int number_sphere_lights; 13 | int number_sun_lights; 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /ColoredUnitSphere.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PathTracer.h" 4 | #include "Material.h" 5 | 6 | class ColoredUnitSphere : public Geometry 7 | { 8 | public: 9 | ColoredUnitSphere(const glm::mat4x4& model, const Material& material); 10 | virtual ~ColoredUnitSphere(); 11 | 12 | virtual GeoCls cls() const; 13 | virtual void get_view(void* view_buf) const; 14 | 15 | 16 | private: 17 | Material m_material; 18 | 19 | }; 20 | -------------------------------------------------------------------------------- /TexturedUnitSphere.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PathTracer.h" 4 | 5 | class TexturedUnitSphere : public Geometry 6 | { 7 | public: 8 | TexturedUnitSphere(const glm::mat4x4& model, int tex_id, const glm::vec3& color = { 1.0f, 1.0f, 1.0f }); 9 | virtual ~TexturedUnitSphere(); 10 | 11 | virtual GeoCls cls() const; 12 | virtual void get_view(void* view_buf) const; 13 | 14 | private: 15 | glm::vec3 m_color; 16 | int m_tex_id; 17 | }; -------------------------------------------------------------------------------- /shaders/common/image.shinc: -------------------------------------------------------------------------------- 1 | layout(buffer_reference, std430, buffer_reference_align = 4) buffer PixBuf 2 | { 3 | vec4 v; 4 | }; 5 | 6 | struct Image 7 | { 8 | PixBuf data; 9 | int width; 10 | int height; 11 | }; 12 | 13 | vec4 read_pixel (in Image img, int x, int y) 14 | { 15 | return img.data[x + y*img.width].v; 16 | } 17 | 18 | void write_pixel(in Image img, int x, int y, in vec4 v) 19 | { 20 | img.data[x + y*img.width].v = v; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /tests/lambertian_obj.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PathTracer.h" 4 | #include "texture_map.h" 5 | 6 | class TexturedTriangleList; 7 | 8 | class LambertianObject 9 | { 10 | public: 11 | LambertianObject(PathTracer& pt, const char* path, const char* fn, const glm::mat4x4& model); 12 | ~LambertianObject(); 13 | 14 | TexturedTriangleList* get_geo() const { return m_ttl; } 15 | 16 | private: 17 | TextureMap m_tex_map; 18 | TexturedTriangleList* m_ttl; 19 | 20 | }; 21 | -------------------------------------------------------------------------------- /shaders/common/vert_srgb.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_ARB_separate_shader_objects : enable 3 | 4 | layout (location = 0) out vec2 vUV; 5 | 6 | void main() 7 | { 8 | // grid should be (0, 0), (2, 0), (0, 2) 9 | vec2 grid = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); 10 | 11 | // pos should be (-1, -1), (3, -1), (-1, 3) 12 | vec2 vpos = grid * vec2(2.0f, 2.0f) + vec2(-1.0f, -1.0f); 13 | 14 | gl_Position = vec4(vpos, 1.0f, 1.0f); 15 | 16 | vUV = grid; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /tests/texture_map.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class PathTracer; 7 | class RGBATexture; 8 | 9 | class TextureMap : private std::unordered_map 10 | { 11 | public: 12 | TextureMap(PathTracer* pt, const char* path); 13 | virtual ~TextureMap(); 14 | 15 | int findTex(const char* texname, bool srgb = true); 16 | 17 | 18 | private: 19 | PathTracer* m_pt; 20 | std::string m_path; 21 | std::vector m_textures; 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /tests/wavefront_obj.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PathTracer.h" 4 | #include "texture_map.h" 5 | 6 | 7 | class WavefrontIndexedTriangleList; 8 | 9 | class WavefrontObject 10 | { 11 | public: 12 | WavefrontObject(PathTracer& pt, const char* path, const char* fn, const glm::mat4x4& model); 13 | ~WavefrontObject(); 14 | 15 | WavefrontIndexedTriangleList* get_geo() const { return m_witl; } 16 | 17 | 18 | private: 19 | TextureMap m_tex_map; 20 | WavefrontIndexedTriangleList* m_witl; 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /PyFeiRays/texture_map.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class PathTracer; 7 | class RGBATexture; 8 | class RGBACubemap; 9 | 10 | class TextureMap : private std::unordered_map 11 | { 12 | public: 13 | TextureMap(PathTracer* pt); 14 | virtual ~TextureMap(); 15 | 16 | int findTex(const char* texname, bool srgb = true); 17 | 18 | 19 | private: 20 | PathTracer* m_pt; 21 | std::vector m_textures; 22 | std::vector m_cubemaps; 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /shaders/common/bindings.h: -------------------------------------------------------------------------------- 1 | #ifndef _BINDINGS_H 2 | #define _BINDINGS_H 3 | 4 | #define BINDING_START 8 5 | #define BINDING_SphereLight BINDING_START 6 | #define BINDING_ColoredIndexedTriangleList (BINDING_START + 1) 7 | #define BINDING_ColoredUnitSphere (BINDING_START + 2) 8 | #define BINDING_UnitSphereCheckerTex (BINDING_START + 3) 9 | #define BINDING_TexturedTriangleList (BINDING_START + 4) 10 | #define BINDING_TexturedUnitSphere (BINDING_START + 5) 11 | #define BINDING_WavefrontIndexedTriangleList (BINDING_START + 6) 12 | 13 | #endif 14 | 15 | -------------------------------------------------------------------------------- /UnitSphereCheckerTex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PathTracer.h" 4 | 5 | class UnitSphereCheckerTex : public Geometry 6 | { 7 | public: 8 | UnitSphereCheckerTex(const glm::mat4x4& model, float interval, const glm::vec3& color1 = { 0.0f, 0.0f, 0.0f }, const glm::vec3& color2 = { 1.0f, 1.0f, 1.0f }); 9 | virtual ~UnitSphereCheckerTex(); 10 | 11 | virtual GeoCls cls() const; 12 | virtual void get_view(void* view_buf) const; 13 | 14 | 15 | private: 16 | glm::vec3 m_color1; 17 | glm::vec3 m_color2; 18 | 19 | float m_interval; 20 | 21 | 22 | }; 23 | -------------------------------------------------------------------------------- /shaders/common/frag_srgb.frag: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_buffer_reference2 : enable 4 | #extension GL_ARB_separate_shader_objects : enable 5 | 6 | layout (location = 0) in vec2 vUV; 7 | layout(location = 0) out vec4 outColor; 8 | 9 | #include "image.shinc" 10 | 11 | layout(std140, binding = 0) uniform SRGBParams 12 | { 13 | Image img; 14 | float boost; 15 | }; 16 | 17 | 18 | void main() 19 | { 20 | int x = int(vUV.x * img.width); 21 | int y = int(vUV.y * img.height); 22 | 23 | vec3 rgb = read_pixel (img, x, y).rgb*boost; 24 | outColor = vec4(rgb, 1.0); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /SRGBConverter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "context.h" 3 | 4 | class SRGBConverter 5 | { 6 | public: 7 | static const SRGBConverter& get_converter(); 8 | 9 | void convert(Texture* dst_srgb, DeviceBuffer* src_rgb, float boost = 1.0f) const; 10 | 11 | private: 12 | SRGBConverter(); 13 | ~SRGBConverter(); 14 | 15 | VkRenderPass m_renderPass; 16 | VkShaderModule m_vertShaderModule; 17 | VkShaderModule m_fragShaderModule; 18 | 19 | VkDescriptorSetLayout m_descriptorSetLayout; 20 | VkPipelineLayout m_pipelineLayout; 21 | 22 | DeviceBuffer* m_ubo; 23 | VkDescriptorPool m_descriptorPool; 24 | VkDescriptorSet m_descriptorSet; 25 | 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /RNGInitializer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "context.h" 3 | 4 | class RNGInitializer 5 | { 6 | public: 7 | static const RNGInitializer& get_initializer(); 8 | void InitRNGs(DeviceBuffer* rng_states) const; 9 | 10 | private: 11 | RNGInitializer(); 12 | ~RNGInitializer(); 13 | 14 | struct UBO 15 | { 16 | VkDeviceAddress d_sequence_matrix; 17 | int count; 18 | }; 19 | 20 | DeviceBuffer* m_seq_mat; 21 | VkDescriptorSetLayout m_descriptorSetLayout; 22 | 23 | VkPipelineLayout m_pipelineLayout; 24 | VkPipeline m_pipeline; 25 | 26 | DeviceBuffer* m_ubo; 27 | VkDescriptorPool m_descriptorPool; 28 | VkDescriptorSet m_descriptorSet; 29 | 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /shaders/common/sunlight.shinc: -------------------------------------------------------------------------------- 1 | #include "light_source_dist.shinc" 2 | 3 | struct Sunlight 4 | { 5 | vec4 dir_radian; 6 | vec4 color; 7 | }; 8 | 9 | layout(std430, binding = 7) buffer Sunlights 10 | { 11 | Sunlight[] sun_lights; 12 | }; 13 | 14 | bool test_sunlights(in vec3 dir, out vec3 color, out int id) 15 | { 16 | for (int i=0; i=target.width || y>=target.height) return; 17 | vec4 v = read_pixel(target, x, y); 18 | v.xyz *= 1.0/float(num_iter); 19 | 20 | write_pixel(target, x, y, v); 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /shaders/common/payload.shinc: -------------------------------------------------------------------------------- 1 | #define MAT_EMIT_BIT 0x1 2 | #define MAT_OPAQUE_BIT 0x2 3 | #define MAT_FRESNEL_BIT 0x4 4 | #define MAT_DIFFUSE_BIT 0x8 5 | #define MAT_SPECULAR_BIT 0x10 6 | #define MAT_SCATTER_BIT 0x20 7 | #define MAT_ABSORB_BIT 0x40 8 | #define MAT_LIGHT_SOURCE_BIT 0x40 9 | 10 | struct Payload 11 | { 12 | // geometry 13 | float t; 14 | vec3 normal; 15 | 16 | // material 17 | uint material_bits; 18 | vec3 color0; // emission 19 | vec3 color1; // diffuse/scattering 20 | vec3 color2; // specular/absorption 21 | float f0; // importance of specular against diffuse / refractive index / light-source id 22 | float f1; // fuzz 23 | float f2; // scattering density 24 | }; 25 | 26 | -------------------------------------------------------------------------------- /ColoredIndexedTriangleList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PathTracer.h" 4 | #include "Material.h" 5 | 6 | class ColoredIndexedTriangleList : public Geometry 7 | { 8 | public: 9 | struct Vertex 10 | { 11 | glm::vec3 Position; 12 | glm::vec3 Normal; 13 | }; 14 | 15 | ColoredIndexedTriangleList(const glm::mat4x4& model, const std::vector& vertices, const std::vector& indices, const Material& material); 16 | 17 | virtual ~ColoredIndexedTriangleList(); 18 | 19 | virtual GeoCls cls() const; 20 | virtual void get_view(void* view_buf) const; 21 | 22 | private: 23 | DeviceBuffer* m_vertexBuffer; 24 | DeviceBuffer* m_indexBuffer; 25 | 26 | Material m_material; 27 | 28 | }; 29 | -------------------------------------------------------------------------------- /shaders/common/rand_init.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | 6 | #include "rand_xorwow.shinc" 7 | 8 | layout(std430, binding = 0) buffer BufStates 9 | { 10 | RNGState states[]; 11 | }; 12 | 13 | layout(std140, binding = 1) uniform ParamsRandInit 14 | { 15 | MatrixBuf d_sequence_matrix; 16 | int count; 17 | }; 18 | 19 | layout(local_size_x = 128) in; 20 | 21 | 22 | void main() 23 | { 24 | int idx = int(gl_GlobalInvocationID.x); 25 | if (idx>=count) return; 26 | state_init(d_sequence_matrix, 1234, uint64_t(idx), states[idx]); 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /python/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from codecs import open 3 | import os 4 | 5 | here = os.path.abspath(os.path.dirname(__file__)) 6 | 7 | with open(os.path.join(here, 'README.md'), encoding='utf-8') as f: 8 | long_description = f.read() 9 | 10 | setup( 11 | name = 'FeiRays', 12 | version = '0.0.6', 13 | description = 'Vulkan based Monte-Carol Ray-tracing', 14 | long_description=long_description, 15 | long_description_content_type='text/markdown', 16 | url='https://github.com/fynv/FeiRays', 17 | license='Anti 996', 18 | author='Fei Yang', 19 | author_email='hyangfeih@gmail.com', 20 | keywords='Vulkan pathtracer xorwow ray-tracing', 21 | packages=['FeiRays'], 22 | package_data = { 'FeiRays': ['*.dll', '*.so']}, 23 | install_requires = ['cffi','pillow'], 24 | ) 25 | 26 | -------------------------------------------------------------------------------- /TexturedTriangleList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PathTracer.h" 4 | 5 | class TexturedTriangleList : public Geometry 6 | { 7 | public: 8 | struct Vertex 9 | { 10 | glm::vec3 Position; 11 | glm::vec3 Normal; 12 | glm::vec2 TexCoord; 13 | }; 14 | 15 | struct Material 16 | { 17 | glm::vec3 diffuse; 18 | int textureId; 19 | }; 20 | 21 | TexturedTriangleList(const glm::mat4x4& model, const std::vector& vertices, const std::vector& materials, const int* materialIdx); 22 | virtual ~TexturedTriangleList(); 23 | 24 | virtual GeoCls cls() const; 25 | virtual void get_view(void* view_buf) const; 26 | 27 | private: 28 | void _blas_create(); 29 | 30 | DeviceBuffer* m_vertexBuffer; 31 | DeviceBuffer* m_materialBuffer; 32 | DeviceBuffer* m_materialIdxBuffer; 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /python/FeiRays/utils.py: -------------------------------------------------------------------------------- 1 | from .Native import native 2 | 3 | class Vec3: 4 | def __init__(self, t): 5 | self.m_cptr = native.n_vec3_create(t[0],t[1],t[2]) 6 | def __del__(self): 7 | native.n_vec3_destroy(self.m_cptr) 8 | 9 | class Transform: 10 | def __init__ (self): 11 | self.m_cptr = native.n_transform_create() 12 | 13 | def __del__ (self): 14 | native.n_transform_destroy(self.m_cptr) 15 | 16 | def translate(self, x, y, z): 17 | v = Vec3((x,y,z)) 18 | native.n_transform_translate(self.m_cptr, v.m_cptr) 19 | 20 | def rotate(self, angle, axis): 21 | v_axis = Vec3(axis) 22 | native.n_transform_rotate(self.m_cptr, angle, v_axis.m_cptr) 23 | 24 | def scale(self, x, y, z): 25 | v = Vec3((x,y,z)) 26 | native.n_transform_scale(self.m_cptr, v.m_cptr) 27 | -------------------------------------------------------------------------------- /tests/test_rng.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "RNGState_xorwow.h" 3 | #include "RNGInitializer.h" 4 | #include "Timing.h" 5 | 6 | int main() 7 | { 8 | size_t count = 1 << 18; 9 | std::vector states(count); 10 | double time0 = GetTime(); 11 | 12 | DeviceBuffer d_states(sizeof(RNGState)*count, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); 13 | const RNGInitializer& initializer = RNGInitializer::get_initializer(); 14 | initializer.InitRNGs(&d_states); 15 | d_states.download(states.data()); 16 | 17 | double time1 = GetTime(); 18 | printf("time: %f\n", time1 - time0); 19 | FILE* fp = fopen("dump_rnd", "w"); 20 | for (int i = 0; i < count; i++) 21 | { 22 | fprintf(fp, "%u %u %u %u %u %u\n", states[i].v.v0, states[i].v.v1, states[i].v.v2, states[i].v.v3, states[i].v.v4, states[i].d); 23 | } 24 | fclose(fp); 25 | 26 | 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /shaders/common/miss.rmiss: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | 7 | #include "payload.shinc" 8 | #include "sunlight.shinc" 9 | 10 | layout(location = 0) rayPayloadInEXT Payload payload; 11 | 12 | layout(std140, binding = 5) uniform Params 13 | { 14 | vec4 color0; 15 | vec4 color1; 16 | }; 17 | 18 | void main() 19 | { 20 | payload.t = -1.0; 21 | payload.material_bits = MAT_OPAQUE_BIT | MAT_EMIT_BIT; 22 | 23 | vec3 color; 24 | int id; 25 | if (test_sunlights(gl_WorldRayDirectionEXT, color, id)) 26 | { 27 | payload.material_bits |= MAT_LIGHT_SOURCE_BIT; 28 | payload.f0 = intBitsToFloat(id); 29 | } 30 | else 31 | { 32 | vec3 direction = gl_WorldRayDirectionEXT; 33 | float t = 0.5 * (direction.y + 1.0); 34 | color = (1.0 - t)*color0.xyz + t * color1.xyz; 35 | } 36 | 37 | payload.color0 = color; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /shaders/geometry/closesthit_sphere_lights.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | 7 | #include "../common/payload.shinc" 8 | #include "../common/bindings.h" 9 | 10 | layout(location = 0) rayPayloadInEXT Payload payload; 11 | hitAttributeEXT vec3 hitpoint; 12 | 13 | 14 | struct SphereLight 15 | { 16 | vec4 center_radius; 17 | vec4 color; 18 | }; 19 | 20 | 21 | layout(std430, binding = BINDING_SphereLight) buffer SpheresLights 22 | { 23 | SphereLight[] sphereLights; 24 | }; 25 | 26 | 27 | void main() 28 | { 29 | SphereLight instance = sphereLights[gl_InstanceCustomIndexEXT]; 30 | vec3 normal = normalize(hitpoint); 31 | 32 | payload.material_bits = MAT_OPAQUE_BIT | MAT_EMIT_BIT | MAT_LIGHT_SOURCE_BIT; 33 | payload.f0 = intBitsToFloat(gl_InstanceCustomIndexEXT); 34 | payload.t = gl_HitTEXT; 35 | payload.color0 = instance.color.xyz; 36 | payload.normal = normal; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Timing.h: -------------------------------------------------------------------------------- 1 | #ifndef _Timing_h 2 | #define _Timing_h 3 | 4 | #include 5 | #include 6 | #ifdef _WIN32 7 | 8 | #define WINDOWS_LEAN_AND_MEAN 9 | #define VC_EXTRALEAN 10 | #define NOMINMAX 11 | #include // QueryPerformanceFrequency, QueryPerformanceCounter 12 | 13 | inline double GetTime() 14 | { 15 | unsigned long long counter, frequency; 16 | QueryPerformanceCounter((LARGE_INTEGER*)(&counter)); 17 | QueryPerformanceFrequency((LARGE_INTEGER*)&frequency); 18 | 19 | return (double)counter / (double)frequency; 20 | } 21 | 22 | #else 23 | # include 24 | # include 25 | 26 | inline double GetTime() 27 | { 28 | timeval tv; 29 | gettimeofday( &tv, NULL ); 30 | return (double)(tv.tv_sec*1000000+tv.tv_usec)/1000000.0; 31 | } 32 | 33 | 34 | #endif 35 | 36 | class ScopedTimer 37 | { 38 | std::string name; 39 | double startTime; 40 | public: 41 | ScopedTimer(const char* name) 42 | { 43 | this->name = name; 44 | startTime = GetTime(); 45 | } 46 | ~ScopedTimer() 47 | { 48 | printf("%s: %f\n", name.c_str(), GetTime() - startTime); 49 | } 50 | }; 51 | 52 | #endif -------------------------------------------------------------------------------- /shaders/common/miss_tex_sky.rmiss: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | #extension GL_EXT_nonuniform_qualifier : enable 7 | 8 | #include "payload.shinc" 9 | #include "sunlight.shinc" 10 | 11 | layout(location = 0) rayPayloadInEXT Payload payload; 12 | 13 | layout(binding = 4) uniform samplerCube[] cubeSamplers; 14 | 15 | layout(std140, binding = 5) uniform Params 16 | { 17 | mat3 transform; 18 | int tex_idx; 19 | }; 20 | 21 | 22 | void main() 23 | { 24 | payload.t = -1.0; 25 | payload.material_bits = MAT_OPAQUE_BIT | MAT_EMIT_BIT; 26 | 27 | vec3 color; 28 | int id; 29 | if (test_sunlights(gl_WorldRayDirectionEXT, color, id)) 30 | { 31 | payload.material_bits |= MAT_LIGHT_SOURCE_BIT; 32 | payload.f0 = intBitsToFloat(id); 33 | } 34 | else 35 | { 36 | vec3 direction = transform*gl_WorldRayDirectionEXT; 37 | color = texture(cubeSamplers[tex_idx], direction).xyz; 38 | } 39 | 40 | payload.color0 = color; 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /shaders/geometry/intersection_unit_spheres.rint: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | 7 | hitAttributeEXT vec3 hitpoint; 8 | 9 | void main() 10 | { 11 | vec3 origin = gl_ObjectRayOriginEXT; 12 | vec3 direction = gl_ObjectRayDirectionEXT; 13 | float tMin = gl_RayTminEXT; 14 | float tMax = gl_RayTmaxEXT; 15 | 16 | const float a = dot(direction, direction); 17 | const float b = dot(origin, direction); 18 | const float c = dot(origin, origin) - 1.0; 19 | const float discriminant = b * b - a * c; 20 | 21 | if (discriminant >= 0) 22 | { 23 | const float t1 = (-b - sqrt(discriminant)) / a; 24 | const float t2 = (-b + sqrt(discriminant)) / a; 25 | 26 | if ((tMin <= t1 && t1 < tMax) || (tMin <= t2 && t2 < tMax)) 27 | { 28 | float t = t1; 29 | if (tMin <= t1 && t1 < tMax) 30 | { 31 | hitpoint = origin + direction * t1; 32 | } 33 | else 34 | { 35 | t = t2; 36 | hitpoint = origin + direction * t2; 37 | } 38 | reportIntersectionEXT(t, 0); 39 | } 40 | } 41 | 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /WavefrontIndexedTriangleList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PathTracer.h" 4 | 5 | class WavefrontIndexedTriangleList : public Geometry 6 | { 7 | public: 8 | struct Material 9 | { 10 | glm::vec3 diffuse; 11 | glm::vec3 specular; 12 | glm::vec3 emission; 13 | float shininess; 14 | int texId_diffuse; 15 | int texId_specular; 16 | int texId_emission; 17 | int texId_bumpmap; 18 | int texId_mask; 19 | int mask; // bit 0 : has diffuse, bit 1: has specular, bit 2: has emission 20 | }; 21 | 22 | struct Index 23 | { 24 | int vertex_index; 25 | int normal_index; 26 | int texcoord_index; 27 | }; 28 | 29 | WavefrontIndexedTriangleList(const glm::mat4x4& model, 30 | const std::vector& positions, 31 | const std::vector& normals, 32 | const std::vector& texcoords, 33 | const std::vector& indices, 34 | std::vector& materials, const int* materialIdx); 35 | 36 | virtual ~WavefrontIndexedTriangleList(); 37 | 38 | virtual GeoCls cls() const; 39 | virtual void get_view(void* view_buf) const; 40 | 41 | private: 42 | DeviceBuffer* m_normalBuffer; 43 | DeviceBuffer* m_texcoordBuffer; 44 | DeviceBuffer* m_indexBuffer; 45 | DeviceBuffer* m_materialBuffer; 46 | DeviceBuffer* m_faceBuffer; 47 | }; 48 | -------------------------------------------------------------------------------- /tests/texture_map.cpp: -------------------------------------------------------------------------------- 1 | #include "texture_map.h" 2 | #include "PathTracer.h" 3 | 4 | #define STB_IMAGE_IMPLEMENTATION 5 | #include "stb_image.h" 6 | 7 | TextureMap::TextureMap(PathTracer* pt, const char* path) 8 | { 9 | m_pt = pt; 10 | m_path = path; 11 | } 12 | 13 | TextureMap::~TextureMap() 14 | { 15 | for (size_t i = 0; i < m_textures.size(); i++) 16 | delete m_textures[i]; 17 | } 18 | 19 | inline std::string fix_path(const std::string& in) 20 | { 21 | std::string ret = ""; 22 | for (size_t i=0; iadd_texture(tex); 44 | m_textures.push_back(tex); 45 | 46 | (*this)[texname] = ret; 47 | 48 | stbi_image_free(pixels); 49 | } 50 | else 51 | { 52 | ret = iter->second; 53 | } 54 | return ret; 55 | } 56 | -------------------------------------------------------------------------------- /PyFeiRays/api_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "api.h" 2 | #include 3 | #include 4 | #define _USE_MATH_DEFINES 5 | #include 6 | 7 | void* n_vec3_create(float x, float y, float z) 8 | { 9 | glm::vec3* v = new glm::vec3(x,y,z); 10 | return v; 11 | } 12 | 13 | void n_vec3_destroy(void* cptr) 14 | { 15 | glm::vec3* v = (glm::vec3*)cptr; 16 | delete v; 17 | } 18 | 19 | void* n_transform_create() 20 | { 21 | glm::mat4x4* trans = new glm::mat4x4; 22 | *trans = glm::identity(); 23 | return trans; 24 | } 25 | 26 | void n_transform_destroy(void* cptr) 27 | { 28 | glm::mat4x4* trans = (glm::mat4x4*)cptr; 29 | delete trans; 30 | } 31 | 32 | void n_transform_translate(void* ptr_trans, void* ptr_vec) 33 | { 34 | glm::mat4x4* trans = (glm::mat4x4*)ptr_trans; 35 | glm::vec3* vec = (glm::vec3*)ptr_vec; 36 | *trans = glm::translate(*trans, *vec); 37 | } 38 | 39 | void n_transform_rotate(void* ptr_trans, float angle, void* ptr_vec) 40 | { 41 | glm::mat4x4* trans = (glm::mat4x4*)ptr_trans; 42 | float rad = angle / 180.0f * (float)M_PI; 43 | glm::vec3* vec = (glm::vec3*)ptr_vec; 44 | *trans = glm::rotate(*trans, rad, *vec); 45 | } 46 | 47 | void n_transform_scale(void* ptr_trans, void* ptr_vec) 48 | { 49 | glm::mat4x4* trans = (glm::mat4x4*)ptr_trans; 50 | glm::vec3* vec = (glm::vec3*)ptr_vec; 51 | *trans = glm::scale(*trans, *vec); 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /python/test.py: -------------------------------------------------------------------------------- 1 | import FeiRays 2 | 3 | scene = FeiRays.Scene(800, 400) 4 | scene.add_sunlight((1,1,1), 2, (500, 500, 500)) 5 | 6 | model = FeiRays.Transform() 7 | model.translate(0,-0.2,0) 8 | model.scale(6,0.2,6) 9 | scene.add_colored_cube(model, color=(0.7,0.7,0.7)) 10 | 11 | model = FeiRays.Transform() 12 | model.translate(0,1,-2) 13 | model.rotate(45, (0,1,0)) 14 | scene.add_colored_cube(model, FeiRays.METAL, color=(0.8,0.6,0.2), fuzz=0.3) 15 | 16 | model = FeiRays.Transform() 17 | model.translate(4,1,-2) 18 | model.rotate(45, (0,1,0)) 19 | scene.add_colored_cube(model, color=(0.1,0.2,0.5)) 20 | 21 | model = FeiRays.Transform() 22 | model.translate(-4,1,-2) 23 | model.rotate(45, (0,1,0)) 24 | scene.add_colored_cube(model, FeiRays.DIELECTRIC, ref_idx=1.5) 25 | 26 | model = FeiRays.Transform() 27 | model.translate(0,1,2) 28 | scene.add_colored_sphere(model, FeiRays.DIELECTRIC, color=(0.5, 1.0, 0.7), ref_idx=1.5, density=10) 29 | 30 | model = FeiRays.Transform() 31 | model.translate(4,1,2) 32 | scene.add_colored_sphere(model, FeiRays.DIELECTRIC, color=(1.0, 0.5, 0.7), ref_idx=1.5, density=10) 33 | 34 | model = FeiRays.Transform() 35 | model.translate(-4,1,2) 36 | scene.add_colored_sphere(model, FeiRays.DIELECTRIC, color=(0.7, 0.5, 1.0), ref_idx=1.5, density=10) 37 | 38 | scene.set_camera((0,8,8),(0,0,0),(0,1,0), 45) 39 | scene.trace(1000, 200) 40 | 41 | img=scene.get_image() 42 | img.save("test.png") 43 | 44 | -------------------------------------------------------------------------------- /shaders/geometry/closesthit_unit_spheres_checker_tex.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | 7 | #include "../common/payload.shinc" 8 | #include "../common/bindings.h" 9 | 10 | layout(location = 0) rayPayloadInEXT Payload payload; 11 | hitAttributeEXT vec3 hitpoint; 12 | 13 | struct UnitSphereCheckerTex 14 | { 15 | mat4 modelMat; 16 | mat3 normalMat; 17 | vec4 color1; 18 | vec4 color2; 19 | float interval; 20 | }; 21 | 22 | layout(std430, binding = BINDING_UnitSphereCheckerTex) buffer Params 23 | { 24 | UnitSphereCheckerTex[] UnitSpheres_checker_tex; 25 | }; 26 | 27 | 28 | void main() 29 | { 30 | UnitSphereCheckerTex instance = UnitSpheres_checker_tex[gl_InstanceCustomIndexEXT]; 31 | 32 | vec4 pos = instance.modelMat*vec4(hitpoint, 1.0); 33 | int i_x = int(pos.x / instance.interval); 34 | int i_y = int(pos.y / instance.interval); 35 | int i_z = int(pos.z / instance.interval); 36 | vec4 color = (i_x+i_y+i_z)%2 == 0 ? instance.color1 : instance.color2; 37 | 38 | vec3 normal = normalize(instance.normalMat * hitpoint); 39 | 40 | payload.t = gl_HitTEXT; 41 | payload.material_bits = MAT_OPAQUE_BIT | MAT_DIFFUSE_BIT; 42 | payload.color1 = color.xyz; 43 | payload.f0 = 0.0; 44 | payload.normal = normal; 45 | 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /shaders/geometry/closesthit_textured_unit_spheres.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | #extension GL_EXT_nonuniform_qualifier : enable 7 | 8 | #include "../common/payload.shinc" 9 | #include "../common/bindings.h" 10 | 11 | layout(location = 0) rayPayloadInEXT Payload payload; 12 | hitAttributeEXT vec3 hitpoint; 13 | 14 | layout(binding = 3) uniform sampler2D[] textureSamplers; 15 | 16 | struct TexturedUnitSphere 17 | { 18 | mat3 normalMat; 19 | vec4 color; 20 | int textureId; 21 | }; 22 | 23 | layout(std430, binding = BINDING_TexturedUnitSphere) buffer Params 24 | { 25 | TexturedUnitSphere[] texturedUnitSpheres; 26 | }; 27 | 28 | 29 | void main() 30 | { 31 | TexturedUnitSphere instance = texturedUnitSpheres[gl_InstanceCustomIndexEXT]; 32 | vec3 normal = normalize(instance.normalMat * hitpoint); 33 | 34 | vec3 c = instance.color.xyz; 35 | vec2 texCoord; 36 | texCoord.y = asin(hitpoint.y)/radians(180.0) + 0.5; 37 | texCoord.x = atan(hitpoint.x, hitpoint.z)/radians(360.0) + 0.5; 38 | c*= texture(textureSamplers[instance.textureId], texCoord).xyz; 39 | 40 | payload.t = gl_HitTEXT; 41 | payload.material_bits = MAT_OPAQUE_BIT | MAT_DIFFUSE_BIT; 42 | payload.color1 = c; 43 | payload.f0 = 0.0; 44 | payload.normal = normal; 45 | 46 | } 47 | 48 | 49 | -------------------------------------------------------------------------------- /TexturedUnitSphere.cpp: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include "TexturedUnitSphere.h" 3 | #include "shaders/common/bindings.h" 4 | 5 | TexturedUnitSphere::TexturedUnitSphere(const glm::mat4x4& model, int tex_id, const glm::vec3& color) : Geometry(model) 6 | { 7 | m_color = color; 8 | m_tex_id = tex_id; 9 | 10 | static float s_aabb[6] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; 11 | 12 | DeviceBuffer aabb_buf(sizeof(float) * 6, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 13 | aabb_buf.upload(s_aabb); 14 | _blas_create_procedure(&aabb_buf); 15 | } 16 | 17 | TexturedUnitSphere::~TexturedUnitSphere() 18 | { 19 | 20 | } 21 | 22 | 23 | struct SphereView 24 | { 25 | glm::mat3x4 normalMat; 26 | glm::vec4 color; 27 | int tex_id; 28 | }; 29 | 30 | GeoCls TexturedUnitSphere::cls() const 31 | { 32 | static const char s_name[] = "TexturedUnitSphere"; 33 | static const char s_fn_rint[] = "geometry/intersection_unit_spheres.spv"; 34 | static const char s_fn_rchit[] = "geometry/closesthit_textured_unit_spheres.spv"; 35 | GeoCls cls = {}; 36 | cls.name = s_name; 37 | cls.size_view = sizeof(SphereView); 38 | cls.binding_view = BINDING_TexturedUnitSphere; 39 | cls.fn_intersection = s_fn_rint; 40 | cls.fn_closesthit = s_fn_rchit; 41 | return cls; 42 | } 43 | 44 | void TexturedUnitSphere::get_view(void* view_buf) const 45 | { 46 | SphereView& view = *(SphereView*)view_buf; 47 | view.normalMat = m_norm_mat; 48 | view.color = { m_color, 1.0f }; 49 | view.tex_id = m_tex_id; 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /ColoredUnitSphere.cpp: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include "ColoredUnitSphere.h" 3 | #include "shaders/common/bindings.h" 4 | 5 | ColoredUnitSphere::ColoredUnitSphere(const glm::mat4x4& model, const Material& material) : Geometry(model) 6 | { 7 | m_material = material; 8 | 9 | static float s_aabb[6] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; 10 | 11 | DeviceBuffer aabb_buf(sizeof(float) * 6, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 12 | aabb_buf.upload(s_aabb); 13 | _blas_create_procedure(&aabb_buf); 14 | } 15 | 16 | ColoredUnitSphere::~ColoredUnitSphere() 17 | { 18 | 19 | } 20 | 21 | struct SphereView 22 | { 23 | glm::mat3x4 normalMat; 24 | glm::vec4 color; 25 | MaterialType type; 26 | float fuzz; 27 | float ref_idx; 28 | float density; 29 | }; 30 | 31 | GeoCls ColoredUnitSphere::cls() const 32 | { 33 | static const char s_name[] = "ColoredUnitSphere"; 34 | static const char s_fn_rint[] = "geometry/intersection_unit_spheres.spv"; 35 | static const char s_fn_rchit[] = "geometry/closesthit_colored_unit_spheres.spv"; 36 | 37 | GeoCls cls = {}; 38 | cls.name = s_name; 39 | cls.size_view = sizeof(SphereView); 40 | cls.binding_view = BINDING_ColoredUnitSphere; 41 | cls.fn_intersection = s_fn_rint; 42 | cls.fn_closesthit = s_fn_rchit; 43 | return cls; 44 | } 45 | 46 | void ColoredUnitSphere::get_view(void* view_buf) const 47 | { 48 | SphereView& view = *(SphereView*)view_buf; 49 | view.normalMat = m_norm_mat; 50 | view.color = { m_material.color, 1.0f }; 51 | view.type = m_material.type; 52 | view.fuzz = m_material.fuzz; 53 | view.ref_idx = m_material.ref_idx; 54 | view.density = m_material.density; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /PyFeiRays/Scene.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PathTracer.h" 4 | #include "ColoredUnitSphere.h" 5 | #include "ColoredIndexedTriangleList.h" 6 | #include "TexturedUnitSphere.h" 7 | #include "WavefrontIndexedTriangleList.h" 8 | #include "texture_map.h" 9 | 10 | #include 11 | 12 | class Scene 13 | { 14 | public: 15 | Scene(int width, int height); 16 | ~Scene(); 17 | 18 | const Image& image() const { return m_Image; } 19 | void set_gradient_sky(const glm::vec3& color0, const glm::vec3& color1); 20 | void set_textured_sky(const char* fn_tex, bool srgb); 21 | void set_textured_sky(const char* fn_tex, bool srgb, float angle, const glm::vec3& v); 22 | void add_colored_sphere(const glm::mat4x4& model, const Material& material); 23 | void add_colored_cube(const glm::mat4x4& model, const Material& material); 24 | void add_textured_sphere(const glm::mat4x4& model, const char* fn_tex, bool srgb, const glm::vec3& color); 25 | void add_wavefront_object(const glm::mat4x4& model, const char* path, const char* fn); 26 | void add_sphere_light(const glm::vec3& center, float r, const glm::vec3& color); 27 | void add_sunlight(glm::vec3 direction, float radian, glm::vec3 color) 28 | { 29 | m_pt.add_sunlight(direction, radian, color); 30 | } 31 | void set_camera(glm::vec3 lookfrom, glm::vec3 lookat, glm::vec3 vup, float vfov, float aperture, float focus_dist) 32 | { 33 | m_pt.set_camera(lookfrom, lookat, vup, vfov, aperture, focus_dist); 34 | } 35 | void trace(int num_iter, int interval) const 36 | { 37 | m_pt.trace(num_iter, interval); 38 | } 39 | 40 | private: 41 | Image m_Image; 42 | PathTracer m_pt; 43 | TextureMap m_tex_map; 44 | Sky* m_sky; 45 | std::vector m_geos; 46 | }; 47 | 48 | 49 | -------------------------------------------------------------------------------- /shaders/geometry/closesthit_colored_unit_spheres.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | 7 | #include "../common/payload.shinc" 8 | #include "../common/bindings.h" 9 | 10 | layout(location = 0) rayPayloadInEXT Payload payload; 11 | hitAttributeEXT vec3 hitpoint; 12 | 13 | struct ColoredUnitSphere 14 | { 15 | mat3 normalMat; 16 | vec4 color; 17 | uint type; // 0: lamertian, 1: metal, 2: dielectric, 3: emissive, 4: foggy 18 | float fuzz; 19 | float ref_idx; 20 | float density; 21 | }; 22 | 23 | 24 | layout(std430, binding = BINDING_ColoredUnitSphere) buffer Params 25 | { 26 | ColoredUnitSphere[] coloredUnitSpheres; 27 | }; 28 | 29 | const uint cPresets[5] = { 30 | MAT_OPAQUE_BIT | MAT_DIFFUSE_BIT, 31 | MAT_OPAQUE_BIT | MAT_SPECULAR_BIT, 32 | MAT_FRESNEL_BIT | MAT_SCATTER_BIT, 33 | MAT_OPAQUE_BIT | MAT_EMIT_BIT, 34 | MAT_SCATTER_BIT 35 | }; 36 | 37 | void main() 38 | { 39 | ColoredUnitSphere instance = coloredUnitSpheres[gl_InstanceCustomIndexEXT]; 40 | vec3 normal = normalize(instance.normalMat * hitpoint); 41 | 42 | payload.material_bits = cPresets[instance.type]; 43 | payload.t = gl_HitTEXT; 44 | payload.color0 = instance.color.xyz; 45 | payload.color1 = instance.color.xyz; 46 | payload.color2 = instance.color.xyz; 47 | payload.normal = normal; 48 | payload.f1 = instance.fuzz; 49 | payload.f2 = instance.density; 50 | 51 | if (instance.type == 0) payload.f0 = 0.0; 52 | if (instance.type == 1) payload.f0 = 1.0; 53 | if (instance.type == 2) payload.f0 = instance.ref_idx; 54 | 55 | } 56 | 57 | 58 | -------------------------------------------------------------------------------- /UnitSphereCheckerTex.cpp: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include "UnitSphereCheckerTex.h" 3 | #include "shaders/common/bindings.h" 4 | 5 | UnitSphereCheckerTex::UnitSphereCheckerTex(const glm::mat4x4& model, float interval, const glm::vec3& color1, const glm::vec3& color2) : Geometry(model) 6 | { 7 | m_color1 = color1; 8 | m_color2 = color2; 9 | m_interval = interval; 10 | 11 | static float s_aabb[6] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; 12 | DeviceBuffer aabb_buf(sizeof(float) * 6, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 13 | aabb_buf.upload(s_aabb); 14 | _blas_create_procedure(&aabb_buf); 15 | } 16 | 17 | UnitSphereCheckerTex::~UnitSphereCheckerTex() 18 | { 19 | 20 | } 21 | 22 | struct SphereView 23 | { 24 | glm::mat4x4 modelMat; 25 | glm::mat3x4 normalMat; 26 | glm::vec4 color1; 27 | glm::vec4 color2; 28 | float interval; 29 | }; 30 | 31 | 32 | GeoCls UnitSphereCheckerTex::cls() const 33 | { 34 | static const char s_name[] = "UnitSphereCheckerTex"; 35 | static const char s_fn_rint[] = "geometry/intersection_unit_spheres.spv"; 36 | static const char s_fn_rchit[] = "geometry/closesthit_unit_spheres_checker_tex.spv"; 37 | GeoCls cls = {}; 38 | cls.name = s_name; 39 | cls.size_view = sizeof(SphereView); 40 | cls.binding_view = BINDING_UnitSphereCheckerTex; 41 | cls.fn_intersection = s_fn_rint; 42 | cls.fn_closesthit = s_fn_rchit; 43 | return cls; 44 | } 45 | 46 | void UnitSphereCheckerTex::get_view(void* view_buf) const 47 | { 48 | SphereView& view = *(SphereView*)view_buf; 49 | view.modelMat = m_model; 50 | view.normalMat = m_norm_mat; 51 | view.color1 = { m_color1, 1.0f }; 52 | view.color2 = { m_color2, 1.0f }; 53 | view.interval = m_interval; 54 | } 55 | -------------------------------------------------------------------------------- /shaders/build.bat: -------------------------------------------------------------------------------- 1 | glslangValidator -V common/rand_init.comp -o common/rand_init.spv --target-env vulkan1.2 2 | glslangValidator -V common/vert_srgb.vert -o common/vert_srgb.spv --target-env vulkan1.2 3 | glslangValidator -V common/frag_srgb.frag -o common/frag_srgb.spv --target-env vulkan1.2 4 | 5 | glslangValidator -V common/miss.rmiss -o common/miss.spv --target-env vulkan1.2 6 | glslangValidator -V common/miss_tex_sky.rmiss -o common/miss_tex_sky.spv --target-env vulkan1.2 7 | 8 | glslangValidator -V geometry/closesthit_colored_indexed_triangle_lists.rchit -o geometry/closesthit_colored_indexed_triangle_lists.spv --target-env vulkan1.2 9 | glslangValidator -V geometry/intersection_unit_spheres.rint -o geometry/intersection_unit_spheres.spv --target-env vulkan1.2 10 | glslangValidator -V geometry/closesthit_colored_unit_spheres.rchit -o geometry/closesthit_colored_unit_spheres.spv --target-env vulkan1.2 11 | glslangValidator -V geometry/closesthit_unit_spheres_checker_tex.rchit -o geometry/closesthit_unit_spheres_checker_tex.spv --target-env vulkan1.2 12 | glslangValidator -V geometry/closesthit_textured_triangle_lists.rchit -o geometry/closesthit_textured_triangle_lists.spv --target-env vulkan1.2 13 | glslangValidator -V geometry/closesthit_textured_unit_spheres.rchit -o geometry/closesthit_textured_unit_spheres.spv --target-env vulkan1.2 14 | glslangValidator -V geometry/closesthit_sphere_lights.rchit -o geometry/closesthit_sphere_lights.spv --target-env vulkan1.2 15 | glslangValidator -V geometry/closesthit_wavefront_indexed_triangle_lists.rchit -o geometry/closesthit_wavefront_indexed_triangle_lists.spv --target-env vulkan1.2 16 | 17 | glslangValidator -V path_tracer/raygen.rgen -o path_tracer/raygen.spv --target-env vulkan1.2 18 | glslangValidator -V path_tracer/final.comp -o path_tracer/final.spv --target-env vulkan1.2 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /shaders/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | glslangValidator -V common/rand_init.comp -o common/rand_init.spv --target-env vulkan1.2 3 | glslangValidator -V common/vert_srgb.vert -o common/vert_srgb.spv --target-env vulkan1.2 4 | glslangValidator -V common/frag_srgb.vert -o common/frag_srgb.spv --target-env vulkan1.2 5 | 6 | glslangValidator -V common/miss.rmiss -o common/miss.spv --target-env vulkan1.2 7 | glslangValidator -V common/miss_tex_sky.rmiss -o common/miss_tex_sky.spv --target-env vulkan1.2 8 | 9 | glslangValidator -V geometry/closesthit_colored_indexed_triangle_lists.rchit -o geometry/closesthit_colored_indexed_triangle_lists.spv --target-env vulkan1.2 10 | glslangValidator -V geometry/intersection_unit_spheres.rint -o geometry/intersection_unit_spheres.spv --target-env vulkan1.2 11 | glslangValidator -V geometry/closesthit_colored_unit_spheres.rchit -o geometry/closesthit_colored_unit_spheres.spv --target-env vulkan1.2 12 | glslangValidator -V geometry/closesthit_unit_spheres_checker_tex.rchit -o geometry/closesthit_unit_spheres_checker_tex.spv --target-env vulkan1.2 13 | glslangValidator -V geometry/closesthit_textured_triangle_lists.rchit -o geometry/closesthit_textured_triangle_lists.spv --target-env vulkan1.2 14 | glslangValidator -V geometry/closesthit_textured_unit_spheres.rchit -o geometry/closesthit_textured_unit_spheres.spv --target-env vulkan1.2 15 | glslangValidator -V geometry/closesthit_sphere_lights.rchit -o geometry/closesthit_sphere_lights.spv --target-env vulkan1.2 16 | glslangValidator -V geometry/closesthit_wavefront_indexed_triangle_lists.rchit -o geometry/closesthit_wavefront_indexed_triangle_lists.spv --target-env vulkan1.2 17 | 18 | glslangValidator -V geometry/closesthit_ply_mesh.rchit -o geometry/closesthit_ply_mesh.spv --target-env vulkan1.2 19 | 20 | 21 | glslangValidator -V path_tracer/raygen.rgen -o path_tracer/raygen.spv --target-env vulkan1.2 22 | glslangValidator -V path_tracer/final.comp -o path_tracer/final.spv --target-env vulkan1.2 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /PyFeiRays/texture_map.cpp: -------------------------------------------------------------------------------- 1 | #include "texture_map.h" 2 | #include "PathTracer.h" 3 | 4 | #define STB_IMAGE_IMPLEMENTATION 5 | #include "stb_image.h" 6 | 7 | #include "dds_reader.hpp" 8 | 9 | #include "string.h" 10 | 11 | TextureMap::TextureMap(PathTracer* pt) 12 | { 13 | m_pt = pt; 14 | } 15 | 16 | TextureMap::~TextureMap() 17 | { 18 | for (size_t i = 0; i < m_textures.size(); i++) 19 | delete m_textures[i]; 20 | for (size_t i = 0; i < m_cubemaps.size(); i++) 21 | delete m_cubemaps[i]; 22 | } 23 | 24 | inline const char* extension(const char* fn) 25 | { 26 | return fn + strlen(fn) - 3; 27 | } 28 | 29 | 30 | inline std::string fix_path(const std::string& in) 31 | { 32 | std::string ret = ""; 33 | for (size_t i=0; iadd_cubemap(cube); 58 | m_cubemaps.push_back(cube); 59 | } 60 | else 61 | { 62 | RGBATexture* tex = new RGBATexture(texWidth, texHeight, pixels, srgb); 63 | ret = m_pt->add_texture(tex); 64 | m_textures.push_back(tex); 65 | } 66 | dds_free(pixels); 67 | } 68 | else 69 | { 70 | stbi_uc* pixels = stbi_load(fn_tex.c_str(), &texWidth, &texHeight, &texChannels, 4); 71 | RGBATexture* tex = new RGBATexture(texWidth, texHeight, pixels, srgb); 72 | ret = m_pt->add_texture(tex); 73 | m_textures.push_back(tex); 74 | stbi_image_free(pixels); 75 | } 76 | 77 | (*this)[fn_tex] = ret; 78 | } 79 | else 80 | { 81 | ret = iter->second; 82 | } 83 | return ret; 84 | } 85 | -------------------------------------------------------------------------------- /tests/test7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "PathTracer.h" 9 | #include "wavefront_obj.h" 10 | #include "TexturedUnitSphere.h" 11 | #include "WavefrontIndexedTriangleList.h" 12 | 13 | #include "stb_image.h" 14 | 15 | #define STB_IMAGE_WRITE_IMPLEMENTATION 16 | #include "stb_image_write.h" 17 | 18 | #include "dds_reader.hpp" 19 | 20 | #ifndef PI 21 | #define PI 3.1415926f 22 | #endif 23 | 24 | int main() 25 | { 26 | const int view_width = 900; 27 | const int view_height = 600; 28 | 29 | PathTracer pt; 30 | 31 | Image target(view_width, view_height, nullptr); 32 | pt.set_target(&target); 33 | 34 | /*int cubeWidth, cubeHeight, cubeChannels, isCube; 35 | void *cube_pixels = dds_load("../data/sky_cube.dds", &cubeWidth, &cubeHeight, &cubeChannels, &isCube); 36 | RGBACubemap cubemap(cubeWidth, cubeHeight, cube_pixels); 37 | dds_free(cube_pixels); 38 | 39 | int id_skybox = pt.add_cubemap(&cubemap); 40 | TexturedSkyBox skybox(id_skybox); 41 | pt.set_sky(&skybox);*/ 42 | 43 | pt.add_sunlight({ 0.3f, 1.0f, 0.2f }, 0.05, { 2000.0f, 2000.0f, 2000.0f }); 44 | 45 | glm::mat4x4 identity = glm::identity(); 46 | 47 | WavefrontObject obj(pt, "../data/sponza", "SponzaNoFlag.obj", identity); 48 | 49 | glm::vec3 cam_pos = { 800.0f, 150.0f, 50.0f }; 50 | glm::vec3 cam_look_pos = { 0.0f, 300.0f, 0.0f }; 51 | glm::vec3 cam_dir = glm::normalize(cam_look_pos - cam_pos); 52 | glm::vec3 light_pos = cam_pos - cam_dir * 50.0f; 53 | 54 | pt.add_geometry(obj.get_geo()); 55 | pt.set_camera(cam_pos, cam_look_pos, { 0.0f, 1.0f, 0.0f }, 45.0f, 3.0f, 1500.0f); 56 | 57 | //SphereLight light1(light_pos, 10.0f, { 100.0f, 100.0f, 100.0f }); 58 | //pt.add_geometry(&light1); 59 | 60 | pt.trace(1000, 50); 61 | 62 | unsigned char* hbuffer = (unsigned char*)malloc(view_width * view_height * 3); 63 | target.to_host_srgb(hbuffer); 64 | stbi_write_png("test7.png", view_width, view_height, 3, hbuffer, view_width * 3); 65 | free(hbuffer); 66 | 67 | system("pause"); 68 | 69 | 70 | return 0; 71 | } -------------------------------------------------------------------------------- /PyFeiRays/dds_reader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #if !defined(MAKEFOURCC) 8 | #define MAKEFOURCC(ch0, ch1, ch2, ch3) \ 9 | (unsigned(ch0) | (unsigned(ch1) << 8) | \ 10 | (unsigned(ch2) << 16) | (unsigned(ch3) << 24 )) 11 | #endif 12 | 13 | 14 | struct DDSPixelFormat 15 | { 16 | unsigned size; 17 | unsigned flags; 18 | unsigned fourcc; 19 | unsigned bitcount; 20 | unsigned rmask; 21 | unsigned gmask; 22 | unsigned bmask; 23 | unsigned amask; 24 | }; 25 | 26 | struct DDSHeader 27 | { 28 | unsigned fourcc; 29 | unsigned size; 30 | unsigned flags; 31 | unsigned height; 32 | unsigned width; 33 | unsigned pitch; 34 | unsigned depth; 35 | unsigned mipmapcount; 36 | unsigned reserved[11]; 37 | DDSPixelFormat pf; 38 | unsigned caps1; 39 | unsigned caps2; 40 | unsigned caps3; 41 | unsigned caps4; 42 | unsigned notused; 43 | }; 44 | 45 | 46 | // This simple dds loader only handles uncompressed, non-pitched, non-mipmaped, dds files for now. 47 | void* dds_load(const char* fn, int* pwidth, int* pheight, int* pchannels, int* isCube) 48 | { 49 | FILE *fp = fopen(fn, "rb"); 50 | if (!fp) return nullptr; 51 | 52 | DDSHeader header; 53 | fread(&header, sizeof(DDSHeader), 1, fp); 54 | 55 | if (header.fourcc != MAKEFOURCC('D', 'D', 'S', ' ')) 56 | { 57 | printf("not a dds file.\n"); 58 | fclose(fp); 59 | return nullptr; 60 | } 61 | 62 | if ((header.flags & 0x8A0008) !=0 || 63 | (header.pf.flags & 0x20204) !=0) 64 | { 65 | printf("feature not supported.\n"); 66 | fclose(fp); 67 | return nullptr; 68 | } 69 | 70 | int chn = 0; 71 | if ((header.pf.flags & 0x3) != 0) 72 | chn++; 73 | if ((header.pf.flags & 0x40) != 0) 74 | chn+= 3; 75 | *pchannels = chn; 76 | *pwidth = header.width; 77 | *pheight = header.height; 78 | *isCube = (header.caps1 & 0x8) == 0x8 && (header.caps2 & 0xFE00) == 0xFE00 ? 1 : 0; 79 | 80 | 81 | size_t size = *pwidth* (*pheight) * (*pchannels); 82 | if (*isCube) size *= 6; 83 | 84 | void *buf = malloc(size); 85 | fread(buf, 1, size, fp); 86 | 87 | fclose(fp); 88 | 89 | return buf; 90 | } 91 | 92 | 93 | void dds_free(void* data) 94 | { 95 | free(data); 96 | } 97 | 98 | -------------------------------------------------------------------------------- /tests/dds_reader.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #if !defined(MAKEFOURCC) 8 | #define MAKEFOURCC(ch0, ch1, ch2, ch3) \ 9 | (unsigned(ch0) | (unsigned(ch1) << 8) | \ 10 | (unsigned(ch2) << 16) | (unsigned(ch3) << 24 )) 11 | #endif 12 | 13 | 14 | struct DDSPixelFormat 15 | { 16 | unsigned size; 17 | unsigned flags; 18 | unsigned fourcc; 19 | unsigned bitcount; 20 | unsigned rmask; 21 | unsigned gmask; 22 | unsigned bmask; 23 | unsigned amask; 24 | }; 25 | 26 | struct DDSHeader 27 | { 28 | unsigned fourcc; 29 | unsigned size; 30 | unsigned flags; 31 | unsigned height; 32 | unsigned width; 33 | unsigned pitch; 34 | unsigned depth; 35 | unsigned mipmapcount; 36 | unsigned reserved[11]; 37 | DDSPixelFormat pf; 38 | unsigned caps1; 39 | unsigned caps2; 40 | unsigned caps3; 41 | unsigned caps4; 42 | unsigned notused; 43 | }; 44 | 45 | 46 | // This simple dds loader only handles uncompressed, non-pitched, non-mipmaped, dds files for now. 47 | void* dds_load(const char* fn, int* pwidth, int* pheight, int* pchannels, int* isCube) 48 | { 49 | FILE *fp = fopen(fn, "rb"); 50 | if (!fp) return nullptr; 51 | 52 | DDSHeader header; 53 | fread(&header, sizeof(DDSHeader), 1, fp); 54 | 55 | if (header.fourcc != MAKEFOURCC('D', 'D', 'S', ' ')) 56 | { 57 | printf("not a dds file.\n"); 58 | fclose(fp); 59 | return nullptr; 60 | } 61 | 62 | if ((header.flags & 0x8A0008) !=0 || 63 | (header.pf.flags & 0x20204) !=0) 64 | { 65 | printf("feature not supported.\n"); 66 | fclose(fp); 67 | return nullptr; 68 | } 69 | 70 | int chn = 0; 71 | if ((header.pf.flags & 0x3) != 0) 72 | chn++; 73 | if ((header.pf.flags & 0x40) != 0) 74 | chn+= 3; 75 | *pchannels = chn; 76 | *pwidth = header.width; 77 | *pheight = header.height; 78 | *isCube = (header.caps1 & 0x8) == 0x8 && (header.caps2 & 0xFE00) == 0xFE00 ? 1 : 0; 79 | 80 | 81 | size_t size = *pwidth* (*pheight) * (*pchannels); 82 | if (*isCube) size *= 6; 83 | 84 | void *buf = malloc(size); 85 | fread(buf, 1, size, fp); 86 | 87 | fclose(fp); 88 | 89 | return buf; 90 | } 91 | 92 | 93 | void dds_free(void* data) 94 | { 95 | free(data); 96 | } 97 | 98 | -------------------------------------------------------------------------------- /python/FeiRays/Native.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import site 4 | from cffi import FFI 5 | 6 | ffi = FFI() 7 | 8 | ffi.cdef(""" 9 | void* n_vec3_create(float x, float y, float z); 10 | void n_vec3_destroy(void* cptr); 11 | void* n_transform_create(); 12 | void n_transform_destroy(void* cptr); 13 | void n_transform_translate(void* ptr_trans, void* ptr_vec); 14 | void n_transform_rotate(void* ptr_trans, float angle, void* ptr_vec); 15 | void n_transform_scale(void* ptr_trans, void* ptr_vec); 16 | void* n_scene_create(int width, int height); 17 | void n_scene_destroy(void* cptr); 18 | int n_scene_width(void* cptr); 19 | int n_scene_height(void* cptr); 20 | void n_scene_get_image(void* cptr, float boost, void* data_out); 21 | void n_scene_set_gradient_sky(void* ptr_scene, void* ptr_color0, void* ptr_color1); 22 | void n_scene_set_textured_sky(void* ptr_scene, const char* fn_tex, unsigned tex_srgb, float angle, void* ptr_vec); 23 | void n_scene_add_colored_sphere(void* ptr_scene, void* ptr_trans, int mat_type, void* ptr_mat_color, float mat_fuzz, float mat_ref_idx, float mat_density); 24 | void n_scene_add_colored_cube(void* ptr_scene, void* ptr_trans, int mat_type, void* ptr_mat_color, float mat_fuzz, float mat_ref_idx, float mat_density); 25 | void n_scene_add_textured_sphere(void* ptr_scene, void* ptr_trans, const char* fn_tex, unsigned tex_srgb, void* ptr_color); 26 | void n_scene_add_wavefront_object(void* ptr_scene, void* ptr_trans, const char* path, const char* fn); 27 | void n_scene_add_sphere_light(void* ptr_scene, void* ptr_center, float radius, void* ptr_color); 28 | void n_scene_add_sunlight(void* ptr_scene, void* ptr_dir, float angle, void* ptr_color); 29 | void n_scene_set_camera(void* ptr_scene, void* ptr_lookfrom, void* ptr_lookat, void* ptr_vup, float vfov, float aperture, float focus_dist); 30 | void n_scene_trace(void* ptr_scene, int num_iter, int interval); 31 | """) 32 | 33 | if os.name == 'nt': 34 | fn_feirays = 'PyFeiRays.dll' 35 | elif os.name == "posix": 36 | fn_feirays = 'libPyFeiRays.so' 37 | 38 | path_feirays = os.path.dirname(__file__)+"/"+fn_feirays 39 | 40 | native = ffi.dlopen(path_feirays) 41 | 42 | 43 | -------------------------------------------------------------------------------- /PyFeiRays/api.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) 4 | #define PY_FEIRAYS_API __declspec(dllexport) 5 | #else 6 | #define PY_FEIRAYS_API 7 | #endif 8 | 9 | extern "C" 10 | { 11 | PY_FEIRAYS_API void* n_vec3_create(float x, float y, float z); 12 | PY_FEIRAYS_API void n_vec3_destroy(void* cptr); 13 | PY_FEIRAYS_API void* n_transform_create(); 14 | PY_FEIRAYS_API void n_transform_destroy(void* cptr); 15 | PY_FEIRAYS_API void n_transform_translate(void* ptr_trans, void* ptr_vec); 16 | PY_FEIRAYS_API void n_transform_rotate(void* ptr_trans, float angle, void* ptr_vec); 17 | PY_FEIRAYS_API void n_transform_scale(void* ptr_trans, void* ptr_vec); 18 | 19 | PY_FEIRAYS_API void* n_scene_create(int width, int height); 20 | PY_FEIRAYS_API void n_scene_destroy(void* cptr); 21 | PY_FEIRAYS_API int n_scene_width(void* cptr); 22 | PY_FEIRAYS_API int n_scene_height(void* cptr); 23 | PY_FEIRAYS_API void n_scene_get_image(void* cptr, float boost, void* data_out); 24 | PY_FEIRAYS_API void n_scene_set_gradient_sky(void* ptr_scene, void* ptr_color0, void* ptr_color1); 25 | PY_FEIRAYS_API void n_scene_set_textured_sky(void* ptr_scene, const char* fn_tex, unsigned tex_srgb, float angle, void* ptr_vec); 26 | PY_FEIRAYS_API void n_scene_add_colored_sphere(void* ptr_scene, void* ptr_trans, int mat_type, void* ptr_mat_color, float mat_fuzz, float mat_ref_idx, float mat_density); 27 | PY_FEIRAYS_API void n_scene_add_colored_cube(void* ptr_scene, void* ptr_trans, int mat_type, void* ptr_mat_color, float mat_fuzz, float mat_ref_idx, float mat_density); 28 | PY_FEIRAYS_API void n_scene_add_textured_sphere(void* ptr_scene, void* ptr_trans, const char* fn_tex, unsigned tex_srgb, void* ptr_color); 29 | PY_FEIRAYS_API void n_scene_add_wavefront_object(void* ptr_scene, void* ptr_trans, const char* path, const char* fn); 30 | PY_FEIRAYS_API void n_scene_add_sphere_light(void* ptr_scene, void* ptr_center, float radius, void* ptr_color); 31 | PY_FEIRAYS_API void n_scene_add_sunlight(void* ptr_scene, void* ptr_dir, float angle, void* ptr_color); 32 | PY_FEIRAYS_API void n_scene_set_camera(void* ptr_scene, void* ptr_lookfrom, void* ptr_lookat, void* ptr_vup, float vfov, float aperture, float focus_dist); 33 | PY_FEIRAYS_API void n_scene_trace(void* ptr_scene, int num_iter, int interval); 34 | } 35 | -------------------------------------------------------------------------------- /tests/lambertian_obj.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define TINYOBJLOADER_IMPLEMENTATION 10 | #include "tiny_obj_loader.h" 11 | 12 | #include "PathTracer.h" 13 | #include "TexturedTriangleList.h" 14 | 15 | #include "lambertian_obj.h" 16 | 17 | LambertianObject::LambertianObject(PathTracer& pt, const char* path, const char* fn, const glm::mat4x4& model) 18 | : m_tex_map(&pt, path) 19 | { 20 | std::string fn_obj = path; 21 | fn_obj += "/"; 22 | fn_obj += fn; 23 | 24 | tinyobj::attrib_t attrib; 25 | std::vector shapes; 26 | std::vector materials; 27 | std::string err; 28 | 29 | tinyobj::LoadObj(&attrib, &shapes, &materials, &err, fn_obj.c_str(), path); 30 | 31 | std::vector materials_in(materials.size()); 32 | 33 | for (size_t i = 0; i < materials.size(); i++) 34 | { 35 | materials_in[i].diffuse = glm::vec3(materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]); 36 | if (!materials[i].diffuse_texname.empty()) 37 | { 38 | materials_in[i].textureId = m_tex_map.findTex(materials[i].diffuse_texname.c_str()); 39 | } 40 | else 41 | { 42 | materials_in[i].textureId = -1; 43 | } 44 | } 45 | 46 | std::vector vertices; 47 | std::vector materials_ids; 48 | 49 | for (size_t i = 0; i < shapes.size(); i++) 50 | { 51 | tinyobj::shape_t& shape = shapes[i]; 52 | 53 | for (size_t j = 0; j < shape.mesh.indices.size(); j++) 54 | { 55 | TexturedTriangleList::Vertex vertex; 56 | 57 | tinyobj::index_t& index = shape.mesh.indices[j]; 58 | float* vp = &attrib.vertices[3 * index.vertex_index]; 59 | vertex.Position = glm::vec3(vp[0], vp[1], vp[2]); 60 | float* np = &attrib.normals[3 * index.normal_index]; 61 | vertex.Normal = glm::vec3(np[0], np[1], np[2]); 62 | float* tp = &attrib.texcoords[2 * index.texcoord_index]; 63 | vertex.TexCoord = glm::vec2(tp[0], 1.0f - tp[1]); 64 | vertices.push_back(vertex); 65 | } 66 | 67 | for (size_t j = 0; j < shape.mesh.material_ids.size(); j++) 68 | materials_ids.push_back(shape.mesh.material_ids[j]); 69 | } 70 | 71 | m_ttl = new TexturedTriangleList(model, vertices, materials_in, materials_ids.data()); 72 | } 73 | 74 | LambertianObject::~LambertianObject() 75 | { 76 | delete m_ttl; 77 | } 78 | -------------------------------------------------------------------------------- /pack_shaders.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const char* s_files[] = 5 | { 6 | "common/rand_init.spv", 7 | "common/vert_srgb.spv", 8 | "common/frag_srgb.spv", 9 | 10 | "common/miss.spv", 11 | "common/miss_tex_sky.spv", 12 | 13 | "geometry/closesthit_colored_indexed_triangle_lists.spv", 14 | "geometry/intersection_unit_spheres.spv", 15 | "geometry/closesthit_colored_unit_spheres.spv", 16 | "geometry/closesthit_unit_spheres_checker_tex.spv", 17 | "geometry/closesthit_textured_triangle_lists.spv", 18 | "geometry/closesthit_textured_unit_spheres.spv", 19 | "geometry/closesthit_sphere_lights.spv", 20 | "geometry/closesthit_wavefront_indexed_triangle_lists.spv", 21 | 22 | "path_tracer/raygen.spv", 23 | "path_tracer/final.spv" 24 | }; 25 | 26 | int main() 27 | { 28 | int num_files = (int)sizeof(s_files) / (int)sizeof(const char*); 29 | FILE *fp = fopen("shaders_packed.hpp", "w"); 30 | 31 | fputs("/* This file is generated by pack_shaders.cpp */ \n", fp); 32 | 33 | std::vector sizes(num_files); 34 | 35 | for (int i = 0; i < num_files; i++) 36 | { 37 | fprintf(fp, "static char s_filename_%d[]=\"%s\";\n", i, s_files[i]); 38 | 39 | char fn[1024]; 40 | sprintf(fn, "shaders/%s", s_files[i]); 41 | 42 | FILE *fheader = fopen(fn, "rb"); 43 | fseek(fheader, 0, SEEK_END); 44 | size_t size = (size_t)ftell(fheader); 45 | fseek(fheader, 0, SEEK_SET); 46 | std::vector buf((size + 3)&(~3)); 47 | fread(buf.data(), 1, size, fheader); 48 | fclose(fheader); 49 | sizes[i] = (int)size; 50 | 51 | size_t num_dwords = buf.size() >> 2; 52 | unsigned *dwords = (unsigned*)buf.data(); 53 | 54 | fprintf(fp, "static unsigned s_file_content_%d[]={\n", i); 55 | for (size_t j = 0; j < num_dwords; j++) 56 | { 57 | fprintf(fp, "0x%x,", dwords[j]); 58 | if (j % 10 == 9) 59 | fputs("\n", fp); 60 | } 61 | fputs("};\n\n", fp); 62 | } 63 | 64 | fprintf(fp, "static int s_num_shaders = %d;\n", num_files); 65 | 66 | fputs("static int s_size_shaders[] = {\n", fp); 67 | for (int i = 0; i < num_files; i++) 68 | fprintf(fp, "%d,\n", sizes[i]); 69 | 70 | fputs("};\n\n", fp); 71 | 72 | fputs("static const char* s_name_shaders[] = {\n", fp); 73 | for (int i = 0; i < num_files; i++) 74 | fprintf(fp, "s_filename_%d,\n", i); 75 | 76 | fputs("};\n\n", fp); 77 | 78 | fputs("static const char* s_content_shaders[] = {\n", fp); 79 | for (int i = 0; i < num_files; i++) 80 | fprintf(fp, "(char*)s_file_content_%d,\n", i); 81 | 82 | fputs("};\n\n", fp); 83 | 84 | fclose(fp); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /shaders/geometry/closesthit_colored_indexed_triangle_lists.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | #extension GL_EXT_scalar_block_layout : enable 7 | 8 | #include "../common/payload.shinc" 9 | #include "../common/bindings.h" 10 | 11 | layout(location = 0) rayPayloadInEXT Payload payload; 12 | hitAttributeEXT vec2 attribs; 13 | 14 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer VextexBuf 15 | { 16 | vec3 v; 17 | }; 18 | 19 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer IndexBuf 20 | { 21 | uint i; 22 | }; 23 | 24 | struct ColoredIndexedTriangleList 25 | { 26 | mat3 normalMat; 27 | vec4 color; 28 | VextexBuf vertexBuf; 29 | IndexBuf indexBuf; 30 | uint type; // 0: lamertian, 1: metal, 2: dielectric, 3: emissive, 4: foggy 31 | float fuzz; 32 | float ref_idx; 33 | float density; 34 | }; 35 | 36 | layout(std430, binding = BINDING_ColoredIndexedTriangleList) buffer Params 37 | { 38 | ColoredIndexedTriangleList[] coloredIndexedTriangleLists; 39 | }; 40 | 41 | const uint cPresets[5] = { 42 | MAT_OPAQUE_BIT | MAT_DIFFUSE_BIT, 43 | MAT_OPAQUE_BIT | MAT_SPECULAR_BIT, 44 | MAT_FRESNEL_BIT | MAT_SCATTER_BIT, 45 | MAT_OPAQUE_BIT | MAT_EMIT_BIT, 46 | MAT_SCATTER_BIT 47 | }; 48 | 49 | void main() 50 | { 51 | ColoredIndexedTriangleList instance = coloredIndexedTriangleLists[gl_InstanceCustomIndexEXT]; 52 | 53 | uint i0 = instance.indexBuf[3 * gl_PrimitiveID].i; 54 | uint i1 = instance.indexBuf[3 * gl_PrimitiveID + 1].i; 55 | uint i2 = instance.indexBuf[3 * gl_PrimitiveID + 2].i; 56 | 57 | vec3 norm0 = instance.vertexBuf[i0].v; 58 | vec3 norm1 = instance.vertexBuf[i1].v; 59 | vec3 norm2 = instance.vertexBuf[i2].v; 60 | 61 | const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); 62 | 63 | vec3 normal = norm0 * barycentrics.x + norm1 * barycentrics.y + norm2 * barycentrics.z; 64 | normal = normalize(instance.normalMat * normal); 65 | 66 | payload.material_bits = cPresets[instance.type]; 67 | payload.t = gl_HitTEXT; 68 | payload.color0 = instance.color.xyz; 69 | payload.color1 = instance.color.xyz; 70 | payload.color2 = instance.color.xyz; 71 | payload.normal = normal; 72 | payload.f1 = instance.fuzz; 73 | payload.f2 = instance.density; 74 | 75 | if (instance.type == 0) payload.f0 = 0.0; 76 | if (instance.type == 1) payload.f0 = 1.0; 77 | if (instance.type == 2) payload.f0 = instance.ref_idx; 78 | } 79 | 80 | -------------------------------------------------------------------------------- /shaders/geometry/closesthit_textured_triangle_lists.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | #extension GL_EXT_nonuniform_qualifier : enable 7 | #extension GL_EXT_scalar_block_layout : enable 8 | 9 | #include "../common/payload.shinc" 10 | #include "../common/bindings.h" 11 | 12 | layout(location = 0) rayPayloadInEXT Payload payload; 13 | hitAttributeEXT vec2 attribs; 14 | 15 | layout(binding = 3) uniform sampler2D[] textureSamplers; 16 | 17 | struct Vertex 18 | { 19 | vec3 Position; 20 | vec3 Normal; 21 | vec2 TexCoord; 22 | }; 23 | 24 | struct Material 25 | { 26 | vec3 diffuse; 27 | int textureId; 28 | }; 29 | 30 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer VextexBuf 31 | { 32 | Vertex v; 33 | }; 34 | 35 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer MaterialBuf 36 | { 37 | Material m; 38 | }; 39 | 40 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer MaterialIndexBuf 41 | { 42 | int i; 43 | }; 44 | 45 | struct TexturedTriangleList 46 | { 47 | mat3 normalMat; 48 | VextexBuf vertexBuf; 49 | MaterialBuf materialBuf; 50 | MaterialIndexBuf materialIdxBuf; 51 | }; 52 | 53 | layout(std430, binding = BINDING_TexturedTriangleList) buffer Params 54 | { 55 | TexturedTriangleList[] texturedTriangleList; 56 | }; 57 | 58 | 59 | void main() 60 | { 61 | TexturedTriangleList instance = texturedTriangleList[gl_InstanceCustomIndexEXT]; 62 | 63 | Vertex v0 = instance.vertexBuf[3 * gl_PrimitiveID].v; 64 | Vertex v1 = instance.vertexBuf[3 * gl_PrimitiveID + 1].v; 65 | Vertex v2 = instance.vertexBuf[3 * gl_PrimitiveID + 2].v; 66 | 67 | Material mat = instance.materialBuf[instance.materialIdxBuf[gl_PrimitiveID].i].m; 68 | 69 | const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); 70 | 71 | vec3 normal = v0.Normal * barycentrics.x + v1.Normal * barycentrics.y + v2.Normal * barycentrics.z; 72 | normal = normalize(instance.normalMat * normal); 73 | 74 | vec3 c = mat.diffuse; 75 | if (mat.textureId >= 0) 76 | { 77 | vec2 texCoord = v0.TexCoord * barycentrics.x + v1.TexCoord * barycentrics.y + v2.TexCoord * barycentrics.z; 78 | c*= texture(textureSamplers[mat.textureId], texCoord).xyz; 79 | } 80 | 81 | payload.t = gl_HitTEXT; 82 | payload.material_bits = MAT_OPAQUE_BIT | MAT_DIFFUSE_BIT; 83 | payload.color1 = c; 84 | payload.f0 = 0.0; 85 | payload.normal = normal; 86 | } 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /ColoredIndexedTriangleList.cpp: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include "ColoredIndexedTriangleList.h" 3 | #include "shaders/common/bindings.h" 4 | 5 | ColoredIndexedTriangleList::ColoredIndexedTriangleList(const glm::mat4x4& model, const std::vector& vertices, const std::vector& indices, const Material& material) : Geometry(model) 6 | { 7 | m_material = material; 8 | 9 | std::vector positions(vertices.size()); 10 | std::vector norms(vertices.size()); 11 | for (size_t i = 0; i < vertices.size(); i++) 12 | { 13 | positions[i] = vertices[i].Position; 14 | norms[i] = vertices[i].Normal; 15 | } 16 | 17 | m_vertexBuffer = new DeviceBuffer(sizeof(glm::vec3)* vertices.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 18 | m_vertexBuffer->upload(norms.data()); 19 | m_indexBuffer = new DeviceBuffer(sizeof(unsigned)*indices.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 20 | m_indexBuffer->upload(indices.data()); 21 | 22 | DeviceBuffer posBuf(sizeof(glm::vec3)* vertices.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 23 | posBuf.upload(positions.data()); 24 | 25 | _blas_create_indexed_triangles(&posBuf, m_indexBuffer); 26 | } 27 | 28 | ColoredIndexedTriangleList::~ColoredIndexedTriangleList() 29 | { 30 | delete m_indexBuffer; 31 | delete m_vertexBuffer; 32 | } 33 | 34 | 35 | struct TriangleMeshView 36 | { 37 | glm::mat3x4 normalMat; 38 | glm::vec4 color; 39 | VkDeviceAddress vertexBuf; 40 | VkDeviceAddress indexBuf; 41 | MaterialType type; 42 | float fuzz; 43 | float ref_idx; 44 | float density; 45 | }; 46 | 47 | GeoCls ColoredIndexedTriangleList::cls() const 48 | { 49 | static const char s_name[] = "ColoredIndexedTriangleList"; 50 | static const char s_fn_rchit[] = "geometry/closesthit_colored_indexed_triangle_lists.spv"; 51 | GeoCls cls = {}; 52 | cls.name = s_name; 53 | cls.size_view = sizeof(TriangleMeshView); 54 | cls.binding_view = BINDING_ColoredIndexedTriangleList; 55 | cls.fn_intersection = nullptr; 56 | cls.fn_closesthit = s_fn_rchit; 57 | return cls; 58 | } 59 | 60 | void ColoredIndexedTriangleList::get_view(void* view_buf) const 61 | { 62 | TriangleMeshView& view = *(TriangleMeshView*)view_buf; 63 | view.normalMat = m_norm_mat; 64 | view.color = { m_material.color, 1.0f }; 65 | view.vertexBuf = m_vertexBuffer->get_device_address(); 66 | view.indexBuf = m_indexBuffer->get_device_address(); 67 | view.type = m_material.type; 68 | view.fuzz = m_material.fuzz; 69 | view.ref_idx = m_material.ref_idx; 70 | view.density = m_material.density; 71 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Fei Yang 2 | 3 | "Anti 996" License Version 1.0 (Draft) 4 | 5 | Permission is hereby granted to any individual or legal entity 6 | obtaining a copy of this licensed work (including the source code, 7 | documentation and/or related items, hereinafter collectively referred 8 | to as the "licensed work"), free of charge, to deal with the licensed 9 | work for any purpose, including without limitation, the rights to use, 10 | reproduce, modify, prepare derivative works of, distribute, publish 11 | and sublicense the licensed work, subject to the following conditions: 12 | 13 | 1. The individual or the legal entity must conspicuously display, 14 | without modification, this License and the notice on each redistributed 15 | or derivative copy of the Licensed Work. 16 | 17 | 2. The individual or the legal entity must strictly comply with all 18 | applicable laws, regulations, rules and standards of the jurisdiction 19 | relating to labor and employment where the individual is physically 20 | located or where the individual was born or naturalized; or where the 21 | legal entity is registered or is operating (whichever is stricter). In 22 | case that the jurisdiction has no such laws, regulations, rules and 23 | standards or its laws, regulations, rules and standards are 24 | unenforceable, the individual or the legal entity are required to 25 | comply with Core International Labor Standards. 26 | 27 | 3. The individual or the legal entity shall not induce, suggest or force 28 | its employee(s), whether full-time or part-time, or its independent 29 | contractor(s), in any methods, to agree in oral or written form, to 30 | directly or indirectly restrict, weaken or relinquish his or her 31 | rights or remedies under such laws, regulations, rules and standards 32 | relating to labor and employment as mentioned above, no matter whether 33 | such written or oral agreements are enforceable under the laws of the 34 | said jurisdiction, nor shall such individual or the legal entity 35 | limit, in any methods, the rights of its employee(s) or independent 36 | contractor(s) from reporting or complaining to the copyright holder or 37 | relevant authorities monitoring the compliance of the license about 38 | its violation(s) of the said license. 39 | 40 | THE LICENSED WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 41 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 42 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 43 | IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, 44 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 45 | OTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE 46 | LICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK. 47 | -------------------------------------------------------------------------------- /tests/test3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "PathTracer.h" 9 | #include "lambertian_obj.h" 10 | #include "TexturedTriangleList.h" 11 | #include "ColoredUnitSphere.h" 12 | #include "TexturedUnitSphere.h" 13 | 14 | #include "stb_image.h" 15 | 16 | #define STB_IMAGE_WRITE_IMPLEMENTATION 17 | #include "stb_image_write.h" 18 | 19 | #include "dds_reader.hpp" 20 | 21 | #ifndef PI 22 | #define PI 3.1415926f 23 | #endif 24 | 25 | int main() 26 | { 27 | const int view_width = 900; 28 | const int view_height = 600; 29 | 30 | PathTracer pt; 31 | 32 | Image target(view_width, view_height, nullptr); 33 | pt.set_target(&target); 34 | 35 | int cubeWidth, cubeHeight, cubeChannels, isCube; 36 | void *cube_pixels = dds_load("../data/sky_cube.dds", &cubeWidth, &cubeHeight, &cubeChannels, &isCube); 37 | RGBACubemap cubemap(cubeWidth, cubeHeight, cube_pixels, false); 38 | dds_free(cube_pixels); 39 | 40 | int id_skybox= pt.add_cubemap(&cubemap); 41 | TexturedSkyBox skybox(id_skybox); 42 | pt.set_sky(&skybox); 43 | 44 | glm::mat4x4 identity = glm::identity(); 45 | 46 | int texWidth, texHeight, texChannels; 47 | stbi_uc* pixels = stbi_load("../data/moon_map.jpg", &texWidth, &texHeight, &texChannels, 4); 48 | RGBATexture tex(texWidth, texHeight, pixels); 49 | stbi_image_free(pixels); 50 | int tex_id = pt.add_texture(&tex); 51 | 52 | glm::mat4x4 model0 = glm::translate(identity, glm::vec3(0.0f, -100.0f, 0.0f)); 53 | model0 = glm::scale(model0, glm::vec3(100.0f, 100.0f, 100.0f)); 54 | model0 = glm::rotate(model0, PI / 6.0f, glm::vec3(1.0f, 0.0f, 1.0f)); 55 | TexturedUnitSphere sphere0(model0, tex_id); 56 | pt.add_geometry(&sphere0); 57 | 58 | glm::mat4x4 model1 = glm::translate(identity, glm::vec3(0.0f, 1.0f, 3.0f)); 59 | ColoredUnitSphere sphere1(model1, { dielectric, { 1.0f, 1.0f, 1.0f }, 0.0f, 1.5f }); 60 | pt.add_geometry(&sphere1); 61 | 62 | glm::mat4x4 model2 = glm::translate(identity, glm::vec3(-3.0f, 1.0f, -1.5f)); 63 | ColoredUnitSphere sphere2(model2, { metal, { 0.7f, 0.6f, 0.5f } }); 64 | pt.add_geometry(&sphere2); 65 | 66 | LambertianObject obj(pt, "../data/Medieval_building", "Medieval_building.obj", identity); 67 | pt.add_geometry(obj.get_geo()); 68 | pt.set_camera({ -12.0f, 6.0f, 12.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 30.0f, 0.2f, 16.0f); 69 | 70 | pt.trace(100); 71 | 72 | unsigned char* hbuffer = (unsigned char*)malloc(view_width * view_height * 3); 73 | target.to_host_srgb(hbuffer); 74 | stbi_write_png("test3.png", view_width, view_height, 3, hbuffer, view_width * 3); 75 | free(hbuffer); 76 | 77 | system("pause"); 78 | 79 | return 0; 80 | } 81 | 82 | 83 | -------------------------------------------------------------------------------- /rand_state_init_xorwow.hpp: -------------------------------------------------------------------------------- 1 | #include "xor_wow_data.hpp" 2 | #include "RNGState_xorwow.h" 3 | 4 | struct RNG 5 | { 6 | const unsigned* p_sequence_matrix; 7 | 8 | inline void state_init(unsigned long long seed, 9 | unsigned long long subsequence, 10 | RNGState& state) 11 | { 12 | unsigned int s0 = ((unsigned int)seed) ^ 0xaad26b49UL; 13 | unsigned int s1 = (unsigned int)(seed >> 32) ^ 0xf7dcefddUL; 14 | unsigned int t0 = 1099087573UL * s0; 15 | unsigned int t1 = 2591861531UL * s1; 16 | state.d = 6615241 + t1 + t0; 17 | state.v.v0 = 123456789UL + t0; 18 | state.v.v1 = 362436069UL ^ t0; 19 | state.v.v2 = 521288629UL + t1; 20 | state.v.v3 = 88675123UL ^ t1; 21 | state.v.v4 = 5783321UL + t0; 22 | 23 | // apply sequence matrix 24 | V5 result; 25 | unsigned long long p = subsequence; 26 | int i_mat = 0; 27 | unsigned matrix[800]; 28 | unsigned matrixA[800]; 29 | 30 | while (p && i_mat < 7) 31 | { 32 | for (unsigned int t = 0; t < (p & 3); t++) 33 | { 34 | matvec(state.v, p_sequence_matrix + i_mat * 800, result); 35 | state.v = result; 36 | } 37 | p >>= 2; 38 | i_mat++; 39 | } 40 | if (p) 41 | { 42 | memcpy(matrix, p_sequence_matrix + i_mat * 800, sizeof(unsigned) * 800); 43 | memcpy(matrixA, p_sequence_matrix + i_mat * 800, sizeof(unsigned) * 800); 44 | } 45 | 46 | while (p) 47 | { 48 | for (unsigned int t = 0; t < (p & 0xF); t++) 49 | { 50 | matvec(state.v, matrixA, result); 51 | state.v = result; 52 | } 53 | p >>= 4; 54 | if (p) 55 | { 56 | for (int i = 0; i < 4; i++) 57 | { 58 | matmat(matrix, matrixA); 59 | memcpy(matrixA, matrix, sizeof(unsigned) * 800); 60 | } 61 | } 62 | } 63 | 64 | } 65 | 66 | private: 67 | static inline void matvec_i(int i, unsigned v_i, const unsigned *matrix, V5& result) 68 | { 69 | for (int j = 0; j < 32; j++) 70 | if (v_i & (1 << j)) 71 | { 72 | V5 mat_row = ((V5*)matrix)[i * 32 + j]; 73 | result.v0 ^= mat_row.v0; 74 | result.v1 ^= mat_row.v1; 75 | result.v2 ^= mat_row.v2; 76 | result.v3 ^= mat_row.v3; 77 | result.v4 ^= mat_row.v4; 78 | } 79 | } 80 | 81 | static inline void matvec(const V5& vector, const unsigned *matrix, V5& result) 82 | { 83 | memset(&result, 0, sizeof(V5)); 84 | matvec_i(0, vector.v0, matrix, result); 85 | matvec_i(1, vector.v1, matrix, result); 86 | matvec_i(2, vector.v2, matrix, result); 87 | matvec_i(3, vector.v3, matrix, result); 88 | matvec_i(4, vector.v4, matrix, result); 89 | } 90 | 91 | static inline void matmat(unsigned int *matrixA, const unsigned int *matrixB) 92 | { 93 | V5 result; 94 | for (int i = 0; i < 160; i++) 95 | { 96 | matvec(((V5*)matrixA)[i], matrixB, result); 97 | ((V5*)matrixA)[i] = result; 98 | } 99 | } 100 | 101 | 102 | }; 103 | 104 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 3.0) 2 | 3 | project(FeiRays) 4 | 5 | set (INCLUDE_DIR 6 | thirdparty 7 | thirdparty/volk 8 | thirdparty/Vulkan-Headers/include 9 | thirdparty/glm/glm 10 | . 11 | ) 12 | 13 | include_directories(${INCLUDE_DIR}) 14 | add_subdirectory(thirdparty/volk) 15 | 16 | 17 | add_executable(PackShaders pack_shaders.cpp) 18 | add_custom_target(Run_PackShaders 19 | COMMAND PackShaders 20 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 21 | COMMENT "Running PackShaders in ${CMAKE_CURRENT_SOURCE_DIR}" 22 | SOURCES pack_shaders.cpp 23 | ) 24 | 25 | 26 | set (SOURCE 27 | context.cpp 28 | RNGInitializer.cpp 29 | SRGBConverter.cpp 30 | PathTracer.cpp 31 | ColoredIndexedTriangleList.cpp 32 | ColoredUnitSphere.cpp 33 | UnitSphereCheckerTex.cpp 34 | TexturedTriangleList.cpp 35 | TexturedUnitSphere.cpp 36 | WavefrontIndexedTriangleList.cpp 37 | ) 38 | 39 | set (HEADER 40 | Timing.h 41 | context.h 42 | RNGState_xorwow.h 43 | xor_wow_data.hpp 44 | Material.h 45 | RNGInitializer.h 46 | SRGBConverter.h 47 | PathTracer.h 48 | ColoredIndexedTriangleList.h 49 | ColoredUnitSphere.h 50 | UnitSphereCheckerTex.h 51 | TexturedTriangleList.h 52 | TexturedUnitSphere.h 53 | WavefrontIndexedTriangleList.h 54 | ) 55 | 56 | if (WIN32) 57 | set (DEFINES ${DEFINES} 58 | -D"_CRT_SECURE_NO_DEPRECATE" 59 | -D"_SCL_SECURE_NO_DEPRECATE" 60 | -D"_CRT_SECURE_NO_WARNINGS" 61 | ) 62 | else() 63 | add_definitions(-std=c++14) 64 | add_compile_options(-fPIC) 65 | endif() 66 | 67 | add_definitions(${DEFINES}) 68 | 69 | add_library(FeiRays ${SOURCE} ${HEADER}) 70 | 71 | add_dependencies(Run_PackShaders PackShaders) 72 | add_dependencies(FeiRays Run_PackShaders) 73 | 74 | add_executable(test_rng tests/test_rng.cpp) 75 | target_link_libraries(test_rng FeiRays volk) 76 | 77 | add_executable(rt_weekend tests/rt_weekend.cpp) 78 | target_link_libraries(rt_weekend FeiRays volk) 79 | 80 | add_executable(test1 tests/test1.cpp) 81 | target_link_libraries(test1 FeiRays volk) 82 | 83 | add_executable(test2 tests/test2.cpp) 84 | target_link_libraries(test2 FeiRays volk) 85 | 86 | add_executable(test3 tests/test3.cpp tests/dds_reader.hpp tests/texture_map.cpp tests/texture_map.h tests/lambertian_obj.cpp tests/lambertian_obj.h) 87 | target_link_libraries(test3 FeiRays volk) 88 | 89 | add_executable(test4 tests/test4.cpp) 90 | target_link_libraries(test4 FeiRays volk) 91 | 92 | add_executable(test5 tests/test5.cpp) 93 | target_link_libraries(test5 FeiRays volk) 94 | 95 | add_executable(test6 tests/test6.cpp) 96 | target_link_libraries(test6 FeiRays volk) 97 | 98 | add_executable(test7 tests/test7.cpp tests/dds_reader.hpp tests/texture_map.cpp tests/texture_map.h tests/wavefront_obj.cpp tests/wavefront_obj.h) 99 | target_link_libraries(test7 FeiRays volk) 100 | 101 | set(BUILD_PYTHON_EXTENSION false CACHE BOOL "Build Python Extension") 102 | 103 | if (BUILD_PYTHON_EXTENSION) 104 | add_subdirectory(PyFeiRays) 105 | endif() 106 | -------------------------------------------------------------------------------- /python/FeiRays/Scene.py: -------------------------------------------------------------------------------- 1 | from .Native import native 2 | from .utils import Vec3, Transform 3 | from PIL import Image as pil_Image 4 | 5 | # material types 6 | LAMBERTIAN = 0 7 | METAL = 1 8 | DIELECTRIC = 2 9 | EMISSIVE = 3 10 | FOGGY = 4 11 | 12 | class Scene: 13 | def __init__ (self, width, height): 14 | self.m_cptr = native.n_scene_create(width, height) 15 | 16 | def __del__ (self): 17 | native.n_scene_destroy(self.m_cptr) 18 | 19 | def size(self): 20 | width = native.n_scene_width(self.m_cptr) 21 | height = native.n_scene_height(self.m_cptr) 22 | return (width, height) 23 | 24 | def get_image(self, boost = 1.0): 25 | width = native.n_scene_width(self.m_cptr) 26 | height = native.n_scene_height(self.m_cptr) 27 | data = b'\x00'*(width*height*3); 28 | native.n_scene_get_image(self.m_cptr, boost, data) 29 | return pil_Image.frombytes('RGB', (width, height), data) 30 | 31 | def set_gradient_sky(self, color0 = (1.0, 1.0, 1.0), color1=(0.5, 0.7, 1.0)): 32 | v_color0 = Vec3(color0) 33 | v_color1 = Vec3(color1) 34 | native.n_scene_set_gradient_sky(self.m_cptr, v_color0.m_cptr, v_color1.m_cptr) 35 | 36 | def set_textured_sky(self, filename, srgb = True, angle = 0.0, axis = None): 37 | p_axis = 0 38 | if axis!=None: 39 | v_axis = Vec3(axis) 40 | p_axis = v_axis.m_cptr 41 | native.n_scene_set_textured_sky(self.m_cptr, filename.encode('utf-8'), srgb, f_angle, p_axis) 42 | 43 | def add_colored_sphere(self, transform, material_type = LAMBERTIAN, color = (1.0, 1.0, 1.0), fuzz = 0.0, ref_idx = 0.0, density = 0.0): 44 | v_color = Vec3(color) 45 | native.n_scene_add_colored_sphere(self.m_cptr, transform.m_cptr, material_type, v_color.m_cptr, fuzz, ref_idx, density) 46 | 47 | def add_colored_cube(self, transform, material_type = LAMBERTIAN, color = (1.0, 1.0, 1.0), fuzz = 0.0, ref_idx = 0.0, density = 0.0): 48 | v_color = Vec3(color) 49 | native.n_scene_add_colored_cube(self.m_cptr, transform.m_cptr, material_type, v_color.m_cptr, fuzz, ref_idx, density) 50 | 51 | def add_textured_sphere(self, transform, filename, srgb=True, color=(1.0, 1.0, 1.0)): 52 | v_color = Vec3(color) 53 | native.n_scene_add_textured_sphere(self.m_cptr, transform.m_cptr, filename.encode('utf-8'), srgb, v_color.m_cptr) 54 | 55 | def add_wavefront_object(self, transform, path, filename): 56 | native.n_scene_add_wavefront_object(self.m_cptr, transform.m_cptr, path.encode('utf-8'), filename.encode('utf-8')) 57 | 58 | def add_sphere_light(self, center, radius, color): 59 | v_center = Vec3(center) 60 | v_color = Vec3(color) 61 | native.n_scene_add_sphere_light(self.m_cptr, v_center.m_cptr, radius, v_color.m_cptr) 62 | 63 | def add_sunlight(self, direction, angle, color): 64 | v_dir = Vec3(direction) 65 | v_color = Vec3(color) 66 | native.n_scene_add_sunlight(self.m_cptr, v_dir.m_cptr, angle, v_color.m_cptr) 67 | 68 | def set_camera(self, look_from, lookat, vup, vfov, aperture = 0.0, focus_dist = 1.0): 69 | v_look_from = Vec3(look_from) 70 | v_look_at = Vec3(lookat) 71 | v_vup = Vec3(vup) 72 | native.n_scene_set_camera(self.m_cptr, v_look_from.m_cptr, v_look_at.m_cptr, v_vup.m_cptr, vfov, aperture, focus_dist) 73 | 74 | def trace(self, num_iter = 100, interval = -1): 75 | native.n_scene_trace(self.m_cptr, num_iter, interval) 76 | -------------------------------------------------------------------------------- /tests/rt_weekend.cpp: -------------------------------------------------------------------------------- 1 | #include "PathTracer.h" 2 | #include "ColoredIndexedTriangleList.h" 3 | #include "ColoredUnitSphere.h" 4 | #include "Timing.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #define STB_IMAGE_WRITE_IMPLEMENTATION 16 | #include "stb_image_write.h" 17 | 18 | typedef ColoredIndexedTriangleList TriangleMesh; 19 | typedef ColoredUnitSphere Sphere; 20 | 21 | double rand01() 22 | { 23 | return (double)rand() / (double)RAND_MAX; 24 | } 25 | 26 | int main() 27 | { 28 | srand(time(0)); 29 | 30 | const int view_width = 900; 31 | const int view_height = 600; 32 | 33 | printf("Generating scene..\n"); 34 | double time0 = GetTime(); 35 | 36 | glm::mat4x4 identity = glm::identity(); 37 | 38 | std::vector spheres; 39 | 40 | 41 | { 42 | glm::mat4x4 model = glm::translate(identity, glm::vec3(0.0f, -1000.0f, 0.0f)); 43 | model = glm::scale(model, glm::vec3(1000.0f, 1000.0f, 1000.0f)); 44 | Sphere* sphere = new Sphere(model, { lambertian, { 0.5f, 0.5f, 0.5f } }); 45 | spheres.push_back(sphere); 46 | } 47 | 48 | { 49 | glm::mat4x4 model = glm::translate(identity, glm::vec3(0.0f, 1.0f, 0.0f)); 50 | Sphere* sphere = new Sphere(model, { dielectric, { 1.0f, 1.0f, 1.0f }, 0.0f, 1.5f }); 51 | spheres.push_back(sphere); 52 | } 53 | 54 | { 55 | glm::mat4x4 model = glm::translate(identity, glm::vec3(-4.0f, 1.0f, 0.0f)); 56 | Sphere* sphere = new Sphere(model, { lambertian, { 0.4f, 0.2f, 0.1f } }); 57 | spheres.push_back(sphere); 58 | } 59 | 60 | { 61 | glm::mat4x4 model = glm::translate(identity, glm::vec3(4.0f, 1.0f, 0.0f)); 62 | Sphere* sphere = new Sphere(model, { metal, { 0.7f, 0.6f, 0.5f } }); 63 | spheres.push_back(sphere); 64 | } 65 | 66 | for (int a = -11; a < 11; a++) 67 | for (int b = -11; b < 11; b++) 68 | { 69 | double choose_mat = rand01(); 70 | glm::vec3 center = { (float)a + 0.9f*rand01(), 0.2f, (float)b + 0.9f*rand01() }; 71 | float dis = (center.x - 4.0f)*(center.x - 4.0f) + center.z*center.z; 72 | if (dis < 1.0f) continue; 73 | dis = center.x*center.x + center.z*center.z; 74 | if (dis < 1.0f) continue; 75 | 76 | glm::mat4x4 model = glm::translate(identity, center); 77 | model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f)); 78 | 79 | if (choose_mat < 0.75f) 80 | { 81 | Sphere* sphere = new Sphere(model, { lambertian, { rand01()*rand01(), rand01()*rand01(), rand01()*rand01() } }); 82 | spheres.push_back(sphere); 83 | } 84 | else if (choose_mat < 0.90f) 85 | { 86 | Sphere* sphere = new Sphere(model, { metal, { 0.5f*(1.0f + rand01()), 0.5f*(1.0f + rand01()),0.5f*(1.0f + rand01()) } }); 87 | spheres.push_back(sphere); 88 | } 89 | else 90 | { 91 | Sphere* sphere = new Sphere(model, { dielectric, { 1.0f, 1.0f, 1.0f }, 0.0f, 1.5f }); 92 | spheres.push_back(sphere); 93 | } 94 | 95 | } 96 | double time1 = GetTime(); 97 | printf("Done generating scene.. %f secs\n", time1-time0); 98 | 99 | 100 | Image target(view_width, view_height, nullptr); 101 | 102 | PathTracer pt; 103 | pt.set_target(&target); 104 | 105 | for (size_t i = 0; i < spheres.size(); i++) 106 | pt.add_geometry(spheres[i]); 107 | 108 | pt.set_camera({ 15.0f, 3.0f, 3.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 20.0f, 0.2f, 12.0f); 109 | pt.trace(100); 110 | 111 | unsigned char* hbuffer = (unsigned char*)malloc(view_width * view_height * 3); 112 | target.to_host_srgb(hbuffer); 113 | stbi_write_png("rt_weekend.png", view_width, view_height, 3, hbuffer, view_width * 3); 114 | free(hbuffer); 115 | 116 | for (size_t i = 0; i < spheres.size(); i++) 117 | delete spheres[i]; 118 | 119 | system("pause"); 120 | 121 | return 0; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /TexturedTriangleList.cpp: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include "TexturedTriangleList.h" 3 | #include "shaders/common/bindings.h" 4 | 5 | void TexturedTriangleList::_blas_create() 6 | { 7 | const Context& ctx = Context::get_context(); 8 | 9 | VkAccelerationStructureGeometryKHR acceleration_geometry{}; 10 | acceleration_geometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; 11 | acceleration_geometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; 12 | acceleration_geometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; 13 | acceleration_geometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; 14 | acceleration_geometry.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; 15 | acceleration_geometry.geometry.triangles.vertexData.deviceAddress = m_vertexBuffer->get_device_address(); 16 | acceleration_geometry.geometry.triangles.maxVertex = (unsigned)(m_vertexBuffer->size() / sizeof(Vertex)); 17 | acceleration_geometry.geometry.triangles.vertexStride = sizeof(Vertex); 18 | acceleration_geometry.geometry.triangles.indexType = VK_INDEX_TYPE_NONE_KHR; 19 | 20 | VkAccelerationStructureBuildGeometryInfoKHR geoBuildInfo{}; 21 | geoBuildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; 22 | geoBuildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; 23 | geoBuildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; 24 | geoBuildInfo.geometryCount = 1; 25 | geoBuildInfo.pGeometries = &acceleration_geometry; 26 | 27 | VkAccelerationStructureBuildRangeInfoKHR range{}; 28 | range.primitiveCount = (unsigned)(m_vertexBuffer->size() / sizeof(Vertex) / 3); 29 | range.primitiveOffset = 0; 30 | range.firstVertex = 0; 31 | range.transformOffset = 0; 32 | const VkAccelerationStructureBuildRangeInfoKHR* ranges = ⦥ 33 | 34 | m_blas = new BaseLevelAS(geoBuildInfo, &acceleration_geometry, &ranges); 35 | } 36 | 37 | 38 | TexturedTriangleList::TexturedTriangleList(const glm::mat4x4& model, const std::vector& vertices, const std::vector& materials, const int* materialIdx) : Geometry(model) 39 | { 40 | m_vertexBuffer = new DeviceBuffer(sizeof(Vertex)* vertices.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 41 | m_vertexBuffer->upload(vertices.data()); 42 | m_materialBuffer = new DeviceBuffer(sizeof(Material)* materials.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 43 | m_materialBuffer->upload(materials.data()); 44 | m_materialIdxBuffer = new DeviceBuffer(sizeof(int)* vertices.size() /3, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 45 | m_materialIdxBuffer->upload(materialIdx); 46 | 47 | _blas_create(); 48 | } 49 | 50 | TexturedTriangleList::~TexturedTriangleList() 51 | { 52 | delete m_materialIdxBuffer; 53 | delete m_materialBuffer; 54 | delete m_vertexBuffer; 55 | } 56 | 57 | struct TriangleMeshView 58 | { 59 | glm::mat3x4 normalMat; 60 | VkDeviceAddress vertexBuf; 61 | VkDeviceAddress materialBuf; 62 | VkDeviceAddress materialIdxBuf; 63 | }; 64 | 65 | GeoCls TexturedTriangleList::cls() const 66 | { 67 | static const char s_name[] = "TexturedTriangleList"; 68 | static const char s_fn_rchit[] = "geometry/closesthit_textured_triangle_lists.spv"; 69 | GeoCls cls = {}; 70 | cls.name = s_name; 71 | cls.size_view = sizeof(TriangleMeshView); 72 | cls.binding_view = BINDING_TexturedTriangleList; 73 | cls.fn_intersection = nullptr; 74 | cls.fn_closesthit = s_fn_rchit; 75 | return cls; 76 | } 77 | 78 | void TexturedTriangleList::get_view(void* view_buf) const 79 | { 80 | TriangleMeshView& view = *(TriangleMeshView*)view_buf; 81 | view.normalMat = m_norm_mat; 82 | view.vertexBuf = m_vertexBuffer->get_device_address(); 83 | view.materialBuf = m_materialBuffer->get_device_address(); 84 | view.materialIdxBuf = m_materialIdxBuffer->get_device_address(); 85 | } 86 | -------------------------------------------------------------------------------- /rand_state_init_xorwow.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "xor_wow_data.hpp" 6 | #include "RNGState_xorwow.h" 7 | 8 | struct RNG 9 | { 10 | unsigned* d_sequence_matrix; 11 | 12 | __device__ inline void state_init(unsigned long long seed, 13 | unsigned long long subsequence, 14 | RNGState& state) 15 | { 16 | unsigned int s0 = ((unsigned int)seed) ^ 0xaad26b49UL; 17 | unsigned int s1 = (unsigned int)(seed >> 32) ^ 0xf7dcefddUL; 18 | unsigned int t0 = 1099087573UL * s0; 19 | unsigned int t1 = 2591861531UL * s1; 20 | state.d = 6615241 + t1 + t0; 21 | state.v.v0 = 123456789UL + t0; 22 | state.v.v1 = 362436069UL ^ t0; 23 | state.v.v2 = 521288629UL + t1; 24 | state.v.v3 = 88675123UL ^ t1; 25 | state.v.v4 = 5783321UL + t0; 26 | 27 | // apply sequence matrix 28 | V5 result; 29 | unsigned long long p = subsequence; 30 | int i_mat = 0; 31 | unsigned matrix[800]; 32 | unsigned matrixA[800]; 33 | 34 | while (p && i_mat < 7) 35 | { 36 | for (unsigned int t = 0; t < (p & 3); t++) 37 | { 38 | matvec(state.v, d_sequence_matrix + i_mat * 800, result); 39 | state.v = result; 40 | } 41 | p >>= 2; 42 | i_mat++; 43 | } 44 | if (p) 45 | { 46 | memcpy(matrix, d_sequence_matrix + i_mat * 800, sizeof(unsigned) * 800); 47 | memcpy(matrixA, d_sequence_matrix + i_mat * 800, sizeof(unsigned) * 800); 48 | } 49 | 50 | while (p) 51 | { 52 | for (unsigned int t = 0; t < (p & 0xF); t++) 53 | { 54 | matvec(state.v, matrixA, result); 55 | state.v = result; 56 | } 57 | p >>= 4; 58 | if (p) 59 | { 60 | for (int i = 0; i < 4; i++) 61 | { 62 | matmat(matrix, matrixA); 63 | memcpy(matrixA, matrix, sizeof(unsigned) * 800); 64 | } 65 | } 66 | } 67 | } 68 | 69 | private: 70 | static __device__ inline void matvec_i(int i, unsigned v_i, const unsigned *matrix, V5& result) 71 | { 72 | for (int j = 0; j < 32; j++) 73 | if (v_i & (1 << j)) 74 | { 75 | V5 mat_row = ((V5*)matrix)[i * 32 + j]; 76 | result.v0 ^= mat_row.v0; 77 | result.v1 ^= mat_row.v1; 78 | result.v2 ^= mat_row.v2; 79 | result.v3 ^= mat_row.v3; 80 | result.v4 ^= mat_row.v4; 81 | } 82 | } 83 | 84 | static __device__ inline void matvec(const V5& vector, const unsigned *matrix, V5& result) 85 | { 86 | memset(&result, 0, sizeof(V5)); 87 | matvec_i(0, vector.v0, matrix, result); 88 | matvec_i(1, vector.v1, matrix, result); 89 | matvec_i(2, vector.v2, matrix, result); 90 | matvec_i(3, vector.v3, matrix, result); 91 | matvec_i(4, vector.v4, matrix, result); 92 | } 93 | 94 | static __device__ inline void matmat(unsigned int *matrixA, const unsigned int *matrixB) 95 | { 96 | V5 result; 97 | for (int i = 0; i < 160; i++) 98 | { 99 | matvec(((V5*)matrixA)[i], matrixB, result); 100 | ((V5*)matrixA)[i] = result; 101 | } 102 | } 103 | }; 104 | 105 | __global__ 106 | void g_rand_init(RNG rng, RNGState* d_states, unsigned count) 107 | { 108 | unsigned id = threadIdx.x + blockIdx.x*blockDim.x; 109 | if (id >= count) return; 110 | rng.state_init(1234, id, d_states[id]); 111 | } 112 | 113 | void cu_rand_init(unsigned count, RNGState* d_states) 114 | { 115 | RNG rng; 116 | cudaMalloc(&rng.d_sequence_matrix, sizeof(unsigned) * 800 * 8); 117 | cudaMemcpy(rng.d_sequence_matrix, xorwow_sequence_matrix, sizeof(unsigned) * 800 * 8, cudaMemcpyHostToDevice); 118 | 119 | unsigned blocks = (count + 127) / 128; 120 | g_rand_init << < blocks, 128 >> > (rng, d_states, count); 121 | 122 | cudaFree(rng.d_sequence_matrix); 123 | 124 | } 125 | 126 | void h_rand_init(unsigned count, RNGState* h_states) 127 | { 128 | 129 | RNGState* d_states; 130 | cudaMalloc(&d_states, sizeof(RNGState)* count); 131 | 132 | cu_rand_init(count, d_states); 133 | 134 | cudaMemcpy(h_states, d_states, sizeof(RNGState)* count, cudaMemcpyDeviceToHost); 135 | cudaFree(d_states); 136 | } 137 | -------------------------------------------------------------------------------- /tests/test2.cpp: -------------------------------------------------------------------------------- 1 | #include "PathTracer.h" 2 | #include "ColoredIndexedTriangleList.h" 3 | #include "ColoredUnitSphere.h" 4 | #include "UnitSphereCheckerTex.h" 5 | #include "Timing.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #define STB_IMAGE_WRITE_IMPLEMENTATION 17 | #include "stb_image_write.h" 18 | 19 | typedef ColoredIndexedTriangleList TriangleMesh; 20 | typedef ColoredUnitSphere SphereA; 21 | typedef UnitSphereCheckerTex SphereB; 22 | 23 | 24 | double rand01() 25 | { 26 | return (double)rand() / (double)RAND_MAX; 27 | } 28 | 29 | int main() 30 | { 31 | srand(time(0)); 32 | 33 | const int view_width = 900; 34 | const int view_height = 600; 35 | 36 | printf("Generating scene..\n"); 37 | double time0 = GetTime(); 38 | 39 | glm::mat4x4 identity = glm::identity(); 40 | 41 | std::vector geometries; 42 | 43 | 44 | { 45 | glm::mat4x4 model = glm::translate(identity, glm::vec3(0.0f, -1000.0f, 0.0f)); 46 | model = glm::scale(model, glm::vec3(1000.0f, 1000.0f, 1000.0f)); 47 | SphereB* sphere = new SphereB(model, 0.3f, {0.2f, 0.3f, 0.1f}, { 0.9f, 0.9f, 0.9f }); 48 | geometries.push_back(sphere); 49 | } 50 | 51 | { 52 | glm::mat4x4 model = glm::translate(identity, glm::vec3(0.0f, 1.0f, 0.0f)); 53 | SphereA* sphere = new SphereA(model, { dielectric, { 1.0f, 1.0f, 1.0f }, 0.0f, 1.5f }); 54 | geometries.push_back(sphere); 55 | } 56 | 57 | { 58 | glm::mat4x4 model = glm::translate(identity, glm::vec3(-4.0f, 1.0f, 0.0f)); 59 | SphereA* sphere = new SphereA(model, { lambertian, { 0.4f, 0.2f, 0.1f } }); 60 | geometries.push_back(sphere); 61 | } 62 | 63 | { 64 | glm::mat4x4 model = glm::translate(identity, glm::vec3(4.0f, 1.0f, 0.0f)); 65 | SphereA* sphere = new SphereA(model, { metal, { 0.7f, 0.6f, 0.5f } }); 66 | geometries.push_back(sphere); 67 | } 68 | 69 | for (int a = -11; a < 11; a++) 70 | for (int b = -11; b < 11; b++) 71 | { 72 | double choose_mat = rand01(); 73 | glm::vec3 center = { (float)a + 0.9f*rand01(), 0.2f, (float)b + 0.9f*rand01() }; 74 | float dis = (center.x - 4.0f)*(center.x - 4.0f) + center.z*center.z; 75 | if (dis < 1.0f) continue; 76 | dis = center.x*center.x + center.z*center.z; 77 | if (dis < 1.0f) continue; 78 | 79 | glm::mat4x4 model = glm::translate(identity, center); 80 | model = glm::scale(model, glm::vec3(0.2f, 0.2f, 0.2f)); 81 | 82 | if (choose_mat < 0.75f) 83 | { 84 | SphereA* sphere = new SphereA(model, { lambertian, { rand01()*rand01(), rand01()*rand01(), rand01()*rand01() } }); 85 | geometries.push_back(sphere); 86 | } 87 | else if (choose_mat < 0.90f) 88 | { 89 | SphereA* sphere = new SphereA(model, { metal, { 0.5f*(1.0f + rand01()), 0.5f*(1.0f + rand01()),0.5f*(1.0f + rand01()) } }); 90 | geometries.push_back(sphere); 91 | } 92 | else 93 | { 94 | SphereA* sphere = new SphereA(model, { dielectric, { 1.0f, 1.0f, 1.0f }, 0.0f, 1.5f }); 95 | geometries.push_back(sphere); 96 | } 97 | 98 | } 99 | double time1 = GetTime(); 100 | printf("Done generating scene.. %f secs\n", time1 - time0); 101 | 102 | 103 | Image target(view_width, view_height, nullptr); 104 | 105 | PathTracer pt; 106 | pt.set_target(&target); 107 | 108 | for (size_t i = 0; i < geometries.size(); i++) 109 | pt.add_geometry(geometries[i]); 110 | 111 | pt.set_camera({ 15.0f, 3.0f, 3.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 20.0f, 0.2f, 12.0f); 112 | pt.trace(100); 113 | 114 | unsigned char* hbuffer = (unsigned char*)malloc(view_width * view_height * 3); 115 | target.to_host_srgb(hbuffer); 116 | stbi_write_png("test2.png", view_width, view_height, 3, hbuffer, view_width * 3); 117 | free(hbuffer); 118 | 119 | for (size_t i = 0; i < geometries.size(); i++) 120 | delete geometries[i]; 121 | 122 | system("pause"); 123 | 124 | return 0; 125 | } 126 | 127 | -------------------------------------------------------------------------------- /shaders/common/rand_xorwow.shinc: -------------------------------------------------------------------------------- 1 | struct V5 2 | { 3 | uint v0; 4 | uint v1; 5 | uint v2; 6 | uint v3; 7 | uint v4; 8 | }; 9 | 10 | struct RNGState 11 | { 12 | V5 v; 13 | uint d; 14 | }; 15 | 16 | 17 | layout(buffer_reference, std430, buffer_reference_align = 4) buffer MatrixBuf 18 | { 19 | uint v; 20 | }; 21 | 22 | 23 | void matvec_i(int i, uint v_i, in MatrixBuf matrix, inout V5 result) 24 | { 25 | for (int j = 0; j < 32; j++) 26 | if ((v_i & (1 << j))!=0) 27 | { 28 | int k = (i * 32 + j)*5; 29 | result.v0 ^= matrix[k].v; 30 | result.v1 ^= matrix[k+1].v; 31 | result.v2 ^= matrix[k+2].v; 32 | result.v3 ^= matrix[k+3].v; 33 | result.v4 ^= matrix[k+4].v; 34 | } 35 | } 36 | 37 | void matvec(in V5 vector, in MatrixBuf matrix, inout V5 result) 38 | { 39 | result.v0 = result.v1 = result.v2 = result.v3 = result.v4 = 0; 40 | matvec_i(0, vector.v0, matrix, result); 41 | matvec_i(1, vector.v1, matrix, result); 42 | matvec_i(2, vector.v2, matrix, result); 43 | matvec_i(3, vector.v3, matrix, result); 44 | matvec_i(4, vector.v4, matrix, result); 45 | } 46 | 47 | void state_init(in MatrixBuf d_sequence_matrix, uint64_t seed, uint64_t subsequence, inout RNGState state) 48 | { 49 | if (subsequence>= (1<<18) ) subsequence= (1<<18) -1; 50 | 51 | uint s0 = uint(seed) ^ 0xaad26b49U; 52 | uint s1 = uint(seed >> 32) ^ 0xf7dcefddU; 53 | uint t0 = 1099087573U * s0; 54 | uint t1 = 2591861531U * s1; 55 | state.d = 6615241 + t1 + t0; 56 | state.v.v0 = 123456789U + t0; 57 | state.v.v1 = 362436069U ^ t0; 58 | state.v.v2 = 521288629U + t1; 59 | state.v.v3 = 88675123U ^ t1; 60 | state.v.v4 = 5783321U + t0; 61 | 62 | // apply sequence matrix 63 | V5 result; 64 | uint64_t p = subsequence; 65 | int i_mat = 0; 66 | 67 | while (p!=0 && i_mat<7) 68 | { 69 | for (uint t = 0; t < (p & 3); t++) 70 | { 71 | matvec(state.v, d_sequence_matrix + i_mat*800, result); 72 | state.v = result; 73 | } 74 | p >>= 2; 75 | i_mat++; 76 | } 77 | 78 | for (uint t = 0; t < (p & 0xF); t++) 79 | { 80 | matvec(state.v, d_sequence_matrix + i_mat*800, result); 81 | state.v = result; 82 | } 83 | } 84 | 85 | uint rand(inout RNGState state) 86 | { 87 | uint t; 88 | t = (state.v.v0 ^ (state.v.v0 >> 2)); 89 | state.v.v0 = state.v.v1; 90 | state.v.v1 = state.v.v2; 91 | state.v.v2 = state.v.v3; 92 | state.v.v3 = state.v.v4; 93 | state.v.v4 = (state.v.v4 ^ (state.v.v4 << 4)) ^ (t ^ (t << 1)); 94 | state.d += 362437; 95 | return state.v.v4 + state.d; 96 | } 97 | 98 | float rand01(inout RNGState state) 99 | { 100 | uint64_t urand = rand(state); 101 | return float(urand) / float(1UL << 32); 102 | } 103 | 104 | vec3 rand_in_unit_sphere(inout RNGState rstate) 105 | { 106 | vec3 ret; 107 | do{ 108 | ret = vec3(rand01(rstate)*2.0 - 1.0, rand01(rstate)*2.0 - 1.0, rand01(rstate)*2.0 - 1.0); 109 | } while (length(ret) > 1.0); 110 | return ret; 111 | } 112 | 113 | vec2 rand_in_unit_disk(inout RNGState rstate) 114 | { 115 | vec2 ret; 116 | do { 117 | ret = vec2(rand01(rstate)*2.0 - 1.0, rand01(rstate)*2.0 - 1.0); 118 | } while (length(ret) > 1.0); 119 | return ret; 120 | } 121 | 122 | vec3 rand_on_unit_sphere(inout RNGState rstate) 123 | { 124 | float theta = rand01(rstate) * radians(360.0); 125 | float z = rand01(rstate)*2.0 - 1.0; 126 | float r = 1.0 - z*z; 127 | if (r<0.0) r = 0.0; 128 | r = sqrt(r); 129 | vec3 ret; 130 | ret.z = z; 131 | ret.x = r*cos(theta); 132 | ret.y = r*sin(theta); 133 | return ret; 134 | } 135 | 136 | vec2 rand_on_unit_circle(inout RNGState rstate) 137 | { 138 | float theta = rand01(rstate) * radians(360.0); 139 | vec2 ret; 140 | ret.x = cos(theta); 141 | ret.y = sin(theta); 142 | return ret; 143 | } 144 | 145 | /* 146 | vec3 rand_in_unit_sphere(inout RNGState rstate) 147 | { 148 | vec3 v = rand_on_unit_sphere(rstate); 149 | float r = pow(rand01(rstate), 1.0/3.0); 150 | return v*r; 151 | } 152 | 153 | vec2 rand_in_unit_disk(inout RNGState rstate) 154 | { 155 | vec2 v = rand_on_unit_circle(rstate); 156 | float r = sqrt(rand01(rstate)); 157 | return v*r; 158 | } 159 | */ 160 | -------------------------------------------------------------------------------- /tests/test4.cpp: -------------------------------------------------------------------------------- 1 | #include "PathTracer.h" 2 | #include "ColoredIndexedTriangleList.h" 3 | #include "ColoredUnitSphere.h" 4 | #include "TexturedUnitSphere.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define STB_IMAGE_IMPLEMENTATION 15 | #include "stb_image.h" 16 | 17 | #define STB_IMAGE_WRITE_IMPLEMENTATION 18 | #include "stb_image_write.h" 19 | 20 | #ifndef PI 21 | #define PI 3.1415926f 22 | #endif 23 | 24 | 25 | int main() 26 | { 27 | std::vector cube_vertices = 28 | { 29 | {{-1.0f, -1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 30 | {{-1.0f, -1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 31 | {{-1.0f, 1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 32 | {{-1.0f, 1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 33 | 34 | {{-1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f }}, 35 | {{1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 36 | {{1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 37 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 38 | 39 | {{1.0f, -1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 40 | {{1.0f, -1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 41 | {{1.0f, 1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 42 | {{1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 43 | 44 | {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 45 | {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 46 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 47 | {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 48 | 49 | {{1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 50 | {{1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 51 | {{-1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 52 | {{-1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 53 | 54 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 55 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 56 | {{1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 57 | {{1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 58 | }; 59 | 60 | std::vector cube_indices = 61 | { 62 | 0, 1, 2, 63 | 0, 2, 3, 64 | 65 | 4, 5, 6, 66 | 4, 6, 7, 67 | 68 | 8, 9, 10, 69 | 8, 10, 11, 70 | 71 | 12, 13, 14, 72 | 12, 14, 15, 73 | 74 | 16, 17, 18, 75 | 16, 18, 19, 76 | 77 | 20, 21, 22, 78 | 20, 22, 23 79 | }; 80 | 81 | const int view_width = 900; 82 | const int view_height = 600; 83 | 84 | Image target(view_width, view_height, nullptr); 85 | 86 | PathTracer pt; 87 | pt.set_target(&target); 88 | 89 | GradientSky sky({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }); 90 | pt.set_sky(&sky); 91 | 92 | glm::mat4x4 identity = glm::identity(); 93 | 94 | glm::mat4x4 model0 = glm::translate(identity, glm::vec3(0.0f, -1000.0f, 0.0f)); 95 | model0 = glm::scale(model0, glm::vec3(1000.0f, 1000.0f, 1000.0f)); 96 | ColoredUnitSphere sphere0(model0, { lambertian, { 0.4f, 0.4f, 0.6f } }); 97 | pt.add_geometry(&sphere0); 98 | 99 | int texWidth, texHeight, texChannels; 100 | stbi_uc* pixels = stbi_load("../data/moon_map.jpg", &texWidth, &texHeight, &texChannels, 4); 101 | RGBATexture tex(texWidth, texHeight, pixels); 102 | stbi_image_free(pixels); 103 | int tex_id = pt.add_texture(&tex); 104 | 105 | glm::mat4x4 model1 = glm::translate(identity, glm::vec3(0.0f, 2.0f, 0.0f)); 106 | model1 = glm::scale(model1, glm::vec3(2.0f, 2.0f, 2.0f)); 107 | model1 = glm::rotate(model1, PI / 3.0f, glm::vec3(0.0f, 1.0f, 0.0f)); 108 | TexturedUnitSphere sphere1(model1, tex_id, { 0.8f, 0.8f, 0.6f }); 109 | pt.add_geometry(&sphere1); 110 | 111 | SphereLight light1({ 4.0f, 2.0f, -2.0f }, 0.25f, { 20.0f, 12.0f, 12.0f }); 112 | pt.add_geometry(&light1); 113 | 114 | SphereLight light2({ 4.0f, 2.0f, 2.0f }, 0.25f, { 12.0f, 20.0f, 12.0f }); 115 | pt.add_geometry(&light2); 116 | 117 | pt.set_camera({ 15.0f, 3.0f, 3.0f }, { 0.0f, 2.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 30.0f, 0.2f, 12.0f); 118 | 119 | pt.trace(100); 120 | 121 | unsigned char* hbuffer = (unsigned char*)malloc(view_width * view_height * 3); 122 | target.to_host_srgb(hbuffer); 123 | stbi_write_png("test4.png", view_width, view_height, 3, hbuffer, view_width * 3); 124 | free(hbuffer); 125 | 126 | system("pause"); 127 | 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FeiRays 2 | Reusable Vulkan based ray-tracing code base. 3 | 4 | The code is evolved from [VkRayTraceWeekend](https://github.com/fynv/VkRayTraceWeekend). 5 | 6 | Here, I'm trying to make it more extendable and reusable, so I can have more fun with it. 7 | 8 | Now playing with [McGuire Computer Graphics Archive](https://casual-effects.com/data/) 9 | 10 | 11 | 12 | The "sponza" model, 900x600x1000 rays, rendered in 11.2 seconds using RTX 2060 super. 13 | 14 | 15 | 16 | The "breakfast_room" model, 900x600x1000 rays, rendered in 18.4 seconds using RTX 2060 super. 17 | 18 | A Python frontend can be found in the "python" folder. 19 | 20 | Using the Python frontend, the above case can be rendered using the following Python script: 21 | 22 | ```python 23 | import FeiRays 24 | 25 | scene = FeiRays.Scene(900, 600) 26 | scene.add_sunlight((1,1,1), 2, (4000,4000,4000)) 27 | 28 | transform = FeiRays.Transform() 29 | scene.add_wavefront_object(transform, "breakfast_room", "breakfast_room.obj") 30 | scene.set_camera((2.5,1.5,2.5), (0,1.5,0), (0,1,0), 45) 31 | scene.trace(1000, 50) 32 | 33 | img = scene.get_image() 34 | img.save("breakfast_room.png") 35 | ``` 36 | (It is assumed that the model file "breakfast_room.obj" is located in the folder "breakfast_room".) 37 | 38 | The Python frontend (prebuilt for Win64 and Linux64) can be fetched from Pypi: 39 | 40 | ``` 41 | # pip install FeiRays 42 | ``` 43 | 44 | ## Building and Running 45 | 46 | Building the project is simple. 47 | 48 | [Volk](https://github.com/zeux/volk.git) and [Vulkan-Headers](https://github.com/KhronosGroup/Vulkan-Headers.git) are included as submodules, 49 | so it should be fine to build without Vulkan SDK. But be sure to have a driver that supports Vulkan 1.2. 50 | Nvidia users should use one of the "beta" drivers from [https://developer.nvidia.com/vulkan-driver](https://developer.nvidia.com/vulkan-driver). 51 | 52 | * Clone the repo and update the submodules 53 | * Use CMake to generate a VS solution at FeiRays/build. 54 | * Build and run the tests. 55 | * Shaders (spv) are expected at ../shaders relative to the starting folder. 56 | 57 | ## License 58 | 59 | I've decided to license this project under ['"Anti 996" License'](https://github.com/996icu/996.ICU/blob/master/LICENSE) 60 | 61 | Basically, you can use the code any way you like unless you are working for a 996 company. 62 | 63 | [![996.icu](https://img.shields.io/badge/link-996.icu-red.svg)](https://996.icu) 64 | 65 | 66 | ## Progress 67 | 68 | In case someone is interested in the progress of the project, here is a list of what have been implemented so far. 69 | 70 | ### Random Number Generator for Shaders 71 | 72 | For monte carlo path-tracing, it is quite essential to have a pseudo-random number generator ready everywhere. 73 | For this purpose, we have a minimal set of XORWOW implementation of CURAND ported here. 74 | 75 | ### Vulkan Resource Management 76 | 77 | Basic Vulkan resource classes are implemented in context.cpp. 78 | 79 | * The Context 80 | * Command Buffers 81 | * Linear Buffers 82 | * Textures and Cubemaps 83 | * Acceleration Structures 84 | 85 | ### Geometries 86 | 87 | There is abstract class called "Geometry". Each sub-class can have its own closest-hit shader and intersection shader (optional). 88 | 89 | * ColoredUnitSphere: support a uniform color and different material types 90 | * ColoredIndexedTriangleList: support a uniform color and different material types 91 | * UnitSphereCheckerTex: procedure texture. diffuse only 92 | * TexturedUnitSphere: 1 texture attached to 1 sphere. diffuse only 93 | * TexturedTriangleList: support multiple textures. diffuse only 94 | * WavefrontIndexedTriangleList: support multiple textures. support diffuse, specular, emissive material types. support alpha-map and bump-map. 95 | 96 | ### Light sources 97 | 98 | There are 3 Kinds of light-sources 99 | 100 | * Emissive material: including the sky-box 101 | * Sphere light sources 102 | * Sunlight: round lights at infinite distance 103 | 104 | ### PathTracer 105 | 106 | The class "PathTracer" maintains a list of the geometries and path-traces them. 107 | 108 | 109 | ### Next 110 | 111 | As I've started [FeiRaysInline](https://github.com/fynv/feiraysinline), further exploration will happen there. 112 | -------------------------------------------------------------------------------- /PyFeiRays/api_scene.cpp: -------------------------------------------------------------------------------- 1 | #include "api.h" 2 | #include "Scene.h" 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | void* n_scene_create(int width, int height) 7 | { 8 | Scene* scene = new Scene(width, height); 9 | return scene; 10 | } 11 | 12 | void n_scene_destroy(void* cptr) 13 | { 14 | Scene* scene = (Scene*)cptr; 15 | delete scene; 16 | } 17 | 18 | int n_scene_width(void* cptr) 19 | { 20 | Scene* scene = (Scene*)cptr; 21 | return scene->image().width(); 22 | } 23 | 24 | int n_scene_height(void* cptr) 25 | { 26 | Scene* scene = (Scene*)cptr; 27 | return scene->image().height(); 28 | } 29 | 30 | void n_scene_get_image(void* cptr, float boost, void* data_out) 31 | { 32 | Scene* scene = (Scene*)cptr; 33 | const Image& image = scene->image(); 34 | int width = image.width(); 35 | int height = image.height(); 36 | image.to_host_srgb((unsigned char*)data_out, boost); 37 | } 38 | 39 | void n_scene_set_gradient_sky(void* ptr_scene, void* ptr_color0, void* ptr_color1) 40 | { 41 | Scene* scene = (Scene*)ptr_scene; 42 | glm::vec3* color0 = (glm::vec3*)ptr_color0; 43 | glm::vec3* color1 = (glm::vec3*)ptr_color1; 44 | scene->set_gradient_sky(*color0, *color1); 45 | } 46 | 47 | void n_scene_set_textured_sky(void* ptr_scene, const char* fn_tex, unsigned tex_srgb, float angle, void* ptr_vec) 48 | { 49 | Scene* scene = (Scene*)ptr_scene; 50 | if (ptr_vec != nullptr && angle != 0.0f) 51 | { 52 | float rad = angle / 180.0f * (float)M_PI; 53 | glm::vec3* v = (glm::vec3*)ptr_vec; 54 | scene->set_textured_sky(fn_tex, tex_srgb!=0, rad, *v); 55 | } 56 | else 57 | { 58 | scene->set_textured_sky(fn_tex, tex_srgb != 0); 59 | } 60 | } 61 | 62 | void n_scene_add_colored_sphere(void* ptr_scene, void* ptr_trans, int mat_type, void* ptr_mat_color, float mat_fuzz, float mat_ref_idx, float mat_density) 63 | { 64 | Scene* scene = (Scene*)ptr_scene; 65 | glm::mat4x4* trans = (glm::mat4x4*)ptr_trans; 66 | Material mat; 67 | mat.type = (MaterialType)mat_type; 68 | if (ptr_mat_color != nullptr) mat.color = *(glm::vec3*)ptr_mat_color; 69 | mat.fuzz = mat_fuzz; 70 | mat.ref_idx = mat_ref_idx; 71 | mat.density = mat_density; 72 | scene->add_colored_sphere(*trans, mat); 73 | } 74 | 75 | void n_scene_add_colored_cube(void* ptr_scene, void* ptr_trans, int mat_type, void* ptr_mat_color, float mat_fuzz, float mat_ref_idx, float mat_density) 76 | { 77 | Scene* scene = (Scene*)ptr_scene; 78 | glm::mat4x4* trans = (glm::mat4x4*)ptr_trans; 79 | Material mat; 80 | mat.type = (MaterialType)mat_type; 81 | if (ptr_mat_color != nullptr) mat.color = *(glm::vec3*)ptr_mat_color; 82 | mat.fuzz = mat_fuzz; 83 | mat.ref_idx = mat_ref_idx; 84 | mat.density = mat_density; 85 | scene->add_colored_cube(*trans, mat); 86 | } 87 | 88 | void n_scene_add_textured_sphere(void* ptr_scene, void* ptr_trans, const char* fn_tex, unsigned tex_srgb, void* ptr_color) 89 | { 90 | Scene* scene = (Scene*)ptr_scene; 91 | glm::mat4x4* trans = (glm::mat4x4*)ptr_trans; 92 | glm::vec3* color = (glm::vec3*)ptr_color; 93 | scene->add_textured_sphere(*trans, fn_tex, tex_srgb!=0, *color); 94 | } 95 | 96 | void n_scene_add_wavefront_object(void* ptr_scene, void* ptr_trans, const char* path, const char* fn) 97 | { 98 | Scene* scene = (Scene*)ptr_scene; 99 | glm::mat4x4* trans = (glm::mat4x4*)ptr_trans; 100 | scene->add_wavefront_object(*trans, path, fn); 101 | } 102 | 103 | void n_scene_add_sphere_light(void* ptr_scene, void* ptr_center, float radius, void* ptr_color) 104 | { 105 | Scene* scene = (Scene*)ptr_scene; 106 | glm::vec3* center = (glm::vec3*)ptr_center; 107 | glm::vec3* color = (glm::vec3*)ptr_color; 108 | scene->add_sphere_light(*center, radius, *color); 109 | } 110 | 111 | void n_scene_add_sunlight(void* ptr_scene, void* ptr_dir, float angle, void* ptr_color) 112 | { 113 | Scene* scene = (Scene*)ptr_scene; 114 | glm::vec3* dir = (glm::vec3*)ptr_dir; 115 | float rad = angle / 180.0f * (float)M_PI; 116 | glm::vec3* color = (glm::vec3*)ptr_color; 117 | scene->add_sunlight(*dir, rad, *color); 118 | } 119 | 120 | void n_scene_set_camera(void* ptr_scene, void* ptr_lookfrom, void* ptr_lookat, void* ptr_vup, float vfov, float aperture, float focus_dist) 121 | { 122 | Scene* scene = (Scene*)ptr_scene; 123 | glm::vec3* lookfrom = (glm::vec3*)ptr_lookfrom; 124 | glm::vec3* lookat = (glm::vec3*)ptr_lookat; 125 | glm::vec3* vup = (glm::vec3*)ptr_vup; 126 | scene->set_camera(*lookfrom, *lookat, *vup, vfov, aperture, focus_dist); 127 | } 128 | 129 | void n_scene_trace(void* ptr_scene, int num_iter, int interval) 130 | { 131 | Scene* scene = (Scene*)ptr_scene; 132 | scene->trace(num_iter, interval); 133 | } 134 | -------------------------------------------------------------------------------- /tests/test6.cpp: -------------------------------------------------------------------------------- 1 | #include "PathTracer.h" 2 | #include "ColoredIndexedTriangleList.h" 3 | #include "ColoredUnitSphere.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define STB_IMAGE_WRITE_IMPLEMENTATION 11 | #include "stb_image_write.h" 12 | 13 | #ifndef PI 14 | #define PI 3.1415926f 15 | #endif 16 | 17 | typedef ColoredIndexedTriangleList TriangleMesh; 18 | typedef ColoredUnitSphere Sphere; 19 | 20 | 21 | int main() 22 | { 23 | std::vector cube_vertices = 24 | { 25 | {{-1.0f, -1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 26 | {{-1.0f, -1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 27 | {{-1.0f, 1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 28 | {{-1.0f, 1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 29 | 30 | {{-1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f }}, 31 | {{1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 32 | {{1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 33 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 34 | 35 | {{1.0f, -1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 36 | {{1.0f, -1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 37 | {{1.0f, 1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 38 | {{1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 39 | 40 | {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 41 | {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 42 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 43 | {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 44 | 45 | {{1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 46 | {{1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 47 | {{-1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 48 | {{-1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 49 | 50 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 51 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 52 | {{1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 53 | {{1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 54 | }; 55 | 56 | std::vector cube_indices = 57 | { 58 | 0, 1, 2, 59 | 0, 2, 3, 60 | 61 | 4, 5, 6, 62 | 4, 6, 7, 63 | 64 | 8, 9, 10, 65 | 8, 10, 11, 66 | 67 | 12, 13, 14, 68 | 12, 14, 15, 69 | 70 | 16, 17, 18, 71 | 16, 18, 19, 72 | 73 | 20, 21, 22, 74 | 20, 22, 23 75 | }; 76 | 77 | const int view_width = 800; 78 | const int view_height = 400; 79 | 80 | glm::mat4x4 identity = glm::identity(); 81 | 82 | glm::mat4x4 model0 = glm::translate(identity, glm::vec3(0.0f, 1.0f, -2.0f)); 83 | model0 = glm::rotate(model0, 45.0f / 180.0f*PI, glm::vec3(0.0f, 1.0f, 0.0f)); 84 | TriangleMesh cube0(model0, cube_vertices, cube_indices, { lambertian, { 0.1f, 0.5f, 0.2f } }); 85 | 86 | glm::mat4x4 model1 = glm::translate(identity, glm::vec3(4.0f, 1.0f, -2.0f)); 87 | model1 = glm::rotate(model1, -45.0f / 180.0f*PI, glm::vec3(0.0f, 1.0f, 0.0f)); 88 | TriangleMesh cube1(model1, cube_vertices, cube_indices, { lambertian, { 0.1f, 0.2f, 0.5f } }); 89 | 90 | glm::mat4x4 model2 = glm::translate(identity, glm::vec3(-4.0, 1.0, -2.0)); 91 | model2 = glm::rotate(model2, -45.0f / 180.0f*PI, glm::vec3(0.0, 1.0, 0.0f)); 92 | TriangleMesh cube2(model2, cube_vertices, cube_indices, { lambertian, { 0.8f, 0.3f, 0.3f }}); 93 | 94 | glm::mat4x4 model3 = glm::translate(identity, glm::vec3(0.0, -0.2, 0.0)); 95 | model3 = glm::scale(model3, glm::vec3(6.0f, 0.2f, 6.0f)); 96 | TriangleMesh cube3(model3, cube_vertices, cube_indices, { lambertian, { 0.7, 0.7, 0.7 } }); 97 | 98 | glm::mat4x4 model4 = glm::translate(identity, glm::vec3(0.0, 1.0, 2.0)); 99 | Sphere sphere4(model4, { lambertian, { 0.1f, 0.2f, 0.5f } }); 100 | 101 | glm::mat4x4 model5 = glm::translate(identity, glm::vec3(4.0, 1.0, 2.0)); 102 | Sphere sphere5(model5, { lambertian, { 0.8f, 0.3f, 0.3f } }); 103 | 104 | glm::mat4x4 model6 = glm::translate(identity, glm::vec3(-4.0, 1.0, 2.0)); 105 | Sphere sphere6(model6, { lambertian, { 0.1f, 0.5f, 0.2f } }); 106 | 107 | Image target(view_width, view_height, nullptr); 108 | 109 | PathTracer pt; 110 | 111 | GradientSky sky({ 0.5f, 0.5f, 0.5f }, { 0.2f, 0.3f, 0.5f }); 112 | pt.set_sky(&sky); 113 | pt.add_sunlight({ 1.0f, 1.0f, 1.0f }, 0.05, { 100.0f, 100.0f, 100.0f }); 114 | 115 | pt.set_target(&target); 116 | pt.add_geometry(&cube0); 117 | pt.add_geometry(&cube1); 118 | pt.add_geometry(&cube2); 119 | pt.add_geometry(&cube3); 120 | pt.add_geometry(&sphere4); 121 | pt.add_geometry(&sphere5); 122 | pt.add_geometry(&sphere6); 123 | pt.set_camera({ 0.0f, 8.0f, 8.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f); 124 | 125 | pt.trace(100); 126 | 127 | unsigned char* hbuffer = (unsigned char*)malloc(view_width * view_height * 3); 128 | target.to_host_srgb(hbuffer); 129 | stbi_write_png("test6.png", view_width, view_height, 3, hbuffer, view_width * 3); 130 | free(hbuffer); 131 | 132 | system("pause"); 133 | 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /tests/test1.cpp: -------------------------------------------------------------------------------- 1 | #include "PathTracer.h" 2 | #include "ColoredIndexedTriangleList.h" 3 | #include "ColoredUnitSphere.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define STB_IMAGE_WRITE_IMPLEMENTATION 11 | #include "stb_image_write.h" 12 | 13 | #ifndef PI 14 | #define PI 3.1415926f 15 | #endif 16 | 17 | typedef ColoredIndexedTriangleList TriangleMesh; 18 | typedef ColoredUnitSphere Sphere; 19 | 20 | 21 | int main() 22 | { 23 | std::vector cube_vertices = 24 | { 25 | {{-1.0f, -1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 26 | {{-1.0f, -1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 27 | {{-1.0f, 1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 28 | {{-1.0f, 1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 29 | 30 | {{-1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f }}, 31 | {{1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 32 | {{1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 33 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 34 | 35 | {{1.0f, -1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 36 | {{1.0f, -1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 37 | {{1.0f, 1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 38 | {{1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 39 | 40 | {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 41 | {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 42 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 43 | {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 44 | 45 | {{1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 46 | {{1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 47 | {{-1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 48 | {{-1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 49 | 50 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 51 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 52 | {{1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 53 | {{1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 54 | }; 55 | 56 | std::vector cube_indices = 57 | { 58 | 0, 1, 2, 59 | 0, 2, 3, 60 | 61 | 4, 5, 6, 62 | 4, 6, 7, 63 | 64 | 8, 9, 10, 65 | 8, 10, 11, 66 | 67 | 12, 13, 14, 68 | 12, 14, 15, 69 | 70 | 16, 17, 18, 71 | 16, 18, 19, 72 | 73 | 20, 21, 22, 74 | 20, 22, 23 75 | }; 76 | 77 | const int view_width = 800; 78 | const int view_height = 400; 79 | 80 | glm::mat4x4 identity = glm::identity(); 81 | 82 | glm::mat4x4 model0 = glm::translate(identity, glm::vec3(0.0f, 1.0f, -2.0f)); 83 | model0 = glm::rotate(model0, 45.0f / 180.0f*PI, glm::vec3(0.0f, 1.0f, 0.0f)); 84 | TriangleMesh cube0(model0, cube_vertices, cube_indices, { metal, { 0.8f, 0.6f, 0.2f }, 0.3f }); 85 | 86 | glm::mat4x4 model1 = glm::translate(identity, glm::vec3(4.0f, 1.0f, -2.0f)); 87 | model1 = glm::rotate(model1, -45.0f / 180.0f*PI, glm::vec3(0.0f, 1.0f, 0.0f)); 88 | TriangleMesh cube1(model1, cube_vertices, cube_indices, { lambertian, { 0.1f, 0.2f, 0.5f } }); 89 | 90 | glm::mat4x4 model2 = glm::translate(identity, glm::vec3(-4.0, 1.0, -2.0)); 91 | model2 = glm::rotate(model2, -45.0f / 180.0f*PI, glm::vec3(0.0, 1.0, 0.0f)); 92 | TriangleMesh cube2(model2, cube_vertices, cube_indices, { dielectric, { 1.0f, 1.0f, 1.0f }, 0.0f, 1.5f }); 93 | 94 | glm::mat4x4 model3 = glm::translate(identity, glm::vec3(0.0, -0.2, 0.0)); 95 | model3 = glm::scale(model3, glm::vec3(6.0f, 0.2f, 6.0f)); 96 | TriangleMesh cube3(model3, cube_vertices, cube_indices, { lambertian, { 0.7, 0.7, 0.7 } }); 97 | 98 | glm::mat4x4 model4 = glm::translate(identity, glm::vec3(0.0, 1.0, 2.0)); 99 | Sphere sphere4(model4, { lambertian, { 0.1f, 0.2f, 0.5f } }); 100 | 101 | glm::mat4x4 model5 = glm::translate(identity, glm::vec3(4.0, 1.0, 2.0)); 102 | Sphere sphere5(model5, { dielectric, { 1.0f, 1.0f, 1.0f }, 0.0f, 1.5f }); 103 | 104 | glm::mat4x4 model6 = glm::translate(identity, glm::vec3(-4.0, 1.0, 2.0)); 105 | Sphere sphere6(model6, { metal, { 0.8f, 0.6f, 0.2f }, 0.3f }); 106 | 107 | glm::mat4x4 model7 = glm::translate(identity, glm::vec3(2.0, 1.0, 4.0)); 108 | Sphere sphere7(model7, { dielectric, { 0.5f, 1.0f, 0.7f }, 0.0f, 1.5f, 10.0f }); 109 | 110 | glm::mat4x4 model8 = glm::translate(identity, glm::vec3(-2.0, 1.0, 4.0)); 111 | Sphere sphere8(model8, { foggy, { 0.8f, 0.6f, 0.2f }, 0.0f, 1.0f, 1.0f }); 112 | 113 | Image target(view_width, view_height, nullptr); 114 | 115 | PathTracer pt; 116 | pt.set_target(&target); 117 | pt.add_geometry(&cube0); 118 | pt.add_geometry(&cube1); 119 | pt.add_geometry(&cube2); 120 | pt.add_geometry(&cube3); 121 | pt.add_geometry(&sphere4); 122 | pt.add_geometry(&sphere5); 123 | pt.add_geometry(&sphere6); 124 | pt.add_geometry(&sphere7); 125 | pt.add_geometry(&sphere8); 126 | pt.set_camera({ 0.0f, 8.0f, 8.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f); 127 | 128 | pt.trace(); 129 | 130 | unsigned char* hbuffer = (unsigned char*)malloc(view_width * view_height * 3); 131 | target.to_host_srgb(hbuffer); 132 | stbi_write_png("test1.png", view_width, view_height, 3, hbuffer, view_width * 3); 133 | free(hbuffer); 134 | 135 | system("pause"); 136 | 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /shaders/geometry/closesthit_wavefront_indexed_triangle_lists.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | #extension GL_EXT_nonuniform_qualifier : enable 7 | #extension GL_EXT_scalar_block_layout : enable 8 | 9 | #include "../common/payload.shinc" 10 | #include "../common/bindings.h" 11 | 12 | layout(location = 0) rayPayloadInEXT Payload payload; 13 | hitAttributeEXT vec2 attribs; 14 | 15 | layout(binding = 3) uniform sampler2D[] textureSamplers; 16 | 17 | struct Index 18 | { 19 | int normal_index; 20 | int texcoord_index; 21 | }; 22 | 23 | struct Material 24 | { 25 | vec3 diffuse; 26 | vec3 specular; 27 | vec3 emission; 28 | float shininess; 29 | int texId_diffuse; 30 | int texId_specular; 31 | int texId_emission; 32 | int texId_bumpmap; 33 | int texId_mask; 34 | int mask; 35 | }; 36 | 37 | struct Face 38 | { 39 | vec3 T; 40 | vec3 B; 41 | int materialIdx; 42 | }; 43 | 44 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer Vec3Buf 45 | { 46 | vec3 v; 47 | }; 48 | 49 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer Vec2Buf 50 | { 51 | vec2 v; 52 | }; 53 | 54 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer IndexBuf 55 | { 56 | Index i; 57 | }; 58 | 59 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer MaterialBuf 60 | { 61 | Material m; 62 | }; 63 | 64 | layout(buffer_reference, scalar, buffer_reference_align = 4) buffer FaceBuf 65 | { 66 | Face f; 67 | }; 68 | 69 | struct WavefrontIndexedTriangleList 70 | { 71 | mat3 normalMat; 72 | Vec3Buf normalBuf; 73 | Vec2Buf texcoordBuf; 74 | IndexBuf indexBuf; 75 | MaterialBuf materialBuf; 76 | FaceBuf faceBuf; 77 | }; 78 | 79 | layout(std430, binding = BINDING_WavefrontIndexedTriangleList) buffer Params 80 | { 81 | WavefrontIndexedTriangleList[] wavefrontIndexedTriangleList; 82 | }; 83 | 84 | 85 | void main() 86 | { 87 | payload.t = gl_HitTEXT; 88 | 89 | WavefrontIndexedTriangleList instance = wavefrontIndexedTriangleList[gl_InstanceCustomIndexEXT]; 90 | 91 | Index i0 = instance.indexBuf[3 * gl_PrimitiveID].i; 92 | Index i1 = instance.indexBuf[3 * gl_PrimitiveID + 1].i; 93 | Index i2 = instance.indexBuf[3 * gl_PrimitiveID + 2].i; 94 | 95 | Face face = instance.faceBuf[gl_PrimitiveID].f; 96 | Material mat = instance.materialBuf[face.materialIdx].m; 97 | 98 | const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y); 99 | 100 | vec2 texCoord; 101 | 102 | if (i0.texcoord_index>=0) 103 | { 104 | vec2 texCoord0 = instance.texcoordBuf[i0.texcoord_index].v; 105 | vec2 texCoord1 = instance.texcoordBuf[i1.texcoord_index].v; 106 | vec2 texCoord2 = instance.texcoordBuf[i2.texcoord_index].v; 107 | texCoord = texCoord0 * barycentrics.x + texCoord1 * barycentrics.y + texCoord2 * barycentrics.z; 108 | } 109 | 110 | if (mat.texId_mask >= 0) 111 | { 112 | float mask = texture(textureSamplers[mat.texId_mask], texCoord).x; 113 | if (mask<0.5) 114 | { 115 | payload.material_bits = 0; 116 | return; 117 | } 118 | } 119 | 120 | vec3 normal; 121 | { 122 | vec3 norm0 = instance.normalBuf[i0.normal_index].v; 123 | vec3 norm1 = instance.normalBuf[i1.normal_index].v; 124 | vec3 norm2 = instance.normalBuf[i2.normal_index].v; 125 | normal = norm0 * barycentrics.x + norm1 * barycentrics.y + norm2 * barycentrics.z; 126 | 127 | if (mat.texId_bumpmap >= 0) 128 | { 129 | normal = normalize(normal); 130 | vec3 bump = texture(textureSamplers[mat.texId_bumpmap], texCoord).xyz; 131 | bump = 2.0 * bump - 1.0; 132 | vec3 new_normal = bump.x*face.T + bump.y*face.B + bump.z*normal; 133 | if (dot(new_normal, normal)>0.0) normal = new_normal; 134 | } 135 | 136 | normal = normalize(instance.normalMat * normal); 137 | } 138 | 139 | payload.normal = normal; 140 | 141 | uint bits = MAT_OPAQUE_BIT | MAT_DIFFUSE_BIT; 142 | 143 | vec3 diffuse = mat.diffuse; 144 | if (mat.texId_diffuse >= 0) 145 | { 146 | diffuse *= texture(textureSamplers[mat.texId_diffuse], texCoord).xyz; 147 | } 148 | 149 | vec3 specular = mat.specular; 150 | float k = 0.0; 151 | if ( (mat.mask&2)!=0) 152 | { 153 | bits |= MAT_SPECULAR_BIT; 154 | if (mat.texId_specular >=0) 155 | { 156 | specular *= texture(textureSamplers[mat.texId_specular], texCoord).xyz; 157 | } 158 | 159 | float sum_s = specular.x + specular.y + specular.z; 160 | float sum_d = diffuse.x + diffuse.y + diffuse.z; 161 | k = sum_s / (sum_s + sum_d); 162 | } 163 | 164 | vec3 emission = mat.emission; 165 | if ((mat.mask&4)!=0) 166 | { 167 | bits |= MAT_EMIT_BIT; 168 | if (mat.texId_emission >=0) 169 | { 170 | emission *= texture(textureSamplers[mat.texId_emission], texCoord).xyz; 171 | } 172 | } 173 | 174 | payload.material_bits = bits; 175 | 176 | payload.color0 = emission; 177 | payload.color1 = diffuse; 178 | payload.color2 = specular; 179 | payload.f0 = k; 180 | payload.f1 = 1.0 / mat.shininess; 181 | 182 | } 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /WavefrontIndexedTriangleList.cpp: -------------------------------------------------------------------------------- 1 | #include "context.h" 2 | #include "WavefrontIndexedTriangleList.h" 3 | #include "shaders/common/bindings.h" 4 | 5 | WavefrontIndexedTriangleList::WavefrontIndexedTriangleList(const glm::mat4x4& model, 6 | const std::vector& positions, 7 | const std::vector& normals, 8 | const std::vector& texcoords, 9 | const std::vector& indices, 10 | std::vector& materials, const int* materialIdx) : Geometry(model) 11 | { 12 | m_normalBuffer = new DeviceBuffer(sizeof(glm::vec3)* normals.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 13 | m_normalBuffer->upload(normals.data()); 14 | m_texcoordBuffer = new DeviceBuffer(sizeof(glm::vec2)* texcoords.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 15 | m_texcoordBuffer->upload(texcoords.data()); 16 | 17 | struct Index2 18 | { 19 | int normal_index; 20 | int texcoord_index; 21 | }; 22 | 23 | std::vector indices2(indices.size()); 24 | for (size_t i = 0; i < indices.size(); i++) 25 | { 26 | indices2[i].normal_index = indices[i].normal_index; 27 | indices2[i].texcoord_index = indices[i].texcoord_index; 28 | } 29 | 30 | m_indexBuffer = new DeviceBuffer(sizeof(Index2)* indices.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 31 | m_indexBuffer->upload(indices2.data()); 32 | m_materialBuffer = new DeviceBuffer(sizeof(Material)* materials.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 33 | m_materialBuffer->upload(materials.data()); 34 | 35 | struct Face 36 | { 37 | glm::vec3 T; 38 | glm::vec3 B; 39 | int materialIdx; 40 | }; 41 | 42 | std::vector faces(indices.size() / 3); 43 | 44 | for (size_t i = 0; i < indices.size() / 3; i++) 45 | { 46 | faces[i].materialIdx = materialIdx[i]; 47 | 48 | Index i0 = indices[i * 3]; 49 | Index i1 = indices[i * 3 + 1]; 50 | Index i2 = indices[i * 3 + 2]; 51 | 52 | if (i0.texcoord_index >= 0) 53 | { 54 | glm::vec3 v0 = positions[i0.vertex_index]; 55 | glm::vec3 v1 = positions[i1.vertex_index]; 56 | glm::vec3 v2 = positions[i2.vertex_index]; 57 | glm::vec2 texCoord0 = texcoords[i0.texcoord_index]; 58 | glm::vec2 texCoord1 = texcoords[i1.texcoord_index]; 59 | glm::vec2 texCoord2 = texcoords[i2.texcoord_index]; 60 | 61 | glm::vec3 edge1 = v1 - v0; 62 | glm::vec3 edge2 = v2 - v0; 63 | glm::vec2 delta1 = texCoord1 - texCoord0; 64 | glm::vec2 delta2 = texCoord2 - texCoord0; 65 | 66 | float f = 1.0f / (delta1[0] * delta2[1] - delta2[0] * delta1[1]); 67 | faces[i].T = glm::normalize((f*delta2[1]) * edge1 - (f*delta1[1])*edge2); 68 | faces[i].B = glm::normalize((-f * delta2[0]) * edge1 + (f*delta1[0])*edge2); 69 | } 70 | } 71 | 72 | m_faceBuffer = new DeviceBuffer(sizeof(Face)* indices.size() / 3, VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 73 | m_faceBuffer->upload(faces.data()); 74 | 75 | std::vector pos_indices(indices.size()); 76 | for (size_t i = 0; i < indices.size(); i++) 77 | pos_indices[i] = indices[i].vertex_index; 78 | 79 | DeviceBuffer posBuf(sizeof(glm::vec3)* positions.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 80 | posBuf.upload(positions.data()); 81 | 82 | DeviceBuffer pos_index_buffer(sizeof(unsigned)* indices.size(), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR); 83 | pos_index_buffer.upload(pos_indices.data()); 84 | 85 | _blas_create_indexed_triangles(&posBuf, &pos_index_buffer); 86 | } 87 | 88 | WavefrontIndexedTriangleList::~WavefrontIndexedTriangleList() 89 | { 90 | delete m_faceBuffer; 91 | delete m_materialBuffer; 92 | delete m_indexBuffer; 93 | delete m_texcoordBuffer; 94 | delete m_normalBuffer; 95 | } 96 | 97 | 98 | struct TriangleMeshView 99 | { 100 | glm::mat3x4 normalMat; 101 | VkDeviceAddress normalBuf; 102 | VkDeviceAddress texcoordBuf; 103 | VkDeviceAddress indexBuf; 104 | VkDeviceAddress materialBuf; 105 | VkDeviceAddress faceBuf; 106 | }; 107 | 108 | 109 | GeoCls WavefrontIndexedTriangleList::cls() const 110 | { 111 | static const char s_name[] = "WavefrontIndexedTriangleList"; 112 | static const char s_fn_rchit[] = "geometry/closesthit_wavefront_indexed_triangle_lists.spv"; 113 | GeoCls cls = {}; 114 | cls.name = s_name; 115 | cls.size_view = sizeof(TriangleMeshView); 116 | cls.binding_view = BINDING_WavefrontIndexedTriangleList; 117 | cls.fn_intersection = nullptr; 118 | cls.fn_closesthit = s_fn_rchit; 119 | return cls; 120 | } 121 | 122 | void WavefrontIndexedTriangleList::get_view(void* view_buf) const 123 | { 124 | TriangleMeshView& view = *(TriangleMeshView*)view_buf; 125 | view.normalMat = m_norm_mat; 126 | view.normalBuf = m_normalBuffer->get_device_address(); 127 | view.texcoordBuf = m_texcoordBuffer->get_device_address(); 128 | view.indexBuf = m_indexBuffer->get_device_address(); 129 | view.materialBuf = m_materialBuffer->get_device_address(); 130 | view.faceBuf = m_faceBuffer->get_device_address(); 131 | } 132 | -------------------------------------------------------------------------------- /tests/test5.cpp: -------------------------------------------------------------------------------- 1 | #include "PathTracer.h" 2 | #include "ColoredIndexedTriangleList.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define STB_IMAGE_IMPLEMENTATION 13 | #include "stb_image.h" 14 | 15 | #define STB_IMAGE_WRITE_IMPLEMENTATION 16 | #include "stb_image_write.h" 17 | 18 | #ifndef PI 19 | #define PI 3.1415926f 20 | #endif 21 | 22 | 23 | int main() 24 | { 25 | std::vector cube_vertices = 26 | { 27 | {{-1.0f, -1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 28 | {{-1.0f, -1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 29 | {{-1.0f, 1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 30 | {{-1.0f, 1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 31 | 32 | {{-1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f }}, 33 | {{1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 34 | {{1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 35 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 36 | 37 | {{1.0f, -1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 38 | {{1.0f, -1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 39 | {{1.0f, 1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 40 | {{1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 41 | 42 | {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 43 | {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 44 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 45 | {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 46 | 47 | {{1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 48 | {{1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 49 | {{-1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 50 | {{-1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 51 | 52 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 53 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 54 | {{1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 55 | {{1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 56 | }; 57 | 58 | std::vector cube_indices = 59 | { 60 | 0, 1, 2, 61 | 0, 2, 3, 62 | 63 | 4, 5, 6, 64 | 4, 6, 7, 65 | 66 | 8, 9, 10, 67 | 8, 10, 11, 68 | 69 | 12, 13, 14, 70 | 12, 14, 15, 71 | 72 | 16, 17, 18, 73 | 16, 18, 19, 74 | 75 | 20, 21, 22, 76 | 20, 22, 23 77 | }; 78 | 79 | const int view_width = 800; 80 | const int view_height = 800; 81 | 82 | Image target(view_width, view_height, nullptr); 83 | 84 | PathTracer pt; 85 | pt.set_target(&target); 86 | 87 | GradientSky sky({ 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }); 88 | pt.set_sky(&sky); 89 | 90 | glm::mat4x4 identity = glm::identity(); 91 | 92 | glm::mat4x4 model0 = glm::translate(identity, glm::vec3(1110.01f, 555.0f, 555.0f)); 93 | model0 = glm::scale(model0, glm::vec3(0.01f, 555.0f, 555.0f)); 94 | ColoredIndexedTriangleList cube0(model0, cube_vertices, cube_indices, { lambertian, { 0.12, 0.45f, 0.15f } }); 95 | pt.add_geometry(&cube0); 96 | 97 | glm::mat4x4 model1 = glm::translate(identity, glm::vec3(-0.01f, 555.0f, 555.0f)); 98 | model1 = glm::scale(model1, glm::vec3(0.01f, 555.0f, 555.0f)); 99 | ColoredIndexedTriangleList cube1(model1, cube_vertices, cube_indices, { lambertian, { 0.65, 0.05f, 0.05f } }); 100 | pt.add_geometry(&cube1); 101 | 102 | glm::mat4x4 model2 = glm::translate(identity, glm::vec3(555.0f, 1108.0f, 555.0f)); 103 | model2 = glm::scale(model2, glm::vec3(130.0f, 0.01f, 105.0f)); 104 | ColoredIndexedTriangleList cube2(model2, cube_vertices, cube_indices, { emissive, { 15.0f, 15.0f, 15.0f } }); 105 | pt.add_geometry(&cube2); 106 | 107 | glm::mat4x4 model3 = glm::translate(identity, glm::vec3(555.0f, 1110.01f, 555.0f)); 108 | model3 = glm::scale(model3, glm::vec3(550.0f, 0.01f, 555.0f)); 109 | ColoredIndexedTriangleList cube3(model3, cube_vertices, cube_indices, { lambertian, { 0.73f, 0.73f, 0.73f } }); 110 | pt.add_geometry(&cube3); 111 | 112 | glm::mat4x4 model4 = glm::translate(identity, glm::vec3(555.0f, -0.01f, 555.0f)); 113 | model4 = glm::scale(model4, glm::vec3(550.0f, 0.01f, 555.0f)); 114 | ColoredIndexedTriangleList cube4(model4, cube_vertices, cube_indices, { lambertian, { 0.73f, 0.73f, 0.73f } }); 115 | pt.add_geometry(&cube4); 116 | 117 | glm::mat4x4 model5 = glm::translate(identity, glm::vec3(555.0f, 555.0f, 1110.01f)); 118 | model5 = glm::scale(model5, glm::vec3(550.0f, 555.0f, 0.01f)); 119 | ColoredIndexedTriangleList cube5(model5, cube_vertices, cube_indices, { lambertian, { 0.73f, 0.73f, 0.73f } }); 120 | pt.add_geometry(&cube5); 121 | 122 | glm::mat4x4 model6 = glm::translate(identity, glm::vec3(425.0f, 165.0f, 295.0f)); 123 | model6 = glm::scale(model6, glm::vec3(165.0f, 165.0f, 165.0f)); 124 | model6 = glm::rotate(model6, -18.0f/180.0f*PI, { 0.0f, 1.0f, 0.0f }); 125 | ColoredIndexedTriangleList cube6(model6, cube_vertices, cube_indices, { lambertian, { 0.73f, 0.73f, 0.73f } }); 126 | pt.add_geometry(&cube6); 127 | 128 | glm::mat4x4 model7 = glm::translate(identity, glm::vec3(695.0f, 330.0f, 755.0f)); 129 | model7 = glm::scale(model7, glm::vec3(165.0f, 330.0f, 165.0f)); 130 | model7 = glm::rotate(model7, 15.0f / 180.0f*PI, { 0.0f, 1.0f, 0.0f }); 131 | ColoredIndexedTriangleList cube7(model7, cube_vertices, cube_indices, { lambertian, { 0.73f, 0.73f, 0.73f } }); 132 | pt.add_geometry(&cube7); 133 | 134 | pt.set_camera({ 556.0f, 556.0f, -1600.0f }, { 556.0f, 556.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 40.0f); 135 | 136 | pt.trace(100); 137 | 138 | unsigned char* hbuffer = (unsigned char*)malloc(view_width * view_height * 3); 139 | target.to_host_srgb(hbuffer); 140 | stbi_write_png("test5.png", view_width, view_height, 3, hbuffer, view_width * 3); 141 | free(hbuffer); 142 | 143 | system("pause"); 144 | 145 | return 0; 146 | 147 | } 148 | -------------------------------------------------------------------------------- /PathTracer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class BaseLevelAS; 9 | class DeviceBuffer; 10 | class Texture; 11 | class Cubemap; 12 | class Sampler; 13 | 14 | 15 | struct GeoCls 16 | { 17 | std::string name; 18 | size_t size_view; 19 | uint32_t binding_view; 20 | const char* fn_intersection = nullptr; 21 | const char* fn_closesthit = nullptr; 22 | }; 23 | 24 | 25 | class Geometry 26 | { 27 | public: 28 | const glm::mat4x4& model() const { return m_model; } 29 | const glm::mat4x4& norm() const { return m_norm_mat; } 30 | const BaseLevelAS& get_blas() const { return *m_blas; } 31 | 32 | Geometry(const glm::mat4x4& model); 33 | virtual ~Geometry(); 34 | 35 | virtual GeoCls cls() const = 0; 36 | virtual void get_view(void* view_buf) const = 0; 37 | 38 | protected: 39 | void _blas_create_procedure(DeviceBuffer* aabb_buf); 40 | void _blas_create_indexed_triangles(DeviceBuffer* positionBuffer, DeviceBuffer* indexBuffer); 41 | 42 | glm::mat4x4 m_model; 43 | glm::mat4x4 m_norm_mat; 44 | BaseLevelAS* m_blas; 45 | }; 46 | 47 | 48 | class SphereLight : public Geometry 49 | { 50 | public: 51 | const glm::vec3& center() const { return m_center; } 52 | float radius() const { return m_radius; } 53 | const glm::vec3& color() const { return m_color; } 54 | 55 | SphereLight(const glm::vec3& center, float r, const glm::vec3& color); 56 | virtual ~SphereLight(); 57 | 58 | virtual GeoCls cls() const; 59 | virtual void get_view(void* view_buf) const; 60 | 61 | private: 62 | glm::vec3 m_center; 63 | float m_radius; 64 | glm::vec3 m_color; 65 | }; 66 | 67 | 68 | struct SkyCls 69 | { 70 | size_t size_view; 71 | const char* fn_missing = nullptr; 72 | }; 73 | 74 | class Sky 75 | { 76 | public: 77 | Sky() {} 78 | virtual ~Sky() {} 79 | 80 | virtual SkyCls cls() const = 0; 81 | virtual void get_view(void* view_buf) const = 0; 82 | }; 83 | 84 | class GradientSky : public Sky 85 | { 86 | public: 87 | GradientSky(const glm::vec3& color0 = { 1.0f, 1.0f, 1.0f }, const glm::vec3& color1 = { 0.5f, 0.7f, 1.0f }); 88 | virtual ~GradientSky(); 89 | 90 | virtual SkyCls cls() const; 91 | virtual void get_view(void* view_buf) const; 92 | 93 | private: 94 | glm::vec3 m_color0; 95 | glm::vec3 m_color1; 96 | }; 97 | 98 | 99 | class RGBATexture 100 | { 101 | public: 102 | Texture* data() const { return m_data; } 103 | 104 | RGBATexture(int width, int height, void* data, bool srgb = true); 105 | ~RGBATexture(); 106 | 107 | private: 108 | Texture *m_data; 109 | }; 110 | 111 | class RGBACubemap 112 | { 113 | public: 114 | Cubemap* data() const { return m_data; } 115 | 116 | RGBACubemap(int width, int height, void* data, bool srgb = true); 117 | ~RGBACubemap(); 118 | 119 | private: 120 | Cubemap* m_data; 121 | }; 122 | 123 | class TexturedSkyBox : public Sky 124 | { 125 | public: 126 | TexturedSkyBox(int texId); 127 | virtual ~TexturedSkyBox(); 128 | 129 | virtual SkyCls cls() const; 130 | virtual void get_view(void* view_buf) const; 131 | 132 | void rotate(float angle, const glm::vec3& v); 133 | 134 | private: 135 | int m_texId; 136 | glm::mat4x4 m_transform; 137 | }; 138 | 139 | class Image 140 | { 141 | public: 142 | DeviceBuffer* data() const { return m_data; } 143 | DeviceBuffer* rng_states(); 144 | int width() const { return m_width; } 145 | int height() const { return m_height; } 146 | int batch_size() const { return m_batch_size; } 147 | 148 | Image(int width, int height, float* hdata = nullptr, int batch_size = 1 << 18); 149 | ~Image(); 150 | 151 | void clear(); 152 | 153 | // f32_vec4 - linear 154 | void to_host_raw(float *hdata) const; 155 | 156 | // u8_vec3 - srgb 157 | void to_host_srgb(unsigned char* hdata, float boost = 1.0f) const; 158 | 159 | 160 | 161 | private: 162 | DeviceBuffer* m_data; 163 | DeviceBuffer* m_rng_states; 164 | int m_width; 165 | int m_height; 166 | int m_batch_size; 167 | 168 | }; 169 | 170 | 171 | struct GeoList 172 | { 173 | GeoCls cls; 174 | std::vector list; 175 | }; 176 | 177 | struct RayTrace; 178 | 179 | class PathTracer 180 | { 181 | public: 182 | PathTracer(); 183 | ~PathTracer(); 184 | 185 | void set_target(Image* target) { m_target = target; } 186 | void set_sky(Sky* sky); 187 | void add_geometry(Geometry* geo); 188 | void add_sunlight(glm::vec3 direction, float radian, glm::vec3 color); 189 | int add_texture(RGBATexture* tex); 190 | int add_cubemap(RGBACubemap* tex); 191 | void set_camera(glm::vec3 lookfrom, glm::vec3 lookat, glm::vec3 vup, float vfov, float aperture = 0.0f, float focus_dist = 1.0f); 192 | 193 | void trace(int num_iter = 100, int interval = -1) const; 194 | 195 | private: 196 | Image* m_target; 197 | std::unordered_map m_geo_lists; 198 | std::vector m_textures; 199 | std::vector m_cubemaps; 200 | Sampler* m_Sampler; 201 | GradientSky* m_default_sky; 202 | Sky* m_current_sky; 203 | 204 | // camera 205 | glm::vec3 m_lookfrom; 206 | glm::vec3 m_lookat; 207 | glm::vec3 m_vup; 208 | float m_vfov; 209 | float m_aperture; 210 | float m_focus_dist; 211 | 212 | void _tlas_create(RayTrace& rt) const; 213 | void _args_create(RayTrace& rt) const; 214 | void _rt_pipeline_create(RayTrace& rt) const; 215 | void _comp_pipeline_create(RayTrace& rt) const; 216 | void _calc_raygen(RayTrace& rt) const; 217 | void _calc_light_source_dist(RayTrace& rt) const; 218 | 219 | void _rt_clean(RayTrace& rt) const; 220 | 221 | struct Sunlight 222 | { 223 | glm::vec4 dir_radian; 224 | glm::vec4 color; 225 | }; 226 | std::vector m_sunlights; 227 | 228 | }; 229 | -------------------------------------------------------------------------------- /tests/wavefront_obj.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define TINYOBJLOADER_IMPLEMENTATION 11 | #include "tiny_obj_loader.h" 12 | 13 | #include "PathTracer.h" 14 | #include "WavefrontIndexedTriangleList.h" 15 | 16 | #include "wavefront_obj.h" 17 | 18 | WavefrontObject::WavefrontObject(PathTracer& pt, const char* path, const char* fn, const glm::mat4x4& model) 19 | : m_tex_map(&pt, path) 20 | { 21 | std::string fn_obj = path; 22 | fn_obj += "/"; 23 | fn_obj += fn; 24 | 25 | tinyobj::attrib_t attrib; 26 | std::vector shapes; 27 | std::vector materials; 28 | std::string err; 29 | 30 | tinyobj::LoadObj(&attrib, &shapes, &materials, &err, fn_obj.c_str(), path); 31 | 32 | std::vector materials_in(materials.size()); 33 | 34 | for (size_t i = 0; i < materials.size(); i++) 35 | { 36 | materials_in[i].diffuse = glm::vec3(materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]); 37 | materials_in[i].specular = glm::vec3(materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]); 38 | materials_in[i].emission = glm::vec3(materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]); 39 | materials_in[i].shininess = materials[i].shininess; 40 | 41 | if (!materials[i].diffuse_texname.empty()) 42 | materials_in[i].texId_diffuse = m_tex_map.findTex(materials[i].diffuse_texname.c_str()); 43 | else 44 | materials_in[i].texId_diffuse = -1; 45 | 46 | if (!materials[i].specular_texname.empty()) 47 | materials_in[i].texId_specular = m_tex_map.findTex(materials[i].specular_texname.c_str()); 48 | else 49 | materials_in[i].texId_specular = -1; 50 | 51 | if (!materials[i].emissive_texname.empty()) 52 | materials_in[i].texId_emission = m_tex_map.findTex(materials[i].emissive_texname.c_str()); 53 | else 54 | materials_in[i].texId_emission = -1; 55 | 56 | if (!materials[i].bump_texname.empty()) 57 | materials_in[i].texId_bumpmap = m_tex_map.findTex(materials[i].bump_texname.c_str(), false); 58 | else 59 | materials_in[i].texId_bumpmap = -1; 60 | 61 | if (!materials[i].alpha_texname.empty()) 62 | materials_in[i].texId_mask = m_tex_map.findTex(materials[i].alpha_texname.c_str(), false); 63 | else 64 | materials_in[i].texId_mask = -1; 65 | 66 | int mask = 0; 67 | if (materials[i].diffuse[0] > 0.0f || materials[i].diffuse[1] > 0.0f || materials[i].diffuse[2] > 0.0f) 68 | { 69 | mask |= 1; 70 | } 71 | else if (materials_in[i].texId_diffuse >= 0) 72 | { 73 | materials_in[i].diffuse = glm::vec3(1.0f, 1.0f, 1.0f); 74 | mask |= 1; 75 | } 76 | if (materials[i].specular[0] > 0.0f || materials[i].specular[1] > 0.0f || materials[i].specular[2] > 0.0f) mask |= 2; 77 | if (materials[i].emission[0] > 0.0f || materials[i].emission[1] > 0.0f || materials[i].emission[2] > 0.0f) mask |= 4; 78 | materials_in[i].mask = mask; 79 | } 80 | 81 | std::vector positions(attrib.vertices.size()/3); 82 | for (size_t i = 0; i < positions.size(); i++) 83 | { 84 | float* vp = &attrib.vertices[3 * i]; 85 | positions[i] = glm::vec3(vp[0], vp[1], vp[2]); 86 | } 87 | 88 | std::vector normals; 89 | bool need_calc_normals = false; 90 | 91 | if (attrib.normals.size() > 0) 92 | { 93 | normals.resize(attrib.normals.size() / 3); 94 | for (size_t i = 0; i < normals.size(); i++) 95 | { 96 | float* np = &attrib.normals[3 * i]; 97 | normals[i] = glm::vec3(np[0], np[1], np[2]); 98 | } 99 | } 100 | else 101 | { 102 | normals.resize(positions.size()); 103 | memset(normals.data(), 0, sizeof(glm::vec3)*positions.size()); 104 | need_calc_normals = true; 105 | } 106 | 107 | std::vector tex_coords(attrib.texcoords.size() / 2); 108 | for (size_t i = 0; i < tex_coords.size(); i++) 109 | { 110 | float* tp = &attrib.texcoords[2 * i]; 111 | tex_coords[i] = glm::vec2(tp[0], 1.0f - tp[1]); 112 | } 113 | 114 | std::vector indices; 115 | std::vector materials_ids; 116 | 117 | for (size_t i = 0; i < shapes.size(); i++) 118 | { 119 | tinyobj::shape_t& shape = shapes[i]; 120 | 121 | for (size_t j = 0; j < shape.mesh.indices.size(); j++) 122 | { 123 | tinyobj::index_t& t_index = shape.mesh.indices[j]; 124 | WavefrontIndexedTriangleList::Index index; 125 | index.vertex_index = t_index.vertex_index; 126 | index.normal_index = need_calc_normals? t_index.vertex_index : t_index.normal_index; 127 | index.texcoord_index = t_index.texcoord_index; 128 | indices.push_back(index); 129 | } 130 | 131 | if (need_calc_normals) 132 | { 133 | for (size_t j = 0; j < shape.mesh.indices.size() / 3; j++) 134 | { 135 | unsigned i0 = shape.mesh.indices[j * 3].vertex_index; 136 | unsigned i1 = shape.mesh.indices[j * 3 + 1].vertex_index; 137 | unsigned i2 = shape.mesh.indices[j * 3 + 2].vertex_index; 138 | 139 | glm::vec3 v0 = positions[i0]; 140 | glm::vec3 v1 = positions[i1]; 141 | glm::vec3 v2 = positions[i2]; 142 | 143 | glm::vec3 face_normal = glm::normalize(glm::cross(v1 - v0, v2 - v0)); 144 | 145 | normals[i0] += face_normal; 146 | normals[i1] += face_normal; 147 | normals[i2] += face_normal; 148 | } 149 | } 150 | 151 | for (size_t j = 0; j < shape.mesh.material_ids.size(); j++) 152 | materials_ids.push_back(shape.mesh.material_ids[j]); 153 | } 154 | 155 | if (need_calc_normals) 156 | { 157 | for (size_t i = 0; i < normals.size(); i++) 158 | { 159 | normals[i] = glm::normalize(normals[i]); 160 | } 161 | } 162 | 163 | m_witl = new WavefrontIndexedTriangleList(model, positions, normals, tex_coords, indices, materials_in, materials_ids.data()); 164 | } 165 | 166 | WavefrontObject::~WavefrontObject() 167 | { 168 | delete m_witl; 169 | } -------------------------------------------------------------------------------- /RNGInitializer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "RNGInitializer.h" 4 | #include "xor_wow_data.hpp" 5 | #include "RNGState_xorwow.h" 6 | 7 | const RNGInitializer& RNGInitializer::get_initializer() 8 | { 9 | static RNGInitializer initializer; 10 | return initializer; 11 | } 12 | 13 | 14 | RNGInitializer::RNGInitializer() 15 | { 16 | m_seq_mat = new DeviceBuffer(sizeof(xorwow_sequence_matrix), VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); 17 | m_seq_mat->upload(xorwow_sequence_matrix); 18 | 19 | const Context& ctx = Context::get_context(); 20 | 21 | { 22 | VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[2]; 23 | descriptorSetLayoutBindings[0] = {}; 24 | descriptorSetLayoutBindings[0].binding = 0; 25 | descriptorSetLayoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 26 | descriptorSetLayoutBindings[0].descriptorCount = 1; 27 | descriptorSetLayoutBindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 28 | descriptorSetLayoutBindings[1] = {}; 29 | descriptorSetLayoutBindings[1].binding = 1; 30 | descriptorSetLayoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 31 | descriptorSetLayoutBindings[1].descriptorCount = 1; 32 | descriptorSetLayoutBindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; 33 | 34 | VkDescriptorSetLayoutCreateInfo layoutInfo = {}; 35 | layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 36 | layoutInfo.bindingCount = 2; 37 | layoutInfo.pBindings = descriptorSetLayoutBindings; 38 | 39 | vkCreateDescriptorSetLayout(ctx.device(), &layoutInfo, nullptr, &m_descriptorSetLayout); 40 | 41 | } 42 | { 43 | VkShaderModule compModule = ctx.get_shader("common/rand_init.spv"); 44 | 45 | VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; 46 | pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 47 | pipelineLayoutInfo.setLayoutCount = 1; 48 | pipelineLayoutInfo.pSetLayouts = &m_descriptorSetLayout; 49 | 50 | vkCreatePipelineLayout(ctx.device(), &pipelineLayoutInfo, nullptr, &m_pipelineLayout); 51 | 52 | VkPipelineShaderStageCreateInfo computeShaderStageInfo = {}; 53 | computeShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 54 | computeShaderStageInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; 55 | computeShaderStageInfo.module = compModule; 56 | computeShaderStageInfo.pName = "main"; 57 | 58 | VkComputePipelineCreateInfo pipelineInfo = {}; 59 | pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; 60 | pipelineInfo.stage = computeShaderStageInfo; 61 | pipelineInfo.layout = m_pipelineLayout; 62 | 63 | vkCreateComputePipelines(ctx.device(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_pipeline); 64 | } 65 | 66 | m_ubo = new DeviceBuffer(sizeof(UBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); 67 | 68 | { 69 | VkDescriptorPoolSize poolSizes[2]; 70 | poolSizes[0].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 71 | poolSizes[0].descriptorCount = 1; 72 | poolSizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 73 | poolSizes[1].descriptorCount = 1; 74 | 75 | VkDescriptorPoolCreateInfo poolInfo = {}; 76 | poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; 77 | poolInfo.poolSizeCount = 2; 78 | poolInfo.pPoolSizes = poolSizes; 79 | poolInfo.maxSets = 1; 80 | vkCreateDescriptorPool(ctx.device(), &poolInfo, nullptr, &m_descriptorPool); 81 | } 82 | 83 | { 84 | VkDescriptorSetAllocateInfo allocInfo = {}; 85 | allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; 86 | allocInfo.descriptorPool = m_descriptorPool; 87 | allocInfo.descriptorSetCount = 1; 88 | allocInfo.pSetLayouts = &m_descriptorSetLayout; 89 | vkAllocateDescriptorSets(ctx.device(), &allocInfo, &m_descriptorSet); 90 | } 91 | } 92 | 93 | RNGInitializer::~RNGInitializer() 94 | { 95 | /* 96 | delete m_ubo; 97 | const Context& ctx = Context::get_context(); 98 | vkDestroyPipeline(ctx.device(), m_pipeline, nullptr); 99 | vkDestroyPipelineLayout(ctx.device(), m_pipelineLayout, nullptr); 100 | vkDestroyDescriptorPool(ctx.device(), m_descriptorPool, nullptr); 101 | vkDestroyDescriptorSetLayout(ctx.device(), m_descriptorSetLayout, nullptr); 102 | delete m_seq_mat;*/ 103 | } 104 | 105 | void RNGInitializer::InitRNGs(DeviceBuffer* rng_states) const 106 | { 107 | const Context& ctx = Context::get_context(); 108 | 109 | size_t count = rng_states->size() / sizeof(RNGState); 110 | UBO ubo_data; 111 | ubo_data.d_sequence_matrix = m_seq_mat->get_device_address(); 112 | ubo_data.count = (int)count; 113 | m_ubo->upload(&ubo_data); 114 | 115 | VkDescriptorBufferInfo ssboInfo = {}; 116 | ssboInfo.buffer = rng_states->buf(); 117 | ssboInfo.range = VK_WHOLE_SIZE; 118 | 119 | VkDescriptorBufferInfo uboInfo = {}; 120 | uboInfo.buffer = m_ubo->buf(); 121 | uboInfo.range = VK_WHOLE_SIZE; 122 | 123 | VkWriteDescriptorSet descriptorWrites[2]; 124 | descriptorWrites[0] = {}; 125 | descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 126 | descriptorWrites[0].dstSet = m_descriptorSet; 127 | descriptorWrites[0].dstBinding = 0; 128 | descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 129 | descriptorWrites[0].descriptorCount = 1; 130 | descriptorWrites[0].pBufferInfo = &ssboInfo; 131 | 132 | descriptorWrites[1] = {}; 133 | descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 134 | descriptorWrites[1].dstSet = m_descriptorSet; 135 | descriptorWrites[1].dstBinding = 1; 136 | descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 137 | descriptorWrites[1].descriptorCount = 1; 138 | descriptorWrites[1].pBufferInfo = &uboInfo; 139 | 140 | vkUpdateDescriptorSets(ctx.device(), 2, descriptorWrites, 0, nullptr); 141 | 142 | { 143 | NTimeCommandBuffer cmdBuf; 144 | vkCmdBindPipeline(cmdBuf.buf(), VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline); 145 | vkCmdBindDescriptorSets(cmdBuf.buf(), VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, 0, 1, &m_descriptorSet, 0, 0); 146 | vkCmdDispatch(cmdBuf.buf(), (unsigned)((count + 127) / 128), 1, 1); 147 | } 148 | 149 | } 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /context.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "volk.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class Context 10 | { 11 | public: 12 | static const Context& get_context(); 13 | 14 | const VkInstance& instance() const { return m_instance; } 15 | const VkPhysicalDevice& physicalDevice() const { return m_physicalDevice; } 16 | const VkPhysicalDeviceRayTracingPipelinePropertiesKHR& raytracing_properties() const { return m_rayTracingPipelineProperties; } 17 | const VkDevice& device() const { return m_device; } 18 | const VkQueue& queue() const { return m_graphicsQueue; } 19 | const VkCommandPool& commandPool() const { return m_commandPool_graphics; } 20 | 21 | VkShaderModule get_shader(const char* name) const; 22 | private: 23 | VkDebugUtilsMessengerEXT m_debugMessenger = VK_NULL_HANDLE; 24 | VkInstance m_instance = VK_NULL_HANDLE; 25 | VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE; 26 | 27 | VkPhysicalDeviceBufferDeviceAddressFeatures m_bufferDeviceAddressFeatures{}; 28 | VkPhysicalDeviceDescriptorIndexingFeatures m_descriptorIndexingFeatures{}; 29 | 30 | VkPhysicalDeviceRayTracingPipelineFeaturesKHR m_rayTracingPipelineFeatures{}; 31 | VkPhysicalDeviceAccelerationStructureFeaturesKHR m_accelerationStructureFeatures{}; 32 | 33 | VkPhysicalDeviceScalarBlockLayoutFeatures m_scalarBlockLayoutFeatures{}; 34 | VkPhysicalDeviceFeatures2 m_features2{}; 35 | 36 | VkPhysicalDeviceRayTracingPipelinePropertiesKHR m_rayTracingPipelineProperties{}; 37 | 38 | uint32_t m_graphicsQueueFamily; 39 | float m_queuePriority; 40 | VkDevice m_device; 41 | VkQueue m_graphicsQueue; 42 | VkCommandPool m_commandPool_graphics; 43 | 44 | 45 | bool _init_vulkan(); 46 | Context(); 47 | ~Context(); 48 | 49 | }; 50 | 51 | 52 | class NTimeCommandBuffer 53 | { 54 | public: 55 | const VkCommandBuffer& buf() const { return m_buf; } 56 | 57 | NTimeCommandBuffer(size_t n = 1); 58 | ~NTimeCommandBuffer(); 59 | 60 | private: 61 | VkCommandBuffer m_buf; 62 | size_t m_n; 63 | }; 64 | 65 | class Buffer 66 | { 67 | public: 68 | VkDeviceSize size() const { return m_size; } 69 | const VkBuffer& buf() const { return m_buf; } 70 | const VkDeviceMemory& memory() const { return m_mem; } 71 | 72 | VkDeviceAddress get_device_address() const; 73 | 74 | protected: 75 | VkDeviceSize m_size; 76 | VkBuffer m_buf; 77 | VkDeviceMemory m_mem; 78 | 79 | 80 | Buffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags flags); 81 | virtual ~Buffer(); 82 | 83 | }; 84 | 85 | class UploadBuffer : public Buffer 86 | { 87 | public: 88 | UploadBuffer(VkDeviceSize size); 89 | virtual ~UploadBuffer(); 90 | 91 | void upload(const void* hdata); 92 | void zero(); 93 | 94 | }; 95 | 96 | class DownloadBuffer : public Buffer 97 | { 98 | public: 99 | DownloadBuffer(VkDeviceSize size); 100 | virtual ~DownloadBuffer(); 101 | 102 | void download(void* hdata) const; 103 | }; 104 | 105 | class DeviceBuffer : public Buffer 106 | { 107 | public: 108 | DeviceBuffer(VkDeviceSize size, VkBufferUsageFlags usage); 109 | virtual ~DeviceBuffer(); 110 | 111 | void upload(const void* hdata); 112 | void zero(); 113 | void download(void* hdata, VkDeviceSize begin = 0, VkDeviceSize end = (VkDeviceSize)(-1)) const; 114 | 115 | }; 116 | 117 | class AS 118 | { 119 | public: 120 | const VkAccelerationStructureKHR & structure() const { return m_structure; } 121 | 122 | protected: 123 | AS(); 124 | virtual ~AS(); 125 | VkAccelerationStructureKHR m_structure; 126 | }; 127 | 128 | class BaseLevelAS : public AS 129 | { 130 | public: 131 | BaseLevelAS( 132 | const VkAccelerationStructureBuildGeometryInfoKHR& geoBuildInfo, 133 | const VkAccelerationStructureGeometryKHR* pGeometries, 134 | const VkAccelerationStructureBuildRangeInfoKHR** ranges); 135 | 136 | virtual ~BaseLevelAS(); 137 | 138 | private: 139 | DeviceBuffer* m_scratchBuffer; 140 | DeviceBuffer* m_resultBuffer; 141 | }; 142 | 143 | 144 | class TopLevelAS : public AS 145 | { 146 | public: 147 | TopLevelAS(size_t num_hitgroups, size_t* num_instances, const VkAccelerationStructureKHR** pblases, const glm::mat4x4** ptransforms); 148 | virtual ~TopLevelAS(); 149 | 150 | private: 151 | DeviceBuffer* m_scratchBuffer; 152 | DeviceBuffer* m_resultBuffer; 153 | DeviceBuffer* m_instancesBuffer; 154 | }; 155 | 156 | class Texture 157 | { 158 | public: 159 | int width() const { return m_width; } 160 | int height() const { return m_height; } 161 | int pixel_size() const { return m_pixel_size; } 162 | const VkFormat& format() const { return m_format; } 163 | const VkImage& image() const { return m_image; } 164 | const VkDeviceMemory& memory() const { return m_mem; } 165 | const VkImageView& view() const { return m_view; } 166 | 167 | Texture(int width, int height, int pixel_size, VkFormat format, VkImageAspectFlags aspectFlags, VkImageUsageFlags usage); 168 | ~Texture(); 169 | 170 | void uploadTexture(const void* hdata); 171 | void downloadTexture(void* hdata) const; 172 | 173 | private: 174 | int m_width; 175 | int m_height; 176 | int m_pixel_size; 177 | VkFormat m_format; 178 | 179 | VkImage m_image; 180 | VkDeviceMemory m_mem; 181 | VkImageView m_view; 182 | 183 | }; 184 | 185 | class Cubemap 186 | { 187 | public: 188 | int width() const { return m_width; } 189 | int height() const { return m_height; } 190 | int pixel_size() const { return m_pixel_size; } 191 | const VkFormat& format() const { return m_format; } 192 | const VkImage& image() const { return m_image; } 193 | const VkDeviceMemory& memory() const { return m_mem; } 194 | const VkImageView& view() const { return m_view; } 195 | 196 | Cubemap(int width, int height, int pixel_size, VkFormat format, VkImageAspectFlags aspectFlags, VkImageUsageFlags usage); 197 | ~Cubemap(); 198 | 199 | void uploadTexture(const void* hdata); 200 | 201 | private: 202 | int m_width; 203 | int m_height; 204 | int m_pixel_size; 205 | VkFormat m_format; 206 | 207 | VkImage m_image; 208 | VkDeviceMemory m_mem; 209 | VkImageView m_view; 210 | }; 211 | 212 | 213 | class Sampler 214 | { 215 | public: 216 | Sampler(); 217 | ~Sampler(); 218 | 219 | const VkSampler& sampler() const { return m_sampler; } 220 | 221 | private: 222 | VkSampler m_sampler; 223 | }; 224 | 225 | -------------------------------------------------------------------------------- /PyFeiRays/Scene.cpp: -------------------------------------------------------------------------------- 1 | #include "Scene.h" 2 | 3 | #define TINYOBJLOADER_IMPLEMENTATION 4 | #include "tiny_obj_loader.h" 5 | 6 | Scene::Scene(int width, int height) : m_Image(width, height), m_tex_map(&m_pt) 7 | { 8 | m_pt.set_target(&m_Image); 9 | m_sky = nullptr; 10 | } 11 | 12 | Scene::~Scene() 13 | { 14 | delete m_sky; 15 | for (size_t i = 0; i < m_geos.size(); i++) 16 | delete m_geos[i]; 17 | } 18 | 19 | void Scene::set_gradient_sky(const glm::vec3& color0, const glm::vec3& color1) 20 | { 21 | delete m_sky; 22 | m_sky = new GradientSky(color0, color1); 23 | m_pt.set_sky(m_sky); 24 | } 25 | 26 | void Scene::set_textured_sky(const char* fn_tex, bool srgb) 27 | { 28 | int texId = m_tex_map.findTex(fn_tex, srgb); 29 | delete m_sky; 30 | m_sky = new TexturedSkyBox(texId); 31 | m_pt.set_sky(m_sky); 32 | } 33 | 34 | void Scene::set_textured_sky(const char* fn_tex, bool srgb, float angle, const glm::vec3& v) 35 | { 36 | int texId = m_tex_map.findTex(fn_tex, srgb); 37 | delete m_sky; 38 | TexturedSkyBox *t_sky = new TexturedSkyBox(texId); 39 | t_sky->rotate(angle, v); 40 | m_sky = t_sky; 41 | m_pt.set_sky(m_sky); 42 | } 43 | 44 | void Scene::add_colored_sphere(const glm::mat4x4& model, const Material& material) 45 | { 46 | ColoredUnitSphere* sphere = new ColoredUnitSphere(model, material); 47 | m_geos.push_back(sphere); 48 | m_pt.add_geometry(sphere); 49 | } 50 | 51 | void Scene::add_colored_cube(const glm::mat4x4& model, const Material& material) 52 | { 53 | static std::vector cube_vertices = 54 | { 55 | {{-1.0f, -1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 56 | {{-1.0f, -1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 57 | {{-1.0f, 1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f } }, 58 | {{-1.0f, 1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f } }, 59 | 60 | {{-1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f }}, 61 | {{1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 62 | {{1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 63 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f } }, 64 | 65 | {{1.0f, -1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 66 | {{1.0f, -1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 67 | {{1.0f, 1.0f, -1.0f}, {1.0f, 0.0f, 0.0f } }, 68 | {{1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f } }, 69 | 70 | {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 71 | {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 72 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 73 | {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f } }, 74 | 75 | {{1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 76 | {{1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 77 | {{-1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f } }, 78 | {{-1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f } }, 79 | 80 | {{-1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 81 | {{-1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 82 | {{1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f } }, 83 | {{1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f } }, 84 | }; 85 | 86 | static std::vector cube_indices = 87 | { 88 | 0, 1, 2, 89 | 0, 2, 3, 90 | 91 | 4, 5, 6, 92 | 4, 6, 7, 93 | 94 | 8, 9, 10, 95 | 8, 10, 11, 96 | 97 | 12, 13, 14, 98 | 12, 14, 15, 99 | 100 | 16, 17, 18, 101 | 16, 18, 19, 102 | 103 | 20, 21, 22, 104 | 20, 22, 23 105 | }; 106 | 107 | 108 | ColoredIndexedTriangleList* cube = new ColoredIndexedTriangleList(model, cube_vertices, cube_indices, material); 109 | m_geos.push_back(cube); 110 | m_pt.add_geometry(cube); 111 | 112 | } 113 | 114 | void Scene::add_textured_sphere(const glm::mat4x4& model, const char* fn_tex, bool srgb, const glm::vec3& color) 115 | { 116 | int texId = m_tex_map.findTex(fn_tex, srgb); 117 | TexturedUnitSphere* sphere = new TexturedUnitSphere(model, texId, color); 118 | m_geos.push_back(sphere); 119 | m_pt.add_geometry(sphere); 120 | } 121 | 122 | void Scene::add_wavefront_object(const glm::mat4x4& model, const char* path, const char* fn) 123 | { 124 | std::string str_path = path; 125 | str_path += "/"; 126 | std::string fn_obj = str_path + fn; 127 | 128 | tinyobj::attrib_t attrib; 129 | std::vector shapes; 130 | std::vector materials; 131 | std::string err; 132 | 133 | tinyobj::LoadObj(&attrib, &shapes, &materials, &err, fn_obj.c_str(), path); 134 | 135 | std::vector materials_in(materials.size()); 136 | 137 | for (size_t i = 0; i < materials.size(); i++) 138 | { 139 | materials_in[i].diffuse = glm::vec3(materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]); 140 | materials_in[i].specular = glm::vec3(materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]); 141 | materials_in[i].emission = glm::vec3(materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]); 142 | materials_in[i].shininess = materials[i].shininess; 143 | 144 | if (!materials[i].diffuse_texname.empty()) 145 | materials_in[i].texId_diffuse = m_tex_map.findTex((str_path+materials[i].diffuse_texname).c_str()); 146 | else 147 | materials_in[i].texId_diffuse = -1; 148 | 149 | if (!materials[i].specular_texname.empty()) 150 | materials_in[i].texId_specular = m_tex_map.findTex((str_path+materials[i].specular_texname).c_str()); 151 | else 152 | materials_in[i].texId_specular = -1; 153 | 154 | if (!materials[i].emissive_texname.empty()) 155 | materials_in[i].texId_emission = m_tex_map.findTex((str_path+materials[i].emissive_texname).c_str()); 156 | else 157 | materials_in[i].texId_emission = -1; 158 | 159 | if (!materials[i].bump_texname.empty()) 160 | materials_in[i].texId_bumpmap = m_tex_map.findTex((str_path+materials[i].bump_texname).c_str(), false); 161 | else 162 | materials_in[i].texId_bumpmap = -1; 163 | 164 | if (!materials[i].alpha_texname.empty()) 165 | materials_in[i].texId_mask = m_tex_map.findTex(materials[i].alpha_texname.c_str(), false); 166 | else 167 | materials_in[i].texId_mask = -1; 168 | 169 | int mask = 0; 170 | if (materials[i].diffuse[0] > 0.0f || materials[i].diffuse[1] > 0.0f || materials[i].diffuse[2] > 0.0f) 171 | { 172 | mask |= 1; 173 | } 174 | else if (materials_in[i].texId_diffuse >= 0) 175 | { 176 | materials_in[i].diffuse = glm::vec3(1.0f, 1.0f, 1.0f); 177 | mask |= 1; 178 | } 179 | if (materials[i].specular[0] > 0.0f || materials[i].specular[1] > 0.0f || materials[i].specular[2] > 0.0f) mask |= 2; 180 | if (materials[i].emission[0] > 0.0f || materials[i].emission[1] > 0.0f || materials[i].emission[2] > 0.0f) mask |= 4; 181 | materials_in[i].mask = mask; 182 | } 183 | 184 | std::vector positions(attrib.vertices.size() / 3); 185 | for (size_t i = 0; i < positions.size(); i++) 186 | { 187 | float* vp = &attrib.vertices[3 * i]; 188 | positions[i] = glm::vec3(vp[0], vp[1], vp[2]); 189 | } 190 | 191 | std::vector normals(attrib.normals.size() / 3); 192 | for (size_t i = 0; i < normals.size(); i++) 193 | { 194 | float* np = &attrib.normals[3 * i]; 195 | normals[i] = glm::vec3(np[0], np[1], np[2]); 196 | } 197 | 198 | std::vector tex_coords(attrib.texcoords.size() / 2); 199 | for (size_t i = 0; i < tex_coords.size(); i++) 200 | { 201 | float* tp = &attrib.texcoords[2 * i]; 202 | tex_coords[i] = glm::vec2(tp[0], 1.0f - tp[1]); 203 | } 204 | 205 | std::vector indices; 206 | std::vector materials_ids; 207 | 208 | for (size_t i = 0; i < shapes.size(); i++) 209 | { 210 | tinyobj::shape_t& shape = shapes[i]; 211 | 212 | for (size_t j = 0; j < shape.mesh.indices.size(); j++) 213 | { 214 | tinyobj::index_t& t_index = shape.mesh.indices[j]; 215 | WavefrontIndexedTriangleList::Index index; 216 | index.vertex_index = t_index.vertex_index; 217 | index.normal_index = t_index.normal_index; 218 | index.texcoord_index = t_index.texcoord_index; 219 | indices.push_back(index); 220 | } 221 | 222 | for (size_t j = 0; j < shape.mesh.material_ids.size(); j++) 223 | materials_ids.push_back(shape.mesh.material_ids[j]); 224 | } 225 | 226 | WavefrontIndexedTriangleList* witl = new WavefrontIndexedTriangleList(model, positions, normals, tex_coords, indices, materials_in, materials_ids.data()); 227 | m_geos.push_back(witl); 228 | m_pt.add_geometry(witl); 229 | } 230 | 231 | void Scene::add_sphere_light(const glm::vec3& center, float r, const glm::vec3& color) 232 | { 233 | SphereLight* light = new SphereLight(center, r, color); 234 | m_geos.push_back(light); 235 | m_pt.add_geometry(light); 236 | } 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /SRGBConverter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "SRGBConverter.h" 4 | 5 | const SRGBConverter& SRGBConverter::get_converter() 6 | { 7 | static SRGBConverter coverter; 8 | return coverter; 9 | } 10 | 11 | struct ImageView 12 | { 13 | VkDeviceAddress data; 14 | int width; 15 | int height; 16 | }; 17 | 18 | struct UBO 19 | { 20 | ImageView img; 21 | float boost; 22 | }; 23 | 24 | SRGBConverter::SRGBConverter() 25 | { 26 | const Context& ctx = Context::get_context(); 27 | 28 | { 29 | VkAttachmentDescription colorAttachment = {}; 30 | colorAttachment.format = VK_FORMAT_R8G8B8A8_SRGB; 31 | colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; 32 | colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 33 | colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; 34 | colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 35 | colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 36 | colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 37 | colorAttachment.finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; 38 | 39 | VkAttachmentReference colorAttachmentRef = {}; 40 | colorAttachmentRef.attachment = 0; 41 | colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 42 | 43 | VkSubpassDescription subpass = {}; 44 | subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 45 | subpass.colorAttachmentCount = 1; 46 | subpass.pColorAttachments = &colorAttachmentRef; 47 | 48 | VkRenderPassCreateInfo renderPassInfo = {}; 49 | renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 50 | renderPassInfo.attachmentCount = 1; 51 | renderPassInfo.pAttachments = &colorAttachment; 52 | renderPassInfo.subpassCount = 1; 53 | renderPassInfo.pSubpasses = &subpass; 54 | 55 | vkCreateRenderPass(ctx.device(), &renderPassInfo, nullptr, &m_renderPass); 56 | } 57 | 58 | { 59 | VkDescriptorSetLayoutBinding uboLayoutBinding = {}; 60 | uboLayoutBinding.binding = 0; 61 | uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 62 | uboLayoutBinding.descriptorCount = 1; 63 | uboLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; 64 | 65 | VkDescriptorSetLayoutCreateInfo layoutInfo = {}; 66 | layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 67 | layoutInfo.bindingCount = 1; 68 | layoutInfo.pBindings = &uboLayoutBinding; 69 | 70 | vkCreateDescriptorSetLayout(ctx.device(), &layoutInfo, nullptr, &m_descriptorSetLayout); 71 | 72 | } 73 | 74 | { 75 | m_vertShaderModule = ctx.get_shader("common/vert_srgb.spv"); 76 | m_fragShaderModule = ctx.get_shader("common/frag_srgb.spv"); 77 | 78 | VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; 79 | pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 80 | pipelineLayoutInfo.setLayoutCount = 1; 81 | pipelineLayoutInfo.pSetLayouts = &m_descriptorSetLayout; 82 | 83 | vkCreatePipelineLayout(ctx.device(), &pipelineLayoutInfo, nullptr, &m_pipelineLayout); 84 | } 85 | 86 | m_ubo = new DeviceBuffer(sizeof(UBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); 87 | 88 | { 89 | VkDescriptorPoolSize poolSize = {}; 90 | poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 91 | poolSize.descriptorCount = 1; 92 | VkDescriptorPoolCreateInfo poolInfo = {}; 93 | poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; 94 | poolInfo.poolSizeCount = 1; 95 | poolInfo.pPoolSizes = &poolSize; 96 | poolInfo.maxSets = 1; 97 | vkCreateDescriptorPool(ctx.device(), &poolInfo, nullptr, &m_descriptorPool); 98 | } 99 | 100 | { 101 | VkDescriptorSetAllocateInfo allocInfo = {}; 102 | allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; 103 | allocInfo.descriptorPool = m_descriptorPool; 104 | allocInfo.descriptorSetCount = 1; 105 | allocInfo.pSetLayouts = &m_descriptorSetLayout; 106 | vkAllocateDescriptorSets(ctx.device(), &allocInfo, &m_descriptorSet); 107 | } 108 | 109 | } 110 | 111 | SRGBConverter::~SRGBConverter() 112 | { 113 | /* 114 | const Context& ctx = Context::get_context(); 115 | vkDestroyDescriptorPool(ctx.device(), m_descriptorPool, nullptr); 116 | delete m_ubo; 117 | 118 | vkDestroyPipelineLayout(ctx.device(), m_pipelineLayout, nullptr); 119 | vkDestroyDescriptorSetLayout(ctx.device(), m_descriptorSetLayout, nullptr); 120 | vkDestroyRenderPass(ctx.device(), m_renderPass, nullptr); 121 | */ 122 | } 123 | 124 | void SRGBConverter::convert(Texture* dst_srgb, DeviceBuffer* src_rgb, float boost) const 125 | { 126 | int width = dst_srgb->width(); 127 | int height = dst_srgb->height(); 128 | const Context& ctx = Context::get_context(); 129 | UBO ubo; 130 | ubo.img.width = width; 131 | ubo.img.height = height; 132 | ubo.img.data = src_rgb->get_device_address(); 133 | ubo.boost = boost; 134 | m_ubo->upload(&ubo); 135 | 136 | VkDescriptorBufferInfo bufferInfo = {}; 137 | bufferInfo.buffer = m_ubo->buf(); 138 | bufferInfo.range = VK_WHOLE_SIZE; 139 | 140 | VkWriteDescriptorSet descriptorWrite = {}; 141 | descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 142 | descriptorWrite.dstSet = m_descriptorSet; 143 | descriptorWrite.dstBinding = 0; 144 | descriptorWrite.dstArrayElement = 0; 145 | descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 146 | descriptorWrite.descriptorCount = 1; 147 | descriptorWrite.pBufferInfo = &bufferInfo; 148 | vkUpdateDescriptorSets(ctx.device(), 1, &descriptorWrite, 0, nullptr); 149 | 150 | VkPipeline graphicsPipeline; 151 | { 152 | VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; 153 | vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 154 | vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; 155 | vertShaderStageInfo.module = m_vertShaderModule; 156 | vertShaderStageInfo.pName = "main"; 157 | 158 | VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; 159 | fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 160 | fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; 161 | fragShaderStageInfo.module = m_fragShaderModule; 162 | fragShaderStageInfo.pName = "main"; 163 | 164 | VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo }; 165 | 166 | VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; 167 | vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 168 | 169 | VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; 170 | inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 171 | inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; 172 | inputAssembly.primitiveRestartEnable = VK_FALSE; 173 | 174 | VkViewport viewport; 175 | viewport.x = 0.0f; 176 | viewport.y = 0.0f; 177 | viewport.width = (float)width; 178 | viewport.height = (float)height; 179 | viewport.minDepth = 0.0f; 180 | viewport.maxDepth = 1.0f; 181 | 182 | VkRect2D scissor = {}; 183 | scissor.offset = { 0, 0 }; 184 | scissor.extent = { (unsigned)width, (unsigned)height }; 185 | 186 | VkPipelineViewportStateCreateInfo viewportState = {}; 187 | viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 188 | viewportState.viewportCount = 1; 189 | viewportState.pViewports = &viewport; 190 | viewportState.scissorCount = 1; 191 | viewportState.pScissors = &scissor; 192 | 193 | VkPipelineRasterizationStateCreateInfo rasterizer = {}; 194 | rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; 195 | rasterizer.lineWidth = 1.0f; 196 | 197 | VkPipelineMultisampleStateCreateInfo multisampling = {}; 198 | multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 199 | multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; 200 | 201 | VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; 202 | colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; 203 | 204 | VkPipelineColorBlendStateCreateInfo colorBlending = {}; 205 | colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 206 | colorBlending.attachmentCount = 1; 207 | colorBlending.pAttachments = &colorBlendAttachment; 208 | 209 | VkPipelineDepthStencilStateCreateInfo depthStencil = {}; 210 | depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 211 | 212 | VkGraphicsPipelineCreateInfo pipelineInfo = {}; 213 | pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 214 | pipelineInfo.stageCount = 2; 215 | pipelineInfo.pStages = shaderStages; 216 | pipelineInfo.pVertexInputState = &vertexInputInfo; 217 | pipelineInfo.pInputAssemblyState = &inputAssembly; 218 | pipelineInfo.pViewportState = &viewportState; 219 | pipelineInfo.pRasterizationState = &rasterizer; 220 | pipelineInfo.pMultisampleState = &multisampling; 221 | pipelineInfo.pColorBlendState = &colorBlending; 222 | pipelineInfo.pDepthStencilState = &depthStencil; 223 | pipelineInfo.layout = m_pipelineLayout; 224 | pipelineInfo.renderPass = m_renderPass; 225 | 226 | vkCreateGraphicsPipelines(ctx.device(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline); 227 | } 228 | 229 | VkFramebuffer framebuffer; 230 | VkImageView colView = dst_srgb->view(); 231 | { 232 | VkFramebufferCreateInfo framebufferInfo = {}; 233 | framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; 234 | framebufferInfo.renderPass = m_renderPass; 235 | framebufferInfo.attachmentCount = 1; 236 | framebufferInfo.pAttachments = &colView; 237 | framebufferInfo.width = width; 238 | framebufferInfo.height = height; 239 | framebufferInfo.layers = 1; 240 | vkCreateFramebuffer(ctx.device(), &framebufferInfo, nullptr, &framebuffer); 241 | } 242 | 243 | { 244 | NTimeCommandBuffer cmdBuf; 245 | 246 | VkRenderPassBeginInfo renderPassInfo = {}; 247 | renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 248 | renderPassInfo.renderPass = m_renderPass; 249 | renderPassInfo.framebuffer = framebuffer; 250 | renderPassInfo.renderArea.offset = { 0, 0 }; 251 | renderPassInfo.renderArea.extent = { (unsigned)width, (unsigned)height }; 252 | 253 | VkClearValue clearValue; 254 | clearValue.color = { 0.0f, 0.0f, 0.0f, 0.0f }; 255 | 256 | renderPassInfo.clearValueCount = 1; 257 | renderPassInfo.pClearValues = &clearValue; 258 | 259 | vkCmdBeginRenderPass(cmdBuf.buf(), &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); 260 | vkCmdBindPipeline(cmdBuf.buf(), VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline); 261 | vkCmdBindDescriptorSets(cmdBuf.buf(), VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descriptorSet, 0, nullptr); 262 | vkCmdDraw(cmdBuf.buf(), 3, 1, 0, 0); 263 | vkCmdEndRenderPass(cmdBuf.buf()); 264 | } 265 | 266 | vkDestroyFramebuffer(ctx.device(), framebuffer, nullptr); 267 | vkDestroyPipeline(ctx.device(), graphicsPipeline, nullptr); 268 | } 269 | 270 | 271 | 272 | 273 | -------------------------------------------------------------------------------- /shaders/path_tracer/raygen.rgen: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable 4 | #extension GL_EXT_buffer_reference2 : enable 5 | #extension GL_EXT_ray_tracing : enable 6 | 7 | #include "../common/bindings.h" 8 | #include "../common/payload.shinc" 9 | #include "../common/rand_xorwow.shinc" 10 | #include "../common/image.shinc" 11 | #include "../common/light_source_dist.shinc" 12 | #include "raygen_params.shinc" 13 | 14 | layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS; 15 | 16 | layout(std430, binding = 2) buffer BufStates 17 | { 18 | RNGState states[]; 19 | }; 20 | 21 | struct SphereLight 22 | { 23 | vec4 center_radius; 24 | vec4 color; 25 | }; 26 | 27 | 28 | layout(std430, binding = BINDING_SphereLight) buffer SpheresLights 29 | { 30 | SphereLight[] sphereLights; 31 | }; 32 | 33 | 34 | struct Sunlight 35 | { 36 | vec4 dir_radian; 37 | vec4 color; 38 | }; 39 | 40 | layout(std430, binding = 7) buffer Sunlights 41 | { 42 | Sunlight[] sun_lights; 43 | }; 44 | 45 | 46 | layout(location = 0) rayPayloadEXT Payload payload; 47 | 48 | 49 | vec3 directional_scatter(inout RNGState state, in vec3 base, in float order) 50 | { 51 | vec3 a, b; 52 | if (abs(base.x)>0.8) 53 | a = vec3(0.0, 1.0, 0.0); 54 | else 55 | a = vec3(1.0, 0.0, 0.0); 56 | 57 | a = normalize(cross(a, base)); 58 | b = cross(a, base); 59 | 60 | float z = pow(rand01(state), 1.0/(order+1.0)); 61 | float xy = sqrt(1.0 - z*z); 62 | float alpha = rand01(state)*radians(360.0); 63 | float x = xy * cos(alpha); 64 | float y = xy * sin(alpha); 65 | 66 | return x*a + y*b + z * base; 67 | } 68 | 69 | 70 | float schlick(float cosine, float ref_idx) 71 | { 72 | float r0 = (1.0 - ref_idx) / (1.0 + ref_idx); 73 | r0 = r0 * r0; 74 | return r0 + (1.0 - r0)*pow(1.0 - cosine, 5.0); 75 | } 76 | 77 | 78 | void rt_main(int ix, int iy, inout RNGState rng_state) 79 | { 80 | float fx = float(ix)+ rand01(rng_state); 81 | float fy = float(iy)+ rand01(rng_state); 82 | 83 | vec3 pos_pix = upper_left.xyz + fx * ux.xyz + fy * uy.xyz; 84 | 85 | uint cullMask = 0xff; 86 | float tmin = 0.001; 87 | float tmax = 1000000.0; 88 | 89 | vec3 ray_origin = origin.xyz; 90 | 91 | if (lens_radius > 0.0) 92 | { 93 | vec3 u = normalize(ux.xyz); 94 | vec3 v = normalize(uy.xyz); 95 | vec2 rd = lens_radius * rand_in_unit_disk(rng_state); 96 | ray_origin += u * rd.x + v * rd.y; 97 | } 98 | 99 | vec3 direction = normalize(pos_pix - ray_origin); 100 | 101 | vec3 color = vec3(0.0, 0.0, 0.0); 102 | vec3 f_att = vec3(1.0, 1.0, 1.0); 103 | int depth = 0; 104 | 105 | bool in_material = false; 106 | bool skip_lights = false; 107 | 108 | const float russian_roulette_factor = 0.1; 109 | 110 | while (depth < 10) 111 | { 112 | // Russian Roulette 113 | float max_att = max(max(f_att.x, f_att.y), f_att.z); 114 | if (max_attmax_att) break; 118 | f_att*=1.0/max_att; 119 | } 120 | 121 | uint rayFlags = gl_RayFlagsOpaqueEXT; 122 | traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, ray_origin, tmin, direction, tmax, 0); 123 | 124 | float t = payload.t; 125 | 126 | bool scattering = false; 127 | if (in_material && (payload.material_bits & MAT_SCATTER_BIT)!=0 && payload.f2>0.0) 128 | { 129 | float t2 = -log(rand01(rng_state))/payload.f2; 130 | if (t20.0) 146 | ray_origin += direction*t; 147 | 148 | if ( (payload.material_bits & MAT_EMIT_BIT) !=0 && (!skip_lights || (payload.material_bits & MAT_LIGHT_SOURCE_BIT)==0)) 149 | color += payload.color0 * f_att; 150 | 151 | bool diffusive = false; 152 | bool directional = false; 153 | vec3 fuzz_dir = payload.normal; 154 | float fuzz; 155 | 156 | if (!scattering) 157 | { 158 | if ((payload.material_bits & MAT_OPAQUE_BIT) !=0) 159 | { 160 | switch(payload.material_bits & (MAT_DIFFUSE_BIT | MAT_SPECULAR_BIT)) 161 | { 162 | case MAT_DIFFUSE_BIT: 163 | diffusive = true; 164 | break; 165 | case MAT_SPECULAR_BIT: 166 | directional = true; 167 | break; 168 | case MAT_DIFFUSE_BIT | MAT_SPECULAR_BIT: 169 | { 170 | float r = rand01(rng_state); 171 | if (r<=payload.f0) 172 | { 173 | directional = true; 174 | f_att *= 1.0/payload.f0; 175 | } 176 | else 177 | { 178 | diffusive = true; 179 | f_att *= 1.0/(1.0 - payload.f0); 180 | } 181 | } 182 | break; 183 | } 184 | 185 | if (diffusive) 186 | { 187 | f_att *= payload.color1; 188 | direction = payload.normal; 189 | fuzz = 1.0; 190 | } 191 | else if (directional) 192 | { 193 | f_att *= payload.color2; 194 | direction = reflect(direction, payload.normal); 195 | fuzz = payload.f1; if (fuzz > 1.0) fuzz = 1.0; 196 | } 197 | } 198 | else if ((payload.material_bits & MAT_FRESNEL_BIT) !=0) 199 | { 200 | bool enter = payload.f0 < 1.0; 201 | float ref_idx = payload.f0; 202 | vec3 normal = -payload.normal; 203 | 204 | if (dot(direction, payload.normal)<0) 205 | { 206 | enter = !enter; 207 | ref_idx = 1.0 / ref_idx; 208 | normal = payload.normal; 209 | } 210 | 211 | float reflect_prob = 1.0; 212 | vec3 refracted = refract(direction, normal, ref_idx); 213 | if (refracted.x != 0.0 || refracted.y!= 0.0 || refracted.z != 0.0) 214 | { 215 | float cosine = -dot(direction, normal); 216 | reflect_prob = schlick(cosine, ref_idx); 217 | } 218 | 219 | if (rand01(rng_state) < reflect_prob) 220 | { 221 | direction = reflect(direction, normal); 222 | fuzz_dir = normal; 223 | } 224 | else 225 | { 226 | direction = refracted; 227 | fuzz_dir = - normal; 228 | in_material = enter; 229 | } 230 | 231 | directional = true; 232 | fuzz = payload.f1; if (fuzz > 1.0) fuzz = 1.0; 233 | } 234 | else 235 | { 236 | if (payload.material_bits!=0) 237 | in_material = dot(direction, payload.normal)<0; 238 | directional = true; 239 | fuzz = 0.0; 240 | } 241 | } 242 | 243 | if (!scattering && !diffusive && !directional) break; 244 | 245 | // handle light-sources here 246 | // skip_lights = false; // cause high-noise because of reflective materials 247 | 248 | if (number_sphere_lights + number_sun_lights>0 && !in_material && diffusive) 249 | { 250 | // choose a light-source 251 | float r = rand01(rng_state); 252 | int id_light; 253 | float weight; 254 | for (id_light = 0; id_light< number_sphere_lights + number_sun_lights; id_light++) 255 | { 256 | weight = buf_lightSourceDist[id_light].d; 257 | if (r<= weight) 258 | { 259 | if (id_light>0) weight-= buf_lightSourceDist[id_light-1].d; 260 | weight = 1.0 / weight; 261 | break; 262 | } 263 | } 264 | 265 | vec3 dir; 266 | float factor; 267 | 268 | // direction and 1 - cos(alpha) 269 | if (id_light0.8) 293 | a = vec3(0.0, 1.0, 0.0); 294 | else 295 | a = vec3(1.0, 0.0, 0.0); 296 | 297 | a = normalize(cross(a, dir)); 298 | b = cross(a, dir); 299 | 300 | float v_z = 1.0 - r1 * factor; 301 | float v_xy = sqrt(1.0 - v_z*v_z); 302 | float v_x = v_xy * cos(r2); 303 | float v_y = v_xy * sin(r2); 304 | 305 | dir = v_z*dir + a*v_x + b*v_y; 306 | } 307 | 308 | // cosine weight 309 | float cosine = dot(dir, direction); 310 | if (cosine>0.0) 311 | { 312 | traceRayEXT(topLevelAS, rayFlags, cullMask, 0, 0, 0, ray_origin, tmin, dir, tmax, 0); 313 | 314 | if ((payload.material_bits & MAT_LIGHT_SOURCE_BIT)!=0 && floatBitsToInt(payload.f0)==id_light) 315 | { 316 | color += payload.color0 * (weight * cosine * 2.0 * factor) * f_att; 317 | } 318 | } 319 | 320 | skip_lights = true; 321 | } 322 | 323 | // hack 324 | if (depth>0) 325 | skip_lights = true; 326 | 327 | if (scattering) 328 | { 329 | direction = rand_on_unit_sphere(rng_state); 330 | } 331 | else if ( (diffusive || directional) && fuzz>0.0) 332 | { 333 | direction = directional_scatter(rng_state, direction, 1.0/fuzz); 334 | if (dot(direction, fuzz_dir)<=0.0) break; 335 | } 336 | 337 | depth++; 338 | } 339 | 340 | vec4 col_old = read_pixel(target, ix, iy); 341 | vec4 col = vec4(col_old.xyz+color, 1.0); 342 | write_pixel(target, ix, iy, col); 343 | } 344 | 345 | void main() 346 | { 347 | int ray_id = int(gl_LaunchIDEXT.x); 348 | int d = ray_id & 0x3F; 349 | int b = ray_id >> 6; 350 | int dx = (d&1)|((d&4)>>1)|((d&16)>>2); 351 | int dy = ((d&2)>>1)|((d&8)>>2)|((d&32)>>3); 352 | 353 | int step = int(gl_LaunchSizeEXT.x)>>6; 354 | int bw = (target.width+7)>>3; 355 | int bh = (target.height+7)>>3; 356 | int total = bw*bh; 357 | 358 | for (int i=b; i