├── .clang-format ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── COPYING.LESSER ├── Doxyfile ├── README.md ├── blender └── tr_gltf_extension │ └── __init__.py ├── data ├── brdf_integration.exr ├── noise_vector_2d.exr ├── noise_vector_3d.exr └── presets │ ├── accumulation.cfg │ ├── ddish-gi.cfg │ ├── denoised.cfg │ ├── direct.cfg │ ├── minimal.cfg │ ├── quality.cfg │ ├── reference.cfg │ └── restir-hybrid.cfg ├── debian ├── changelog ├── compat ├── control └── rules ├── docs ├── DEVELOPERS.md ├── MANUAL.md ├── images │ ├── albedo.png │ ├── alpha_to_transmittance_off.png │ ├── alpha_to_transmittance_on.png │ ├── aspect_ratio_regular.png │ ├── aspect_ratio_wonky.png │ ├── bias_acne.png │ ├── bias_good.png │ ├── bias_pan.png │ ├── blender_addon_install.png │ ├── blender_addon_install2.png │ ├── blender_enable_addon.png │ ├── blender_export_menu.png │ ├── blender_export_settings.png │ ├── blender_preferences.png │ ├── cornell100.png │ ├── cornell100rr.png │ ├── cornell100rr2.png │ ├── cornell3.png │ ├── cornell8.png │ ├── cornell_box_ds.png │ ├── cornell_box_ss.png │ ├── default_one.png │ ├── default_zero.png │ ├── denoiser_none.png │ ├── denoiser_svgf.png │ ├── depth_of_field.png │ ├── direct.png │ ├── distance.png │ ├── dshgi.png │ ├── dshgi_msaa.png │ ├── dshgi_noaa.png │ ├── dshgi_ssaa.png │ ├── dshgi_taa.png │ ├── envmap_sampled.png │ ├── envmap_unsampled.png │ ├── envmap_with.png │ ├── envmap_without.png │ ├── exposure_0_5.png │ ├── exposure_2_0.png │ ├── fireflies.png │ ├── fireflies_clamped.png │ ├── fireflies_regularized.png │ ├── fov_30.png │ ├── fov_40.png │ ├── fov_40_hide.png │ ├── gamma_1_5.png │ ├── gamma_2_5.png │ ├── instance_id.png │ ├── nee_off.png │ ├── nee_on.png │ ├── path_tracer.png │ ├── pcf0.png │ ├── pcf1.png │ ├── pcf64.png │ ├── pcf8.png │ ├── pcss0.png │ ├── pcss1.png │ ├── pcss32.png │ ├── pcss8.png │ ├── preset_accumulation.png │ ├── preset_ddish-gi.png │ ├── preset_denoised.png │ ├── preset_direct.png │ ├── preset_quality.png │ ├── preset_reference.png │ ├── preset_restir_hybrid.png │ ├── proj_equirectangular.png │ ├── proj_ortho.png │ ├── proj_perspective.png │ ├── pt1.png │ ├── pt1024.png │ ├── pt16.png │ ├── pt256.png │ ├── pt4.png │ ├── pt4096.png │ ├── pt64.png │ ├── pt_blackman_harris.png │ ├── pt_blackman_harris4.png │ ├── pt_box.png │ ├── pt_point.png │ ├── raster.png │ ├── raster_blue_ambient.png │ ├── raster_no_ambient.png │ ├── restir-hybrid.png │ ├── restir-overconfident.png │ ├── restir.png │ ├── sampler_sobol_owen.png │ ├── sampler_sobol_z2.png │ ├── sampler_sobol_z3.png │ ├── sampler_uniform_random.png │ ├── screen_motion.png │ ├── sh_l2.png │ ├── sh_l2_vis.png │ ├── sh_l4.png │ ├── shadow1024.png │ ├── shadow256.png │ ├── shadow4096.png │ ├── tauray_interactive.png │ ├── tauray_logo.png │ ├── teapot_sponza.png │ ├── tonemap_filmic.png │ ├── tonemap_gamma.png │ ├── tonemap_linear.png │ ├── tonemap_reinhard.png │ ├── tonemap_reinhardl.png │ ├── view_motion.png │ ├── view_normal.png │ ├── view_pos.png │ ├── vsync_off.png │ ├── vsync_on.png │ ├── white_albedo.png │ ├── whitted.png │ ├── world_motion.png │ ├── world_normal.png │ └── world_pos.png ├── notes-1.0.txt └── tauray_user_manual.pdf ├── external ├── json.hpp ├── monkeroecs.hh ├── spirv_reflect.c ├── spirv_reflect.h ├── stb_image.c ├── stb_image.h ├── stb_image_write.h ├── tiny_gltf.cc ├── tiny_gltf.h ├── tinyexr.cc ├── tinyexr.h ├── tinyply.cc ├── tinyply.h ├── vk_mem_alloc.cc └── vk_mem_alloc.h ├── shader ├── alias_table.glsl ├── alias_table_importance.comp ├── array_reorder.comp ├── bmfr.glsl ├── bmfr_accumulate_output.comp ├── bmfr_fit.comp ├── bmfr_preprocess.comp ├── bmfr_weighted_sum.comp ├── camera.glsl ├── color.glsl ├── direct.rgen ├── envmap.frag ├── envmap.vert ├── extract_tri_lights.comp ├── forward.frag ├── forward.glsl ├── forward.vert ├── gbuffer.glsl ├── ggx.glsl ├── light.glsl ├── looking_glass_composition.comp ├── material.glsl ├── math.glsl ├── path_tracer.glsl ├── path_tracer.rgen ├── poisson_samples_2d.glsl ├── pre_transform.comp ├── projection.glsl ├── random_sampler.glsl ├── ray_cone.glsl ├── restir.glsl ├── restir_canonical.comp ├── restir_core.glsl ├── restir_di.glsl ├── restir_di_canonical_and_temporal.rgen ├── restir_di_spatial.rgen ├── restir_spatial_gather.comp ├── restir_spatial_trace.comp ├── restir_temporal.comp ├── rt.glsl ├── rt_common.glsl ├── rt_common.rahit ├── rt_common.rchit ├── rt_common.rmiss ├── rt_common_payload.glsl ├── rt_common_point_light.rchit ├── rt_common_point_light.rint ├── rt_common_shadow.rahit ├── rt_common_shadow.rchit ├── rt_common_shadow.rmiss ├── rt_feature.glsl ├── rt_feature.rahit ├── rt_feature.rchit ├── rt_feature.rgen ├── rt_feature.rmiss ├── sampling.glsl ├── scene.glsl ├── scene_raster.glsl ├── sh_compact.comp ├── sh_grid_blend.comp ├── sh_path_tracer.rgen ├── shadow_map.frag ├── shadow_map.vert ├── shadow_map_common.glsl ├── shadow_mapping.glsl ├── skinning.comp ├── sobol_lookup_table.glsl ├── sobol_owen_sampler.glsl ├── sobol_z_sampler.glsl ├── spatial_reprojection.comp ├── spherical_harmonics.glsl ├── stitch_scanline.comp ├── stitch_shuffled_strips.comp ├── svgf.glsl ├── svgf_atrous.comp ├── svgf_disocclusion_fix.comp ├── svgf_firefly_suppression.comp ├── svgf_hit_dist_reconstruction.comp ├── svgf_temporal.comp ├── taa.comp ├── temporal_reprojection.comp ├── temporal_tables.glsl ├── tonemap.glsl ├── tonemap_filmic.comp ├── tonemap_gamma.comp ├── tonemap_reinhard.comp ├── tonemap_reinhard_luminance.comp ├── z_pass.frag └── z_pass.vert ├── src ├── acceleration_structure.cc ├── acceleration_structure.hh ├── animation.cc ├── animation.hh ├── animation.tcc ├── assimp.cc ├── assimp.hh ├── atlas.cc ├── atlas.hh ├── basic_pipeline.cc ├── basic_pipeline.hh ├── bmfr_stage.cc ├── bmfr_stage.hh ├── camera.cc ├── camera.hh ├── compute_pipeline.cc ├── compute_pipeline.hh ├── context.cc ├── context.hh ├── dependency.cc ├── dependency.hh ├── descriptor_set.cc ├── descriptor_set.hh ├── device.cc ├── device.hh ├── device.tcc ├── device_transfer.cc ├── device_transfer.hh ├── direct_stage.cc ├── direct_stage.hh ├── distribution_strategy.cc ├── distribution_strategy.hh ├── dshgi_client.cc ├── dshgi_client.hh ├── dshgi_renderer.cc ├── dshgi_renderer.hh ├── dshgi_server.cc ├── dshgi_server.hh ├── environment_map.cc ├── environment_map.hh ├── envmap_stage.cc ├── envmap_stage.hh ├── feature_stage.cc ├── feature_stage.hh ├── frame_client.cc ├── frame_client.hh ├── frame_delay_stage.cc ├── frame_delay_stage.hh ├── frame_server.cc ├── frame_server.hh ├── gbuffer.cc ├── gbuffer.hh ├── gbuffer_copy_stage.cc ├── gbuffer_copy_stage.hh ├── gltf.cc ├── gltf.hh ├── gpu_buffer.cc ├── gpu_buffer.hh ├── headless.cc ├── headless.hh ├── light.cc ├── light.hh ├── load_balancer.cc ├── load_balancer.hh ├── log.cc ├── log.hh ├── looking_glass.cc ├── looking_glass.hh ├── looking_glass_composition_stage.cc ├── looking_glass_composition_stage.hh ├── main.cc ├── material.cc ├── material.hh ├── math.cc ├── math.hh ├── math.tcc ├── mesh.cc ├── mesh.hh ├── misc.cc ├── misc.hh ├── model.cc ├── model.hh ├── openxr.cc ├── openxr.hh ├── options.cc ├── options.hh ├── path_tracer_stage.cc ├── path_tracer_stage.hh ├── placeholders.cc ├── placeholders.hh ├── post_processing_renderer.cc ├── post_processing_renderer.hh ├── progress_tracker.cc ├── progress_tracker.hh ├── radix_sort.cc ├── radix_sort.hh ├── raster_pipeline.cc ├── raster_pipeline.hh ├── raster_renderer.cc ├── raster_renderer.hh ├── raster_stage.cc ├── raster_stage.hh ├── rectangle_packer.cc ├── rectangle_packer.hh ├── render_target.cc ├── render_target.hh ├── renderer.hh ├── restir_renderer.cc ├── restir_renderer.hh ├── restir_stage.cc ├── restir_stage.hh ├── rt_camera_stage.cc ├── rt_camera_stage.hh ├── rt_common.cc ├── rt_common.hh ├── rt_pipeline.cc ├── rt_pipeline.hh ├── rt_renderer.cc ├── rt_renderer.hh ├── rt_stage.cc ├── rt_stage.hh ├── sampler.cc ├── sampler.hh ├── sampler_table.cc ├── sampler_table.hh ├── scene.cc ├── scene.hh ├── scene_assets.hh ├── scene_stage.cc ├── scene_stage.hh ├── server_context.cc ├── server_context.hh ├── sh_compact_stage.cc ├── sh_compact_stage.hh ├── sh_grid.cc ├── sh_grid.hh ├── sh_path_tracer_stage.cc ├── sh_path_tracer_stage.hh ├── sh_renderer.cc ├── sh_renderer.hh ├── shader_source.cc ├── shader_source.hh ├── shadow_map.cc ├── shadow_map.hh ├── shadow_map_stage.cc ├── shadow_map_stage.hh ├── spatial_reprojection_stage.cc ├── spatial_reprojection_stage.hh ├── stage.cc ├── stage.hh ├── stitch_stage.cc ├── stitch_stage.hh ├── svgf_stage.cc ├── svgf_stage.hh ├── taa_stage.cc ├── taa_stage.hh ├── tauray.cc ├── tauray.hh ├── temporal_reprojection_stage.cc ├── temporal_reprojection_stage.hh ├── texture.cc ├── texture.hh ├── timer.cc ├── timer.hh ├── tonemap_stage.cc ├── tonemap_stage.hh ├── tracing.cc ├── tracing.hh ├── transformable.cc ├── transformable.hh ├── vkm.cc ├── vkm.hh ├── window.cc ├── window.hh ├── z_pass_stage.cc └── z_pass_stage.hh ├── test ├── CMakeLists.txt ├── crash_test.cc ├── references │ ├── validate_albedo.exr │ ├── validate_distance.exr │ ├── validate_dshgi.exr │ ├── validate_path-tracer.exr │ ├── validate_raster.exr │ ├── validate_view-normal.exr │ ├── validate_view-pos.exr │ ├── validate_whitted.exr │ ├── validate_world-normal.exr │ └── validate_world-pos.exr ├── test.glb └── validate_render.py └── vcpkg.json /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | docs/doxygen 3 | *.swp 4 | *.swo 5 | compile_commands.json 6 | .vim 7 | .clangd 8 | __pycache__ 9 | obj-x86_64-linux-gnu 10 | debian/tauray 11 | *.deb 12 | debian/debhelper-build-stamp 13 | debian/files 14 | debian/tauray.substvars 15 | debian/.debhelper 16 | deploy.sh 17 | paper 18 | .vs/ 19 | TauRay.vcxproj.user 20 | builddir/ 21 | external/SDL2-2.0.12/ 22 | external/packagecache/ 23 | x64/ 24 | .vscode 25 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/Vulkan-Headers"] 2 | path = external/Vulkan-Headers 3 | url = https://github.com/KhronosGroup/Vulkan-Headers.git 4 | [submodule "external/glslang"] 5 | path = external/glslang 6 | url = https://github.com/KhronosGroup/glslang.git 7 | [submodule "external/SPIRV-Headers"] 8 | path = external/SPIRV-Headers 9 | url = https://github.com/KhronosGroup/SPIRV-Headers.git 10 | [submodule "external/OpenXR-SDK"] 11 | path = external/OpenXR-SDK 12 | url = https://github.com/KhronosGroup/OpenXR-SDK.git 13 | [submodule "external/fuchsia_radix_sort"] 14 | path = external/fuchsia_radix_sort 15 | url = https://github.com/juliusikkala/fuchsia_radix_sort.git 16 | -------------------------------------------------------------------------------- /data/brdf_integration.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/data/brdf_integration.exr -------------------------------------------------------------------------------- /data/noise_vector_2d.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/data/noise_vector_2d.exr -------------------------------------------------------------------------------- /data/noise_vector_3d.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/data/noise_vector_3d.exr -------------------------------------------------------------------------------- /data/presets/accumulation.cfg: -------------------------------------------------------------------------------- 1 | # Don't want validation layers ruining our performance. 2 | validation off 3 | film blackman-harris 4 | force-double-sided on 5 | max-ray-depth 5 6 | accumulation on 7 | renderer path-tracer 8 | sampler uniform-random 9 | samples-per-pixel 1 10 | regularization 0.2 11 | -------------------------------------------------------------------------------- /data/presets/ddish-gi.cfg: -------------------------------------------------------------------------------- 1 | # This preset has the recommended settings for DDISH-GI. Note that these 2 | # settings are pretty slow, so not suitable for LF displays. You should set 3 | # pcf & pcss to zero for those, drop the shadow map resolution a bit, and 4 | # set samples-per-pixel to 1. 5 | validation off 6 | renderer dshgi 7 | dshgi-temporal-ratio 0.01 8 | max-ray-depth 4 9 | sampler uniform-random 10 | regularization 1.0 11 | indirect-clamping 10 12 | samples-per-probe 512 13 | shadow-map-resolution 4096 14 | pcf 64 15 | pcss 32 16 | film box 17 | film-radius 0.5 18 | shadow-map-bias 0.02 19 | # Here, this means MSAA. 20 | samples-per-pixel 8 21 | 22 | tonemap filmic 23 | -------------------------------------------------------------------------------- /data/presets/denoised.cfg: -------------------------------------------------------------------------------- 1 | # This preset is for denoised real-time path tracing. 2 | validation off 3 | 4 | renderer restir 5 | restir.sample-spatial-disk false 6 | restir.shift-mapping-type hybrid-shift 7 | max-ray-depth 4 8 | denoiser svgf 9 | taa 8 10 | 11 | force-double-sided on 12 | 13 | samples-per-pixel 1 14 | 15 | regularization 0.5 16 | -------------------------------------------------------------------------------- /data/presets/direct.cfg: -------------------------------------------------------------------------------- 1 | # This preset only samples direct lights, and doesn't even allow secondary 2 | # rays to end up in the light sources. This setup is useful for evaluating 3 | # quality of various light sampling techniques without MIS stepping on your 4 | # toes. 5 | 6 | # Don't want validation layers ruining our performance. 7 | validation off 8 | film blackman-harris 9 | force-double-sided on 10 | multiple-importance-sampling off 11 | accumulation on 12 | renderer direct 13 | sampler uniform-random 14 | samples-per-pixel 1 15 | -------------------------------------------------------------------------------- /data/presets/minimal.cfg: -------------------------------------------------------------------------------- 1 | # This preset forces a minimum-viable path tracer setup, where nothing is 2 | # importance sampled. 3 | renderer path-tracer 4 | validation off 5 | sample-point-lights 0 6 | sample-directional-lights 0 7 | sample-envmap 0 8 | sample-emissive-triangles 0 9 | multiple-importance-sampling off 10 | bounce-mode hemisphere 11 | regularization 0 12 | indirect-clamping 0 13 | shadow-terminator-fix off 14 | force-double-sided on 15 | samples-per-pixel 1 16 | max-ray-depth 8 17 | sampler uniform-random 18 | -------------------------------------------------------------------------------- /data/presets/quality.cfg: -------------------------------------------------------------------------------- 1 | # This preset creates a "high-quality" render, if you just want pretty offline 2 | # images pretty quickly. 3 | validation off 4 | film blackman-harris 5 | max-ray-depth 4 6 | samples-per-pixel 4096 7 | force-double-sided on 8 | sampler uniform-random 9 | regularization 0.1 10 | renderer path-tracer 11 | 12 | tonemap filmic 13 | filetype png 14 | headless quality 15 | -------------------------------------------------------------------------------- /data/presets/reference.cfg: -------------------------------------------------------------------------------- 1 | # This is a proper reference render; not the fastest setup for this SPP. See 2 | # quality preset for better quality and speed options. 3 | film blackman-harris 4 | max-ray-depth 8 5 | samples-per-pixel 16384 6 | sampler uniform-random 7 | tri-light-mode hybrid 8 | renderer path-tracer 9 | 10 | tonemap linear 11 | filetype exr 12 | headless reference 13 | -------------------------------------------------------------------------------- /data/presets/restir-hybrid.cfg: -------------------------------------------------------------------------------- 1 | validation off 2 | renderer restir-hybrid 3 | 4 | max-ray-depth 2 5 | camera-clip-range 0.01,100 6 | 7 | sample-emissive-triangles 0 8 | sample-envmap 0 9 | regularization 0.5 10 | shadow-map-bias=0.01 11 | shadow-map-cascades=2 12 | shadow-map-radius=7 13 | shadow-map-resolution=1024 14 | max-ray-depth=2 15 | pcss=0 16 | pcf=8 17 | 18 | indirect-clamping 100 19 | dshgi-temporal-ratio 0.02 20 | tonemap filmic 21 | 22 | taa 8 23 | denoiser svgf 24 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | tauray (0.0-0) UNRELEASED; urgency=medium 2 | 3 | * Initial internal release 4 | 5 | -- Julius Ikkala Tue, 01 Sep 2020 14:04:00 +0200 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 11 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: tauray 2 | Section: graphics 3 | Priority: optional 4 | Maintainer: Julius Ikkala 5 | Build-Depends: debhelper (>= 11~) 6 | Standards-Version: 4.1.3 7 | 8 | Package: tauray 9 | Architecture: amd64 10 | Depends: ${shlibs:Depends} 11 | Description: A real-time physically based path tracer 12 | Tauray is a physically based path tracing renderer, currently focusing on research problems. 13 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # debian/rules 3 | # -*- makefile -*- 4 | 5 | %: 6 | dh $@ 7 | -------------------------------------------------------------------------------- /docs/images/albedo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/albedo.png -------------------------------------------------------------------------------- /docs/images/alpha_to_transmittance_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/alpha_to_transmittance_off.png -------------------------------------------------------------------------------- /docs/images/alpha_to_transmittance_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/alpha_to_transmittance_on.png -------------------------------------------------------------------------------- /docs/images/aspect_ratio_regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/aspect_ratio_regular.png -------------------------------------------------------------------------------- /docs/images/aspect_ratio_wonky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/aspect_ratio_wonky.png -------------------------------------------------------------------------------- /docs/images/bias_acne.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/bias_acne.png -------------------------------------------------------------------------------- /docs/images/bias_good.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/bias_good.png -------------------------------------------------------------------------------- /docs/images/bias_pan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/bias_pan.png -------------------------------------------------------------------------------- /docs/images/blender_addon_install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/blender_addon_install.png -------------------------------------------------------------------------------- /docs/images/blender_addon_install2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/blender_addon_install2.png -------------------------------------------------------------------------------- /docs/images/blender_enable_addon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/blender_enable_addon.png -------------------------------------------------------------------------------- /docs/images/blender_export_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/blender_export_menu.png -------------------------------------------------------------------------------- /docs/images/blender_export_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/blender_export_settings.png -------------------------------------------------------------------------------- /docs/images/blender_preferences.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/blender_preferences.png -------------------------------------------------------------------------------- /docs/images/cornell100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/cornell100.png -------------------------------------------------------------------------------- /docs/images/cornell100rr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/cornell100rr.png -------------------------------------------------------------------------------- /docs/images/cornell100rr2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/cornell100rr2.png -------------------------------------------------------------------------------- /docs/images/cornell3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/cornell3.png -------------------------------------------------------------------------------- /docs/images/cornell8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/cornell8.png -------------------------------------------------------------------------------- /docs/images/cornell_box_ds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/cornell_box_ds.png -------------------------------------------------------------------------------- /docs/images/cornell_box_ss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/cornell_box_ss.png -------------------------------------------------------------------------------- /docs/images/default_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/default_one.png -------------------------------------------------------------------------------- /docs/images/default_zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/default_zero.png -------------------------------------------------------------------------------- /docs/images/denoiser_none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/denoiser_none.png -------------------------------------------------------------------------------- /docs/images/denoiser_svgf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/denoiser_svgf.png -------------------------------------------------------------------------------- /docs/images/depth_of_field.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/depth_of_field.png -------------------------------------------------------------------------------- /docs/images/direct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/direct.png -------------------------------------------------------------------------------- /docs/images/distance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/distance.png -------------------------------------------------------------------------------- /docs/images/dshgi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/dshgi.png -------------------------------------------------------------------------------- /docs/images/dshgi_msaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/dshgi_msaa.png -------------------------------------------------------------------------------- /docs/images/dshgi_noaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/dshgi_noaa.png -------------------------------------------------------------------------------- /docs/images/dshgi_ssaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/dshgi_ssaa.png -------------------------------------------------------------------------------- /docs/images/dshgi_taa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/dshgi_taa.png -------------------------------------------------------------------------------- /docs/images/envmap_sampled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/envmap_sampled.png -------------------------------------------------------------------------------- /docs/images/envmap_unsampled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/envmap_unsampled.png -------------------------------------------------------------------------------- /docs/images/envmap_with.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/envmap_with.png -------------------------------------------------------------------------------- /docs/images/envmap_without.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/envmap_without.png -------------------------------------------------------------------------------- /docs/images/exposure_0_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/exposure_0_5.png -------------------------------------------------------------------------------- /docs/images/exposure_2_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/exposure_2_0.png -------------------------------------------------------------------------------- /docs/images/fireflies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/fireflies.png -------------------------------------------------------------------------------- /docs/images/fireflies_clamped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/fireflies_clamped.png -------------------------------------------------------------------------------- /docs/images/fireflies_regularized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/fireflies_regularized.png -------------------------------------------------------------------------------- /docs/images/fov_30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/fov_30.png -------------------------------------------------------------------------------- /docs/images/fov_40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/fov_40.png -------------------------------------------------------------------------------- /docs/images/fov_40_hide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/fov_40_hide.png -------------------------------------------------------------------------------- /docs/images/gamma_1_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/gamma_1_5.png -------------------------------------------------------------------------------- /docs/images/gamma_2_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/gamma_2_5.png -------------------------------------------------------------------------------- /docs/images/instance_id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/instance_id.png -------------------------------------------------------------------------------- /docs/images/nee_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/nee_off.png -------------------------------------------------------------------------------- /docs/images/nee_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/nee_on.png -------------------------------------------------------------------------------- /docs/images/path_tracer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/path_tracer.png -------------------------------------------------------------------------------- /docs/images/pcf0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pcf0.png -------------------------------------------------------------------------------- /docs/images/pcf1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pcf1.png -------------------------------------------------------------------------------- /docs/images/pcf64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pcf64.png -------------------------------------------------------------------------------- /docs/images/pcf8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pcf8.png -------------------------------------------------------------------------------- /docs/images/pcss0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pcss0.png -------------------------------------------------------------------------------- /docs/images/pcss1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pcss1.png -------------------------------------------------------------------------------- /docs/images/pcss32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pcss32.png -------------------------------------------------------------------------------- /docs/images/pcss8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pcss8.png -------------------------------------------------------------------------------- /docs/images/preset_accumulation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/preset_accumulation.png -------------------------------------------------------------------------------- /docs/images/preset_ddish-gi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/preset_ddish-gi.png -------------------------------------------------------------------------------- /docs/images/preset_denoised.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/preset_denoised.png -------------------------------------------------------------------------------- /docs/images/preset_direct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/preset_direct.png -------------------------------------------------------------------------------- /docs/images/preset_quality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/preset_quality.png -------------------------------------------------------------------------------- /docs/images/preset_reference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/preset_reference.png -------------------------------------------------------------------------------- /docs/images/preset_restir_hybrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/preset_restir_hybrid.png -------------------------------------------------------------------------------- /docs/images/proj_equirectangular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/proj_equirectangular.png -------------------------------------------------------------------------------- /docs/images/proj_ortho.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/proj_ortho.png -------------------------------------------------------------------------------- /docs/images/proj_perspective.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/proj_perspective.png -------------------------------------------------------------------------------- /docs/images/pt1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt1.png -------------------------------------------------------------------------------- /docs/images/pt1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt1024.png -------------------------------------------------------------------------------- /docs/images/pt16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt16.png -------------------------------------------------------------------------------- /docs/images/pt256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt256.png -------------------------------------------------------------------------------- /docs/images/pt4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt4.png -------------------------------------------------------------------------------- /docs/images/pt4096.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt4096.png -------------------------------------------------------------------------------- /docs/images/pt64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt64.png -------------------------------------------------------------------------------- /docs/images/pt_blackman_harris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt_blackman_harris.png -------------------------------------------------------------------------------- /docs/images/pt_blackman_harris4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt_blackman_harris4.png -------------------------------------------------------------------------------- /docs/images/pt_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt_box.png -------------------------------------------------------------------------------- /docs/images/pt_point.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/pt_point.png -------------------------------------------------------------------------------- /docs/images/raster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/raster.png -------------------------------------------------------------------------------- /docs/images/raster_blue_ambient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/raster_blue_ambient.png -------------------------------------------------------------------------------- /docs/images/raster_no_ambient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/raster_no_ambient.png -------------------------------------------------------------------------------- /docs/images/restir-hybrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/restir-hybrid.png -------------------------------------------------------------------------------- /docs/images/restir-overconfident.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/restir-overconfident.png -------------------------------------------------------------------------------- /docs/images/restir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/restir.png -------------------------------------------------------------------------------- /docs/images/sampler_sobol_owen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/sampler_sobol_owen.png -------------------------------------------------------------------------------- /docs/images/sampler_sobol_z2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/sampler_sobol_z2.png -------------------------------------------------------------------------------- /docs/images/sampler_sobol_z3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/sampler_sobol_z3.png -------------------------------------------------------------------------------- /docs/images/sampler_uniform_random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/sampler_uniform_random.png -------------------------------------------------------------------------------- /docs/images/screen_motion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/screen_motion.png -------------------------------------------------------------------------------- /docs/images/sh_l2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/sh_l2.png -------------------------------------------------------------------------------- /docs/images/sh_l2_vis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/sh_l2_vis.png -------------------------------------------------------------------------------- /docs/images/sh_l4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/sh_l4.png -------------------------------------------------------------------------------- /docs/images/shadow1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/shadow1024.png -------------------------------------------------------------------------------- /docs/images/shadow256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/shadow256.png -------------------------------------------------------------------------------- /docs/images/shadow4096.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/shadow4096.png -------------------------------------------------------------------------------- /docs/images/tauray_interactive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/tauray_interactive.png -------------------------------------------------------------------------------- /docs/images/tauray_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/tauray_logo.png -------------------------------------------------------------------------------- /docs/images/teapot_sponza.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/teapot_sponza.png -------------------------------------------------------------------------------- /docs/images/tonemap_filmic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/tonemap_filmic.png -------------------------------------------------------------------------------- /docs/images/tonemap_gamma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/tonemap_gamma.png -------------------------------------------------------------------------------- /docs/images/tonemap_linear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/tonemap_linear.png -------------------------------------------------------------------------------- /docs/images/tonemap_reinhard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/tonemap_reinhard.png -------------------------------------------------------------------------------- /docs/images/tonemap_reinhardl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/tonemap_reinhardl.png -------------------------------------------------------------------------------- /docs/images/view_motion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/view_motion.png -------------------------------------------------------------------------------- /docs/images/view_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/view_normal.png -------------------------------------------------------------------------------- /docs/images/view_pos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/view_pos.png -------------------------------------------------------------------------------- /docs/images/vsync_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/vsync_off.png -------------------------------------------------------------------------------- /docs/images/vsync_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/vsync_on.png -------------------------------------------------------------------------------- /docs/images/white_albedo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/white_albedo.png -------------------------------------------------------------------------------- /docs/images/whitted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/whitted.png -------------------------------------------------------------------------------- /docs/images/world_motion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/world_motion.png -------------------------------------------------------------------------------- /docs/images/world_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/world_normal.png -------------------------------------------------------------------------------- /docs/images/world_pos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/images/world_pos.png -------------------------------------------------------------------------------- /docs/notes-1.0.txt: -------------------------------------------------------------------------------- 1 | Tauray v1.0 release 2 | --------------------- 3 | 4 | Tauray is a real-time rendering framework, with a focus on distributed 5 | computing, scalability, portability and low latency. It uses C++17 and Vulkan, 6 | primarily relying on the cross-vendor ray tracing extensions, but comes with a 7 | fallback rasterization mode that can be used on devices that do not have that 8 | extension. 9 | 10 | Tauray development is led by the [VGA research group](https://webpages.tuni.fi/vga/) 11 | in Tampere University. The project is described in a conference publication ([DOI link](https://doi.org/10.1145/3550340.3564225)), 12 | which includes performance benchmarks and more information on Tauray. 13 | [A pre-print is available.](https://webpages.tuni.fi/vga/publications/Tauray2022.pdf) 14 | 15 | Release Highlights 16 | ------------------ 17 | 18 | * Initial release in the state it was used in the conference publication 19 | * Headless rendering for dataset generation 20 | * Real-time rendering for interactive viewing 21 | * Path tracing renderer 22 | * Real-time Looking Glass Portrait display support 23 | * OpenXR support for VR rendering 24 | * Denoising filters (BMFR, SVGF) 25 | * Multi-GPU support (Linux only) 26 | * DDISH-GI renderer (client + server supported) 27 | 28 | Acknowledgements 29 | ---------------- 30 | 31 | This work was supported by European Union’s Horizon 2020 research and innovation 32 | programme under Grant Agreement No 871738 (CPSoSaware) and by the Academy of 33 | Finland under Grant 325530. 34 | -------------------------------------------------------------------------------- /docs/tauray_user_manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/docs/tauray_user_manual.pdf -------------------------------------------------------------------------------- /external/stb_image.c: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #include "stb_image.h" 3 | 4 | #define STB_IMAGE_WRITE_IMPLEMENTATION 5 | #include "stb_image_write.h" 6 | -------------------------------------------------------------------------------- /external/tiny_gltf.cc: -------------------------------------------------------------------------------- 1 | #define TINYGLTF_IMPLEMENTATION 2 | #define TINYGLTF_NO_STB_IMAGE_WRITE 3 | #include "tiny_gltf.h" 4 | -------------------------------------------------------------------------------- /external/tinyexr.cc: -------------------------------------------------------------------------------- 1 | #if defined(_WIN32) 2 | #ifndef NOMINMAX 3 | #define NOMINMAX 4 | #endif 5 | #endif 6 | 7 | #define TINYEXR_IMPLEMENTATION 8 | #define TINYEXR_USE_THREAD 1 9 | #include "tinyexr.h" 10 | -------------------------------------------------------------------------------- /external/tinyply.cc: -------------------------------------------------------------------------------- 1 | #define TINYPLY_IMPLEMENTATION 2 | #include "tinyply.h" 3 | -------------------------------------------------------------------------------- /external/vk_mem_alloc.cc: -------------------------------------------------------------------------------- 1 | #define VMA_IMPLEMENTATION 2 | #include "vk_mem_alloc.h" 3 | -------------------------------------------------------------------------------- /shader/alias_table.glsl: -------------------------------------------------------------------------------- 1 | #ifndef ALIAS_TABLE_GLSL 2 | #define ALIAS_TABLE_GLSL 3 | 4 | #include "math.glsl" 5 | 6 | // Based on CC0 code from https://gist.github.com/juliusikkala/6c8c186f0150fe877a55cee4d266b1b0 7 | struct alias_table_entry 8 | { 9 | uint alias_id; 10 | uint probability; 11 | float pdf; 12 | float alias_pdf; 13 | }; 14 | 15 | float latlong_texel_solid_angle(ivec2 p, ivec2 size) 16 | { 17 | float y0 = float(p.y) / size.y; 18 | float y1 = float(p.y+1) / size.y; 19 | return 2.0f * M_PI * (cos(M_PI * y0) - cos(M_PI * y1)) / float(size.x); 20 | } 21 | 22 | int latlong_direction_to_pixel_id(vec3 dir, ivec2 size) 23 | { 24 | vec2 uv = vec2(atan(dir.z, dir.x) * 0.5f, asin(-dir.y)) / M_PI + 0.5f; 25 | ivec2 p = ivec2(uv * size + 0.5f); 26 | return p.x + p.y * size.x; 27 | } 28 | 29 | vec3 uv_to_latlong_direction(vec2 uv) 30 | { 31 | uv = (uv - 0.5f) * M_PI; 32 | vec3 dir = vec3(cos(2.0f * uv.x), -sin(uv.y), sin(2.0f * uv.x)); 33 | dir.xz *= sqrt(1 - dir.y*dir.y); 34 | return dir; 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /shader/alias_table_importance.comp: -------------------------------------------------------------------------------- 1 | // Based on CC0 code from https://gist.github.com/juliusikkala/6c8c186f0150fe877a55cee4d266b1b0 2 | #version 460 3 | #extension GL_EXT_scalar_block_layout : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | 6 | #include "alias_table.glsl" 7 | 8 | layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; 9 | 10 | layout(binding = 0) uniform sampler2D environment; 11 | layout(binding = 1, scalar) writeonly buffer importance_buffer 12 | { 13 | float array[]; 14 | } importances; 15 | 16 | void main() 17 | { 18 | ivec2 size = textureSize(environment, 0).xy; 19 | ivec2 p = ivec2(gl_GlobalInvocationID.xy); 20 | if(p.x < size.x && p.y < size.y) 21 | { 22 | int pixel_id = p.x + p.y * size.x; 23 | vec3 color = texelFetch(environment, p, 0).rgb; 24 | float importance = dot(color, vec3(0.2126, 0.7152, 0.0722)); // luminance 25 | importance *= latlong_texel_solid_angle(p.xy, size); 26 | importances.array[pixel_id] = importance; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /shader/array_reorder.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | layout(local_size_x = 256) in; 3 | 4 | layout(binding = 0) readonly buffer input_buffer 5 | { 6 | uint entries[]; 7 | } input_data; 8 | 9 | layout(binding = 1) writeonly buffer output_buffer 10 | { 11 | uint entries[]; 12 | } output_data; 13 | 14 | layout(binding = 2) readonly buffer keyval_buffer 15 | { 16 | uvec2 entries[]; 17 | } keyval_data; 18 | 19 | layout(push_constant) uniform push_constant_buffer 20 | { 21 | uint item_size; 22 | uint item_count; 23 | } control; 24 | 25 | void main() 26 | { 27 | uint output_item_index = gl_GlobalInvocationID.x / control.item_size; 28 | uint uint_index = gl_GlobalInvocationID.x % control.item_size; 29 | 30 | if(output_item_index < control.item_count) 31 | { 32 | uint input_item_index = keyval_data.entries[output_item_index].x; 33 | output_data.entries[gl_GlobalInvocationID.x] = input_data.entries[ 34 | input_item_index * control.item_size + uint_index 35 | ]; 36 | } 37 | } 38 | 39 | -------------------------------------------------------------------------------- /shader/bmfr.glsl: -------------------------------------------------------------------------------- 1 | #ifndef BMFR_GLSL 2 | #define BMFR_GLSL 3 | #define BLOCK_SIZE 32 4 | #define LOCAL_SIZE 16 5 | #define BLOCK_EDGE_LENGTH 32 6 | #define BLOCK_PIXELS (BLOCK_EDGE_LENGTH * BLOCK_EDGE_LENGTH) 7 | #define FEATURE_COUNT 10 8 | 9 | #define BLOCK_OFFSETS_COUNT 16u 10 | ivec2 BLOCK_OFFSETS[BLOCK_OFFSETS_COUNT] = ivec2[]( 11 | ivec2( -14, -14 ), 12 | ivec2( 4, -6 ), 13 | ivec2( -8, 14 ), 14 | ivec2( 8, 0 ), 15 | ivec2( -10, -8 ), 16 | ivec2( 2, 12 ), 17 | ivec2( 12, -12 ), 18 | ivec2( -10, 0 ), 19 | ivec2( 12, 14 ), 20 | ivec2( -8, -16 ), 21 | ivec2( 6, 6 ), 22 | ivec2( -2, -2 ), 23 | ivec2( 6, -14 ), 24 | ivec2( -16, 12 ), 25 | ivec2( 14, -4 ), 26 | ivec2( -6, 4 ) 27 | ); 28 | 29 | layout(push_constant) uniform push_constant_buffer 30 | { 31 | ivec2 workset_size; // x and y block counts 32 | ivec2 size; 33 | } control; 34 | 35 | float scale(float value, float min, float max) 36 | { 37 | if (abs(max - min) > 1.0) 38 | { 39 | return (value - min) / (max - min); 40 | } 41 | return value - min; 42 | } 43 | 44 | #endif -------------------------------------------------------------------------------- /shader/color.glsl: -------------------------------------------------------------------------------- 1 | #ifndef COLOR_GLSL 2 | #define COLOR_GLSL 3 | 4 | // As described in 5 | // https://en.wikipedia.org/wiki/SRGB#Specification_of_the_transformation, 6 | // but branchless and SIMD-optimized. 7 | vec3 inverse_srgb_correction(vec3 col) 8 | { 9 | vec3 low = col * 0.07739938f; 10 | vec3 high = pow(fma(col, vec3(0.94786729f), vec3(0.05213270f)), vec3(2.4f)); 11 | return mix(low, high, lessThan(vec3(0.04045f), col)); 12 | } 13 | 14 | float rgb_to_luminance(vec3 col) 15 | { 16 | return dot(col, vec3(0.2126, 0.7152, 0.0722)); 17 | } 18 | 19 | uint rgb_to_r9g9b9e5(vec3 color) 20 | { 21 | ivec3 ex; 22 | frexp(color, ex); 23 | int e = clamp(max(ex.r, max(ex.g, ex.b)), -16, 15); 24 | ivec3 icolor = clamp(ivec3( 25 | floor(color * exp2(-e) * 512.0f) 26 | ), ivec3(0), ivec3(511)); 27 | return icolor.r|(icolor.g<<9)|(icolor.b<<18)|((e+16)<<27); 28 | } 29 | 30 | vec3 r9g9b9e5_to_rgb(uint rgbe) 31 | { 32 | ivec4 icolor = ivec4(rgbe, rgbe>>9, rgbe>>18, rgbe>>27) & 0x1FF; 33 | return vec3(icolor) * (1.0f / 512.0f) * exp2(icolor.a-16); 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /shader/envmap.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_multiview : enable 4 | 5 | #define SCENE_SET 0 6 | #include "scene.glsl" 7 | 8 | layout(location = 0) out vec4 out_color; 9 | 10 | layout(push_constant) uniform push_constant_buffer 11 | { 12 | vec4 environment_factor; 13 | vec2 screen_size; 14 | int environment_proj; 15 | int base_camera_index; 16 | } control; 17 | 18 | void main() 19 | { 20 | vec3 origin; 21 | vec3 view_dir; 22 | get_camera_ray( 23 | camera.pairs[control.base_camera_index+gl_ViewIndex].current, 24 | vec2( 25 | gl_FragCoord.x, 26 | control.screen_size.y - gl_FragCoord.y 27 | ), 28 | control.screen_size, 29 | vec2(0), 30 | origin, 31 | view_dir 32 | ); 33 | 34 | out_color = control.environment_factor; 35 | 36 | if(control.environment_proj >= 0) 37 | { 38 | vec3 view = normalize(view_dir); 39 | vec2 uv = vec2(0); 40 | uv.y = asin(-view.y)/3.141592+0.5f; 41 | uv.x = atan(view.z, view.x)/(2*3.141592)+0.5f; 42 | out_color *= vec4(texture(environment_map_tex, uv).rgb, 1.0f); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /shader/envmap.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | vec2 pos[6] = vec2[]( 4 | vec2(1, -1), vec2(1, 1), vec2(-1, 1), vec2(-1, 1), vec2(-1, -1), vec2(1, -1) 5 | ); 6 | 7 | void main() 8 | { 9 | vec2 p = pos[gl_VertexIndex]; 10 | gl_Position = vec4(p, 0.0f, 1.0f); 11 | } 12 | -------------------------------------------------------------------------------- /shader/extract_tri_lights.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_scalar_block_layout : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | #extension GL_EXT_nonuniform_qualifier : enable 5 | 6 | #define SCENE_SET 0 7 | #include "scene.glsl" 8 | 9 | layout(local_size_x = 256) in; 10 | 11 | layout(push_constant, scalar) uniform push_constant_buffer 12 | { 13 | uint triangle_count; 14 | uint instance_id; 15 | } control; 16 | 17 | void main() 18 | { 19 | uint input_index = gl_GlobalInvocationID.x; 20 | if(input_index < control.triangle_count) 21 | { 22 | instance o = instances.o[control.instance_id]; 23 | 24 | uint output_index = o.light_base_id + gl_GlobalInvocationID.x; 25 | tri_light light; 26 | light.emission_tex_id = o.mat.emission_tex_id; 27 | light.emission_factor = rgb_to_r9g9b9e5(o.mat.emission_factor.rgb); 28 | light.instance_id = control.instance_id; 29 | light.primitive_id = gl_GlobalInvocationID.x; 30 | 31 | ivec3 i = ivec3( 32 | indices[nonuniformEXT(control.instance_id)].i[3*input_index+0], 33 | indices[nonuniformEXT(control.instance_id)].i[3*input_index+1], 34 | indices[nonuniformEXT(control.instance_id)].i[3*input_index+2] 35 | ); 36 | vertex v0 = vertices[nonuniformEXT(control.instance_id)].v[i.x]; 37 | vertex v1 = vertices[nonuniformEXT(control.instance_id)].v[i.y]; 38 | vertex v2 = vertices[nonuniformEXT(control.instance_id)].v[i.z]; 39 | #ifdef PRE_TRANSFORMED_VERTICES 40 | light.pos[0] = v0.pos; 41 | light.pos[1] = v1.pos; 42 | light.pos[2] = v2.pos; 43 | #else 44 | light.pos[0] = (o.model * vec4(v0.pos, 1)).xyz; 45 | light.pos[1] = (o.model * vec4(v1.pos, 1)).xyz; 46 | light.pos[2] = (o.model * vec4(v2.pos, 1)).xyz; 47 | #endif 48 | light.uv[0] = packHalf2x16(v0.uv); 49 | light.uv[1] = packHalf2x16(v1.uv); 50 | light.uv[2] = packHalf2x16(v2.uv); 51 | 52 | tri_lights.lights[output_index] = light; 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /shader/forward.glsl: -------------------------------------------------------------------------------- 1 | #ifndef FORWARD_GLSL 2 | #define FORWARD_GLSL 3 | #define USE_SHADOW_MAPPING 4 | #define SCENE_SET 0 5 | #define SCENE_RASTER_SET 1 6 | #include "scene_raster.glsl" 7 | 8 | layout(push_constant) uniform push_constant_buffer 9 | { 10 | ivec2 size; 11 | uint instance_id; 12 | int base_camera_index; 13 | int frame_index; 14 | int flipped_winding_order; 15 | int has_prev_pos_data; 16 | int pad[1]; 17 | shadow_mapping_parameters sm_params; 18 | vec3 ambient_color; 19 | } control; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /shader/forward.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_EXT_scalar_block_layout : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | #extension GL_EXT_multiview : enable 6 | 7 | #define CALC_PREV_VERTEX_POS 8 | #include "forward.glsl" 9 | 10 | layout(location = 0) in vec3 in_pos; 11 | layout(location = 1) in vec3 in_normal; 12 | layout(location = 2) in vec2 in_uv; 13 | layout(location = 3) in vec4 in_tangent; 14 | 15 | layout(location = 4) in vec3 in_prev_pos; 16 | 17 | layout(location = 0) out vec3 out_pos; 18 | layout(location = 1) out vec3 out_prev_pos; 19 | layout(location = 2) out vec3 out_normal; 20 | layout(location = 3) out vec2 out_uv; 21 | layout(location = 4) out vec3 out_tangent; 22 | layout(location = 5) out vec3 out_bitangent; 23 | 24 | void main() 25 | { 26 | instance o = instances.o[control.instance_id]; 27 | out_pos = vec3(o.model * vec4(in_pos, 1.0f)); 28 | out_prev_pos = vec3(o.model_prev * vec4(control.has_prev_pos_data != 0 ? in_prev_pos : in_pos, 1.0f)); 29 | gl_Position = camera.pairs[control.base_camera_index + gl_ViewIndex].current.view_proj * vec4(out_pos, 1.0f); 30 | out_normal = normalize(mat3(o.model_normal) * in_normal); 31 | out_tangent = normalize(mat3(o.model_normal) * in_tangent.xyz); 32 | out_bitangent = (cross(out_normal, out_tangent) * in_tangent.w); 33 | 34 | out_uv = in_uv; 35 | } 36 | -------------------------------------------------------------------------------- /shader/looking_glass_composition.comp: -------------------------------------------------------------------------------- 1 | 2 | #version 460 3 | 4 | layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; 5 | 6 | layout(binding = 0) uniform sampler2DArray in_color; 7 | layout(binding = 1, rgba8) uniform writeonly image2D out_color; 8 | 9 | layout(push_constant) uniform push_constant_buffer 10 | { 11 | vec4 calibration_info; 12 | uvec2 output_size; 13 | uvec2 viewport_size; 14 | uint viewport_count; 15 | } control; 16 | 17 | vec3 sample_viewport(vec2 uv, int viewport_index) 18 | { 19 | return texture(in_color, vec3(uv.x, 1.0-uv.y, viewport_index)).rgb; 20 | } 21 | 22 | void main() 23 | { 24 | uvec2 p = gl_GlobalInvocationID.xy; 25 | 26 | if(any(greaterThanEqual(p, control.output_size))) 27 | return; 28 | 29 | vec2 uv = (vec2(p)+0.5f)/vec2(control.output_size); 30 | uv.y = 1.0f - uv.y; 31 | vec3 color = vec3(0); 32 | for(int channel = 0; channel < 3; ++channel) 33 | { 34 | float horizontal = fract(dot(vec4(uv, channel, 1.0f), control.calibration_info)); 35 | int viewport_index = clamp( 36 | int(floor(horizontal * control.viewport_count)), 0, int(control.viewport_count)-1 37 | ); 38 | color[channel] = sample_viewport(uv, viewport_index)[channel]; 39 | } 40 | 41 | imageStore(out_color, ivec2(p), vec4(color, 1.0f)); 42 | } 43 | -------------------------------------------------------------------------------- /shader/material.glsl: -------------------------------------------------------------------------------- 1 | #ifndef MATERIAL_GLSL 2 | #define MATERIAL_GLSL 3 | 4 | #define MATERIAL_FLAG_DOUBLE_SIDED (1<<0) 5 | // If set object or its material will not have any temporal consistency and may 6 | // require different handling in temporal algorithms. 7 | #define MATERIAL_FLAG_TRANSIENT (1<<1) 8 | 9 | struct material 10 | { 11 | vec4 albedo_factor; 12 | vec4 metallic_roughness_factor; 13 | vec4 emission_factor; 14 | float transmittance; 15 | float ior; 16 | float normal_factor; 17 | uint flags; 18 | int albedo_tex_id; 19 | int metallic_roughness_tex_id; 20 | int normal_tex_id; 21 | int emission_tex_id; 22 | }; 23 | 24 | struct sampled_material 25 | { 26 | vec4 albedo; 27 | float metallic; 28 | float roughness; 29 | vec3 emission; 30 | float transmittance; 31 | float ior_in; 32 | float ior_out; 33 | float f0; 34 | uint flags; 35 | float shadow_terminator_mul; 36 | }; 37 | 38 | #define MATERIAL_LOBE_REFLECTION 3 39 | #define MATERIAL_LOBE_TRANSMISSION 2 40 | #define MATERIAL_LOBE_DIFFUSE 1 41 | #define MATERIAL_LOBE_ALL 0 42 | 43 | // Stores the strength of each lobe. Initialize to zero before use! 44 | struct bsdf_lobes 45 | { 46 | float transmission; 47 | float diffuse; 48 | float dielectric_reflection; 49 | float metallic_reflection; 50 | }; 51 | 52 | vec3 modulate_bsdf(sampled_material mat, bsdf_lobes bsdf) 53 | { 54 | return mat.albedo.rgb * (bsdf.metallic_reflection + bsdf.transmission + bsdf.diffuse) + bsdf.dielectric_reflection; 55 | } 56 | 57 | vec3 modulate_color(sampled_material mat, vec3 diffuse, vec3 reflected) 58 | { 59 | float approx_fresnel = 0.02f; 60 | diffuse = diffuse * mat.albedo.rgb * (1-mat.metallic); 61 | reflected = reflected 62 | * mix(vec3(approx_fresnel), mat.albedo.rgb, mat.metallic) 63 | / mix(approx_fresnel, 1, mat.metallic); 64 | return diffuse + reflected; 65 | } 66 | 67 | void add_demodulated_color( 68 | bsdf_lobes primary_bsdf, vec3 light_color, 69 | inout vec3 diffuse, inout vec3 reflected 70 | ){ 71 | diffuse += light_color * (primary_bsdf.diffuse + primary_bsdf.transmission); 72 | reflected += light_color * (primary_bsdf.dielectric_reflection + primary_bsdf.metallic_reflection); 73 | } 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /shader/poisson_samples_2d.glsl: -------------------------------------------------------------------------------- 1 | #ifndef POISSON_SAMPLES_GLSL 2 | #define POISSON_SAMPLES_GLSL 3 | 4 | // 64 samples of 2D poisson disk distribution. 5 | // 6 | // TODO: This might be risky in terms of performance, as it is a quite large 7 | // constant array. Try out texture lookup and uniform buffer on relevant 8 | // platforms. 9 | const vec2 poisson_disk_samples[64] = vec2[]( 10 | vec2(-0.695065, -0.317671), vec2( 0.910942, 0.412491), 11 | vec2(-0.303778, 0.952665), vec2( 0.518187, -0.854809), 12 | vec2( 0.064410, 0.143302), vec2(-0.897262, 0.440243), 13 | vec2(-0.256688, -0.966451), vec2( 0.406177, 0.913495), 14 | vec2( 0.955344, -0.295435), vec2( 0.065461, -0.458306), 15 | vec2(-0.372877, 0.432738), vec2( 0.564884, 0.035607), 16 | vec2( 0.057368, 0.607356), vec2(-0.272403, -0.158090), 17 | vec2( 0.510804, -0.407973), vec2(-0.999315, 0.007125), 18 | vec2(-0.649618, -0.759558), vec2( 0.474175, 0.466568), 19 | vec2(-0.598217, 0.090578), vec2(-0.652515, 0.756754), 20 | vec2( 0.142136, -0.989197), vec2(-0.317785, -0.548586), 21 | vec2( 0.054322, 0.991461), vec2( 0.991411, 0.062224), 22 | vec2( 0.258940, -0.155479), vec2( 0.796365, -0.604791), 23 | vec2( 0.685861, 0.727529), vec2(-0.245210, 0.150298), 24 | vec2( 0.251747, -0.702386), vec2(-0.051031, -0.741023), 25 | vec2(-0.221569, 0.677006), vec2( 0.341205, 0.213390), 26 | vec2( 0.696124, -0.205655), vec2(-0.086215, 0.373800), 27 | vec2(-0.963839, -0.264658), vec2(-0.831231, -0.555220), 28 | vec2(-0.636080, 0.360776), vec2( 0.673304, 0.283633), 29 | vec2(-0.006615, -0.198311), vec2( 0.310994, 0.670550), 30 | vec2(-0.829011, 0.195663), vec2(-0.447090, -0.334952), 31 | vec2( 0.160887, 0.382701), vec2(-0.771199, -0.084460), 32 | vec2(-0.406718, -0.774974), vec2(-0.585245, -0.529782), 33 | vec2(-0.156756, -0.378295), vec2( 0.567336, -0.630606), 34 | vec2(-0.449549, 0.649124), vec2( 0.282586, -0.384085), 35 | vec2(-0.495726, -0.112737), vec2( 0.706657, 0.504904), 36 | vec2( 0.478992, -0.167310), vec2( 0.781413, -0.002990), 37 | vec2(-0.043730, 0.799185), vec2(-0.094402, -0.002422), 38 | vec2(-0.719609, 0.555853), vec2(-0.441099, 0.232549), 39 | vec2( 0.207514, 0.851013), vec2( 0.774662, -0.398131), 40 | vec2(-0.055589, -0.943590), vec2( 0.319790, -0.893468), 41 | vec2(-0.488119, 0.872496), vec2( 0.863541, 0.217313) 42 | ); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /shader/pre_transform.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_scalar_block_layout : enable 3 | #extension GL_GOOGLE_include_directive : enable 4 | #extension GL_EXT_nonuniform_qualifier : enable 5 | 6 | #include "scene.glsl" 7 | 8 | layout(local_size_x = 256) in; 9 | 10 | layout(binding = 0, set = 0, scalar) readonly buffer input_vertex_buffer 11 | { 12 | vertex v[]; 13 | } input_verts; 14 | 15 | layout(binding = 1, set = 0, scalar) writeonly buffer output_vertex_buffer 16 | { 17 | vertex v[]; 18 | } output_verts; 19 | 20 | layout(push_constant, scalar) uniform push_constant_buffer 21 | { 22 | uint vertex_count; 23 | uint instance_id; 24 | } control; 25 | 26 | void main() 27 | { 28 | uint i = gl_GlobalInvocationID.x; 29 | if(i < control.vertex_count) 30 | { 31 | instance o = instances.o[control.instance_id]; 32 | vertex v = input_verts.v[i]; 33 | v.pos = (o.model * vec4(v.pos, 1)).xyz; 34 | v.normal = normalize(mat3(o.model_normal) * v.normal); 35 | v.tangent = vec4(normalize(mat3(o.model_normal) * v.tangent.xyz), v.tangent.w); 36 | if(determinant(mat3(o.model_normal)) < 0) 37 | { 38 | v.normal = -v.normal; 39 | v.tangent = -v.tangent; 40 | } 41 | output_verts.v[i] = v; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /shader/projection.glsl: -------------------------------------------------------------------------------- 1 | #ifndef PROJECTION_GLSL 2 | #define PROJECTION_GLSL 3 | #include "math.glsl" 4 | 5 | vec3 unproject_position(float linear_depth, vec2 uv, vec4 projection_info, vec2 pan) 6 | { 7 | return vec3((0.5f-uv-0.5f*pan) * projection_info.zw * linear_depth, linear_depth); 8 | } 9 | 10 | vec2 project_position(vec3 pos, vec4 projection_info, vec2 pan) 11 | { 12 | return 0.5f - pos.xy / (projection_info.zw * pos.z) - 0.5f * pan; 13 | } 14 | 15 | // Note that this assumes that depth is -1 to 1, depth buffer has them at 0 to 16 | // 1. You can just do the usual *2-1 to it. 17 | float linearize_depth(float depth, vec4 proj_info) 18 | { 19 | return -2.0f * proj_info.x / (depth + proj_info.y); 20 | } 21 | 22 | vec4 linearize_depth(vec4 depth, vec4 proj_info) 23 | { 24 | return -2.0f * proj_info.x / (depth + proj_info.y); 25 | } 26 | 27 | float hyperbolic_depth(float linear_depth, vec4 proj_info) 28 | { 29 | return (-2.0f * proj_info.x - proj_info.y * linear_depth) / linear_depth; 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /shader/random_sampler.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RANDOM_SAMPLER_GLSL 2 | #define RANDOM_SAMPLER_GLSL 3 | 4 | #include "math.glsl" 5 | 6 | struct random_sampler 7 | { 8 | uvec4 seed; 9 | }; 10 | 11 | random_sampler init_random_sampler(uvec4 coord) 12 | { 13 | random_sampler rsampler; 14 | rsampler.seed = coord; 15 | rsampler.seed.y ^= pcg(rsampler.seed.x); 16 | rsampler.seed.z ^= pcg(rsampler.seed.y); 17 | rsampler.seed.w ^= pcg(rsampler.seed.z); 18 | return rsampler; 19 | } 20 | 21 | // Only the 4d version is performed, because fewer dimensioned use cases can 22 | // just take the first N values that they need and there should be almost no 23 | // extra cost due to SIMD stuff. 24 | // Returns 4 uncorrelated uniform random unsigned integers. 25 | uvec4 generate_uniform_random_uint(inout random_sampler rsampler) 26 | { 27 | return pcg4d(rsampler.seed); 28 | } 29 | 30 | vec4 generate_uniform_random(inout random_sampler rsampler) 31 | { 32 | return vec4(generate_uniform_random_uint(rsampler)) * INV_UINT32_MAX; 33 | } 34 | 35 | float generate_single_uniform_random(inout uint seed) 36 | { 37 | return float(pcg(seed)) * INV_UINT32_MAX; 38 | } 39 | 40 | vec4 generate_single_uniform_random(inout uvec4 seed) 41 | { 42 | return vec4(pcg4d(seed)) * INV_UINT32_MAX; 43 | } 44 | 45 | // Gives a random color, useful for debugging. 46 | vec3 debug_color(uvec4 param) 47 | { 48 | return vec3(pcg4d(param).xyz) * INV_UINT32_MAX; 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /shader/rt_common.rahit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_EXT_scalar_block_layout : enable 5 | #extension GL_GOOGLE_include_directive : enable 6 | 7 | hitAttributeEXT vec2 attribs; 8 | 9 | #include "rt.glsl" 10 | #include "random_sampler.glsl" 11 | 12 | #define PAYLOAD_IN 13 | #include "rt_common_payload.glsl" 14 | 15 | void main() 16 | { 17 | vec3 view = gl_WorldRayDirectionEXT; 18 | vec2 uv; 19 | int instance_id = gl_InstanceCustomIndexEXT + gl_GeometryIndexEXT; 20 | get_interpolated_vertex_light(view, attribs, instance_id, gl_PrimitiveID, uv); 21 | float alpha_cutoff = generate_single_uniform_random(payload.random_seed); 22 | if(is_material_skippable(instance_id, uv, alpha_cutoff)) 23 | ignoreIntersectionEXT; 24 | } 25 | 26 | -------------------------------------------------------------------------------- /shader/rt_common.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | hitAttributeEXT vec2 attribs; 6 | 7 | #define PAYLOAD_IN 8 | #include "rt_common_payload.glsl" 9 | 10 | void main() 11 | { 12 | payload.instance_id = gl_InstanceCustomIndexEXT + gl_GeometryIndexEXT; 13 | payload.primitive_id = gl_PrimitiveID; 14 | payload.barycentrics = attribs; 15 | } 16 | -------------------------------------------------------------------------------- /shader/rt_common.rmiss: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #define PAYLOAD_IN 6 | #include "rt_common_payload.glsl" 7 | 8 | void main() 9 | { 10 | payload.instance_id = -1; 11 | payload.primitive_id = -1; 12 | } 13 | -------------------------------------------------------------------------------- /shader/rt_common_payload.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RT_COMMON_PAYLOAD_GLSL 2 | #define RT_COMMON_PAYLOAD_GLSL 3 | 4 | struct hit_payload 5 | { 6 | // Needed by anyhit alpha handling. 7 | uint random_seed; 8 | 9 | // Negative if the ray escaped the scene or otherwise died. Otherwise, it's 10 | // the index of the mesh instance, and primitive_id and barycentrics are 11 | // valid as well. 12 | int instance_id; 13 | // If instance_id is non-negative, this is the triangle index. Otherwise, 14 | // if primitive_id is non-negative, it is the light index. If it is negative, 15 | // that means that the ray escaped the scene and hit the environment map 16 | // instead. 17 | int primitive_id; 18 | 19 | // Barycentric coordinates to the triangle that was hit. 20 | vec2 barycentrics; 21 | }; 22 | 23 | #ifdef PAYLOAD_IN 24 | layout(location = 0) rayPayloadInEXT hit_payload payload; 25 | layout(location = 1) rayPayloadInEXT float shadow_visibility; 26 | #else 27 | layout(location = 0) rayPayloadEXT hit_payload payload; 28 | layout(location = 1) rayPayloadEXT float shadow_visibility; 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /shader/rt_common_point_light.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | hitAttributeEXT vec2 attribs; 6 | 7 | #define PAYLOAD_IN 8 | #include "rt_common_payload.glsl" 9 | 10 | void main() 11 | { 12 | payload.instance_id = -1; 13 | payload.primitive_id = gl_PrimitiveID; 14 | payload.barycentrics.x = gl_HitTEXT; 15 | } 16 | -------------------------------------------------------------------------------- /shader/rt_common_point_light.rint: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_EXT_scalar_block_layout : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | #extension GL_EXT_nonuniform_qualifier : enable 6 | 7 | #include "rt_common.glsl" 8 | 9 | hitAttributeEXT vec3 attribs; 10 | 11 | void main() 12 | { 13 | point_light pl = point_lights.lights[gl_PrimitiveID]; 14 | float hit = get_point_light_hit_t(pl, gl_WorldRayOriginEXT, gl_WorldRayDirectionEXT); 15 | if(hit > 0) 16 | reportIntersectionEXT(hit, 0); 17 | } 18 | -------------------------------------------------------------------------------- /shader/rt_common_shadow.rahit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_EXT_scalar_block_layout : enable 5 | #extension GL_GOOGLE_include_directive : enable 6 | 7 | hitAttributeEXT vec2 attribs; 8 | 9 | #include "rt.glsl" 10 | #include "ggx.glsl" 11 | 12 | #define PAYLOAD_IN 13 | #include "rt_common_payload.glsl" 14 | 15 | void main() 16 | { 17 | vec3 view = gl_WorldRayDirectionEXT; 18 | int instance_id = gl_InstanceCustomIndexEXT + gl_GeometryIndexEXT; 19 | material mat = instances.o[instance_id].mat; 20 | 21 | vec2 uv; 22 | get_interpolated_vertex_light(view, attribs, instance_id, gl_PrimitiveID, uv); 23 | 24 | float alpha = mat.albedo_factor.a; 25 | if(mat.albedo_tex_id >= 0) 26 | alpha *= texture(textures[nonuniformEXT(mat.albedo_tex_id)], uv).a; 27 | 28 | shadow_visibility *= 1.0f-alpha; 29 | if(shadow_visibility == 0.0f) terminateRayEXT; 30 | else ignoreIntersectionEXT; 31 | } 32 | -------------------------------------------------------------------------------- /shader/rt_common_shadow.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #define PAYLOAD_IN 6 | #include "rt_common_payload.glsl" 7 | 8 | void main() 9 | { 10 | // If we're here, we hit an opaque object that didn't go to the any hit 11 | // shader. 12 | shadow_visibility = 0.0f; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /shader/rt_common_shadow.rmiss: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #define PAYLOAD_IN 6 | #include "rt_common_payload.glsl" 7 | 8 | void main() {} 9 | -------------------------------------------------------------------------------- /shader/rt_feature.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RT_FEATURE_GLSL 2 | #define RT_FEATURE_GLSL 3 | #include "rt.glsl" 4 | 5 | struct hit_payload 6 | { 7 | vec4 data; 8 | }; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /shader/rt_feature.rahit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_EXT_scalar_block_layout : enable 5 | #extension GL_GOOGLE_include_directive : enable 6 | 7 | hitAttributeEXT vec2 attribs; 8 | 9 | #include "rt.glsl" 10 | 11 | void main() 12 | { 13 | vec3 view = gl_WorldRayDirectionEXT; 14 | vec2 uv; 15 | int instance_id = gl_InstanceCustomIndexEXT + gl_GeometryIndexEXT; 16 | get_interpolated_vertex_light(view, attribs, instance_id, gl_PrimitiveID, uv); 17 | if(is_material_skippable(instance_id, uv, 0.0001f)) 18 | ignoreIntersectionEXT; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /shader/rt_feature.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_EXT_scalar_block_layout : enable 5 | #extension GL_GOOGLE_include_directive : enable 6 | 7 | hitAttributeEXT vec2 attribs; 8 | 9 | #define CALC_PREV_VERTEX_POS 10 | #define DISTRIBUTION_DATA_BINDING 0 11 | #include "rt_feature.glsl" 12 | 13 | layout(location = 0) rayPayloadInEXT hit_payload payload; 14 | 15 | void main() 16 | { 17 | vec3 view = gl_WorldRayDirectionEXT; 18 | int instance_id = gl_InstanceCustomIndexEXT + gl_GeometryIndexEXT; 19 | vertex_data v = get_interpolated_vertex(view, attribs, instance_id, gl_PrimitiveID); 20 | 21 | sampled_material mat = sample_material(instance_id, v); 22 | const camera_data cam = get_camera(); 23 | const camera_data prev_cam = get_prev_camera(); 24 | 25 | payload.data = FEATURE; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /shader/rt_feature.rgen: -------------------------------------------------------------------------------- 1 | #version 460 2 | #line 3 3 | #extension GL_EXT_ray_tracing : require 4 | #extension GL_GOOGLE_include_directive : enable 5 | 6 | #define DISTRIBUTION_DATA_BINDING 0 7 | #define COLOR_TARGET_BINDING 1 8 | #include "rt_feature.glsl" 9 | 10 | layout(location = 0) rayPayloadEXT hit_payload payload; 11 | 12 | layout(push_constant) uniform push_constant_buffer 13 | { 14 | vec4 default_value; 15 | float min_ray_dist; 16 | } control; 17 | 18 | void main() 19 | { 20 | const camera_data cam = get_camera(); 21 | vec3 origin; 22 | vec3 dir; 23 | get_screen_camera_ray(cam, vec2(0), origin, dir); 24 | 25 | payload.data = control.default_value; 26 | 27 | traceRayEXT( 28 | tlas, 29 | gl_RayFlagsNoneEXT, 30 | 0xFF, 31 | 0, 32 | 0, 33 | 0, 34 | cam.origin.xyz, 35 | control.min_ray_dist, 36 | dir, 37 | RAY_MAX_DIST, 38 | 0 39 | ); 40 | 41 | ivec3 write_pos = ivec3(get_write_pixel_pos(cam)); 42 | #if DISTRIBUTION_STRATEGY != 0 43 | if(write_pos == ivec3(-1)) 44 | return; 45 | #endif 46 | write_gbuffer_color(payload.data, write_pos); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /shader/rt_feature.rmiss: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | void main() { } 6 | 7 | -------------------------------------------------------------------------------- /shader/sampling.glsl: -------------------------------------------------------------------------------- 1 | #ifndef SAMPLING_GLSL 2 | #define SAMPLING_GLSL 3 | #include "math.glsl" 4 | 5 | #include "random_sampler.glsl" 6 | #include "sobol_z_sampler.glsl" 7 | #include "sobol_owen_sampler.glsl" 8 | 9 | 10 | struct local_sampler 11 | { 12 | random_sampler rs; 13 | #if defined(USE_SOBOL_Z_ORDER_SAMPLING) 14 | sobol_z_sampler ss; 15 | #elif defined(USE_SOBOL_OWEN_SAMPLING) 16 | sobol_owen_sampler ss; 17 | #endif 18 | }; 19 | 20 | #ifdef SAMPLING_DATA_BINDING 21 | layout(binding = SAMPLING_DATA_BINDING, set = 0) uniform sampling_data_buffer 22 | { 23 | uint sample_counter; 24 | uint rng_seed; 25 | } sampling_data; 26 | 27 | // coord.xy = pixel screen coordinate 28 | // coord.z = viewport index 29 | // coord.w = time/path index 30 | // size.xy = screen size (width/height) 31 | // size.z = total viewport count 32 | local_sampler init_local_sampler(uvec4 coord) 33 | { 34 | local_sampler ls; 35 | coord.w += sampling_data.sample_counter; 36 | coord.z += sampling_data.rng_seed; 37 | 38 | #if defined(USE_SOBOL_Z_ORDER_SAMPLING) 39 | ls.ss = init_sobol_z_sampler(coord); 40 | #elif defined(USE_SOBOL_OWEN_SAMPLING) 41 | ls.ss = init_sobol_owen_sampler(coord); 42 | #endif 43 | ls.rs = init_random_sampler(coord); 44 | return ls; 45 | } 46 | #endif 47 | 48 | float generate_alpha_sample(inout local_sampler ls) 49 | { 50 | return generate_uniform_random(ls.rs).x; 51 | } 52 | 53 | vec2 generate_film_sample(inout local_sampler ls) 54 | { 55 | return generate_uniform_random(ls.rs).xy; 56 | } 57 | 58 | vec3 generate_spatial_sample(inout local_sampler ls) 59 | { 60 | return generate_uniform_random(ls.rs).xyz; 61 | } 62 | 63 | // Generates a 2D sample in xy, 1D samples in z and w. This sampler is only 64 | // called once per bounce, so you can safely employ stratification or some 65 | // other scheme, as long as you take bounce_index into account. 66 | uvec4 generate_ray_sample_uint(inout local_sampler ls, uint bounce_index) 67 | { 68 | #if defined(USE_SOBOL_Z_ORDER_SAMPLING) 69 | return get_sobol_z_sample_uint(ls.ss, bounce_index); 70 | #elif defined(USE_SOBOL_OWEN_SAMPLING) 71 | return get_shuffled_scrambled_sobol_pt_uint(ls.ss, bounce_index); 72 | #else 73 | return generate_uniform_random_uint(ls.rs); 74 | #endif 75 | } 76 | 77 | vec4 generate_ray_sample(inout local_sampler ls, uint bounce_index) 78 | { 79 | return vec4(generate_ray_sample_uint(ls, bounce_index)) * INV_UINT32_MAX; 80 | } 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /shader/scene_raster.glsl: -------------------------------------------------------------------------------- 1 | #ifndef SCENE_RASTER_GLSL 2 | #define SCENE_RASTER_GLSL 3 | #include "scene.glsl" 4 | 5 | #ifndef SCENE_RASTER_SET 6 | #define SCENE_RASTER_SET 2 7 | #endif 8 | 9 | layout(binding = 0, set = SCENE_RASTER_SET) uniform sampler3D sh_grid_data[]; 10 | 11 | struct sh_grid 12 | { 13 | mat4 pos_from_world; 14 | mat4 normal_from_world; 15 | vec3 grid_clamp; 16 | float pad0; 17 | vec3 grid_resolution; 18 | float pad1; 19 | }; 20 | 21 | layout(binding = 1, set = SCENE_RASTER_SET, scalar) buffer sh_grid_buffer 22 | { 23 | sh_grid grids[]; 24 | } sh_grids; 25 | 26 | struct shadow_map 27 | { 28 | int type; 29 | float min_bias; 30 | float max_bias; 31 | int cascade_index; 32 | vec4 rect; 33 | vec4 projection_info; 34 | vec4 range_radius; 35 | mat4 world_to_shadow; 36 | }; 37 | 38 | struct shadow_map_cascade 39 | { 40 | vec4 offset_scale; 41 | vec4 rect; 42 | }; 43 | 44 | struct shadow_mapping_parameters 45 | { 46 | vec2 shadow_map_atlas_pixel_margin; 47 | float pcss_minimum_radius; 48 | float noise_scale; 49 | int pcf_samples; 50 | int omni_pcf_samples; 51 | int pcss_samples; 52 | int pad[1]; 53 | }; 54 | 55 | layout(binding = 2, set = SCENE_RASTER_SET, std430) readonly buffer shadow_map_buffer 56 | { 57 | shadow_map maps[]; 58 | } shadow_maps; 59 | 60 | layout(binding = 3, set = SCENE_RASTER_SET, std430) readonly buffer shadow_map_cascade_buffer 61 | { 62 | shadow_map_cascade cascades[]; 63 | } shadow_map_cascades; 64 | 65 | layout(binding = 4, set = SCENE_RASTER_SET) uniform sampler2D shadow_map_atlas; 66 | layout(binding = 5, set = SCENE_RASTER_SET) uniform sampler2DShadow shadow_map_atlas_test; 67 | layout(binding = 6, set = SCENE_RASTER_SET) uniform sampler2D pcf_noise_vector_2d; 68 | layout(binding = 7, set = SCENE_RASTER_SET) uniform sampler2D pcf_noise_vector_3d; 69 | layout(binding = 8, set = SCENE_RASTER_SET) uniform sampler2D brdf_integration; 70 | 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /shader/sh_compact.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_nonuniform_qualifier : enable 3 | 4 | layout(local_size_x = 256) in; 5 | 6 | layout(binding = 0, set = 0, rgba32f) uniform readonly image3D input_sh; 7 | layout(binding = 1, set = 0, rgba16f) uniform writeonly image3D output_sh; 8 | 9 | layout(push_constant) uniform push_constant_buffer 10 | { 11 | int samples; 12 | int samples_per_work_item; 13 | } control; 14 | 15 | shared vec4 coef[256]; 16 | 17 | void main() 18 | { 19 | ivec3 write_pos = ivec3(gl_WorkGroupID.xyz); 20 | 21 | vec4 local_coef = vec4(0); 22 | for(int i = 0; i < control.samples_per_work_item; ++i) 23 | { 24 | int sample_index = int(gl_LocalInvocationIndex) + int(gl_WorkGroupSize.x) * i; 25 | if(sample_index >= control.samples) break; 26 | 27 | ivec3 read_pos = ivec3( 28 | write_pos.x, 29 | write_pos.y, 30 | write_pos.z * control.samples + sample_index 31 | ); 32 | local_coef += imageLoad(input_sh, read_pos); 33 | } 34 | 35 | coef[gl_LocalInvocationIndex] = local_coef; 36 | barrier(); 37 | 38 | uint j = gl_LocalInvocationIndex; 39 | for(uint i = 1; i < 256; i <<= 1) 40 | { 41 | if((j & ((i<<1)-1)) == 0) coef[j] += coef[j+i]; 42 | barrier(); 43 | } 44 | 45 | if(gl_LocalInvocationIndex == 0) 46 | imageStore(output_sh, write_pos, coef[0]); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /shader/sh_grid_blend.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | 3 | layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; 4 | 5 | layout(binding = 0, set = 0, rgba16f) uniform readonly image3D input_sh; 6 | layout(binding = 1, set = 0, rgba16f) uniform image3D inout_sh; 7 | layout(binding = 2, set = 0, rgba16f) uniform writeonly image3D output_sh; 8 | 9 | layout(binding = 3) uniform blend_info_buffer 10 | { 11 | float ratio; 12 | } info; 13 | 14 | layout(push_constant) uniform push_constant_buffer 15 | { 16 | ivec3 size; 17 | } control; 18 | 19 | void main() 20 | { 21 | ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); 22 | 23 | if(all(lessThan(pos, control.size))) 24 | { 25 | vec4 a = imageLoad(input_sh, pos); 26 | vec4 b = imageLoad(inout_sh, pos); 27 | vec4 c = mix(b, a, info.ratio); 28 | imageStore(inout_sh, pos, c); 29 | imageStore(output_sh, pos, c); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /shader/shadow_map.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_EXT_scalar_block_layout : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | 6 | #include "shadow_map_common.glsl" 7 | 8 | layout(location = 0) in vec2 in_uv; 9 | 10 | void main() 11 | { 12 | instance o = instances.o[control.instance_id]; 13 | if(control.alpha_clip < 1.0f) 14 | { 15 | float alpha = o.mat.albedo_factor.a; 16 | if(o.mat.albedo_tex_id >= 0) 17 | alpha *= texture(textures[nonuniformEXT(o.mat.albedo_tex_id)], in_uv).a; 18 | if(alpha < control.alpha_clip) 19 | discard; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /shader/shadow_map.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_EXT_scalar_block_layout : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | 6 | #include "shadow_map_common.glsl" 7 | 8 | layout(location = 0) in vec3 in_pos; 9 | layout(location = 2) in vec2 in_uv; 10 | layout(location = 0) out vec2 out_uv; 11 | 12 | void main() 13 | { 14 | instance o = instances.o[control.instance_id]; 15 | vec3 pos = vec3(o.model * vec4(in_pos, 1.0f)); 16 | gl_Position = shadow_camera.view_proj[control.camera_index] * vec4(pos, 1.0f); 17 | out_uv = in_uv; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /shader/shadow_map_common.glsl: -------------------------------------------------------------------------------- 1 | // This is for rendering the shadow maps, not using them. See 2 | // shadow_mapping.glsl for the use code. 3 | #ifndef SHADOW_MAP_COMMON_GLSL 4 | #define SHADOW_MAP_COMMON_GLSL 5 | 6 | #include "scene.glsl" 7 | 8 | layout(binding = 0, set = 0) buffer shadow_camera_data_buffer 9 | { 10 | mat4 view_proj[]; 11 | } shadow_camera; 12 | 13 | layout(push_constant) uniform push_constant_buffer 14 | { 15 | uint instance_id; 16 | float alpha_clip; 17 | uint camera_index; 18 | } control; 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /shader/skinning.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_scalar_block_layout : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | #include "scene.glsl" 6 | 7 | layout (local_size_x = 32) in; 8 | 9 | struct skin 10 | { 11 | uvec4 joints; 12 | vec4 weights; 13 | }; 14 | 15 | layout(binding = 0, scalar) readonly buffer source_buffer 16 | { 17 | vertex vertices[]; 18 | } source_data; 19 | 20 | layout(binding = 1) readonly buffer skin_buffer 21 | { 22 | skin skins[]; 23 | } skin_data; 24 | 25 | layout(binding = 2, scalar) buffer destination_buffer 26 | { 27 | vertex vertices[]; 28 | } destination_data; 29 | 30 | layout(binding = 3) readonly buffer joint_buffer 31 | { 32 | mat4 transforms[]; 33 | } joint_data; 34 | 35 | layout(binding = 4, scalar) buffer prev_pos_buffer 36 | { 37 | vec4 prev_pos[]; 38 | } prev_pos_data; 39 | 40 | layout(push_constant) uniform push_constant_buffer 41 | { 42 | uint vertex_count; 43 | } control; 44 | 45 | void main() 46 | { 47 | uint i = gl_GlobalInvocationID.x; 48 | 49 | if(i < control.vertex_count) 50 | { 51 | skin s = skin_data.skins[i]; 52 | 53 | mat4 skin_mat = 54 | s.weights.x * joint_data.transforms[s.joints.x] + 55 | s.weights.y * joint_data.transforms[s.joints.y] + 56 | s.weights.z * joint_data.transforms[s.joints.z] + 57 | s.weights.w * joint_data.transforms[s.joints.w]; 58 | mat4 it_skin_mat = transpose(inverse(skin_mat)); 59 | 60 | vertex src = source_data.vertices[i]; 61 | vertex dst = src; 62 | 63 | dst.pos = vec3(skin_mat * vec4(src.pos, 1.0)); 64 | dst.normal = normalize(vec3(it_skin_mat * vec4(src.normal, 0.0))); 65 | dst.tangent = vec4(normalize(vec3(it_skin_mat * vec4(src.tangent.xyz, 0.0))), src.tangent.w); 66 | 67 | vec3 prev_pos = destination_data.vertices[i].pos; 68 | destination_data.vertices[i] = dst; 69 | prev_pos_data.prev_pos[i] = vec4(prev_pos, 0); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /shader/sobol_owen_sampler.glsl: -------------------------------------------------------------------------------- 1 | #ifndef SOBOL_OWEN_SAMPLER_GLSL 2 | #define SOBOL_OWEN_SAMPLER_GLSL 3 | 4 | #include "random_sampler.glsl" 5 | 6 | struct sobol_owen_sampler 7 | { 8 | uvec4 seed; 9 | }; 10 | 11 | uvec4 get_shuffled_scrambled_sobol_pt_uint(sobol_owen_sampler ssampler, uint bounce) 12 | { 13 | uint index = ssampler.seed.w; 14 | ssampler.seed.w = bounce; 15 | uint shuffled_index = owen_scramble_2d( 16 | uvec4(index), pcg4d(ssampler.seed) 17 | ).x; 18 | ssampler.seed.w = index; 19 | 20 | return owen_scramble_2d(generate_sobol_sample(shuffled_index, bounce), ssampler.seed.yzwx); 21 | } 22 | 23 | sobol_owen_sampler init_sobol_owen_sampler(uvec4 seed) 24 | { 25 | sobol_owen_sampler ssampler; 26 | ssampler.seed = pcg4d(seed); 27 | return ssampler; 28 | } 29 | #endif 30 | -------------------------------------------------------------------------------- /shader/sobol_z_sampler.glsl: -------------------------------------------------------------------------------- 1 | #ifndef SOBOL_Z_SAMPLER_GLSL 2 | #define SOBOL_Z_SAMPLER_GLSL 3 | 4 | #include "math.glsl" 5 | 6 | // A Sobol sampler with indices drawn from the Morton / Z-curve. Similar to 7 | // what is described in http://abdallagafar.com/publications/zsampler/ and 8 | // https://psychopath.io/post/2022_07_24_owen_scrambling_based_dithered_blue_noise_sampling, 9 | // but simplified for Tauray usage. 10 | struct sobol_z_sampler 11 | { 12 | uint sobol_index; 13 | }; 14 | 15 | #ifndef SOBOL_Z_ORDER_CURVE_DIMS 16 | #define SOBOL_Z_ORDER_CURVE_DIMS 3 17 | #endif 18 | 19 | uvec4 get_sobol_z_sample_uint(sobol_z_sampler ssampler, uint bounce) 20 | { 21 | return generate_sobol_sample(ssampler.sobol_index, bounce); 22 | } 23 | 24 | sobol_z_sampler init_sobol_z_sampler(uvec4 coord) 25 | { 26 | sobol_z_sampler ssampler; 27 | #if SOBOL_Z_ORDER_CURVE_DIMS == 3 28 | // Worse blue noise, better accumulation 29 | // The seed for the Owen scrambling is that because the morton curve is 30 | // limited to 1024 in depth (= in paths sampled). So, every 1024 samples, 31 | // we scramble differently. 32 | ssampler.sobol_index = owen_scramble_8d(morton_3d(coord.xyw), coord.w>>10u); 33 | #else 34 | // Better blue noise, worse accumulation 35 | // The path index is used to scramble differently. 36 | ssampler.sobol_index = owen_scramble_4d(morton_2d(coord.xy), coord.w); 37 | #endif 38 | return ssampler; 39 | } 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /shader/stitch_scanline.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_nonuniform_qualifier : enable 3 | #extension GL_EXT_scalar_block_layout : enable 4 | 5 | layout (local_size_x = 16, local_size_y = 16) in; 6 | 7 | layout(binding = 0, set = 0, rgba16f) uniform readonly image2DArray input_images[]; 8 | layout(binding = 1, set = 0, rgba16f) uniform image2DArray output_images[]; 9 | 10 | layout(push_constant) uniform push_constant_buffer 11 | { 12 | uvec2 size; 13 | int device_count; 14 | int primary_index; 15 | int subimage_count; 16 | int subimage_index; 17 | float blend_ratio; 18 | } control; 19 | 20 | void main() 21 | { 22 | uvec3 p = gl_GlobalInvocationID.xyz; 23 | uint input_image_id = p.z%(control.device_count-1); 24 | p.z = p.z/(control.device_count-1); 25 | 26 | uint input_subimage_id = 27 | input_image_id * control.subimage_count + control.subimage_index; 28 | uint cur_index = 29 | input_image_id + (input_image_id >= control.primary_index ? 1 : 0); 30 | 31 | uvec2 input_image_size = uvec2( 32 | control.size.x, 33 | (control.size.y-cur_index+control.device_count-1)/control.device_count 34 | ); 35 | 36 | uvec3 out_p = uvec3(p.x, p.y * control.device_count + cur_index, p.z); 37 | 38 | if(all(lessThan(p.xy, input_image_size))) 39 | { 40 | vec4 color = imageLoad( 41 | input_images[nonuniformEXT(input_subimage_id)], ivec3(p) 42 | ); 43 | if(control.blend_ratio < 1.0) 44 | { 45 | vec4 old_color = imageLoad(output_images[control.subimage_index], ivec3(out_p)); 46 | color = mix(old_color, color, control.blend_ratio); 47 | } 48 | imageStore(output_images[control.subimage_index], ivec3(out_p), color); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /shader/stitch_shuffled_strips.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_nonuniform_qualifier : enable 3 | 4 | layout (local_size_x = 256) in; 5 | 6 | layout(binding = 0, set = 0, rgba16f) uniform readonly image2DArray input_images[]; 7 | layout(binding = 1, set = 0, rgba16f) uniform image2DArray output_images[]; 8 | 9 | layout(push_constant) uniform push_constant_buffer 10 | { 11 | uvec2 size; 12 | int start_p_offset; 13 | int count; 14 | uint input_img_id; 15 | uint output_img_id; 16 | uint b; 17 | float blend_ratio; 18 | } control; 19 | 20 | //Permute region for the pixel i 21 | uint permute_region_id(uint i) 22 | { 23 | uint region_size = ((control.size.x * control.size.y) + (1<> control.b; 24 | uint region_id = i / region_size; //Get the id of the region 25 | uint k = bitfieldReverse(region_id) >> (32 - control.b); 26 | return k * region_size + i % region_size; 27 | } 28 | 29 | void main() 30 | { 31 | uint p = gl_GlobalInvocationID.x + control.start_p_offset; 32 | uint in_gpu_buffer_p = gl_GlobalInvocationID.x; 33 | ivec2 in_buffer_pos = ivec2(in_gpu_buffer_p%control.size.x, in_gpu_buffer_p/control.size.x); 34 | 35 | ivec2 pos = ivec2(p%control.size.x, p/control.size.x); 36 | 37 | uint viewport_id = gl_GlobalInvocationID.z; 38 | 39 | uint j = permute_region_id(p); 40 | ivec2 shuffled_pos = ivec2(j%control.size.x, j/control.size.x); 41 | 42 | vec4 output_color = vec4(0, 1, 0, 0); 43 | 44 | if((j < control.size.x*control.size.y) && in_gpu_buffer_p < control.count) 45 | { 46 | output_color = imageLoad( 47 | input_images[nonuniformEXT(control.input_img_id)], 48 | ivec3(in_buffer_pos, viewport_id) 49 | ); 50 | if(control.blend_ratio < 1.0) 51 | { 52 | vec4 old_color = imageLoad( 53 | output_images[control.output_img_id], 54 | ivec3(shuffled_pos, viewport_id) 55 | ); 56 | output_color = mix(old_color, output_color, control.blend_ratio); 57 | } 58 | imageStore( 59 | output_images[control.output_img_id], 60 | ivec3(shuffled_pos, viewport_id), 61 | output_color 62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /shader/temporal_tables.glsl: -------------------------------------------------------------------------------- 1 | #ifndef TEMPORAL_TABLES_GLSL 2 | #define TEMPORAL_TABLES_GLSL 3 | #include "scene.glsl" 4 | 5 | #ifndef TEMPORAL_TABLE_SET 6 | #define TEMPORAL_TABLE_SET 3 7 | #endif 8 | 9 | layout(binding = 0, set = TEMPORAL_TABLE_SET) readonly buffer instance_forward_map_buffer 10 | { 11 | uint array[]; 12 | } instance_forward_map; 13 | layout(binding = 1, set = TEMPORAL_TABLE_SET) readonly buffer instance_backward_map_buffer 14 | { 15 | uint array[]; 16 | } instance_backward_map; 17 | layout(binding = 2, set = TEMPORAL_TABLE_SET) readonly buffer point_light_forward_map_buffer 18 | { 19 | uint array[]; 20 | } point_light_forward_map; 21 | layout(binding = 3, set = TEMPORAL_TABLE_SET) readonly buffer point_light_backward_map_buffer 22 | { 23 | uint array[]; 24 | } point_light_backward_map; 25 | 26 | layout(binding = 4, set = TEMPORAL_TABLE_SET, scalar) buffer prev_point_light_buffer 27 | { 28 | point_light lights[]; 29 | } prev_point_lights; 30 | 31 | #ifdef RAY_TRACING 32 | layout(binding = 5, set = TEMPORAL_TABLE_SET) uniform accelerationStructureEXT prev_tlas; 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /shader/tonemap.glsl: -------------------------------------------------------------------------------- 1 | layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in; 2 | 3 | layout(binding = 2, rgba32f) uniform writeonly image2DArray out_color; 4 | 5 | #ifdef MSAA_SAMPLES 6 | layout(binding = 1, rgba32f) uniform readonly image2DMSArray in_color; 7 | vec4 read_tonemap(ivec3 p) 8 | { 9 | vec4 sum_col = vec4(0); 10 | for(int i = 0; i < MSAA_SAMPLES; ++i) 11 | { 12 | vec4 src_col = imageLoad(in_color, p, i); 13 | #ifndef POST_RESOLVE 14 | src_col = tonemap(src_col); 15 | #endif 16 | sum_col += src_col; 17 | } 18 | sum_col *= (1.0f/float(MSAA_SAMPLES)); 19 | #ifdef POST_RESOLVE 20 | return tonemap(sum_col); 21 | #else 22 | return sum_col; 23 | #endif 24 | } 25 | #else 26 | layout(binding = 1, rgba32f) uniform readonly image2DArray in_color; 27 | vec4 read_tonemap(ivec3 p) { return tonemap(imageLoad(in_color, p)); } 28 | #endif 29 | 30 | layout(binding = 3, scalar) buffer output_reorder_buffer 31 | { 32 | int indices[]; 33 | } output_reorder; 34 | 35 | void main() 36 | { 37 | ivec3 p = ivec3(gl_GlobalInvocationID.xyz); 38 | p.z += info.base_layer; 39 | if(all(lessThan(p.xy, info.size))) 40 | { 41 | vec4 col = read_tonemap(p); 42 | 43 | // pow() breaks with negative values whether gamma is 1 or not. 44 | if(info.gamma != 1.0f) 45 | col.rgb = pow(col.rgb, vec3(1.0f/info.gamma)); 46 | 47 | if(info.alpha_grid_background != 0) 48 | { 49 | ivec2 grid = (p.xy/info.alpha_grid_background)&1; 50 | vec3 alpha_color = (grid.x^grid.y) == 0 ? vec3(0.4) : vec3(0.6); 51 | col.rgb = mix(alpha_color, col.rgb, col.a); 52 | } 53 | imageStore(out_color, ivec3(p.xy, output_reorder.indices[p.z]), col); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /shader/tonemap_filmic.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_scalar_block_layout : enable 4 | #extension GL_EXT_nonuniform_qualifier : enable 5 | 6 | layout(binding = 0, scalar) uniform tonemap_info_buffer 7 | { 8 | ivec2 size; 9 | int alpha_grid_background; 10 | int base_layer; 11 | float exposure; 12 | float gamma; 13 | } info; 14 | 15 | vec4 tonemap(vec4 col) 16 | { 17 | vec3 c = clamp(col.rgb * info.exposure, vec3(0), vec3(1000)); 18 | c = max(vec3(0.0f), c-0.004f); 19 | return vec4( 20 | pow((c * (6.2f * c + 0.5f))/(c * (6.2f * c + 1.7f) + 0.06f), vec3(2.2)), 21 | col.a 22 | ); 23 | } 24 | 25 | #include "tonemap.glsl" 26 | -------------------------------------------------------------------------------- /shader/tonemap_gamma.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_scalar_block_layout : enable 4 | #extension GL_EXT_nonuniform_qualifier : enable 5 | 6 | layout(binding = 0, scalar) uniform tonemap_info_buffer 7 | { 8 | ivec2 size; 9 | int alpha_grid_background; 10 | int base_layer; 11 | float exposure; 12 | float gamma; 13 | } info; 14 | 15 | vec4 tonemap(vec4 c) 16 | { 17 | c.rgb *= info.exposure; 18 | return c; 19 | } 20 | 21 | #include "tonemap.glsl" 22 | -------------------------------------------------------------------------------- /shader/tonemap_reinhard.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_scalar_block_layout : enable 4 | #extension GL_EXT_nonuniform_qualifier : enable 5 | 6 | layout(binding = 0, scalar) uniform tonemap_info_buffer 7 | { 8 | ivec2 size; 9 | int alpha_grid_background; 10 | int base_layer; 11 | float exposure; 12 | float gamma; 13 | } info; 14 | 15 | vec4 tonemap(vec4 col) 16 | { 17 | vec3 c = clamp(col.rgb * info.exposure, vec3(0), vec3(1000)); 18 | return vec4(c/(1+c), col.a); 19 | } 20 | 21 | #include "tonemap.glsl" 22 | -------------------------------------------------------------------------------- /shader/tonemap_reinhard_luminance.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | #extension GL_EXT_scalar_block_layout : enable 4 | #extension GL_EXT_nonuniform_qualifier : enable 5 | #include "color.glsl" 6 | 7 | layout(binding = 0, scalar) uniform tonemap_info_buffer 8 | { 9 | ivec2 size; 10 | int alpha_grid_background; 11 | int base_layer; 12 | float exposure; 13 | float gamma; 14 | } info; 15 | 16 | vec4 tonemap(vec4 col) 17 | { 18 | vec3 c = clamp(col.rgb * info.exposure, vec3(0), vec3(1000)); 19 | float lum = rgb_to_luminance(c); 20 | float new_lum = lum/(1.0f + lum); 21 | return vec4(c / max(lum, 1e-4) * new_lum, col.a); 22 | } 23 | 24 | #include "tonemap.glsl" 25 | -------------------------------------------------------------------------------- /shader/z_pass.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | void main() {} 3 | -------------------------------------------------------------------------------- /shader/z_pass.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | #extension GL_EXT_scalar_block_layout : enable 3 | #extension GL_EXT_nonuniform_qualifier : enable 4 | #extension GL_GOOGLE_include_directive : enable 5 | #extension GL_EXT_multiview : enable 6 | 7 | layout(location = 0) in vec3 in_pos; 8 | 9 | #define SCENE_SET 0 10 | #include "scene.glsl" 11 | 12 | layout(push_constant) uniform push_constant_buffer 13 | { 14 | uint instance_id; 15 | int base_camera_index; 16 | } control; 17 | 18 | void main() 19 | { 20 | instance o = instances.o[control.instance_id]; 21 | vec3 pos = vec3(o.model * vec4(in_pos, 1.0f)); 22 | gl_Position = camera.pairs[control.base_camera_index+gl_ViewIndex].current.view_proj * vec4(pos, 1.0f); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/assimp.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_ASSIMP_HH 2 | #define TAURAY_ASSIMP_HH 3 | #include "scene_assets.hh" 4 | #include "scene.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | scene_assets load_assimp(device_mask dev, scene& s, const std::string& path); 10 | 11 | } 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/atlas.hh: -------------------------------------------------------------------------------- 1 | #ifndef TR_ATLAS_HH 2 | #define TR_ATLAS_HH 3 | #include "texture.hh" 4 | #include 5 | 6 | namespace tr 7 | { 8 | 9 | // Texture atlas. 10 | class atlas: public texture 11 | { 12 | public: 13 | // If sub_sizes is empty, a 1x1 texture is created so that samplers don't 14 | // cause errors. 15 | atlas( 16 | device_mask dev, 17 | const std::vector& sub_sizes = {}, 18 | unsigned pad_size = 1, 19 | vk::Format fmt = vk::Format::eR8G8B8A8Unorm, 20 | vk::ImageTiling tiling = vk::ImageTiling::eOptimal, 21 | vk::ImageUsageFlags usage = vk::ImageUsageFlagBits::eSampled, 22 | vk::ImageLayout layout = vk::ImageLayout::eGeneral 23 | ); 24 | ~atlas(); 25 | 26 | // This may be a no-op if the sub_sizes match current sizes. First tries to 27 | // re-accommodate all sub sizes in the current texture, then allocates a 28 | // larger one if that doesn't work. Returns true if the layout was 29 | // changed or the texture was recreated. 30 | bool set_sub_textures( 31 | const std::vector& sub_sizes, 32 | unsigned pad_size = 1 33 | ); 34 | 35 | uvec4 get_rect_px(unsigned i) const; 36 | vec4 get_rect(unsigned i) const; 37 | unsigned get_sub_texture_count() const; 38 | 39 | private: 40 | std::vector rects; 41 | }; 42 | 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/basic_pipeline.cc: -------------------------------------------------------------------------------- 1 | #include "basic_pipeline.hh" 2 | #include "descriptor_set.hh" 3 | #include "misc.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | basic_pipeline::basic_pipeline( 9 | device& dev, 10 | vk::PipelineBindPoint bind_point 11 | ): dev(&dev), 12 | bind_point(bind_point) 13 | { 14 | } 15 | 16 | void basic_pipeline::init( 17 | std::vector&& push_constant_ranges, 18 | const std::vector& layout 19 | ){ 20 | this->push_constant_ranges = std::move(push_constant_ranges); 21 | 22 | std::vector descriptor_sets; 23 | 24 | for(tr::descriptor_set_layout* layout: layout) 25 | descriptor_sets.push_back(layout->get_layout(dev->id)); 26 | 27 | vk::PipelineLayoutCreateInfo pipeline_layout_info( 28 | {}, descriptor_sets.size(), descriptor_sets.data(), 29 | this->push_constant_ranges.size(), 30 | this->push_constant_ranges.data() 31 | ); 32 | 33 | pipeline_layout = vkm(*dev, dev->logical.createPipelineLayout(pipeline_layout_info)); 34 | } 35 | 36 | device* basic_pipeline::get_device() const 37 | { 38 | return dev; 39 | } 40 | 41 | void basic_pipeline::set_descriptors(vk::CommandBuffer cmd, descriptor_set& set, uint32_t index, uint32_t set_index) const 42 | { 43 | set.bind(dev->id, cmd, pipeline_layout, bind_point, index, set_index); 44 | } 45 | 46 | void basic_pipeline::push_descriptors(vk::CommandBuffer cmd, push_descriptor_set& set, uint32_t set_index) const 47 | { 48 | set.push(dev->id, cmd, pipeline_layout, bind_point, set_index); 49 | } 50 | 51 | void basic_pipeline::bind(vk::CommandBuffer cmd) const 52 | { 53 | cmd.bindPipeline(bind_point, *pipeline); 54 | } 55 | 56 | void basic_pipeline::load_shader_module( 57 | shader_source src, 58 | vk::ShaderStageFlagBits stage, 59 | std::vector& stages, 60 | const vk::SpecializationInfo& specialization 61 | ){ 62 | if(src.data.empty()) return; 63 | 64 | vkm mod = vkm(*dev, dev->logical.createShaderModule({ 65 | {}, src.data.size()*sizeof(uint32_t), src.data.data() 66 | })); 67 | stages.push_back({{}, stage, mod, "main", specialization.pData != nullptr ? &specialization : nullptr}); 68 | } 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/basic_pipeline.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_BASIC_PIPELINE_HH 2 | #define TAURAY_BASIC_PIPELINE_HH 3 | #include "context.hh" 4 | #include "shader_source.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | struct shader_sources; 10 | class descriptor_set_layout; 11 | class descriptor_set; 12 | class push_descriptor_set; 13 | 14 | // Pipelines are per-device. This is the base class for multiple pipeline types. 15 | // It exists mostly for code reuse purposes, since all pipelines have some 16 | // common amenities for buffer handling. 17 | class basic_pipeline 18 | { 19 | public: 20 | basic_pipeline(device& dev, vk::PipelineBindPoint bind_point); 21 | basic_pipeline(const basic_pipeline& other) = delete; 22 | basic_pipeline(basic_pipeline&& other) = delete; 23 | virtual ~basic_pipeline() = default; 24 | 25 | void init( 26 | std::vector&& push_constant_ranges, 27 | const std::vector& layout 28 | ); 29 | 30 | template 31 | void push_constants( 32 | vk::CommandBuffer cb, 33 | const T& pc, 34 | size_t pc_index = 0 35 | ){ 36 | cb.pushConstants( 37 | pipeline_layout, push_constant_ranges[pc_index].stageFlags, 38 | 0, sizeof(T), &pc 39 | ); 40 | } 41 | 42 | device* get_device() const; 43 | 44 | void set_descriptors(vk::CommandBuffer cmd, descriptor_set& set, uint32_t index, uint32_t set_index) const; 45 | void push_descriptors(vk::CommandBuffer cmd, push_descriptor_set& set, uint32_t set_index) const; 46 | void bind(vk::CommandBuffer cmd) const; 47 | 48 | protected: 49 | void load_shader_module( 50 | shader_source src, 51 | vk::ShaderStageFlagBits stage, 52 | std::vector& stages, 53 | const vk::SpecializationInfo& specialization 54 | ); 55 | device* dev; 56 | vk::PipelineBindPoint bind_point; 57 | vkm pipeline; 58 | vkm pipeline_layout; 59 | 60 | private: 61 | std::vector push_constant_ranges; 62 | }; 63 | 64 | } 65 | 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /src/bmfr_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_BMFR_STAGE_HH 2 | #define TAURAY_BMFR_STAGE_HH 3 | 4 | #include "stage.hh" 5 | #include "compute_pipeline.hh" 6 | #include "descriptor_set.hh" 7 | #include "gbuffer.hh" 8 | #include "timer.hh" 9 | #include "gpu_buffer.hh" 10 | 11 | namespace tr 12 | { 13 | 14 | class bmfr_stage: public single_device_stage 15 | { 16 | public: 17 | enum class bmfr_settings 18 | { 19 | DIFFUSE_ONLY = 0, 20 | DIFFUSE_SPECULAR = 1 21 | }; 22 | struct options 23 | { 24 | bmfr_settings settings; 25 | }; 26 | 27 | bmfr_stage( 28 | device& dev, 29 | gbuffer_target& current_features, 30 | gbuffer_target& prev_features, 31 | const options& opt 32 | ); 33 | bmfr_stage(const bmfr_stage& other) = delete; 34 | bmfr_stage(bmfr_stage&& other) = delete; 35 | 36 | virtual void update(uint32_t frame_index) override; 37 | 38 | private: 39 | void init_resources(); 40 | void record_command_buffers(); 41 | static shader_source load_shader_source(const std::string& path, const options& opt); 42 | 43 | void copy_image(vk::CommandBuffer& cb, render_target& src, render_target& dst); 44 | 45 | descriptor_set bmfr_preprocess_desc; 46 | compute_pipeline bmfr_preprocess_comp; 47 | descriptor_set bmfr_fit_desc; 48 | compute_pipeline bmfr_fit_comp; 49 | descriptor_set bmfr_weighted_sum_desc; 50 | compute_pipeline bmfr_weighted_sum_comp; 51 | descriptor_set bmfr_accumulate_output_desc; 52 | compute_pipeline bmfr_accumulate_output_comp; 53 | gbuffer_target current_features; 54 | gbuffer_target prev_features; 55 | render_target tmp_noisy[2]; 56 | render_target tmp_filtered[2]; 57 | render_target diffuse_hist; 58 | render_target specular_hist; 59 | render_target filtered_hist[2]; 60 | render_target weighted_sum[2]; 61 | vkm min_max_buffer[MAX_FRAMES_IN_FLIGHT]; 62 | vkm tmp_data[MAX_FRAMES_IN_FLIGHT]; 63 | vkm weights[MAX_FRAMES_IN_FLIGHT]; 64 | vkm accepts[MAX_FRAMES_IN_FLIGHT]; 65 | gpu_buffer uniform_buffer; 66 | std::unique_ptr rt_textures[10]; 67 | options opt; 68 | timer stage_timer, bmfr_preprocess_timer, bmfr_fit_timer, bmfr_weighted_sum_timer, bmfr_accumulate_output_timer, image_copy_timer; 69 | }; 70 | 71 | } // namespace tr 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/compute_pipeline.cc: -------------------------------------------------------------------------------- 1 | #include "compute_pipeline.hh" 2 | #include "misc.hh" 3 | #include 4 | 5 | namespace tr 6 | { 7 | 8 | compute_pipeline::compute_pipeline(device& dev) 9 | : basic_pipeline(dev, vk::PipelineBindPoint::eCompute) 10 | { 11 | } 12 | 13 | void compute_pipeline::init( 14 | shader_source src, 15 | std::vector layout 16 | ){ 17 | basic_pipeline::init(get_push_constant_ranges(src), layout); 18 | if(src.data.empty()) 19 | throw std::runtime_error("The shader source code is missing!"); 20 | 21 | vkm comp(*dev, dev->logical.createShaderModule({ 22 | {}, src.data.size() * sizeof(uint32_t), src.data.data() 23 | })); 24 | 25 | vk::ComputePipelineCreateInfo pipeline_info( 26 | {}, {{}, vk::ShaderStageFlagBits::eCompute, comp, "main"}, 27 | pipeline_layout, {}, 0 28 | ); 29 | 30 | pipeline = vkm(*dev, dev->logical.createComputePipeline(dev->pp_cache, pipeline_info).value); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/compute_pipeline.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_COMPUTE_PIPELINE_HH 2 | #define TAURAY_COMPUTE_PIPELINE_HH 3 | #include "basic_pipeline.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | struct shader_sources; 9 | 10 | // Compute pipelines are per-device. Because of the nature of this program as a 11 | // renderer, even the compute pipeline is somewhat related to graphics 12 | // (in-flight mechanics) 13 | class compute_pipeline: public basic_pipeline 14 | { 15 | public: 16 | compute_pipeline(device& dev); 17 | void init( 18 | shader_source src, 19 | std::vector layout 20 | ); 21 | }; 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/dependency.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_DEPENDENCY_HH 2 | #define TAURAY_DEPENDENCY_HH 3 | 4 | #include "device.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | // This class is similar to events in OpenCL, but I didn't name it as 'event' so 10 | // that it wouldn't get mixed up with Vulkan events which are a different thing. 11 | // You can insert dependencies between rendering steps by passing these around. 12 | struct dependency 13 | { 14 | device_id id; 15 | vk::Semaphore timeline_semaphore; 16 | uint64_t wait_value; 17 | vk::PipelineStageFlags wait_stage = vk::PipelineStageFlagBits::eTopOfPipe; 18 | }; 19 | 20 | // Bundles of dependencies are stored in this structure instead of a vector, 21 | // because this makes it easier to pass to Vulkan mostly. You can include 22 | // semaphores for various different devices as well, and request ones for only 23 | // specific devices. 24 | class dependencies 25 | { 26 | public: 27 | template 28 | dependencies(Args... deps) { (add(deps), ...); } 29 | 30 | void add(dependency dep); 31 | void concat(dependencies deps); 32 | void concat(dependencies deps, device_id only_id); 33 | void clear(); 34 | void clear(device_id id); 35 | size_t size(device_id id) const; 36 | size_t total_size() const; 37 | size_t count_unique_devices() const; 38 | uint64_t value(device_id id, size_t index) const; 39 | 40 | void wait(device& dev); 41 | 42 | vk::TimelineSemaphoreSubmitInfo get_timeline_info(device_id id) const; 43 | vk::SubmitInfo get_submit_info(device_id id, vk::TimelineSemaphoreSubmitInfo& s) const; 44 | 45 | private: 46 | void get_range(device_id id, size_t& begin, size_t& end) const; 47 | 48 | std::vector ids; 49 | std::vector semaphores; 50 | std::vector values; 51 | std::vector wait_stages; 52 | }; 53 | 54 | } 55 | 56 | #endif 57 | 58 | -------------------------------------------------------------------------------- /src/device_transfer.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_DEVICE_TRANSFER_HH 2 | #define TAURAY_DEVICE_TRANSFER_HH 3 | #include "dependency.hh" 4 | #include 5 | 6 | namespace tr 7 | { 8 | 9 | // Facilitates device-to-device memory transfers in multi-GPU contexts. 10 | class device_transfer_interface 11 | { 12 | public: 13 | virtual ~device_transfer_interface() = default; 14 | 15 | virtual vk::ImageUsageFlagBits required_src_img_flags() = 0; 16 | virtual vk::ImageUsageFlagBits required_dst_img_flags() = 0; 17 | virtual vk::BufferUsageFlagBits required_src_buffer_flags() = 0; 18 | virtual vk::BufferUsageFlagBits required_dst_buffer_flags() = 0; 19 | 20 | struct image_transfer 21 | { 22 | vk::Image src; 23 | vk::Image dst; 24 | size_t bytes_per_pixel; 25 | vk::ImageCopy info; 26 | vk::ImageLayout src_layout = vk::ImageLayout::eTransferSrcOptimal; 27 | vk::ImageLayout dst_layout = vk::ImageLayout::eGeneral; 28 | }; 29 | 30 | struct buffer_transfer 31 | { 32 | vk::Buffer src; 33 | vk::Buffer dst; 34 | vk::BufferCopy info; 35 | }; 36 | 37 | virtual void reserve( 38 | const std::vector& images, 39 | const std::vector& buffers 40 | ) = 0; 41 | 42 | // You can re-record commands for the transfer method whenever needed. 43 | virtual void build( 44 | const std::vector& images, 45 | const std::vector& buffers 46 | ) = 0; 47 | 48 | // Run can only be called after build(). 'deps' can only be dependencies 49 | // for the 'src' buffers and their device. Returned dependency is for the 50 | // 'dst' buffers and their device. 51 | virtual dependency run(const dependencies& deps, uint32_t frame_index) = 0; 52 | }; 53 | 54 | enum device_transfer_strategy 55 | { 56 | DTI_AUTO = 0, 57 | DTI_EXTERNAL_SEMAPHORE_HOST_BUFFER 58 | //DTI_WAIT_THREAD_HOST_BUFFER 59 | //DTI_CUDA_INTEROP 60 | //DTI_RDMA_PEER_TO_PEER 61 | }; 62 | 63 | std::unique_ptr create_device_transfer_interface( 64 | device& from, 65 | device& to, 66 | device_transfer_strategy strat = DTI_AUTO 67 | ); 68 | 69 | } 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/direct_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_DIRECT_STAGE_HH 2 | #define TAURAY_DIRECT_STAGE_HH 3 | #include "path_tracer_stage.hh" 4 | #include "descriptor_set.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | class direct_stage: public rt_camera_stage 10 | { 11 | public: 12 | struct options: public rt_camera_stage::options 13 | { 14 | film_filter film = film_filter::BLACKMAN_HARRIS; 15 | float film_radius = 1.0f; // 0.5 is "correct" for the box filter. 16 | 17 | light_sampling_weights sampling_weights; 18 | bounce_sampling_mode bounce_mode = bounce_sampling_mode::MATERIAL; 19 | tri_light_sampling_mode tri_light_mode = tri_light_sampling_mode::HYBRID; 20 | }; 21 | 22 | direct_stage( 23 | device& dev, 24 | scene_stage& ss, 25 | const gbuffer_target& output_target, 26 | const options& opt 27 | ); 28 | 29 | protected: 30 | void record_command_buffer_pass( 31 | vk::CommandBuffer cb, 32 | uint32_t frame_index, 33 | uint32_t pass_index, 34 | uvec3 expected_dispatch_size, 35 | bool first_in_command_buffer 36 | ) override; 37 | 38 | private: 39 | push_descriptor_set desc; 40 | rt_pipeline gfx; 41 | options opt; 42 | }; 43 | 44 | } 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /src/distribution_strategy.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_DISTRIBUTION_STRATEGY_HH 2 | #define TAURAY_DISTRIBUTION_STRATEGY_HH 3 | #include "math.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | enum distribution_strategy 9 | { 10 | // Just duplicate renders on each device == no real distribution 11 | DISTRIBUTION_DUPLICATE = 0, 12 | // The output image is divided evenly among rendering devices using 13 | // interleaved scanlines. The primary device draws directly into a full-size 14 | // image, others into vertically smaller images. These smaller images are 15 | // then merged into the full-size image. 16 | DISTRIBUTION_SCANLINE = 1, 17 | DISTRIBUTION_SHUFFLED_STRIPS = 2 18 | }; 19 | 20 | struct distribution_params 21 | { 22 | uvec2 size = uvec2(0); 23 | distribution_strategy strategy = DISTRIBUTION_SCANLINE; 24 | unsigned index = 0; 25 | unsigned count = 1; 26 | bool primary = true; 27 | }; 28 | 29 | // Size of the active portion of the render target. 30 | uvec2 get_distribution_target_size(const distribution_params& params); 31 | // Maximum size of the render target, so that buffer resizing can be avoided. 32 | uvec2 get_distribution_target_max_size(const distribution_params& params); 33 | uvec2 get_distribution_render_size(const distribution_params& params); 34 | uvec2 get_ray_count(const distribution_params& params); 35 | 36 | unsigned calculate_shuffled_strips_b(uvec2 size); 37 | 38 | distribution_params get_device_distribution_params( 39 | uvec2 full_image_size, 40 | distribution_strategy strategy, 41 | double workload_offset, 42 | double workload_size, 43 | unsigned device_index, 44 | unsigned device_count, 45 | bool primary 46 | ); 47 | 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/dshgi_client.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_DSHGI_CLIENT_HH 2 | #define TAURAY_DSHGI_CLIENT_HH 3 | #include "context.hh" 4 | #include "stage.hh" 5 | #include "texture.hh" 6 | #include "scene_stage.hh" 7 | #include "compute_pipeline.hh" 8 | #include "sh_grid.hh" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace tr 16 | { 17 | 18 | class dshgi_client_stage; 19 | class dshgi_client 20 | { 21 | friend class dshgi_client_stage; 22 | public: 23 | struct options 24 | { 25 | std::string server_address; 26 | }; 27 | 28 | dshgi_client(context& ctx, scene_stage& ss, const options& opt); 29 | dshgi_client(const dshgi_client& other) = delete; 30 | dshgi_client(dshgi_client&& other) = delete; 31 | ~dshgi_client(); 32 | 33 | // If this returns true, you will need to rebuild the scene buffers. 34 | bool refresh(); 35 | dependencies render(dependencies deps); 36 | 37 | private: 38 | static void receiver_worker(dshgi_client* s); 39 | 40 | context* ctx; 41 | options opt; 42 | scene_stage* ss; 43 | 44 | std::mutex remote_grids_mutex; 45 | struct sh_grid_data 46 | { 47 | bool topo_changed = true; 48 | bool data_updated = true; 49 | entity id = INVALID_ENTITY; 50 | sh_grid* grid = nullptr; 51 | transformable* transform = nullptr; 52 | std::vector data; 53 | }; 54 | std::vector remote_grids; 55 | 56 | // Updated only when refresh() is called, so it's safe from the main thread. 57 | std::vector local_grids; 58 | // The latest states of the grid data should be uploaded here. 59 | std::unordered_map sh_grid_upload_textures; 60 | std::unordered_map sh_grid_tmp_textures; 61 | // The blended result textures are stored in scene_stage's sh grid textures! 62 | 63 | time_ticks remote_timestamp; 64 | bool new_remote_timestamp; 65 | 66 | std::optional update_event; 67 | time_ticks local_timestamp; 68 | 69 | bool exit_receiver; 70 | std::thread receiver_thread; 71 | std::unique_ptr sh_refresher; 72 | }; 73 | 74 | } 75 | 76 | #endif 77 | 78 | -------------------------------------------------------------------------------- /src/dshgi_renderer.cc: -------------------------------------------------------------------------------- 1 | #include "dshgi_renderer.hh" 2 | #include "sh_grid.hh" 3 | #include "scene.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | dshgi_renderer::dshgi_renderer(context& ctx, const options& opt) 9 | : raster_renderer(ctx, opt), opt(opt) 10 | { 11 | if(auto rtype = std::get_if(&opt.sh_source)) 12 | sh.reset(new sh_renderer(ctx.get_display_device(), *scene_update, *rtype)); 13 | else if(auto rtype = std::get_if(&opt.sh_source)) 14 | client.reset(new dshgi_client(ctx, *scene_update, *rtype)); 15 | } 16 | 17 | dshgi_renderer::~dshgi_renderer() 18 | { 19 | } 20 | 21 | void dshgi_renderer::render() 22 | { 23 | if(client && client->refresh()) 24 | set_scene(cur_scene); 25 | 26 | dependencies deps(ctx->begin_frame()); 27 | 28 | deps = scene_update->run(deps); 29 | if(sh) deps = sh->render(deps); 30 | else if(client) deps = client->render(deps); 31 | deps = render_core(deps); 32 | 33 | ctx->end_frame(deps); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/dshgi_renderer.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_DSHGI_RENDERER_HH 2 | #define TAURAY_DSHGI_RENDERER_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "raster_renderer.hh" 6 | #include "sh_renderer.hh" 7 | #include "dshgi_client.hh" 8 | #include 9 | 10 | namespace tr 11 | { 12 | 13 | class dshgi_renderer: public raster_renderer 14 | { 15 | public: 16 | struct options: raster_renderer::options 17 | { 18 | std::variant< 19 | sh_renderer::options, 20 | dshgi_client::options 21 | > sh_source; 22 | }; 23 | 24 | dshgi_renderer(context& ctx, const options& opt); 25 | dshgi_renderer(const dshgi_renderer& other) = delete; 26 | dshgi_renderer(dshgi_renderer&& other) = delete; 27 | ~dshgi_renderer(); 28 | 29 | void render() override; 30 | 31 | private: 32 | options opt; 33 | std::unique_ptr sh; 34 | std::unique_ptr client; 35 | }; 36 | 37 | } 38 | 39 | #endif 40 | 41 | -------------------------------------------------------------------------------- /src/dshgi_server.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_DSHGI_SERVER_HH 2 | #define TAURAY_DSHGI_SERVER_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "scene_stage.hh" 6 | #include "sh_renderer.hh" 7 | #include "renderer.hh" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace tr 14 | { 15 | 16 | class sh_grid_to_cpu_stage; 17 | class dshgi_server: public renderer 18 | { 19 | public: 20 | struct options 21 | { 22 | sh_renderer::options sh; 23 | uint16_t port_number; 24 | }; 25 | 26 | dshgi_server(context& ctx, const options& opt); 27 | dshgi_server(const dshgi_server& other) = delete; 28 | dshgi_server(dshgi_server&& other) = delete; 29 | ~dshgi_server(); 30 | 31 | void set_scene(scene* s) override; 32 | void render() override; 33 | 34 | private: 35 | static void sender_worker(dshgi_server* s); 36 | 37 | context* ctx; 38 | options opt; 39 | scene* cur_scene = nullptr; 40 | std::unique_ptr scene_update; 41 | std::unique_ptr sh_grid_to_cpu; 42 | std::optional sh; 43 | 44 | std::mutex frame_queue_mutex; 45 | std::condition_variable frame_queue_cv; 46 | std::vector frame_queue; 47 | vkm sender_semaphore; 48 | 49 | std::optional update_event; 50 | time_ticks timestamp; 51 | 52 | std::atomic_bool exit_sender; 53 | std::atomic_uint subscriber_count; 54 | std::thread sender_thread; 55 | }; 56 | 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/environment_map.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_ENVIRONMENT_MAP_HH 2 | #define TAURAY_ENVIRONMENT_MAP_HH 3 | #include "texture.hh" 4 | #include "transformable.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | class environment_map: public texture, public transformable 10 | { 11 | public: 12 | enum projection 13 | { 14 | LAT_LONG = 0 15 | }; 16 | 17 | environment_map( 18 | device_mask dev, 19 | const std::string& path, 20 | projection proj = LAT_LONG, 21 | vec3 factor = vec3(1.0f) 22 | ); 23 | 24 | void set_factor(vec3 factor); 25 | vec3 get_factor() const; 26 | 27 | projection get_projection() const; 28 | vk::Buffer get_alias_table(size_t device_index) const; 29 | 30 | private: 31 | void generate_alias_table(); 32 | 33 | vec3 factor; 34 | projection proj; 35 | 36 | double average_luminance; 37 | struct alias_table_entry 38 | { 39 | uint32_t alias_id; 40 | uint32_t probability; 41 | float pdf; 42 | float alias_pdf; 43 | }; 44 | std::vector alias_table; 45 | 46 | per_device> alias_table_buffers; 47 | }; 48 | 49 | } 50 | 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /src/envmap_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_ENVMAP_STAGE_HH 2 | #define TAURAY_ENVMAP_STAGE_HH 3 | #include "stage.hh" 4 | #include "raster_pipeline.hh" 5 | #include "sampler.hh" 6 | #include "timer.hh" 7 | #include "gpu_buffer.hh" 8 | 9 | namespace tr 10 | { 11 | 12 | class scene_stage; 13 | // Just renders the environment map from the given scene as the sky, if present. 14 | class envmap_stage: public single_device_stage 15 | { 16 | public: 17 | envmap_stage( 18 | device& dev, 19 | scene_stage& ss, 20 | const std::vector& color_arrays 21 | ); 22 | 23 | envmap_stage( 24 | device& dev, 25 | scene_stage& ss, 26 | render_target& color_target, 27 | unsigned base_camera_index = 0 28 | ); 29 | 30 | protected: 31 | void update(uint32_t frame_index) override; 32 | 33 | private: 34 | std::vector> array_pipelines; 35 | timer envmap_timer; 36 | 37 | uint32_t scene_state_counter; 38 | unsigned base_camera_index; 39 | scene_stage* ss; 40 | }; 41 | 42 | } 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /src/feature_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_FEATURE_STAGE_HH 2 | #define TAURAY_FEATURE_STAGE_HH 3 | #include "rt_camera_stage.hh" 4 | #include "descriptor_set.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | class feature_stage: public rt_camera_stage 10 | { 11 | public: 12 | enum feature 13 | { 14 | ALBEDO = 0, 15 | WORLD_NORMAL, 16 | VIEW_NORMAL, 17 | WORLD_POS, 18 | VIEW_POS, 19 | DISTANCE, 20 | WORLD_MOTION, 21 | VIEW_MOTION, 22 | SCREEN_MOTION, 23 | INSTANCE_ID 24 | }; 25 | 26 | struct options: public rt_camera_stage::options 27 | { 28 | feature feat; 29 | // Missing rays are filled with the default value. 30 | vec4 default_value = vec4(NAN); 31 | }; 32 | 33 | feature_stage( 34 | device& dev, 35 | scene_stage& ss, 36 | const gbuffer_target& output_target, 37 | const options& opt 38 | ); 39 | 40 | protected: 41 | void record_command_buffer_pass( 42 | vk::CommandBuffer cb, 43 | uint32_t frame_index, 44 | uint32_t pass_index, 45 | uvec3 expected_dispatch_size, 46 | bool first_in_command_buffer 47 | ) override; 48 | 49 | private: 50 | push_descriptor_set desc; 51 | rt_pipeline gfx; 52 | options opt; 53 | }; 54 | 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/frame_client.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_FRAME_CLIENT_HH 2 | #define TAURAY_FRAME_CLIENT_HH 3 | #include "options.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | void frame_client(const options& opt); 9 | 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /src/frame_delay_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_FRAME_DELAY_STAGE_HH 2 | #define TAURAY_FRAME_DELAY_STAGE_HH 3 | #include "context.hh" 4 | #include "stage.hh" 5 | #include "timer.hh" 6 | #include "gbuffer.hh" 7 | 8 | namespace tr 9 | { 10 | 11 | // This stage outputs a G-Buffer that is delayed by one frame. It's needed 12 | // for temporal algorithms, to access the previous frame. 13 | // 14 | // Run this stage directly after post-processing. Additionally, all stages 15 | // which generate the input_features for the next frame must wait for the 16 | // dependency of the frame_delay_stage. These cross-frame dependencies ensure 17 | // that we can avoid synchronization issues. 18 | class frame_delay_stage: public single_device_stage 19 | { 20 | public: 21 | frame_delay_stage( 22 | device& dev, 23 | gbuffer_target& input_features 24 | ); 25 | gbuffer_target get_output(); 26 | 27 | protected: 28 | private: 29 | gbuffer_target output_features; 30 | std::unique_ptr textures; 31 | timer delay_timer; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/frame_server.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_FRAME_SERVER_HH 2 | #define TAURAY_FRAME_SERVER_HH 3 | #include "context.hh" 4 | 5 | #if _WIN32 6 | #include 7 | #include 8 | #else 9 | #include 10 | #include 11 | #endif 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace tr 20 | { 21 | 22 | // This context renders an image and streams it over the network. It also 23 | // accepts input events, which it stuffs into SDLs event buffer. This allows for 24 | // remote control. Has no LF or VR support, a different scheme should be used 25 | // for that. 26 | class frame_server: public context 27 | { 28 | public: 29 | struct options: context::options 30 | { 31 | uvec2 size = uvec2(1280, 720); 32 | uint16_t port_number; 33 | 34 | // TODO: Compression schemes? 35 | }; 36 | 37 | frame_server(const options& opt); 38 | frame_server(const frame_server& other) = delete; 39 | frame_server(frame_server&& other) = delete; 40 | ~frame_server(); 41 | 42 | bool init_frame() override; 43 | 44 | protected: 45 | uint32_t prepare_next_image(uint32_t frame_index) override; 46 | void finish_image( 47 | uint32_t frame_index, 48 | uint32_t swapchain_index, 49 | bool display 50 | ) override; 51 | bool queue_can_present( 52 | const vk::PhysicalDevice& device, 53 | uint32_t queue_index, 54 | const vk::QueueFamilyProperties& props 55 | ) override final; 56 | 57 | private: 58 | void init_images(); 59 | void deinit_images(); 60 | 61 | // These only init events. 62 | void init_sdl(); 63 | void deinit_sdl(); 64 | 65 | static void read_image_worker(frame_server* s); 66 | static void streamer_worker(frame_server* s); 67 | 68 | options opt; 69 | 70 | struct per_image_data 71 | { 72 | vkm staging_buffer; 73 | vkm copy_cb; 74 | vkm copy_fence; 75 | bool copy_ongoing = false; 76 | }; 77 | 78 | std::vector per_image; 79 | std::mutex image_mutex; 80 | std::condition_variable copy_start_cv, copy_finish_cv; 81 | std::vector image_read_queue; 82 | 83 | std::mutex frame_queue_mutex; 84 | std::condition_variable frame_queue_cv; 85 | std::vector> frame_queue; 86 | 87 | std::atomic_bool exit_streamer; 88 | std::atomic_bool pause_rendering; 89 | std::thread image_reader_thread; 90 | std::thread streamer_thread; 91 | }; 92 | 93 | } 94 | 95 | #endif 96 | 97 | -------------------------------------------------------------------------------- /src/gbuffer_copy_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_GBUFFER_COPY_STAGE_HH 2 | #define TAURAY_GBUFFER_COPY_STAGE_HH 3 | #include "context.hh" 4 | #include "stage.hh" 5 | #include "timer.hh" 6 | #include "gbuffer.hh" 7 | 8 | namespace tr 9 | { 10 | 11 | // Copies the common entries of G-Buffer A to G-Buffer B. 12 | class gbuffer_copy_stage: public single_device_stage 13 | { 14 | public: 15 | gbuffer_copy_stage( 16 | device& dev, 17 | gbuffer_target& in, 18 | gbuffer_target& out, 19 | int force_input_layer = -1, 20 | int force_output_layer = -1 21 | ); 22 | 23 | private: 24 | timer copy_timer; 25 | }; 26 | 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/gltf.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_GLTF_HH 2 | #define TAURAY_GLTF_HH 3 | #include "scene_assets.hh" 4 | #include "scene.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | scene_assets load_gltf( 10 | device_mask dev, 11 | scene& s, 12 | const std::string& path, 13 | bool force_single_sided = false, 14 | bool force_double_sided = false 15 | ); 16 | 17 | } 18 | 19 | #endif 20 | 21 | -------------------------------------------------------------------------------- /src/light.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_LIGHT_HH 2 | #define TAURAY_LIGHT_HH 3 | #include "transformable.hh" 4 | #include "animation.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | struct ambient_light 10 | { 11 | vec3 color; 12 | }; 13 | 14 | class light 15 | { 16 | public: 17 | light(vec3 color = vec3(1.0)); 18 | 19 | void set_color(vec3 color); 20 | vec3 get_color() const; 21 | 22 | private: 23 | vec3 color; 24 | }; 25 | 26 | class directional_light: public light 27 | { 28 | public: 29 | directional_light( 30 | vec3 color = vec3(1.0), 31 | float angle = 0.0f 32 | ); 33 | 34 | float get_angle() const; 35 | void set_angle(float angle); 36 | 37 | private: 38 | float angle; 39 | }; 40 | 41 | class point_light: public light 42 | { 43 | public: 44 | point_light( 45 | vec3 color = vec3(1.0), 46 | float radius = 0.0f, 47 | float cutoff_brightness = 5.0f/256.0f 48 | ); 49 | 50 | void set_radius(float radius); 51 | float get_radius() const; 52 | 53 | void set_cutoff_brightness(float cutoff_brightness = 5.0f/256.0f); 54 | float get_cutoff_brightness() const; 55 | void set_cutoff_radius(float cutoff_radius); 56 | float get_cutoff_radius() const; 57 | 58 | private: 59 | float radius; 60 | float cutoff_brightness; 61 | }; 62 | 63 | class spotlight: public point_light 64 | { 65 | public: 66 | spotlight( 67 | vec3 color = vec3(1.0), 68 | float cutoff_angle = 30, 69 | float falloff_exponent = 1, 70 | float radius = 0.02f 71 | ); 72 | 73 | void set_cutoff_angle(float cutoff_angle); 74 | float get_cutoff_angle() const; 75 | 76 | void set_falloff_exponent(float falloff_exponent); 77 | float get_falloff_exponent() const; 78 | 79 | // Approximates falloff exponent from the inner angle representation. 80 | void set_inner_angle(float inner_angle, float ratio = 1.f/255.f); 81 | 82 | private: 83 | float cutoff_angle; 84 | float falloff_exponent; 85 | }; 86 | 87 | } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /src/load_balancer.cc: -------------------------------------------------------------------------------- 1 | #include "load_balancer.hh" 2 | 3 | namespace tr 4 | { 5 | 6 | load_balancer::load_balancer(context& ctx, const std::vector& initial_weights) 7 | : ctx(&ctx), workloads(initial_weights) 8 | { 9 | normalize_workloads(); 10 | } 11 | 12 | void load_balancer::update(renderer& ren) 13 | { 14 | double sum_speed = 0; 15 | for(size_t i = 0; i < workloads.size(); ++i) 16 | { 17 | double time = ctx->get_timing().get_duration(i, "path tracing"); 18 | double speed = max(workloads[i] / time, 0.0); 19 | sum_speed += speed; 20 | } 21 | 22 | if(sum_speed > 0 && std::isfinite(sum_speed)) 23 | { 24 | for(size_t i = 0; i < workloads.size(); ++i) 25 | { 26 | double time = ctx->get_timing().get_duration(i, "path tracing"); 27 | double speed = workloads[i] / time; 28 | workloads[i] = mix(workloads[i], speed/sum_speed, 0.1); 29 | } 30 | } 31 | ren.set_device_workloads(workloads); 32 | } 33 | 34 | void load_balancer::normalize_workloads() 35 | { 36 | workloads.resize(ctx->get_devices().size()); 37 | double sum = 0; 38 | double add = 0; 39 | for(double w: workloads) sum += w; 40 | 41 | if(sum == 0) 42 | { 43 | add = 1.0f; 44 | sum = workloads.size(); 45 | } 46 | 47 | for(double& w: workloads) 48 | { 49 | w = (max(w, 0.0)+add)/sum; 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/load_balancer.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_LOAD_BALANCER_HH 2 | #define TAURAY_LOAD_BALANCER_HH 3 | #include "context.hh" 4 | #include "renderer.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | class load_balancer 10 | { 11 | public: 12 | load_balancer(context& ctx, const std::vector& initial_weights = {}); 13 | 14 | void update(renderer& ren); 15 | 16 | private: 17 | void normalize_workloads(); 18 | 19 | context* ctx; 20 | std::vector workloads; 21 | }; 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/log.cc: -------------------------------------------------------------------------------- 1 | #include "log.hh" 2 | 3 | namespace tr 4 | { 5 | 6 | bool enabled_log_types[5] = {true, true, true, true, true}; 7 | std::ostream* log_output_streams[5] = { 8 | &std::cout, 9 | &std::cerr, 10 | &std::cerr, 11 | &std::cout, 12 | &std::cout 13 | }; 14 | 15 | void apply_color(log_type type, std::ostream& os) 16 | { 17 | #ifdef __unix__ 18 | if(&os != &std::cout && &os != &std::cerr) 19 | return; 20 | 21 | switch(type) 22 | { 23 | case log_type::GENERAL: 24 | os << "\x1b[0;39m"; 25 | break; 26 | case log_type::ERROR: 27 | os << "\x1b[0;31m"; 28 | break; 29 | case log_type::WARNING: 30 | os << "\x1b[0;33m"; 31 | break; 32 | case log_type::DEBUG: 33 | os << "\x1b[0;32m"; 34 | break; 35 | case log_type::TIMING: 36 | os << "\x1b[0;94m"; 37 | break; 38 | } 39 | #endif 40 | } 41 | 42 | std::chrono::system_clock::time_point get_initial_time() 43 | { 44 | static std::chrono::system_clock::time_point initial = 45 | std::chrono::system_clock::now(); 46 | return initial; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/looking_glass_composition_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_LOOKING_GLASS_COMPOSITION_STAGE_HH 2 | #define TAURAY_LOOKING_GLASS_COMPOSITION_STAGE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "compute_pipeline.hh" 6 | #include "descriptor_set.hh" 7 | #include "sampler.hh" 8 | #include "timer.hh" 9 | #include "stage.hh" 10 | 11 | namespace tr 12 | { 13 | 14 | class looking_glass_composition_stage: public single_device_stage 15 | { 16 | public: 17 | struct options 18 | { 19 | uint32_t viewport_count; 20 | float pitch; 21 | float tilt; 22 | float center; 23 | bool invert; 24 | }; 25 | 26 | looking_glass_composition_stage( 27 | device& dev, 28 | render_target& input, 29 | std::vector& output_frames, 30 | const options& opt 31 | ); 32 | 33 | private: 34 | push_descriptor_set desc; 35 | compute_pipeline comp; 36 | sampler input_sampler; 37 | timer stage_timer; 38 | }; 39 | 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/main.cc: -------------------------------------------------------------------------------- 1 | #include "tauray.hh" 2 | #include 3 | #include 4 | 5 | int main(int, char** argv) try 6 | { 7 | std::ios_base::sync_with_stdio(false); 8 | 9 | tr::options opt; 10 | tr::parse_command_line_options(argv, opt); 11 | 12 | // Initialize log timer. 13 | tr::get_initial_time(); 14 | std::optional timing_output_file; 15 | 16 | if(opt.silent) 17 | { 18 | tr::enabled_log_types[(uint32_t)tr::log_type::GENERAL] = false; 19 | tr::enabled_log_types[(uint32_t)tr::log_type::WARNING] = false; 20 | } 21 | 22 | if(opt.timing_output.size() != 0) 23 | { 24 | timing_output_file.emplace(opt.timing_output, std::ios::binary|std::ios::trunc); 25 | tr::log_output_streams[(uint32_t)tr::log_type::TIMING] = &timing_output_file.value(); 26 | } 27 | 28 | std::unique_ptr ctx(tr::create_context(opt)); 29 | 30 | tr::scene_data sd = tr::load_scenes(*ctx, opt); 31 | 32 | tr::run(*ctx, sd, opt); 33 | 34 | return 0; 35 | } 36 | catch (std::runtime_error& e) 37 | { 38 | // Can't use TR_ERR here, because the logger may not yet be initialized or 39 | // it's output file may already be closed. 40 | if (strlen(e.what())) std::cerr << e.what() << "\n" << std::endl; 41 | return 1; 42 | } 43 | -------------------------------------------------------------------------------- /src/material.cc: -------------------------------------------------------------------------------- 1 | #include "material.hh" 2 | #include "texture.hh" 3 | 4 | namespace tr 5 | { 6 | 7 | bool material::potentially_transparent() const 8 | { 9 | return transmittance > 0.0f || albedo_factor.a < 1.0f || 10 | (albedo_tex.first && albedo_tex.first->potentially_transparent()); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/material.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_MATERIAL_HH 2 | #define TAURAY_MATERIAL_HH 3 | #include "math.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | class texture; 9 | class sampler; 10 | 11 | using combined_tex_sampler = std::pair; 12 | struct material 13 | { 14 | vec4 albedo_factor = vec4(1); 15 | combined_tex_sampler albedo_tex = combined_tex_sampler(nullptr, nullptr); 16 | 17 | float metallic_factor = 0.0f; 18 | float roughness_factor = 1.0f; 19 | combined_tex_sampler metallic_roughness_tex = 20 | combined_tex_sampler(nullptr, nullptr); 21 | 22 | float normal_factor = 1.0f; 23 | combined_tex_sampler normal_tex = combined_tex_sampler(nullptr, nullptr); 24 | 25 | float ior = 1.45f; 26 | vec3 emission_factor = vec3(0); 27 | combined_tex_sampler emission_tex = combined_tex_sampler(nullptr, nullptr); 28 | 29 | float transmittance = 0.0f; 30 | 31 | bool double_sided = true; 32 | // Flag to imply that the material / object it's attached to can change 33 | // wildly between frames. 34 | bool transient = false; 35 | 36 | std::string name = ""; 37 | 38 | bool potentially_transparent() const; 39 | }; 40 | 41 | struct combined_tex_sampler_hash 42 | { 43 | size_t operator()(const combined_tex_sampler & v) const 44 | { 45 | return hash_combine( 46 | std::hash()(v.first), 47 | std::hash()(v.second) 48 | ); 49 | } 50 | }; 51 | 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/math.tcc: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_MATH_TCC 2 | #define TAURAY_MATH_TCC 3 | #include "math.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | template 9 | T vecmax(const vec& v) 10 | { 11 | T m = v[0]; 12 | for(length_t i = 1; i < L; ++i) m = max(m, v[i]); 13 | return m; 14 | } 15 | 16 | template 17 | T vecmin(const vec& v) 18 | { 19 | T m = v[0]; 20 | for(length_t i = 1; i < L; ++i) m = min(m, v[i]); 21 | return m; 22 | } 23 | 24 | template 25 | T cubic_spline(T p1, T m1, T p2, T m2, float t) 26 | { 27 | float t2 = t * t; 28 | float t3 = t2 * t; 29 | float tmp = 2 * t3 - 3 * t2; 30 | return 31 | (tmp + 1) * p1 + 32 | (t3 - 2 * t2 + t) * m1 + 33 | (-tmp) * p2 + 34 | (t3 - t2) * m2; 35 | } 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/model.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_MODEL_HH 2 | #define TAURAY_MODEL_HH 3 | #include "mesh.hh" 4 | #include "material.hh" 5 | #include 6 | 7 | namespace tr 8 | { 9 | 10 | class model 11 | { 12 | public: 13 | model(); 14 | model(const model& other); 15 | model(model&& other); 16 | model(const material& mat, mesh* m); 17 | 18 | model& operator=(const model& other); 19 | model& operator=(model&& other); 20 | 21 | struct vertex_group 22 | { 23 | material mat; 24 | mesh* m; 25 | }; 26 | 27 | struct joint_data 28 | { 29 | transformable* node; 30 | mat4 inverse_bind_matrix; 31 | }; 32 | 33 | void add_vertex_group(const material& mat, mesh* m); 34 | void clear_vertex_groups(); 35 | 36 | bool is_skinned() const; 37 | 38 | size_t group_count() const; 39 | vertex_group& operator[](size_t i); 40 | const vertex_group& operator[](size_t i) const; 41 | 42 | using iterator = std::vector::iterator; 43 | using const_iterator = std::vector::const_iterator; 44 | 45 | iterator begin(); 46 | const_iterator begin() const; 47 | const_iterator cbegin() const; 48 | 49 | iterator end(); 50 | const_iterator end() const; 51 | const_iterator cend() const; 52 | 53 | std::vector& get_joints(); 54 | const std::vector& get_joints() const; 55 | 56 | void init_joints_buffer(device_mask dev); 57 | bool has_joints_buffer(); 58 | const gpu_buffer& get_joint_buffer() const; 59 | 60 | void update_joints(uint32_t frame_index); 61 | void upload_joints(vk::CommandBuffer buf, device_id id, uint32_t frame_index); 62 | 63 | void set_shadow_terminator_offset(float offset = 0.0f); 64 | float get_shadow_terminator_offset() const; 65 | 66 | private: 67 | std::vector groups; 68 | std::vector joints; 69 | std::optional joint_buffer; 70 | float shadow_terminator_offset; 71 | }; 72 | 73 | } 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /src/path_tracer_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_PATH_TRACER_STAGE_HH 2 | #define TAURAY_PATH_TRACER_STAGE_HH 3 | #include "rt_camera_stage.hh" 4 | #include "rt_common.hh" 5 | #include "descriptor_set.hh" 6 | 7 | namespace tr 8 | { 9 | 10 | class path_tracer_stage: public rt_camera_stage 11 | { 12 | public: 13 | struct options: public rt_camera_stage::options 14 | { 15 | bool use_shadow_terminator_fix = false; 16 | bool use_white_albedo_on_first_bounce = false; 17 | bool hide_lights = false; 18 | film_filter film = film_filter::BLACKMAN_HARRIS; 19 | multiple_importance_sampling_mode mis_mode = 20 | multiple_importance_sampling_mode::MIS_POWER_HEURISTIC; 21 | float film_radius = 1.0f; // 0.5 is "correct" for the box filter. 22 | float russian_roulette_delta = 0; // 0 disables russian roulette. 23 | float indirect_clamping = 0; // 0 disables indirect clamping. 24 | float regularization_gamma = 0.0f; // 0 disables path regularization 25 | bool depth_of_field = false; // false disregards camera focus parameters. 26 | 27 | light_sampling_weights sampling_weights; 28 | bounce_sampling_mode bounce_mode = bounce_sampling_mode::MATERIAL; 29 | tri_light_sampling_mode tri_light_mode = tri_light_sampling_mode::HYBRID; 30 | }; 31 | 32 | path_tracer_stage( 33 | device& dev, 34 | scene_stage& ss, 35 | const gbuffer_target& output_target, 36 | const options& opt 37 | ); 38 | 39 | protected: 40 | void record_command_buffer_pass( 41 | vk::CommandBuffer cb, 42 | uint32_t frame_index, 43 | uint32_t pass_index, 44 | uvec3 expected_dispatch_size, 45 | bool first_in_command_buffer 46 | ) override; 47 | 48 | private: 49 | push_descriptor_set desc; 50 | rt_pipeline gfx; 51 | options opt; 52 | }; 53 | 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /src/placeholders.cc: -------------------------------------------------------------------------------- 1 | #include "placeholders.hh" 2 | #include "misc.hh" 3 | 4 | namespace tr 5 | { 6 | 7 | placeholders::placeholders(context& ctx) 8 | : ctx(&ctx), 9 | sample2d( 10 | device_mask::all(ctx), 11 | uvec2(1), 12 | 1, 13 | vk::Format::eR8G8B8A8Unorm, 14 | 0, nullptr, 15 | vk::ImageTiling::eOptimal, 16 | vk::ImageUsageFlagBits::eSampled, 17 | vk::ImageLayout::eShaderReadOnlyOptimal 18 | ), 19 | sample3d( 20 | device_mask::all(ctx), 21 | uvec3(1), 22 | vk::Format::eR8G8B8A8Unorm, 23 | vk::ImageTiling::eOptimal, 24 | vk::ImageUsageFlagBits::eSampled, 25 | vk::ImageLayout::eShaderReadOnlyOptimal 26 | ), 27 | depth_test_sample( 28 | device_mask::all(ctx), 29 | uvec2(1), 30 | 1, 31 | vk::Format::eD32Sfloat, 32 | 0, nullptr, 33 | vk::ImageTiling::eOptimal, 34 | vk::ImageUsageFlagBits::eSampled, 35 | vk::ImageLayout::eShaderReadOnlyOptimal 36 | ), 37 | default_sampler( 38 | device_mask::all(ctx), 39 | vk::Filter::eNearest, vk::Filter::eNearest, 40 | vk::SamplerAddressMode::eRepeat, 41 | vk::SamplerAddressMode::eRepeat, 42 | vk::SamplerMipmapMode::eNearest, 0, 43 | true, false 44 | ), 45 | buffers(device_mask::all(ctx)) 46 | { 47 | for(auto[d, buf]: buffers) 48 | { 49 | buf.storage_buffer = create_buffer( 50 | d, 51 | { 52 | {}, 53 | 4, 54 | vk::BufferUsageFlagBits::eStorageBuffer, 55 | vk::SharingMode::eExclusive 56 | }, 57 | VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT 58 | ); 59 | 60 | buf.img_2d_info = { 61 | default_sampler.get_sampler(d.id), 62 | sample2d.get_image_view(d.id), 63 | vk::ImageLayout::eShaderReadOnlyOptimal 64 | }; 65 | buf.img_3d_info = { 66 | default_sampler.get_sampler(d.id), 67 | sample3d.get_image_view(d.id), 68 | vk::ImageLayout::eShaderReadOnlyOptimal 69 | }; 70 | buf.storage_info = vk::DescriptorBufferInfo{ 71 | buf.storage_buffer, 0, VK_WHOLE_SIZE 72 | }; 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/placeholders.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_PLACEHOLDERS_HH 2 | #define TAURAY_PLACEHOLDERS_HH 3 | #include "texture.hh" 4 | #include "sampler.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | // These placeholder assets are used when some resource is missing. 10 | struct placeholders 11 | { 12 | placeholders(context& ctx); 13 | 14 | context* ctx; 15 | texture sample2d; 16 | texture sample3d; 17 | texture depth_test_sample; 18 | sampler default_sampler; 19 | 20 | struct buffer 21 | { 22 | vkm storage_buffer; 23 | 24 | vk::DescriptorImageInfo img_2d_info; 25 | vk::DescriptorImageInfo img_3d_info; 26 | vk::DescriptorBufferInfo storage_info; 27 | }; 28 | per_device buffers; 29 | }; 30 | 31 | } 32 | 33 | #endif 34 | 35 | -------------------------------------------------------------------------------- /src/progress_tracker.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_PROGRESS_TRACKER_HH 2 | #define TAURAY_PROGRESS_TRACKER_HH 3 | 4 | #include "device.hh" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace tr 11 | { 12 | 13 | class context; 14 | 15 | class progress_tracker 16 | { 17 | public: 18 | progress_tracker(context* ctx); 19 | ~progress_tracker(); 20 | 21 | struct options 22 | { 23 | size_t expected_frame_count; 24 | size_t poll_ms = 10; 25 | }; 26 | 27 | void begin(options opt); 28 | void end(); 29 | 30 | void set_timeline(device_id id, vk::Semaphore timeline, size_t expected_steps_per_frame); 31 | void erase_timeline(vk::Semaphore timeline); 32 | 33 | private: 34 | void update_progress_bar( 35 | std::chrono::steady_clock::time_point start, float progress 36 | ); 37 | 38 | context* ctx; 39 | options opt; 40 | std::optional poll_thread; 41 | std::condition_variable cv; 42 | bool running; 43 | 44 | static void poll_worker(progress_tracker* self); 45 | 46 | struct tracking_data 47 | { 48 | device_id id; 49 | vk::Semaphore timeline; 50 | size_t expected_steps_per_frame; 51 | }; 52 | std::mutex tracking_mutex; 53 | std::vector tracking_resources; 54 | }; 55 | 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/radix_sort.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RADIX_SORT_HH 2 | #define TAURAY_RADIX_SORT_HH 3 | #include "vkm.hh" 4 | #include "compute_pipeline.hh" 5 | #include "descriptor_set.hh" 6 | 7 | namespace tr 8 | { 9 | 10 | struct device; 11 | 12 | class radix_sort 13 | { 14 | public: 15 | radix_sort(device& ctx); 16 | radix_sort(radix_sort&& other) = delete; 17 | radix_sort(const radix_sort& other) = delete; 18 | ~radix_sort(); 19 | 20 | vkm create_keyval_buffer(size_t max_items); 21 | 22 | void sort( 23 | vk::CommandBuffer cb, 24 | vk::Buffer input_items, 25 | vk::Buffer output_items, 26 | vk::Buffer item_keyvals, // Must be allocated via create_keyval_buffer 27 | size_t item_size, 28 | size_t item_count, 29 | size_t key_bits = 32 30 | ); 31 | 32 | private: 33 | device* dev; 34 | void* rs_instance; 35 | push_descriptor_set desc; 36 | compute_pipeline reorder; 37 | }; 38 | 39 | } 40 | 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /src/raster_renderer.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RASTER_RENDERER_HH 2 | #define TAURAY_RASTER_RENDERER_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "z_pass_stage.hh" 6 | #include "raster_stage.hh" 7 | #include "envmap_stage.hh" 8 | #include "scene_stage.hh" 9 | #include "shadow_map_stage.hh" 10 | #include "post_processing_renderer.hh" 11 | #include "renderer.hh" 12 | 13 | namespace tr 14 | { 15 | 16 | class raster_renderer: public renderer 17 | { 18 | public: 19 | struct options: raster_stage::options 20 | { 21 | int msaa_samples = 1; 22 | scene_stage::options scene_options = {}; 23 | post_processing_renderer::options post_process = {}; 24 | // Enabling the Z pre-pass can help with performance if the scene is 25 | // overdraw + bandwidth-heavy. It essentially just prevents all overdraw 26 | // from taking place during final rasterization at the cost of an extra 27 | // z pass. 28 | bool z_pre_pass = true; 29 | }; 30 | 31 | raster_renderer(context& ctx, const options& opt); 32 | raster_renderer(const raster_renderer& other) = delete; 33 | raster_renderer(raster_renderer&& other) = delete; 34 | ~raster_renderer(); 35 | 36 | void set_scene(scene* s) override; 37 | void render() override; 38 | 39 | protected: 40 | dependencies render_core(dependencies deps); 41 | void init_common_resources(); 42 | void init_resources(size_t display_index); 43 | 44 | context* ctx; 45 | options opt; 46 | scene* cur_scene = nullptr; 47 | std::unique_ptr scene_update; 48 | 49 | private: 50 | std::optional post_processing; 51 | std::vector> shared_resource_semaphores; 52 | gbuffer_texture gbuffer; 53 | std::optional sms; 54 | std::optional envmap; 55 | std::optional z_pass; 56 | std::optional raster; 57 | }; 58 | 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/raster_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RASTER_STAGE_HH 2 | #define TAURAY_RASTER_STAGE_HH 3 | #include "context.hh" 4 | #include "timer.hh" 5 | #include "texture.hh" 6 | #include "raster_pipeline.hh" 7 | #include "sampler.hh" 8 | #include "gbuffer.hh" 9 | #include "gpu_buffer.hh" 10 | #include "shadow_map.hh" 11 | #include "stage.hh" 12 | 13 | namespace tr 14 | { 15 | 16 | class scene_stage; 17 | class shadow_map_renderer; 18 | class sh_grid; 19 | class raster_stage: public single_device_stage 20 | { 21 | public: 22 | struct options 23 | { 24 | bool clear_color = true; 25 | bool clear_depth = true; 26 | bool sample_shading = false; 27 | 28 | shadow_map_filter filter = {}; 29 | 30 | // Spherical harmonics options 31 | bool use_probe_visibility = false; 32 | int sh_order = 2; 33 | bool estimate_indirect = true; 34 | bool estimate_direct = true; 35 | 36 | // Required for some denoisers to drop albedo from transparent textures in the gbuffer 37 | bool force_alpha_to_coverage = false; 38 | // Output layout to avoid excess work in render pass 39 | vk::ImageLayout output_layout = vk::ImageLayout::eColorAttachmentOptimal; 40 | 41 | unsigned base_camera_index = 0; 42 | 43 | // Attempts to undo TAA jitter for textures, increasing their clarity. 44 | bool unjitter_textures = false; 45 | }; 46 | 47 | raster_stage( 48 | device& dev, 49 | scene_stage& ss, 50 | const std::vector& output_array_targets, 51 | const options& opt 52 | ); 53 | 54 | raster_stage( 55 | device& dev, 56 | scene_stage& ss, 57 | gbuffer_target& output_target, 58 | const options& opt 59 | ); 60 | 61 | protected: 62 | void update(uint32_t frame_index) override; 63 | 64 | private: 65 | std::vector> array_pipelines; 66 | std::vector output_targets; 67 | options opt; 68 | 69 | uint32_t scene_state_counter; 70 | scene_stage* ss; 71 | timer raster_timer; 72 | }; 73 | 74 | } 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /src/render_target.cc: -------------------------------------------------------------------------------- 1 | #include "render_target.hh" 2 | #include "misc.hh" 3 | 4 | namespace tr 5 | { 6 | 7 | render_target::render_target( 8 | uvec2 size, 9 | unsigned base_layer, 10 | unsigned layer_count, 11 | vk::Image image, 12 | vk::ImageView view, 13 | vk::ImageLayout layout, 14 | vk::Format format, 15 | vk::SampleCountFlagBits msaa 16 | ): size(size), base_layer(base_layer), layer_count(layer_count), 17 | msaa(msaa), format(format), image(image), view(view), layout(layout) 18 | { 19 | } 20 | 21 | render_target::operator bool() const 22 | { 23 | return !!image; 24 | } 25 | 26 | void render_target::transition_layout_temporary( 27 | vk::CommandBuffer cb, 28 | vk::ImageLayout layout, 29 | bool ignore_src_stage_mask, 30 | bool ignore_dst_stage_mask 31 | ){ 32 | transition_image_layout( 33 | cb, image, format, this->layout, layout, 0, 1, 34 | base_layer, layer_count, ignore_src_stage_mask, ignore_dst_stage_mask 35 | ); 36 | } 37 | 38 | void render_target::transition_layout( 39 | vk::CommandBuffer cb, 40 | vk::ImageLayout from, 41 | vk::ImageLayout to, 42 | bool ignore_src_stage_mask, 43 | bool ignore_dst_stage_mask 44 | ){ 45 | transition_image_layout( 46 | cb, image, format, from, to, 0, 1, 47 | base_layer, layer_count, ignore_src_stage_mask, ignore_dst_stage_mask 48 | ); 49 | } 50 | 51 | vk::ImageSubresourceLayers render_target::get_layers() const 52 | { 53 | return {deduce_aspect_mask(format), 0, base_layer, layer_count}; 54 | } 55 | 56 | vk::ImageSubresourceRange render_target::get_range() const 57 | { 58 | return {deduce_aspect_mask(format), 0, 1, base_layer, layer_count}; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/render_target.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RENDER_TARGET_HH 2 | #define TAURAY_RENDER_TARGET_HH 3 | #include "vkm.hh" 4 | #include "math.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | struct render_target 10 | { 11 | public: 12 | render_target() = default; 13 | 14 | render_target( 15 | uvec2 size, 16 | unsigned base_layer, 17 | unsigned layer_count, 18 | vk::Image image, 19 | vk::ImageView view, 20 | vk::ImageLayout layout, 21 | vk::Format format, 22 | vk::SampleCountFlagBits msaa = vk::SampleCountFlagBits::e1 23 | ); 24 | 25 | operator bool() const; 26 | 27 | // Does not save the new layout, but assumes that it's reset every time. 28 | void transition_layout_temporary( 29 | vk::CommandBuffer cb, 30 | vk::ImageLayout layout, 31 | bool ignore_src_stage_mask = false, 32 | bool ignore_dst_stage_mask = false 33 | ); 34 | 35 | void transition_layout( 36 | vk::CommandBuffer cb, 37 | vk::ImageLayout from, 38 | vk::ImageLayout to, 39 | bool ignore_src_stage_mask = false, 40 | bool ignore_dst_stage_mask = false 41 | ); 42 | 43 | vk::ImageSubresourceLayers get_layers() const; 44 | vk::ImageSubresourceRange get_range() const; 45 | 46 | uvec2 size; 47 | unsigned base_layer; 48 | unsigned layer_count; 49 | vk::SampleCountFlagBits msaa; 50 | vk::Format format; 51 | vk::Image image = VK_NULL_HANDLE; 52 | vk::ImageView view = VK_NULL_HANDLE; 53 | vk::ImageLayout layout; 54 | }; 55 | 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /src/renderer.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RENDERER_HH 2 | #define TAURAY_RENDERER_HH 3 | #include "dependency.hh" 4 | #include "scene.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | class renderer 10 | { 11 | public: 12 | virtual ~renderer() = default; 13 | 14 | virtual void set_scene(scene* s) = 0; 15 | virtual void reset_accumulation(bool reset_sample_counter = false) {(void)reset_sample_counter;}; 16 | virtual void render() = 0; 17 | virtual void set_device_workloads(const std::vector&) {} 18 | 19 | private: 20 | }; 21 | 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/rt_camera_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RT_CAMERA_STAGE_HH 2 | #define TAURAY_RT_CAMERA_STAGE_HH 3 | #include "rt_stage.hh" 4 | #include "distribution_strategy.hh" 5 | #include "gbuffer.hh" 6 | #include "camera.hh" 7 | 8 | namespace tr 9 | { 10 | 11 | // Same as rt_stage, but additionally assumes that: 12 | // * There is a single camera 13 | // * The result is a 2D image 14 | class rt_camera_stage: public rt_stage 15 | { 16 | public: 17 | struct options: public rt_stage::options 18 | { 19 | distribution_params distribution; 20 | size_t active_viewport_count = 1; 21 | int samples_per_pixel = 1; 22 | int samples_per_pass = 1; 23 | camera::projection_type projection = camera::PERSPECTIVE; 24 | bool transparent_background = false; 25 | }; 26 | 27 | rt_camera_stage( 28 | device& dev, 29 | scene_stage& ss, 30 | const gbuffer_target& output_target, 31 | const options& opt, 32 | const std::string& timer_name = "ray tracing", 33 | unsigned pass_count = 1 34 | ); 35 | 36 | void reset_accumulated_samples(); 37 | 38 | // You can change everything except the distribution strategy. 39 | void reset_distribution_params(distribution_params distribution); 40 | 41 | void get_common_defines(std::map& defines); 42 | 43 | 44 | protected: 45 | void update(uint32_t frame_index) override; 46 | void record_command_buffer( 47 | vk::CommandBuffer cb, uint32_t frame_index, uint32_t pass_index, 48 | bool first_in_command_buffer 49 | ) override; 50 | int get_accumulated_samples() const; 51 | 52 | void get_descriptors(push_descriptor_set& desc); 53 | 54 | virtual void record_command_buffer_pass( 55 | vk::CommandBuffer cb, 56 | uint32_t frame_index, 57 | uint32_t pass_index, 58 | uvec3 expected_dispatch_size, 59 | bool first_in_command_buffer 60 | ) = 0; 61 | 62 | gpu_buffer distribution_data; 63 | 64 | private: 65 | options opt; 66 | gbuffer_target target; 67 | 68 | int accumulated_samples; 69 | }; 70 | 71 | } 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /src/rt_common.cc: -------------------------------------------------------------------------------- 1 | #include "rt_common.hh" 2 | 3 | namespace tr 4 | { 5 | 6 | void add_defines(film_filter filter, std::map& defines) 7 | { 8 | switch(filter) 9 | { 10 | case film_filter::POINT: 11 | defines["USE_POINT_FILTER"]; 12 | break; 13 | case film_filter::BOX: 14 | defines["USE_BOX_FILTER"]; 15 | break; 16 | case film_filter::BLACKMAN_HARRIS: 17 | defines["USE_BLACKMAN_HARRIS_FILTER"]; 18 | break; 19 | } 20 | } 21 | 22 | void add_defines(multiple_importance_sampling_mode mode, std::map& defines) 23 | { 24 | switch(mode) 25 | { 26 | case multiple_importance_sampling_mode::MIS_DISABLED: 27 | break; 28 | case multiple_importance_sampling_mode::MIS_BALANCE_HEURISTIC: 29 | defines["MIS_BALANCE_HEURISTIC"]; 30 | break; 31 | case multiple_importance_sampling_mode::MIS_POWER_HEURISTIC: 32 | defines["MIS_POWER_HEURISTIC"]; 33 | break; 34 | } 35 | } 36 | 37 | void add_defines(bounce_sampling_mode mode, std::map& defines) 38 | { 39 | switch(mode) 40 | { 41 | case bounce_sampling_mode::HEMISPHERE: 42 | defines["BOUNCE_HEMISPHERE"]; 43 | break; 44 | case bounce_sampling_mode::COSINE_HEMISPHERE: 45 | defines["BOUNCE_COSINE_HEMISPHERE"]; 46 | break; 47 | case bounce_sampling_mode::MATERIAL: 48 | defines["BOUNCE_MATERIAL"]; 49 | break; 50 | } 51 | } 52 | 53 | void add_defines(tri_light_sampling_mode mode, std::map& defines) 54 | { 55 | switch(mode) 56 | { 57 | case tri_light_sampling_mode::AREA: 58 | defines["TRI_LIGHT_SAMPLE_AREA"]; 59 | break; 60 | case tri_light_sampling_mode::SOLID_ANGLE: 61 | defines["TRI_LIGHT_SAMPLE_SOLID_ANGLE"]; 62 | break; 63 | case tri_light_sampling_mode::HYBRID: 64 | defines["TRI_LIGHT_SAMPLE_HYBRID"]; 65 | break; 66 | } 67 | } 68 | 69 | void add_defines(light_sampling_weights weights, std::map& defines) 70 | { 71 | if(weights.point_lights > 0) 72 | defines["NEE_SAMPLE_POINT_LIGHTS"] = std::to_string(weights.point_lights); 73 | if(weights.directional_lights > 0) 74 | defines["NEE_SAMPLE_DIRECTIONAL_LIGHTS"] = std::to_string(weights.directional_lights); 75 | if(weights.envmap > 0) 76 | defines["NEE_SAMPLE_ENVMAP"] = std::to_string(weights.envmap); 77 | if(weights.emissive_triangles > 0) 78 | defines["NEE_SAMPLE_EMISSIVE_TRIANGLES"] = std::to_string(weights.emissive_triangles); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/rt_common.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RT_COMMON_HH 2 | #define TAURAY_RT_COMMON_HH 3 | #include 4 | #include 5 | 6 | namespace tr 7 | { 8 | enum class film_filter 9 | { 10 | POINT = 0, 11 | BOX, 12 | BLACKMAN_HARRIS 13 | }; 14 | void add_defines(film_filter filter, std::map& defines); 15 | 16 | enum class multiple_importance_sampling_mode 17 | { 18 | MIS_DISABLED, 19 | MIS_BALANCE_HEURISTIC, 20 | MIS_POWER_HEURISTIC 21 | }; 22 | void add_defines(multiple_importance_sampling_mode mode, std::map& defines); 23 | 24 | enum class bounce_sampling_mode 25 | { 26 | HEMISPHERE, // Degrades to spherical for transmissive objects 27 | COSINE_HEMISPHERE, // Degrades to double-sided for transmissive objects 28 | MATERIAL 29 | }; 30 | void add_defines(bounce_sampling_mode mode, std::map& defines); 31 | 32 | enum class tri_light_sampling_mode 33 | { 34 | AREA, // Okay for small solid angles, pretty bad for large solid angles 35 | SOLID_ANGLE, // Good for large solid angles, bad for small due to precision issues 36 | HYBRID // Tries to switch between area and solid angle sampling depending on precision pitfalls 37 | }; 38 | void add_defines(tri_light_sampling_mode mode, std::map& defines); 39 | 40 | struct light_sampling_weights 41 | { 42 | float point_lights = 1.0f; 43 | float directional_lights = 1.0f; 44 | float envmap = 1.0f; 45 | float emissive_triangles = 1.0f; 46 | }; 47 | void add_defines(light_sampling_weights weights, std::map& defines); 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/rt_pipeline.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RT_PIPELINE_HH 2 | #define TAURAY_RT_PIPELINE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "basic_pipeline.hh" 6 | #include "render_target.hh" 7 | #include 8 | 9 | namespace tr 10 | { 11 | 12 | class rt_pipeline: public basic_pipeline 13 | { 14 | public: 15 | rt_pipeline(device& dev); 16 | 17 | void init( 18 | rt_shader_sources src, 19 | std::vector layout, 20 | int max_recursion_depth = 1, 21 | vk::SpecializationInfo specialization = {} 22 | ); 23 | 24 | void trace_rays(vk::CommandBuffer buf, uvec3 size); 25 | 26 | protected: 27 | vkm sbt_buffer; 28 | vk::StridedDeviceAddressRegionKHR rgen_sbt; 29 | vk::StridedDeviceAddressRegionKHR rchit_sbt; 30 | vk::StridedDeviceAddressRegionKHR rmiss_sbt; 31 | vk::StridedDeviceAddressRegionKHR rcallable_sbt; 32 | }; 33 | 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/rt_renderer.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RT_RENDERER_HH 2 | #define TAURAY_RT_RENDERER_HH 3 | #ifdef WIN32 4 | #include "windows.h" 5 | #ifdef near 6 | #undef near 7 | #endif 8 | #ifdef far 9 | #undef far 10 | #endif 11 | #endif 12 | #include "context.hh" 13 | #include "texture.hh" 14 | #include "path_tracer_stage.hh" 15 | #include "direct_stage.hh" 16 | #include "raster_stage.hh" 17 | #include "feature_stage.hh" 18 | #include "stitch_stage.hh" 19 | #include "scene_stage.hh" 20 | #include "renderer.hh" 21 | #include "device_transfer.hh" 22 | #include "post_processing_renderer.hh" 23 | #include 24 | 25 | namespace tr 26 | { 27 | 28 | template 29 | class rt_renderer: public renderer 30 | { 31 | public: 32 | struct options: Pipeline::options 33 | { 34 | scene_stage::options scene_options = {}; 35 | post_processing_renderer::options post_process = {}; 36 | bool accumulate = false; 37 | }; 38 | 39 | rt_renderer(context& ctx, const options& opt); 40 | rt_renderer(const rt_renderer& other) = delete; 41 | rt_renderer(rt_renderer&& other) = delete; 42 | ~rt_renderer(); 43 | 44 | void set_scene(scene* s) override; 45 | void reset_accumulation(bool reset_sample_counter = true) override; 46 | void render() override; 47 | void set_device_workloads(const std::vector& ratios) override; 48 | 49 | private: 50 | void init_resources(); 51 | void prepare_transfers(bool reserve); 52 | 53 | context* ctx; 54 | options opt; 55 | std::optional post_processing; 56 | bool use_raster_gbuffer = true; 57 | unsigned accumulated_frames = 0; 58 | 59 | gbuffer_texture gbuffer; 60 | 61 | struct per_device_data 62 | { 63 | gbuffer_texture gbuffer_copy; 64 | std::unique_ptr transfer; 65 | std::unique_ptr ray_tracer; 66 | distribution_params dist; 67 | }; 68 | std::vector per_device; 69 | std::optional scene_update; 70 | std::optional stitch; 71 | std::optional gbuffer_rasterizer; 72 | dependencies last_frame_deps; 73 | }; 74 | 75 | using path_tracer_renderer = rt_renderer; 76 | using feature_renderer = rt_renderer; 77 | using direct_renderer = rt_renderer; 78 | 79 | } 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /src/rt_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_RT_STAGE_HH 2 | #define TAURAY_RT_STAGE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "basic_pipeline.hh" 6 | #include "material.hh" 7 | #include "distribution_strategy.hh" 8 | #include "sampler_table.hh" 9 | #include "timer.hh" 10 | #include "gpu_buffer.hh" 11 | #include "stage.hh" 12 | #include "rt_pipeline.hh" 13 | 14 | namespace tr 15 | { 16 | 17 | class scene_stage; 18 | class rt_stage: public single_device_stage 19 | { 20 | public: 21 | enum class sampler_type 22 | { 23 | UNIFORM_RANDOM = 0, 24 | SOBOL_OWEN, 25 | SOBOL_Z_ORDER_2D, 26 | SOBOL_Z_ORDER_3D 27 | }; 28 | 29 | struct options 30 | { 31 | int max_ray_depth = 8; 32 | float min_ray_dist = 0.001f; 33 | 34 | int rng_seed = 0; 35 | sampler_type local_sampler = sampler_type::UNIFORM_RANDOM; 36 | 37 | // Small values add overhead but allow more detailed progression 38 | // tracking. 0 puts all in one command buffer and is fastest. 39 | size_t max_passes_per_command_buffer = 0; 40 | }; 41 | 42 | rt_stage( 43 | device& dev, 44 | scene_stage& ss, 45 | const options& opt, 46 | const std::string& timer_name, 47 | unsigned pass_count = 1 48 | ); 49 | rt_stage(const rt_stage& other) = delete; 50 | rt_stage(rt_stage&& other) = delete; 51 | 52 | void reset_sample_counter(); 53 | 54 | void get_common_defines(std::map& defines); 55 | 56 | 57 | protected: 58 | void update(uint32_t frame_index) override; 59 | virtual void record_command_buffer( 60 | vk::CommandBuffer cb, 61 | uint32_t frame_index, 62 | uint32_t pass_index, 63 | bool first_in_command_buffer 64 | ) = 0; 65 | void get_descriptors(push_descriptor_set& desc); 66 | void record_command_buffers(); 67 | void force_command_buffer_refresh(); 68 | 69 | unsigned get_pass_count() const; 70 | 71 | scene_stage* ss; 72 | unsigned sample_count_multiplier; 73 | 74 | private: 75 | options opt; 76 | unsigned pass_count = 1; 77 | timer rt_timer; 78 | 79 | gpu_buffer sampling_data; 80 | uint32_t frame_counter; 81 | uint32_t scene_state_counter; 82 | bool force_refresh; 83 | }; 84 | 85 | } 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /src/sampler.cc: -------------------------------------------------------------------------------- 1 | #include "sampler.hh" 2 | 3 | namespace tr 4 | { 5 | 6 | sampler::sampler( 7 | device_mask dev, vk::Filter min, vk::Filter mag, 8 | vk::SamplerAddressMode extend_x, 9 | vk::SamplerAddressMode extend_y, 10 | vk::SamplerMipmapMode mip, 11 | int anisotropy, bool normalized, bool use_mipmaps, 12 | bool shadow, float mip_bias 13 | ){ 14 | vk::SamplerCreateInfo info = vk::SamplerCreateInfo{ 15 | {}, 16 | min, mag, mip, extend_x, extend_y, extend_x, mip_bias, 17 | anisotropy > 0, (float)anisotropy, 18 | shadow, shadow ? vk::CompareOp::eLess : vk::CompareOp::eAlways, 19 | 0.0f, use_mipmaps ? 1000.0f : 0.0f, 20 | vk::BorderColor::eFloatTransparentBlack, 21 | !normalized 22 | }; 23 | samplers.init(dev, [&](device& d){ 24 | return vkm(d, d.logical.createSampler(info)); 25 | }); 26 | } 27 | 28 | vk::Sampler sampler::get_sampler(device_id id) const 29 | { 30 | return samplers[id]; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/sampler.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SAMPLER_HH 2 | #define TAURAY_SAMPLER_HH 3 | #include "context.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | class sampler 9 | { 10 | public: 11 | sampler( 12 | device_mask dev, 13 | vk::Filter min = vk::Filter::eLinear, 14 | vk::Filter mag = vk::Filter::eLinear, 15 | vk::SamplerAddressMode extend_x = vk::SamplerAddressMode::eRepeat, 16 | vk::SamplerAddressMode extend_y = vk::SamplerAddressMode::eRepeat, 17 | vk::SamplerMipmapMode mip = vk::SamplerMipmapMode::eLinear, 18 | int anisotropy = 16, 19 | bool normalized = true, 20 | bool use_mipmaps = true, 21 | bool shadow = false, 22 | float mip_bias = 0.0f 23 | ); 24 | sampler(const sampler& other) = delete; 25 | sampler(sampler&& other) = default; 26 | 27 | vk::Sampler get_sampler(device_id id) const; 28 | 29 | private: 30 | per_device> samplers; 31 | }; 32 | 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /src/sampler_table.cc: -------------------------------------------------------------------------------- 1 | #include "sampler_table.hh" 2 | #include "placeholders.hh" 3 | #include "scene_stage.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | sampler_table::sampler_table(device_mask dev, bool use_mipmaps) 9 | : default_sampler( 10 | dev, vk::Filter::eLinear, vk::Filter::eLinear, 11 | vk::SamplerAddressMode::eRepeat, 12 | vk::SamplerAddressMode::eRepeat, 13 | vk::SamplerMipmapMode::eLinear, 14 | use_mipmaps ? 16 : 0, true, use_mipmaps, false, 0.0f 15 | ) 16 | { 17 | } 18 | 19 | void sampler_table::update_scene(scene_stage* s) 20 | { 21 | const std::vector& instances = s->get_instances(); 22 | table.clear(); 23 | index_counter = 0; 24 | for(size_t i = 0; i < instances.size(); ++i) 25 | { 26 | const material& mat = *instances[i].mat; 27 | register_tex_id(mat.albedo_tex); 28 | register_tex_id(mat.metallic_roughness_tex); 29 | register_tex_id(mat.normal_tex); 30 | register_tex_id(mat.emission_tex); 31 | } 32 | } 33 | 34 | std::vector sampler_table::get_image_infos(device_id id) const 35 | { 36 | std::vector dii(index_counter); 37 | for(const auto& pair: table) 38 | { 39 | dii[pair.second] = { 40 | pair.first.second->get_sampler(id), 41 | pair.first.first->get_image_view(id), 42 | vk::ImageLayout::eShaderReadOnlyOptimal 43 | }; 44 | } 45 | return dii; 46 | } 47 | 48 | void sampler_table::register_tex_id(combined_tex_sampler cs) 49 | { 50 | if(cs.first) 51 | { 52 | const sampler* s = cs.second ? cs.second : &default_sampler; 53 | combined_tex_sampler key(cs.first, s); 54 | 55 | auto it = table.find(key); 56 | if(it == table.end()) 57 | { 58 | table[key] = index_counter++; 59 | } 60 | } 61 | } 62 | 63 | int sampler_table::find_tex_id(combined_tex_sampler cs) 64 | { 65 | if(cs.first) 66 | { 67 | const sampler* s = cs.second ? cs.second : &default_sampler; 68 | combined_tex_sampler key(cs.first, s); 69 | auto it = table.find(key); 70 | if(it == table.end()) 71 | throw std::runtime_error("Sampler table is out of date!"); 72 | return it->second; 73 | } 74 | else return -1; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/sampler_table.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SAMPLER_TABLE_HH 2 | #define TAURAY_SAMPLER_TABLE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "material.hh" 6 | #include "sampler.hh" 7 | 8 | namespace tr 9 | { 10 | 11 | class scene_stage; 12 | 13 | // This class exists to create a list of sampler-texture pairs out of all 14 | // materials in a given scene, with no duplicate pairs. If only a texture is 15 | // specified, this also fills out the default sampler. 16 | // It exists separately from rt_pipeline and raster_pipeline only for code 17 | // reuse. 18 | class sampler_table 19 | { 20 | public: 21 | sampler_table(device_mask dev, bool mipmap_default); 22 | 23 | void update_scene(scene_stage* s); 24 | std::vector get_image_infos(device_id id) const; 25 | int find_tex_id(combined_tex_sampler cs); 26 | 27 | private: 28 | void register_tex_id(combined_tex_sampler cs); 29 | 30 | sampler default_sampler; 31 | int index_counter = 0; 32 | std::unordered_map< 33 | combined_tex_sampler, int, combined_tex_sampler_hash 34 | > table; 35 | }; 36 | 37 | } 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /src/scene.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SCENE_HH 2 | #define TAURAY_SCENE_HH 3 | #include "monkeroecs.hh" 4 | #include "math.hh" 5 | #include "animation.hh" 6 | #include 7 | 8 | namespace tr 9 | { 10 | using namespace monkero; 11 | 12 | class environment_map; 13 | class sh_grid; 14 | // Used for internal camera list reordering; it's needed for spatial 15 | // reprojection from sparsely rendered viewports. 16 | struct camera_metadata 17 | { 18 | bool enabled; 19 | int index; 20 | bool actively_rendered; 21 | }; 22 | 23 | // You can listen to this if you want to track the time passing on scene 24 | // updates. 25 | struct animation_update_event 26 | { 27 | bool reset; 28 | time_ticks delta; 29 | }; 30 | 31 | void set_camera_jitter(scene& s, const std::vector& jitter); 32 | std::vector get_sorted_cameras(scene& s); 33 | 34 | std::vector get_viewport_reorder_mask( 35 | const std::set& active_indices, 36 | size_t viewport_count 37 | ); 38 | 39 | size_t get_instance_count(scene& s); 40 | size_t get_sampler_count(scene& s); 41 | environment_map* get_environment_map(scene& s); 42 | vec3 get_ambient_light(scene& s); 43 | void auto_assign_shadow_maps( 44 | scene& s, 45 | unsigned directional_res = 2048, 46 | vec3 directional_volume = vec3(10, 10, 100), 47 | vec2 directional_bias = vec2(0.01, 0.05), 48 | unsigned cascades = 4, 49 | unsigned point_res = 512, 50 | float point_near = 0.01f, 51 | vec2 point_bias = vec2(0.006, 0.02) 52 | ); 53 | void track_shadow_maps(scene& s); 54 | 55 | sh_grid* get_sh_grid(scene& s, vec3 pos, int* index = nullptr); 56 | sh_grid* get_largest_sh_grid(scene& s, int* index = nullptr); 57 | 58 | void play( 59 | scene& s, 60 | const std::string& name, 61 | bool loop = false, 62 | bool use_fallback = false 63 | ); 64 | void update(scene& s, time_ticks dt, bool force_update = false); 65 | bool is_playing(scene& s); 66 | void set_animation_time(scene& s, time_ticks dt); 67 | 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/scene_assets.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SCENE_ASSETS_HH 2 | #define TAURAY_SCENE_ASSETS_HH 3 | #include "animation.hh" 4 | #include "mesh.hh" 5 | #include "texture.hh" 6 | #include 7 | #include 8 | #include 9 | 10 | namespace tr 11 | { 12 | 13 | struct name_component 14 | { 15 | std::string name; 16 | }; 17 | 18 | struct scene_assets 19 | { 20 | std::vector> textures; 21 | std::vector> meshes; 22 | std::vector> animation_pools; 23 | }; 24 | 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/server_context.cc: -------------------------------------------------------------------------------- 1 | #include "server_context.hh" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace 7 | { 8 | bool should_exit = false; 9 | 10 | void exit_handler(int) 11 | { 12 | should_exit = true; 13 | } 14 | 15 | }; 16 | 17 | namespace tr 18 | { 19 | 20 | server_context::server_context(const options& opt) 21 | : context(opt) 22 | { 23 | init_vulkan(vkGetInstanceProcAddr); 24 | image_array_layers = 0; 25 | init_devices(); 26 | init_resources(); 27 | signal(SIGINT, exit_handler); 28 | } 29 | 30 | server_context::~server_context() 31 | { 32 | deinit_resources(); 33 | deinit_devices(); 34 | deinit_vulkan(); 35 | } 36 | 37 | bool server_context::init_frame() 38 | { 39 | return should_exit; 40 | } 41 | 42 | uint32_t server_context::prepare_next_image(uint32_t) 43 | { 44 | return 0; 45 | } 46 | 47 | void server_context::finish_image( 48 | uint32_t, uint32_t, bool 49 | ){ 50 | } 51 | 52 | bool server_context::queue_can_present( 53 | const vk::PhysicalDevice&, uint32_t, 54 | const vk::QueueFamilyProperties& 55 | ){ 56 | return false; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/server_context.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SERVER_CONTEXT_HH 2 | #define TAURAY_SERVER_CONTEXT_HH 3 | #include "context.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | // While the regular headless context is still geared towards rendering images, 9 | // this context doesn't do that either. It has no outputs at all. It's only 10 | // intended to be used by resource-streaming server modes that need Vulkan but 11 | // never produce images. 12 | class server_context: public context 13 | { 14 | public: 15 | using options = context::options; 16 | 17 | server_context(const options& opt); 18 | server_context(const server_context& other) = delete; 19 | server_context(server_context&& other) = delete; 20 | ~server_context(); 21 | 22 | bool init_frame() override; 23 | 24 | protected: 25 | uint32_t prepare_next_image(uint32_t frame_index) override; 26 | void finish_image( 27 | uint32_t frame_index, 28 | uint32_t swapchain_index, 29 | bool display 30 | ) override; 31 | bool queue_can_present( 32 | const vk::PhysicalDevice& device, 33 | uint32_t queue_index, 34 | const vk::QueueFamilyProperties& props 35 | ) override final; 36 | }; 37 | 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/sh_compact_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SH_COMPACT_STAGE_HH 2 | #define TAURAY_SH_COMPACT_STAGE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "compute_pipeline.hh" 6 | #include "descriptor_set.hh" 7 | #include "timer.hh" 8 | #include "stage.hh" 9 | 10 | namespace tr 11 | { 12 | 13 | class sh_compact_stage: public single_device_stage 14 | { 15 | public: 16 | sh_compact_stage( 17 | device& dev, 18 | texture& inflated_source, 19 | texture& compacted_output 20 | ); 21 | 22 | private: 23 | push_descriptor_set desc; 24 | compute_pipeline comp; 25 | timer compact_timer; 26 | }; 27 | 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/sh_grid.hh: -------------------------------------------------------------------------------- 1 | #ifndef TR_SH_GRID_HH 2 | #define TR_SH_GRID_HH 3 | #include "texture.hh" 4 | #include "transformable.hh" 5 | #include 6 | 7 | namespace tr 8 | { 9 | 10 | // A 3D grid of spherical harmonics probes. Coefficients are stacked vertically 11 | // in the 3D texture, so lookup must clamp manually. Similar to the shadow_map 12 | // classes, this is only a specification that becomes fulfilled by a renderer. 13 | class sh_grid 14 | { 15 | public: 16 | sh_grid( 17 | uvec3 resolution = uvec3(1), 18 | int order = 3 19 | ); 20 | 21 | texture create_target_texture( 22 | device_mask dev, 23 | int samples_per_probe 24 | ); 25 | void get_target_sampling_info( 26 | device_mask dev, 27 | int& samples_per_probe, 28 | int& samples_per_invocation 29 | ); 30 | texture create_texture(device_mask dev); 31 | size_t get_required_bytes() const; 32 | 33 | void set_resolution(uvec3 res); 34 | uvec3 get_resolution() const; 35 | 36 | // Radius is added to the actual volume size. 37 | void set_radius(float radius = 0.0f); 38 | float get_radius() const; 39 | 40 | void set_order(int order); 41 | int get_order() const; 42 | 43 | int get_coef_count() const; 44 | static int get_coef_count(int order); 45 | 46 | // Negative: out of influence. Zero: fully in influence. Positive: outside, 47 | // but within radius. 48 | float point_distance(transformable& self, vec3 p) const; 49 | float calc_density(transformable& self) const; 50 | float calc_volume(transformable& self) const; 51 | 52 | private: 53 | float radius; 54 | int order; 55 | uvec3 resolution; 56 | }; 57 | 58 | } 59 | 60 | #endif 61 | 62 | -------------------------------------------------------------------------------- /src/sh_path_tracer_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SH_PATH_TRACER_HH 2 | #define TAURAY_SH_PATH_TRACER_HH 3 | #include "rt_stage.hh" 4 | #include "scene.hh" 5 | #include "path_tracer_stage.hh" 6 | #include "descriptor_set.hh" 7 | 8 | namespace tr 9 | { 10 | 11 | class sh_path_tracer_stage: public rt_stage 12 | { 13 | public: 14 | struct options: public rt_stage::options 15 | { 16 | int samples_per_probe = 1; 17 | int samples_per_invocation = 1; 18 | film_filter film = film_filter::BLACKMAN_HARRIS; 19 | multiple_importance_sampling_mode mis_mode = 20 | multiple_importance_sampling_mode::MIS_POWER_HEURISTIC; 21 | float film_radius = 1.0f; // 0.5 is "correct" for the box filter. 22 | float russian_roulette_delta = 0; 23 | float temporal_ratio = 0.02f; 24 | float indirect_clamping = 100.0f; 25 | float regularization_gamma = 1.0f; // 0 disables path regularization 26 | 27 | light_sampling_weights sampling_weights; 28 | 29 | entity sh_grid_id = 0; 30 | int sh_order = 2; 31 | }; 32 | 33 | sh_path_tracer_stage( 34 | device& dev, 35 | scene_stage& ss, 36 | texture& output_grid, 37 | vk::ImageLayout output_layout, 38 | const options& opt 39 | ); 40 | 41 | protected: 42 | void update(uint32_t frame_index) override; 43 | void record_command_buffer( 44 | vk::CommandBuffer cb, uint32_t frame_index, uint32_t pass_index, 45 | bool first_in_command_buffer 46 | ) override; 47 | 48 | push_descriptor_set desc; 49 | rt_pipeline gfx; 50 | 51 | private: 52 | void record_command_buffer_push_constants( 53 | vk::CommandBuffer cb, 54 | uint32_t frame_index, 55 | uint32_t pass_index 56 | ); 57 | 58 | options opt; 59 | texture* output_grid; 60 | vk::ImageLayout output_layout; 61 | gpu_buffer grid_data; 62 | uint64_t history_length; 63 | }; 64 | 65 | } 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/sh_renderer.cc: -------------------------------------------------------------------------------- 1 | #include "sh_renderer.hh" 2 | #include "sh_grid.hh" 3 | #include "scene_stage.hh" 4 | #include "log.hh" 5 | 6 | namespace tr 7 | { 8 | 9 | sh_renderer::sh_renderer( 10 | device_mask dev, 11 | scene_stage& ss, 12 | const options& opt 13 | ): dev(dev), opt(opt), ss(&ss) 14 | { 15 | } 16 | 17 | sh_renderer::~sh_renderer() 18 | { 19 | } 20 | 21 | void sh_renderer::update_grids() 22 | { 23 | per_grid.clear(); 24 | ss->get_scene()->foreach([&](entity id, sh_grid& s){ 25 | sh_grid_targets.emplace( 26 | &s, s.create_target_texture(dev, opt.samples_per_probe) 27 | ); 28 | 29 | texture* output_grids = &sh_grid_targets.at(&s); 30 | const texture* compact_grids = &ss->get_sh_grid_textures().at(&s); 31 | 32 | sh_path_tracer_stage::options sh_opt = opt; 33 | sh_opt.sh_grid_id = id; 34 | sh_opt.sh_order = s.get_order(); 35 | 36 | s.get_target_sampling_info( 37 | dev, 38 | sh_opt.samples_per_probe, 39 | sh_opt.samples_per_invocation 40 | ); 41 | 42 | per_grid_data& p = per_grid.emplace_back(); 43 | for(device& d: dev) 44 | { 45 | p.pt.emplace_back(new sh_path_tracer_stage( 46 | d, *ss, *output_grids, vk::ImageLayout::eGeneral, sh_opt 47 | )); 48 | 49 | p.compact.emplace_back(new sh_compact_stage( 50 | d, *output_grids, *const_cast(compact_grids) 51 | )); 52 | } 53 | }); 54 | } 55 | 56 | dependencies sh_renderer::render(dependencies deps) 57 | { 58 | if(ss->check_update(scene_stage::LIGHT, scene_state_counter)) 59 | update_grids(); 60 | 61 | for(auto& p: per_grid) 62 | { 63 | for(auto& s: p.pt) deps = s->run(deps); 64 | for(auto& s: p.compact) deps = s->run(deps); 65 | } 66 | 67 | return deps; 68 | } 69 | 70 | } 71 | 72 | -------------------------------------------------------------------------------- /src/sh_renderer.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SH_RENDERER_HH 2 | #define TAURAY_SH_RENDERER_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "renderer.hh" 6 | #include "sh_path_tracer_stage.hh" 7 | #include "sh_compact_stage.hh" 8 | #include "renderer.hh" 9 | 10 | namespace tr 11 | { 12 | 13 | class scene_stage; 14 | class sh_grid; 15 | // This renderer is a bit odd in that it doesn't actually draw anything to the 16 | // context; it only updates SH probe grids. As such, this renderer is not useful 17 | // on its own and must be used as a part of a more comprehensive renderer 18 | // (= dshgi_renderer). 19 | class sh_renderer 20 | { 21 | public: 22 | using options = sh_path_tracer_stage::options; 23 | 24 | sh_renderer(device_mask dev, scene_stage& ss, const options& opt); 25 | sh_renderer(const sh_renderer& other) = delete; 26 | sh_renderer(sh_renderer&& other) = delete; 27 | ~sh_renderer(); 28 | 29 | dependencies render(dependencies deps); 30 | 31 | private: 32 | void update_grids(); 33 | 34 | device_mask dev; 35 | options opt; 36 | scene_stage* ss = nullptr; 37 | uint32_t scene_state_counter = 0; 38 | 39 | std::unordered_map sh_grid_targets; 40 | 41 | struct per_grid_data 42 | { 43 | std::vector> pt; 44 | std::vector> compact; 45 | }; 46 | std::vector per_grid; 47 | }; 48 | 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/shader_source.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SHADER_SOURCE_HH 2 | #define TAURAY_SHADER_SOURCE_HH 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "context.hh" 9 | 10 | namespace tr 11 | { 12 | 13 | struct shader_source 14 | { 15 | shader_source() = default; 16 | // Reads and compiles the given shader, inserting the 'preamble' after 17 | // the #version line. 18 | shader_source( 19 | const std::string& path, 20 | const std::map& defines = {} 21 | ); 22 | 23 | shader_source(const shader_source& other) = default; 24 | shader_source(shader_source&& other) = default; 25 | 26 | shader_source& operator=(const shader_source& other) = default; 27 | shader_source& operator=(shader_source&& other) = default; 28 | 29 | struct binding_info 30 | { 31 | uint32_t set; 32 | vk::DescriptorSetLayoutBinding binding; 33 | }; 34 | std::map bindings; 35 | std::vector push_constant_ranges; 36 | std::vector data; 37 | 38 | static void clear_binary_cache(); 39 | }; 40 | 41 | struct raster_shader_sources 42 | { 43 | shader_source vert = {}; 44 | shader_source frag = {}; 45 | }; 46 | 47 | struct rt_shader_sources 48 | { 49 | shader_source rgen = {}; 50 | 51 | struct hit_group 52 | { 53 | vk::RayTracingShaderGroupTypeKHR type = 54 | vk::RayTracingShaderGroupTypeKHR::eTrianglesHitGroup; 55 | shader_source rchit = {}; 56 | shader_source rahit = {}; 57 | shader_source rint = {}; 58 | }; 59 | 60 | std::vector rhit = {}; 61 | std::vector rmiss = {}; 62 | }; 63 | 64 | std::vector get_push_constant_ranges(const rt_shader_sources& src); 65 | std::vector get_push_constant_ranges(const raster_shader_sources& src); 66 | std::vector get_push_constant_ranges(const shader_source& compute_src); 67 | 68 | } 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/shadow_map.hh: -------------------------------------------------------------------------------- 1 | #ifndef TR_SHADOW_MAP_HH 2 | #define TR_SHADOW_MAP_HH 3 | #include "math.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | class camera; 9 | class transformable; 10 | struct directional_shadow_map 11 | { 12 | uvec2 resolution = uvec2(512); 13 | vec2 x_range = glm::vec2(-10.0f, 10.0f); 14 | vec2 y_range = glm::vec2(-10.0f, 10.0f); 15 | vec2 depth_range = glm::vec2(-100.0f, 100.0f); 16 | float min_bias = 0.01; 17 | float max_bias = 0.02; 18 | 19 | // vec2 is cascade offset in shadow map space. If you plan to call 20 | // track_camera(), you only need to resize cascades to the number of 21 | // cascades you want. 4-5 is a good number, if you don't know what to 22 | // pick. 23 | std::vector cascades; 24 | 25 | void track_cameras( 26 | const mat4& light_transform, 27 | const std::vector& cam, 28 | const std::vector& camera_transforms, 29 | bool conservative = true 30 | ); 31 | }; 32 | 33 | struct point_shadow_map 34 | { 35 | uvec2 resolution = uvec2(512); 36 | float near = 0.01f; 37 | float min_bias = 0.006; 38 | float max_bias = 0.02; 39 | }; 40 | 41 | struct shadow_map_filter 42 | { 43 | // Shadow filtering options. 44 | int pcf_samples = 64; // 0 => bilinear interpolation 45 | int omni_pcf_samples = 16; // 0 => bilinear interpolation 46 | int pcss_samples = 32; // 0 => disable PCSS 47 | // The minimum radius prevents PCSS from degrading to bilinear filtering 48 | // near shadow caster. 49 | float pcss_minimum_radius = 0.0f; 50 | }; 51 | 52 | struct gpu_shadow_mapping_parameters 53 | { 54 | pvec2 shadow_map_atlas_pixel_margin; 55 | float pcss_minimum_radius; 56 | float noise_scale; 57 | int pcf_samples; 58 | int omni_pcf_samples; 59 | int pcss_samples; 60 | int pad[1]; 61 | }; 62 | 63 | class scene_stage; 64 | gpu_shadow_mapping_parameters create_shadow_mapping_parameters(shadow_map_filter filter, scene_stage& ss); 65 | 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/shadow_map_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SHADOW_MAP_STAGE_HH 2 | #define TAURAY_SHADOW_MAP_STAGE_HH 3 | #include "context.hh" 4 | #include "raster_pipeline.hh" 5 | #include "camera.hh" 6 | #include "sampler_table.hh" 7 | #include "timer.hh" 8 | #include "gpu_buffer.hh" 9 | #include "stage.hh" 10 | #include "atlas.hh" 11 | #include "scene_stage.hh" 12 | 13 | namespace tr 14 | { 15 | 16 | class shadow_map_stage: public single_device_stage 17 | { 18 | public: 19 | struct options 20 | { 21 | }; 22 | 23 | shadow_map_stage(device& dev, scene_stage& ss, const options& opt); 24 | 25 | private: 26 | void update(uint32_t frame_index) override; 27 | 28 | push_descriptor_set desc; 29 | raster_pipeline gfx; 30 | options opt; 31 | gpu_buffer camera_data; 32 | std::vector shadow_maps; 33 | uvec2 prev_atlas_size; 34 | 35 | timer shadow_timer; 36 | 37 | scene_stage* ss; 38 | uint32_t scene_state_counter; 39 | }; 40 | 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /src/spatial_reprojection_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_SPATIAL_REPROJECTION_STAGE_HH 2 | #define TAURAY_SPATIAL_REPROJECTION_STAGE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "stage.hh" 6 | #include "compute_pipeline.hh" 7 | #include "timer.hh" 8 | #include "gbuffer.hh" 9 | #include "scene_stage.hh" 10 | 11 | namespace tr 12 | { 13 | 14 | class spatial_reprojection_stage: public single_device_stage 15 | { 16 | public: 17 | struct options 18 | { 19 | size_t active_viewport_count; 20 | }; 21 | 22 | spatial_reprojection_stage( 23 | device& dev, 24 | scene_stage& ss, 25 | gbuffer_target& target_viewport, 26 | const options& opt 27 | ); 28 | 29 | private: 30 | void update(uint32_t frame_index) override; 31 | 32 | scene_stage* ss; 33 | 34 | gbuffer_target target_viewport; 35 | 36 | push_descriptor_set desc; 37 | compute_pipeline comp; 38 | options opt; 39 | 40 | gpu_buffer camera_data; 41 | timer stage_timer; 42 | }; 43 | 44 | } 45 | 46 | #endif 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/stitch_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_STITCH_STAGE_HH 2 | #define TAURAY_STITCH_STAGE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "compute_pipeline.hh" 6 | #include "distribution_strategy.hh" 7 | #include "gbuffer.hh" 8 | #include "descriptor_set.hh" 9 | #include "timer.hh" 10 | #include "stage.hh" 11 | 12 | namespace tr 13 | { 14 | 15 | class stitch_stage: public single_device_stage 16 | { 17 | public: 18 | struct options 19 | { 20 | distribution_strategy strategy = DISTRIBUTION_SCANLINE; 21 | size_t active_viewport_count = 1; 22 | }; 23 | 24 | stitch_stage( 25 | device& dev, 26 | uvec2 size, 27 | const std::vector& images, 28 | const std::vector& params, 29 | const options& opt 30 | ); 31 | 32 | void set_blend_ratio(float blend_ratio); 33 | void set_distribution_params( 34 | const std::vector& params 35 | ); 36 | void refresh_params(); 37 | 38 | private: 39 | void record_commands(); 40 | 41 | descriptor_set io_set; 42 | compute_pipeline comp; 43 | options opt; 44 | uvec2 size; 45 | float blend_ratio; 46 | 47 | std::vector images; 48 | std::vector params; 49 | timer stitch_timer; 50 | }; 51 | 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /src/taa_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_TAA_STAGE_HH 2 | #define TAURAY_TAA_STAGE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "stage.hh" 6 | #include "compute_pipeline.hh" 7 | #include "timer.hh" 8 | #include "gbuffer.hh" 9 | #include "gpu_buffer.hh" 10 | #include "scene_stage.hh" 11 | #include "sampler.hh" 12 | 13 | namespace tr 14 | { 15 | 16 | class taa_stage: public single_device_stage 17 | { 18 | public: 19 | struct options 20 | { 21 | size_t active_viewport_count = 1; 22 | int base_camera_index = 0; 23 | int output_layer = 0; 24 | 25 | // Set this to 2.2 if running TAA after gamma/srgb correction. 26 | // Optimally, you'd run TAA after tonemapping but before gamma/srgb 27 | // correction, this variable won't fix all issues. 28 | float gamma = 1.0f; 29 | 30 | // Set this to 1/taa_steps by default 31 | float alpha = 0.125f; 32 | 33 | // True antialiases harder but can blur a bit more. False can falsely 34 | // fail on antialiasing some edges. 35 | bool edge_dilation = true; 36 | 37 | // Avoids shimmering by darkening details that would cause it. 38 | bool anti_shimmer = false; 39 | }; 40 | 41 | taa_stage( 42 | device& dev, 43 | scene_stage& ss, 44 | render_target& src, 45 | render_target& motion, 46 | render_target& depth, 47 | render_target& dst, 48 | const options& opt 49 | ); 50 | taa_stage( 51 | device& dev, 52 | scene_stage& ss, 53 | render_target& src, 54 | render_target& motion, 55 | render_target& depth, 56 | std::vector& swapchain_dst, 57 | const options& opt 58 | ); 59 | taa_stage(const taa_stage& other) = delete; 60 | taa_stage(taa_stage&& other) = delete; 61 | 62 | protected: 63 | void init(); 64 | void update(uint32_t frame_index) override; 65 | 66 | private: 67 | options opt; 68 | scene_stage* scene; 69 | 70 | render_target src, motion, depth; 71 | std::vector dst; 72 | 73 | bool first_frame; 74 | 75 | std::optional color_history[2]; 76 | compute_pipeline pipeline; 77 | push_descriptor_set descriptors; 78 | sampler target_sampler; 79 | sampler history_sampler; 80 | timer stage_timer; 81 | }; 82 | 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /src/tauray.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_HH 2 | #define TAURAY_HH 3 | #include "options.hh" 4 | #include "environment_map.hh" 5 | #include "scene.hh" 6 | #include "scene_assets.hh" 7 | #include "log.hh" 8 | #include 9 | #include 10 | 11 | namespace tr 12 | { 13 | struct scene_data 14 | { 15 | std::vector assets; 16 | std::unique_ptr s; 17 | }; 18 | 19 | scene_data load_scenes(context& ctx, const options& opt); 20 | context* create_context(const options& opt); 21 | void run(context& ctx, scene_data& s, options& opt); 22 | } 23 | 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /src/temporal_reprojection_stage.cc: -------------------------------------------------------------------------------- 1 | #include "temporal_reprojection_stage.hh" 2 | #include "misc.hh" 3 | 4 | namespace 5 | { 6 | using namespace tr; 7 | 8 | struct push_constant_buffer 9 | { 10 | pivec2 size; 11 | float temporal_ratio; 12 | }; 13 | 14 | static_assert(sizeof(push_constant_buffer) <= 128); 15 | 16 | } 17 | 18 | namespace tr 19 | { 20 | 21 | temporal_reprojection_stage::temporal_reprojection_stage( 22 | device& dev, 23 | gbuffer_target& current_features, 24 | gbuffer_target& previous_features, 25 | const options& opt 26 | ): single_device_stage(dev), 27 | desc(dev), 28 | comp(dev), 29 | opt(opt), 30 | stage_timer(dev, "temporal reprojection (" + std::to_string(opt.active_viewport_count) + " viewports)") 31 | { 32 | shader_source src("shader/temporal_reprojection.comp"); 33 | desc.add(src); 34 | comp.init(src, {&desc}); 35 | 36 | for(uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) 37 | { 38 | vk::CommandBuffer cb = begin_compute(); 39 | 40 | stage_timer.begin(cb, dev.id, i); 41 | 42 | comp.bind(cb); 43 | 44 | desc.set_image(dev.id, "current_color", {{{}, current_features.color.view, vk::ImageLayout::eGeneral}}); 45 | desc.set_image(dev.id, "current_normal", {{{}, current_features.normal.view, vk::ImageLayout::eGeneral}}); 46 | desc.set_image(dev.id, "current_pos", {{{}, current_features.pos.view, vk::ImageLayout::eGeneral}}); 47 | desc.set_image(dev.id, "current_screen_motion", {{{}, current_features.screen_motion.view, vk::ImageLayout::eGeneral}}); 48 | desc.set_image(dev.id, "previous_color", {{{}, previous_features.color.view, vk::ImageLayout::eGeneral}}); 49 | desc.set_image(dev.id, "previous_normal", {{{}, previous_features.normal.view, vk::ImageLayout::eGeneral}}); 50 | desc.set_image(dev.id, "previous_pos", {{{}, previous_features.pos.view, vk::ImageLayout::eGeneral}}); 51 | 52 | comp.push_descriptors(cb, desc, 0); 53 | 54 | uvec2 wg = (current_features.get_size()+15u)/16u; 55 | push_constant_buffer control; 56 | control.size = current_features.get_size(); 57 | control.temporal_ratio = opt.temporal_ratio; 58 | 59 | comp.push_constants(cb, control); 60 | cb.dispatch(wg.x, wg.y, opt.active_viewport_count); 61 | 62 | stage_timer.end(cb, dev.id, i); 63 | end_compute(cb, i); 64 | } 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/temporal_reprojection_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_TEMPORAL_REPROJECTION_STAGE_HH 2 | #define TAURAY_TEMPORAL_REPROJECTION_STAGE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "stage.hh" 6 | #include "compute_pipeline.hh" 7 | #include "descriptor_set.hh" 8 | #include "timer.hh" 9 | #include "gbuffer.hh" 10 | 11 | namespace tr 12 | { 13 | 14 | class temporal_reprojection_stage: public single_device_stage 15 | { 16 | public: 17 | struct options 18 | { 19 | float temporal_ratio = 0.75; 20 | size_t active_viewport_count = 1; 21 | }; 22 | 23 | temporal_reprojection_stage( 24 | device& dev, 25 | gbuffer_target& current_features, 26 | gbuffer_target& previous_features, 27 | const options& opt 28 | ); 29 | temporal_reprojection_stage(const temporal_reprojection_stage& other) = delete; 30 | temporal_reprojection_stage(temporal_reprojection_stage&& other) = delete; 31 | 32 | private: 33 | push_descriptor_set desc; 34 | compute_pipeline comp; 35 | options opt; 36 | timer stage_timer; 37 | }; 38 | 39 | } 40 | 41 | #endif 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/timer.cc: -------------------------------------------------------------------------------- 1 | #include "timer.hh" 2 | 3 | namespace tr 4 | { 5 | 6 | timer::timer(){} 7 | 8 | timer::timer(device_mask dev, const std::string& name) 9 | { 10 | timer_id.init(dev, 11 | [&](device& d){ 12 | return d.ctx->get_timing().register_timer(d.id, name); 13 | } 14 | ); 15 | } 16 | 17 | timer::timer(timer&& other) 18 | : timer_id(std::move(other.timer_id)) 19 | { 20 | other.timer_id.clear(); 21 | } 22 | 23 | timer::~timer() 24 | { 25 | for(auto[d, timer_id]: timer_id) 26 | d.ctx->get_timing().unregister_timer(d.id, timer_id); 27 | } 28 | 29 | timer& timer::operator=(timer&& other) 30 | { 31 | for(auto[d, timer_id]: timer_id) 32 | d.ctx->get_timing().unregister_timer(d.id, timer_id); 33 | timer_id = std::move(other.timer_id); 34 | other.timer_id.clear(); 35 | return *this; 36 | } 37 | 38 | void timer::begin( 39 | vk::CommandBuffer cb, device_id id, uint32_t frame_index, vk::PipelineStageFlagBits stage 40 | ){ 41 | int tid = timer_id[id]; 42 | if(tid < 0) return; 43 | uint32_t query_id = tid * 2u; 44 | vk::QueryPool pool = timer_id.get_context()->get_timing().get_timestamp_pool(id, frame_index); 45 | cb.resetQueryPool(pool, query_id, 2); 46 | cb.writeTimestamp(stage, pool, query_id); 47 | } 48 | 49 | void timer::end( 50 | vk::CommandBuffer cb, device_id id, uint32_t frame_index, vk::PipelineStageFlagBits stage 51 | ){ 52 | int tid = timer_id[id]; 53 | if(tid < 0) return; 54 | uint32_t query_id = tid * 2u; 55 | vk::QueryPool pool = timer_id.get_context()->get_timing().get_timestamp_pool(id, frame_index); 56 | cb.writeTimestamp(stage, pool, query_id+1); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/timer.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_TIMER_HH 2 | #define TAURAY_TIMER_HH 3 | #include "context.hh" 4 | 5 | namespace tr 6 | { 7 | 8 | // You have to hold the timer instance as long as the command buffers using it 9 | // exist. Otherwise, timing info will be broken! Typically, you would have this 10 | // as a class member. 11 | class timer 12 | { 13 | public: 14 | timer(); 15 | timer(device_mask dev, const std::string& name); 16 | timer(timer&& other); 17 | ~timer(); 18 | 19 | timer& operator=(timer&& other); 20 | 21 | void begin( 22 | vk::CommandBuffer cb, 23 | device_id id, 24 | uint32_t frame_index, 25 | vk::PipelineStageFlagBits stage = vk::PipelineStageFlagBits::eTopOfPipe 26 | ); 27 | void end( 28 | vk::CommandBuffer cb, 29 | device_id id, 30 | uint32_t frame_index, 31 | vk::PipelineStageFlagBits stage = vk::PipelineStageFlagBits::eBottomOfPipe 32 | ); 33 | 34 | private: 35 | per_device timer_id; 36 | }; 37 | 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/tonemap_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_TONEMAP_STAGE_HH 2 | #define TAURAY_TONEMAP_STAGE_HH 3 | #include "context.hh" 4 | #include "texture.hh" 5 | #include "compute_pipeline.hh" 6 | #include "descriptor_set.hh" 7 | #include "timer.hh" 8 | #include "gpu_buffer.hh" 9 | #include "stage.hh" 10 | 11 | namespace tr 12 | { 13 | 14 | class tonemap_stage: public single_device_stage 15 | { 16 | public: 17 | enum operator_type 18 | { 19 | LINEAR = 0, 20 | GAMMA_CORRECTION, 21 | FILMIC, 22 | REINHARD, 23 | REINHARD_LUMINANCE 24 | }; 25 | 26 | struct options 27 | { 28 | operator_type tonemap_operator = FILMIC; 29 | float exposure = 1.0f; 30 | float gamma = 2.2f; 31 | int input_msaa = 1; 32 | bool post_resolve = false; 33 | bool transition_output_layout = true; 34 | bool alpha_grid_background = false; 35 | std::vector reorder = {}; 36 | // If you only want to tonemap one layer of an array, use this. 37 | int limit_to_input_layer = -1; 38 | int limit_to_output_layer = -1; 39 | // eUndefined deduces. 40 | vk::ImageLayout output_image_layout = vk::ImageLayout::eUndefined; 41 | }; 42 | 43 | tonemap_stage( 44 | device& dev, 45 | render_target& input, 46 | std::vector& output_frames, 47 | const options& opt 48 | ); 49 | 50 | tonemap_stage( 51 | device& dev, 52 | render_target& input, 53 | render_target& output, 54 | const options& opt 55 | ); 56 | private: 57 | void init(std::vector& output_frames); 58 | void update(uint32_t frame_index) override; 59 | 60 | descriptor_set desc; 61 | compute_pipeline comp; 62 | options opt; 63 | render_target input_target; 64 | vkm output_reorder_buf; 65 | gpu_buffer index_data; 66 | timer tonemap_timer; 67 | }; 68 | 69 | } 70 | 71 | #endif 72 | 73 | -------------------------------------------------------------------------------- /src/tracing.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_TRACING_HH 2 | #define TAURAY_TRACING_HH 3 | 4 | #include "vkm.hh" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace tr 11 | { 12 | 13 | struct trace_event 14 | { 15 | double start_ns; 16 | double duration_ns; 17 | std::string name; 18 | }; 19 | 20 | class context; 21 | 22 | class tracing_record 23 | { 24 | public: 25 | enum trace_format 26 | { 27 | SIMPLE, 28 | TRACE_EVENT_FORMAT 29 | }; 30 | 31 | tracing_record(context* ctx); 32 | void init(unsigned max_timestamps); 33 | void deinit(); 34 | 35 | void begin_frame(); 36 | void host_wait(); 37 | void device_finish_frame(); 38 | void wait_all_frames(bool print_traces, trace_format format = SIMPLE); 39 | 40 | int register_timer(size_t device_index, const std::string& name); 41 | void unregister_timer(size_t device_index, int timer_id); 42 | vk::QueryPool get_timestamp_pool(size_t device_index, uint32_t frame_index); 43 | 44 | float get_duration(size_t device_index, const std::string& name) const; 45 | void print_last_trace(trace_format format = SIMPLE); 46 | 47 | private: 48 | struct timing_result 49 | { 50 | uint32_t frame_number = 0; 51 | std::vector host_traces; 52 | std::vector> device_traces; 53 | }; 54 | 55 | void finish_host_frame(); 56 | const timing_result* find_latest_finished_frame() const; 57 | void print_simple_trace(const timing_result& res); 58 | void print_tef_trace(const timing_result& res); 59 | 60 | context* ctx; 61 | unsigned max_timestamps; 62 | uint32_t frame_counter; 63 | uint32_t host_finished_frame_counter; 64 | uint32_t device_finished_frame_counter; 65 | std::deque times; 66 | 67 | struct timing_data 68 | { 69 | timing_data() = default; 70 | timing_data(timing_data&& other) = default; 71 | timing_data(const timing_data& other) = delete; 72 | 73 | std::vector> timestamp_pools; 74 | 75 | std::set available_queries; 76 | std::map reserved_queries; 77 | std::vector last_results; 78 | 79 | double device_reference_ns; 80 | }; 81 | std::vector timing_resources; 82 | std::chrono::steady_clock::time_point frame_start_time; 83 | std::chrono::steady_clock::time_point wait_start_time; 84 | 85 | double host_reference_ns; 86 | }; 87 | 88 | } 89 | 90 | #endif 91 | 92 | -------------------------------------------------------------------------------- /src/window.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_WINDOW_HH 2 | #define TAURAY_WINDOW_HH 3 | 4 | #include "context.hh" 5 | 6 | #if _WIN32 7 | #include 8 | #include 9 | #else 10 | #include 11 | #include 12 | #endif 13 | 14 | namespace tr 15 | { 16 | 17 | class window: public context 18 | { 19 | public: 20 | struct options: context::options 21 | { 22 | const char* title = "TauRay"; 23 | uvec2 size = uvec2(1280, 720); 24 | bool fullscreen = false; 25 | bool vsync = false; 26 | bool hdr_display = false; 27 | }; 28 | 29 | window(const options& opt); 30 | window(const window& other) = delete; 31 | window(window&& other) = delete; 32 | ~window(); 33 | 34 | void recreate_swapchains(); 35 | 36 | protected: 37 | uint32_t prepare_next_image(uint32_t frame_index) override; 38 | void finish_image( 39 | uint32_t frame_index, 40 | uint32_t swapchain_index, 41 | bool display 42 | ) override; 43 | bool queue_can_present( 44 | const vk::PhysicalDevice& device, 45 | uint32_t queue_index, 46 | const vk::QueueFamilyProperties& props 47 | ) override final; 48 | 49 | private: 50 | void init_sdl(); 51 | void deinit_sdl(); 52 | 53 | void init_swapchain(); 54 | void deinit_swapchain(); 55 | 56 | options opt; 57 | 58 | SDL_Window* win; 59 | VkSurfaceKHR surface; 60 | vk::SwapchainKHR swapchain; 61 | }; 62 | 63 | } 64 | 65 | #endif 66 | 67 | -------------------------------------------------------------------------------- /src/z_pass_stage.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAURAY_Z_PASS_STAGE_HH 2 | #define TAURAY_Z_PASS_STAGE_HH 3 | #include "context.hh" 4 | #include "timer.hh" 5 | #include "raster_pipeline.hh" 6 | #include "gpu_buffer.hh" 7 | #include "stage.hh" 8 | 9 | namespace tr 10 | { 11 | 12 | class scene_stage; 13 | class z_pass_stage: public single_device_stage 14 | { 15 | public: 16 | z_pass_stage( 17 | device& dev, 18 | scene_stage& ss, 19 | const std::vector& depth_buffer_arrays 20 | ); 21 | 22 | protected: 23 | void update(uint32_t frame_index) override; 24 | 25 | private: 26 | std::vector> array_pipelines; 27 | 28 | scene_stage* ss; 29 | timer z_pass_timer; 30 | uint32_t scene_state_counter; 31 | }; 32 | 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_program(PYTHON_PROG python3 OPTIONAL) 2 | find_program(COMPARE_PROG compare OPTIONAL) 3 | 4 | #message(SEND_ERROR ${PYTHON_PROG}) 5 | function(renderer_test renderer stage tolerance) 6 | add_executable("${renderer}_crash" 7 | crash_test.cc 8 | ) 9 | target_link_libraries("${renderer}_crash" PUBLIC tauray-core SDL2::SDL2main) 10 | target_compile_definitions("${renderer}_crash" PUBLIC "TEST_RENDERER=tr::${stage}") 11 | target_include_directories("${renderer}_crash" PUBLIC "${CMAKE_SOURCE_DIR}/src") 12 | add_test(NAME "${renderer}_crash_test" 13 | COMMAND "${renderer}_crash" 14 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 15 | ) 16 | add_test(NAME "validate_${renderer}_test" 17 | COMMAND ${PYTHON_PROG} 18 | "${CMAKE_CURRENT_SOURCE_DIR}/validate_render.py" 19 | "--executable=${CMAKE_BINARY_DIR}/tauray" 20 | "--scene=${CMAKE_CURRENT_SOURCE_DIR}/test.glb" 21 | "--renderer=${renderer}" 22 | "--reference=${CMAKE_CURRENT_SOURCE_DIR}/references/validate_${renderer}.exr" 23 | "--metric=mse" 24 | "--tolerance=${tolerance}" 25 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 26 | ) 27 | endfunction() 28 | 29 | renderer_test("raster" "options::RASTER" 1) 30 | renderer_test("path-tracer" "options::PATH_TRACER" 10000) 31 | renderer_test("dshgi" "options::DSHGI" 10) 32 | renderer_test("albedo" "feature_stage::ALBEDO" 1) 33 | renderer_test("world-normal" "feature_stage::WORLD_NORMAL" 1) 34 | renderer_test("view-normal" "feature_stage::VIEW_NORMAL" 1) 35 | renderer_test("world-pos" "feature_stage::WORLD_POS" 1) 36 | renderer_test("view-pos" "feature_stage::VIEW_POS" 1) 37 | renderer_test("distance" "feature_stage::DISTANCE" 1) 38 | -------------------------------------------------------------------------------- /test/crash_test.cc: -------------------------------------------------------------------------------- 1 | #include "tauray.hh" 2 | #include 3 | 4 | int main() try 5 | { 6 | tr::options opt; 7 | 8 | opt.renderer = TEST_RENDERER; 9 | opt.scene_paths = {"test/test.glb"}; 10 | opt.headless = "test"; 11 | opt.filetype = tr::headless::EMPTY; 12 | opt.replay = true; 13 | 14 | std::unique_ptr ctx(tr::create_context(opt)); 15 | tr::scene_data sd = tr::load_scenes(*ctx, opt); 16 | tr::run(*ctx, sd, opt); 17 | return 0; 18 | } 19 | catch(tr::option_parse_error& e) 20 | { 21 | if(strlen(e.what())) std::cerr << e.what() << "\n" << std::endl; 22 | return 1; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /test/references/validate_albedo.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_albedo.exr -------------------------------------------------------------------------------- /test/references/validate_distance.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_distance.exr -------------------------------------------------------------------------------- /test/references/validate_dshgi.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_dshgi.exr -------------------------------------------------------------------------------- /test/references/validate_path-tracer.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_path-tracer.exr -------------------------------------------------------------------------------- /test/references/validate_raster.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_raster.exr -------------------------------------------------------------------------------- /test/references/validate_view-normal.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_view-normal.exr -------------------------------------------------------------------------------- /test/references/validate_view-pos.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_view-pos.exr -------------------------------------------------------------------------------- /test/references/validate_whitted.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_whitted.exr -------------------------------------------------------------------------------- /test/references/validate_world-normal.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_world-normal.exr -------------------------------------------------------------------------------- /test/references/validate_world-pos.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/references/validate_world-pos.exr -------------------------------------------------------------------------------- /test/test.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vga-group/tauray/0f3e095c04e083dd4c950d13f0263e7dfb139afb/test/test.glb -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tauray", 3 | "version-string": "0.0.0", 4 | "dependencies": [ 5 | "sdl2", 6 | "glm", 7 | "czmq", 8 | "nng", 9 | "libcbor", 10 | "assimp", 11 | "vulkan", 12 | "openxr-loader", 13 | { 14 | "name": "sdl2", 15 | "default-features": false, 16 | "features": [ "x11", "vulkan" ], 17 | "platform": "linux" 18 | }, 19 | { 20 | "name": "sdl2", 21 | "default-features": false, 22 | "features": [ "vulkan" ], 23 | "platform": "windows" 24 | } 25 | ] 26 | } 27 | --------------------------------------------------------------------------------