diff --git a/doc/Castor3D/Castor3D Scene.xml b/doc/Castor3D/Castor3D Scene.xml index eb7a3ed79e..d11c98e4e5 100644 --- a/doc/Castor3D/Castor3D Scene.xml +++ b/doc/Castor3D/Castor3D Scene.xml @@ -26,7 +26,7 @@ animated_object_group animation atmospheric_scattering billboard biome border_panel_overlay box_layout button button_style camera clouds clusters colour_grading combobox combobox_style constants_buffer content default_materials density depth_of_field diamond_square_terrain draw_edges edit edit_style expand expandable_panel expandable_panel_style fft_waves font frame frame_style gui hdr_config header import layout_ctrl light listbox listbox_style lpv_config material materials mesh morph_animation motion_blur object panel panel_overlay panel_style particle particle_system pass pbr_bloom pcf_config positions progress progress_style raw_config render_target rsm_config sampler scene scene_node scrollbar_style shader_object shader_program shadows skeleton skybox slider slider_style smaa ssao static static_style submesh subsurface_scattering text_overlay texture texture_animation texture_remap texture_remap_channel texture_transform texture_unit theme transmittance_profile variable viewport voxel_cone_tracing vsm_config wave waves weather window - absorption absorptionExtinction albedo albedo_mask allow_hdr alpha alpha_blend_mode alpha_func ambient ambient_colour ambient_factor ambient_light amplitude animated_mesh animated_node animated_object animated_object_group animated_skeleton animation anisotropic_filtering aspect_ratio atmosphereVolumeResolution atmospheric_scattering attenuation attenuation_colour attenuation_distance back background_colour background_image background_invisible background_material bar_border_size bar_style begin_style bend_step_count bend_step_size bias billboard biome blend_alpha_func blocksCount bloomStrength blurRadius blur_high_quality blur_radius blur_step_size bokeh_scale border_colour border_inner_uv border_invisible border_material border_outer_uv border_panel_overlay border_position border_size bottom bottomColour bottomRadius bottom_to_top box_layout button button_style bw_accumulation camera camera_node caption cast_shadows center_uv channel clearcoat clearcoat_factor clearcoat_mask clearcoat_normal clearcoat_normal_mask clearcoat_roughness clearcoat_roughness_factor clearcoat_roughness_mask clouds clusters colour colour_blend_mode colour_hdr colour_mask colour_srgb combobox combobox_style comparison_func comparison_mode compute_program conservative_rasterization constantTerm constants_buffer container_border_size container_style content content_style cornerRounding count coverage crispiness cross cs_shader_program cullable curlResolution curliness cut_off dampeningFactor debug_max_image_size debug_overlays default_font default_material default_materials default_unit density depth depthSofteningDistance depthSubdiv detail diamond_square_terrain diffuse diffuse_mask dimensions direction directional_shadow_cascades disableCornerDetection disableDiagonalDetection disableRandomSeed disabled_background_material disabled_foreground_material disabled_text_material displacementDownsample domain_program draw_edges edgeDetection edge_colour edge_depth_factor edge_normal_factor edge_object_factor edge_sharpness edge_width edit edit_style elements_style emissive emissive_colour emissive_factor emissive_mask emissive_mult enablePowder enablePredication enableReprojection enable_bvh_warp_optimisation enable_full_loading enable_reduce_warp_optimisation enabled end_style equirectangular expScale expTerm expand expand_caption expand_style expandable_panel expandable_panel_style exponent exposure face face_normals face_tangents face_uv face_uvw factor far fft_waves file file_anim filter filter_size foamAngleExponent foamBrightness foamFadeDistance foamHeightStart foamNoiseTiling foamTiling focal_distance focal_length fog_density fog_type font foreground_invisible foreground_material format fov_y fpsScale fractal frame frame_style frequency front fullscreen gamma gaussian_width geometry_program global_illumination glossiness glossiness_mask grid_size groundAlbedo group_sizes gui has_refraction hdr_config hdr_format header header_caption header_font header_horizontal_align header_style header_text_material header_vertical_align heatOffset height heightMapSamples heightRange height_factor height_mask hide_title highSteepness high_quality highlighted_background_material highlighted_foreground_material highlighted_item_style highlighted_text_material horizontal horizontal_align horizontal_scrollbar horizontal_scrollbar_style hull_program ignore_vertex_colour image import import_anim import_morph_target indirect_attenuation innerRadius inner_cut_off intensity interpolation invert_y iridescence iridescence_factor iridescence_ior iridescence_mask iridescence_max_thickness iridescence_min_thickness iridescence_thickness iridescence_thickness_mask island item item_style layerWidth layout_ctrl layout_dynspace layout_staspace left left_to_right length levels_count light light_bleeding_reduction lighting lighting_model limit_clusters_to_lights_aabb line_spacing_mode line_style linearTerm linear_motion_blur listbox listbox_style loading_screen localContrastAdaptationFactor lod0Distance lod_bias looped lowSteepness lpv_config lpv_grid_size lpv_indirect_attenuation mag_filter material materials maxAbsorptionDensity maxMieDensity maxRayleighDensity maxSearchSteps maxSearchStepsDiag maxSunZenithAngle max_anisotropy max_distance max_image_size max_lod max_slope_offset mediumSteepness mesh metalness metalness_mask mieExtinction miePhaseFunctionG mieScattering minAbsorptionDensity minMieDensity minRayleighDensity min_filter min_lod min_offset min_radius min_size min_variance mip_filter mixed_interpolation mode morph_animation movable multiScatterResolution multiline multipleScatteringFactor near no_optimisations noiseTiling normal normalDepthWidth normalMapFreqMod normal_2channels normal_directx normal_factor normal_mask num_cones num_samples object objectWidth occlusion occlusion_mask octaves opacity opacity_mask orientation outerRadius outer_cut_off pad_bottom pad_left pad_right pad_top padding panel panel_overlay panel_style parallax_occlusion parent parse_depth_buffer particle particle_system particles_count pass passes patchSize pause_animation pbr_bloom pcf_config perlinWorleyResolution pickable pitch pixel_border_size pixel_position pixel_program pixel_size planetNode pos position positions postfx predicationScale predicationStrength predicationThreshold preferred_importer prefix preset primitive producer progress progress_style pushed_background_material pushed_foreground_material pushed_text_material pxl_border_size pxl_position pxl_size radius range raw_config rayMarchMaxSPP rayMarchMinSPP ray_step_size rayleighScattering receive_shadows recenter_camera reflections refractionDistanceFactor refractionDistortionFactor refractionHeightFactor refraction_ratio render_pass render_target reprojectionWeightScale rescale reserve_if_hidden resizable retract_caption right right_to_left roll rotate roughness roughness_mask sample_count sampler samples scale scene scene_node scrollbar_style secondary_bounce selected_item_style selection_material shader_program shaders shadow_producer shadows sheen sheen_colour sheen_mask sheen_roughness sheen_roughness_mask shininess shininess_mask size skeleton skyViewResolution skybox slider slider_style smaa smooth_band_width solarIrradiance sort_lights specular specular_colour specular_factor specular_factor_mask specular_mask speed split_scheme srgb_format ssao ssrBackwardStepsCount ssrDepthMult ssrForwardStepsCount ssrStepSize start_animation start_at static static_style steepness stereo stop_at strength stretch style submesh subsurface_scattering sunAngularRadius sunIlluminance sunIlluminanceScale sunNode tangent target_weight temporal_smoothing tessellationFactor texcoord_set texel_area_modifier text text_font text_material text_overlay text_wrapping texture texture_remap_config texture_unit texturing_mode theme thickness thickness_factor thickness_mask thickness_scale threshold thumb_style tick_style tile tiles tileset title_font title_material tone_mapping top topColour topOffset topRadius top_to_bottom transform translate transmission transmission_mask transmittance transmittanceResolution transmittance_mask transmittance_profile two_sided type u_wrap_mode untile use_lights_bvh use_normals_buffer use_spot_bounding_cone use_spot_tight_aabb uv uvScale uvw v_wrap_mode value variable vectorDivider vertex vertex_program vertical_align vertical_scrollbar vertical_scrollbar_style viewport visible volumetric_scattering volumetric_steps voxel_cone_tracing voxel_size vsm_config vsync w_wrap_mode waterDensity water_foam water_foam_mask water_noise water_noise_mask water_normal1 water_normal1_mask water_normal2 water_normal2_mask wave waves weather weatherResolution width widthSubdiv windDirection windVelocity window worleyResolution xzScale yaw + absorption absorptionExtinction albedo albedo_mask allow_hdr alpha alpha_blend_mode alpha_func ambient ambient_colour ambient_factor ambient_light amplitude animated_mesh animated_node animated_object animated_object_group animated_skeleton animation anisotropic_filtering aspect_ratio atmosphereVolumeResolution atmospheric_scattering attenuation attenuation_colour attenuation_distance back background_colour background_image background_invisible background_material bar_border_size bar_style begin_style bend_step_count bend_step_size bias billboard biome blend_alpha_func blocksCount bloomStrength blurRadius blur_high_quality blur_radius blur_step_size bokeh_scale border_colour border_inner_uv border_invisible border_material border_outer_uv border_panel_overlay border_position border_size bottom bottomColour bottomRadius bottom_to_top box_layout button button_style bw_accumulation camera camera_node caption cast_shadows center_uv channel clearcoat clearcoat_factor clearcoat_mask clearcoat_normal clearcoat_normal_mask clearcoat_roughness clearcoat_roughness_factor clearcoat_roughness_mask clouds clusters colour colour_blend_mode colour_hdr colour_mask colour_srgb combobox combobox_style comparison_func comparison_mode compute_program conservative_rasterization constantTerm constants_buffer container_border_size container_style content content_style cornerRounding count coverage crispiness cross cs_shader_program cullable curlResolution curliness cut_off dampeningFactor debug_max_image_size debug_overlays default_font default_material default_materials default_unit density depth depthSofteningDistance depthSubdiv detail diamond_square_terrain diffuse diffuse_mask dimensions direction directional_shadow_cascades disableCornerDetection disableDiagonalDetection disableRandomSeed disabled_background_material disabled_foreground_material disabled_text_material displacementDownsample domain_program draw_edges edgeDetection edge_colour edge_depth_factor edge_normal_factor edge_object_factor edge_sharpness edge_width edit edit_style elements_style emissive emissive_colour emissive_factor emissive_mask emissive_mult enablePowder enablePredication enableReprojection enable_bvh_warp_optimisation enable_full_loading enable_reduce_warp_optimisation enabled end_style equirectangular expScale expTerm expand expand_caption expand_style expandable_panel expandable_panel_style exponent exposure face face_normals face_tangents face_uv face_uvw factor far fft_waves file file_anim filter filter_size foamAngleExponent foamBrightness foamFadeDistance foamHeightStart foamNoiseTiling foamTiling focal_distance focal_length fog_density fog_type font foreground_invisible foreground_material format fov_y fpsScale fractal frame frame_style frequency front fullscreen gamma gaussian_width geometry_program global_illumination glossiness glossiness_mask grid_size groundAlbedo group_sizes gui has_refraction hdr_config hdr_format header header_caption header_font header_horizontal_align header_style header_text_material header_vertical_align heatOffset height heightMapSamples heightRange height_factor height_mask hide_title highSteepness high_quality highlighted_background_material highlighted_foreground_material highlighted_item_style highlighted_text_material horizontal horizontal_align horizontal_scrollbar horizontal_scrollbar_style hull_program ignore_vertex_colour image import import_anim import_morph_target indirect_attenuation innerRadius inner_cut_off intensity interpolation invert_y iridescence iridescence_factor iridescence_ior iridescence_mask iridescence_max_thickness iridescence_min_thickness iridescence_thickness iridescence_thickness_mask island item item_style layerWidth layout_ctrl layout_dynspace layout_staspace left left_to_right length levels_count light light_bleeding_reduction lighting lighting_model limit_clusters_to_lights_aabb line_spacing_mode line_style linearTerm linear_motion_blur listbox listbox_style loading_screen localContrastAdaptationFactor lod0Distance lod_bias looped lowSteepness lpv_config lpv_grid_size lpv_indirect_attenuation mag_filter material materials maxAbsorptionDensity maxMieDensity maxRayleighDensity maxSearchSteps maxSearchStepsDiag maxSunZenithAngle max_anisotropy max_distance max_image_size max_lod max_radius max_slope_offset mediumSteepness mesh metalness metalness_mask mieExtinction miePhaseFunctionG mieScattering minAbsorptionDensity minMieDensity minRayleighDensity min_filter min_lod min_offset min_radius min_size min_variance mip_filter mixed_interpolation mode morph_animation movable multiScatterResolution multiline multipleScatteringFactor near no_optimisations noiseTiling normal normalDepthWidth normalMapFreqMod normal_2channels normal_directx normal_factor normal_mask num_cones num_samples object objectWidth occlusion occlusion_mask octaves opacity opacity_mask orientation outerRadius outer_cut_off pad_bottom pad_left pad_right pad_top padding panel panel_overlay panel_style parallax_occlusion parent parse_depth_buffer particle particle_system particles_count pass passes patchSize pause_animation pbr_bloom pcf_config perlinWorleyResolution pickable pitch pixel_border_size pixel_position pixel_program pixel_size planetNode pos position positions postfx predicationScale predicationStrength predicationThreshold preferred_importer prefix preset primitive producer progress progress_style pushed_background_material pushed_foreground_material pushed_text_material pxl_border_size pxl_position pxl_size radius range raw_config rayMarchMaxSPP rayMarchMinSPP ray_step_size rayleighScattering receive_shadows recenter_camera reflections refractionDistanceFactor refractionDistortionFactor refractionHeightFactor refraction_ratio render_pass render_target reprojectionWeightScale rescale reserve_if_hidden resizable retract_caption right right_to_left roll rotate roughness roughness_mask sample_count sampler samples scale scene scene_node scrollbar_style secondary_bounce selected_item_style selection_material shader_program shaders shadow_producer shadows sheen sheen_colour sheen_mask sheen_roughness sheen_roughness_mask shininess shininess_mask size skeleton skyViewResolution skybox slider slider_style smaa smooth_band_width solarIrradiance sort_lights specular specular_colour specular_factor specular_factor_mask specular_mask speed split_scheme srgb_format ssao ssrBackwardStepsCount ssrDepthMult ssrForwardStepsCount ssrStepSize start_animation start_at static static_style steepness stereo stop_at strength stretch style submesh subsurface_scattering sunAngularRadius sunIlluminance sunIlluminanceScale sunNode tangent target_weight temporal_smoothing tessellationFactor texcoord_set texel_area_modifier text text_font text_material text_overlay text_wrapping texture texture_remap_config texture_unit texturing_mode theme thickness thickness_factor thickness_mask thickness_scale threshold thumb_style tick_style tile tiles tileset title_font title_material tone_mapping top topColour topOffset topRadius top_to_bottom transform translate transmission transmission_mask transmittance transmittanceResolution transmittance_mask transmittance_profile two_sided type u_wrap_mode untile use_lights_bvh use_normals_buffer use_spot_bounding_cone use_spot_tight_aabb uv uvScale uvw v_wrap_mode value variable vectorDivider vertex vertex_program vertical_align vertical_scrollbar vertical_scrollbar_style viewport visible volumetric_scattering volumetric_steps voxel_cone_tracing voxel_size vsm_config vsync w_wrap_mode waterDensity water_foam water_foam_mask water_noise water_noise_mask water_normal1 water_normal1_mask water_normal2 water_normal2_mask wave waves weather weatherResolution width widthSubdiv windDirection windVelocity window worleyResolution xzScale yaw define include faces radius height axis x y z height depth sort_around_center tile_uv flipYZ subdiv angle inner_size outer_size inner_count outer_count width_subdiv depth_subdiv 1X 4X S2X T2X a_buffer abgr2101010 abgr2101010s abgr2101010si abgr2101010ss abgr2101010ui abgr2101010us abgr32 abgr32s abgr32si abgr32srgb abgr32ss abgr32ui abgr32us additive albedo always argb1555 argb2101010 argb2101010s argb2101010si argb2101010ss argb2101010ui argb2101010us astc_10x10 astc_10x10_srgb astc_10x5 astc_10x5_srgb astc_10x6 astc_10x6_srgb astc_10x8 astc_10x8_srgb astc_12x10 astc_12x10_srgb astc_12x12 astc_12x12_srgb astc_4x4 astc_4x4_srgb astc_5x4 astc_5x4_srgb astc_5x5 astc_5x5_srgb astc_6x5 astc_6x5_srgb astc_6x6 astc_6x6_srgb astc_8x5 astc_8x5_srgb astc_8x6 astc_8x6_srgb astc_8x8 astc_8x8_srgb bc1_rgb bc1_rgba bc1_rgba_srgb bc1_srgb bc2_rgba bc2_rgba_srgb bc3_rgba bc3_rgba_srgb bc4_r bc4_r_s bc5_rg bc5_rg_s bc6h bc6h_s bc7 bc7_srgb bgr24 bgr24s bgr24si bgr24srgb bgr24ss bgr24ui bgr24us bgr32f bgr565 bgra32 bgra32s bgra32si bgra32srgb bgra32ss bgra32ui bgra32us bgra5551 bottom break break_words center clamp_to_border clamp_to_edge clearcoat clearcoat_normal clearcoat_roughness cm colour compute custom cylindrical depth depth16 depth16s8 depth24 depth24s8 depth32f depth32fs8 depth_peeling diffuse directional dynamic eac_r eac_r_s eac_rg eac_rg_s ebgr32f emissive equal etc2_rgb etc2_rgb_srgb etc2_rgba etc2_rgba1 etc2_rgba1_srgb etc2_rgba_srgb exponential exponential_biased external false fixed float float_opaque_black float_opaque_white float_transparent_black fragment frustum ft geometry glossiness greater greater_equal height high hybrid in infinite_perspective int int_opaque_black int_opaque_white int_transparent_black internal interpolative iridescence iridescence_thickness km layered_lpv layered_lpv_geometry left less less_equal letter line_list line_list_adj line_strip line_strip_adj linear low lpv lpv_geometry luma m mat2x2f mat3x3f mat4x4f max_font_height max_lines_height medium metalness middle mirrored_clamp_to_edge mirrored_repeat mm multiplicative nearest never none normal not_equal occlusion one opacity ortho own_height pcf perspective point point_list r16 r32f r32si r32ui r64f r64si r64ui r8 r8s r8si r8srgb r8ss r8ui r8us raw ref_to_texture repeat rg128f rg128si rg128ui rg16 rg16f rg16s rg16si rg16srgb rg16ss rg16ui rg16us rg32 rg32f rg32s rg32si rg32ss rg32ui rg32us rg64f rg64si rg64ui rg8 rgb192f rgb192si rgb192ui rgb24 rgb24s rgb24si rgb24srgb rgb24ss rgb24ui rgb24us rgb48 rgb48f rgb48s rgb48si rgb48ss rgb48ui rgb48us rgb565 rgb96f rgb96si rgb96ui rgba128f rgba128si rgba128ui rgba16 rgba16s rgba256f rgba256si rgba256ui rgba32 rgba32s rgba32si rgba32srgb rgba32ss rgba32ui rgba32us rgba5551 rgba64 rgba64f rgba64s rgba64si rgba64ss rgba64ui rgba64us right roughness rsm screen_size sheen sheen_roughness shininess specular specular_factor spherical spot squared_exponential stencil8 tess_control tess_eval text thickness top transmission transmittance triangle_fan triangle_list triangle_list_adj triangle_strip triangle_strip_adj true uint ultra undefined variance vct vec2f vec2i vec2ui vec3f vec3i vec3ui vec4f vec4i vec4ui vertex water_foam water_noise water_normal1 water_normal2 yd argb32 c3d pbr phong toon water diff --git a/include/Core/Castor3D/Render/GlobalIllumination/GlobalIlluminationModule.hpp b/include/Core/Castor3D/Render/GlobalIllumination/GlobalIlluminationModule.hpp index 9f116f91f3..ebe53aef51 100644 --- a/include/Core/Castor3D/Render/GlobalIllumination/GlobalIlluminationModule.hpp +++ b/include/Core/Castor3D/Render/GlobalIllumination/GlobalIlluminationModule.hpp @@ -25,10 +25,10 @@ namespace castor3d : uint32_t { eNone = 0, - // Reflective shadow maps. - eRsm = 1, // Voxel Cone Tracing. - eVoxelConeTracing = 2, + eVoxelConeTracing = 1, + // Reflective shadow maps. + eRsm = 2, // Light Propagation Volumes without geometry injection. eLpv = 3, // Light Propagation Volumes with geometry injection. @@ -86,6 +86,7 @@ namespace castor3d LpvGridConfigUbo const * lpvConfigUbo{}; LayeredLpvGridConfigUbo const * llpvConfigUbo{}; VoxelizerUbo const * vctConfigUbo{}; + Texture const * rsmResult{}; LightVolumePassResult const * lpvResult{}; LightVolumePassResultArray const * llpvResult{}; Texture const * vctFirstBounce{}; diff --git a/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.hpp b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.hpp new file mode 100644 index 0000000000..3f4b710667 --- /dev/null +++ b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.hpp @@ -0,0 +1,59 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___C3D_ReflectiveShadowMapping_HPP___ +#define ___C3D_ReflectiveShadowMapping_HPP___ + +#include "ReflectiveShadowMapsModule.hpp" +#include "Castor3D/Shader/Ubos/UbosModule.hpp" + +#include "Castor3D/Shader/Shaders/GlslLight.hpp" + +#include + +namespace castor3d +{ + class ReflectiveShadowMapping + { + public: + C3D_API ReflectiveShadowMapping( sdw::ShaderWriter & writer + , sdw::ArrayStorageBufferT< sdw::Vec4 > & rsmSamples ); + C3D_API sdw::Vec3 directional( shader::DirectionalShadowData const & shadowData + , sdw::Vec3 const & viewPosition + , sdw::Vec3 const & worldPosition + , sdw::Vec3 const & worldNormal + , shader::RsmConfigData const & rsmData ); + C3D_API sdw::Vec3 point( shader::PointShadowData const & shadowData + , sdw::Vec3 const & lightPosition + , sdw::Vec3 const & worldPosition + , sdw::Vec3 const & worldNormal + , shader::RsmConfigData const & rsmData ); + C3D_API sdw::Vec3 spot( shader::SpotShadowData const & shadowData + , sdw::Vec3 const & worldPosition + , sdw::Vec3 const & worldNormal + , shader::RsmConfigData const & rsmData ); + + private: + sdw::ShaderWriter & m_writer; + sdw::ArrayStorageBufferT< sdw::Vec4 > & m_rsmSamples; + sdw::Function< sdw::Vec3 + , shader::InDirectionalShadowData + , sdw::InVec3 + , sdw::InVec3 + , sdw::InVec3 + , shader::InRsmConfigData > m_directional; + sdw::Function< sdw::Vec3 + , shader::InPointShadowData + , sdw::InVec3 + , sdw::InVec3 + , sdw::InVec3 + , shader::InRsmConfigData > m_point; + sdw::Function< sdw::Vec3 + , shader::InSpotShadowData + , sdw::InVec3 + , sdw::InVec3 + , shader::InRsmConfigData > m_spot; + }; +} + +#endif diff --git a/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.hpp b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.hpp new file mode 100644 index 0000000000..2e4e802deb --- /dev/null +++ b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.hpp @@ -0,0 +1,93 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___C3D_ReflectiveShadowMaps_H___ +#define ___C3D_ReflectiveShadowMaps_H___ + +#include "ReflectiveShadowMapsModule.hpp" + +#include "Castor3D/Cache/CacheModule.hpp" +#include "Castor3D/Miscellaneous/MiscellaneousModule.hpp" +#include "Castor3D/Render/ShadowMap/ShadowMapModule.hpp" + +#include + +#include +#include + +namespace castor3d +{ + class ReflectiveShadowMaps + : public castor::Named + { + public: + C3D_API ReflectiveShadowMaps( crg::ResourceHandler & handler + , Scene const & scene + , RenderDevice const & device + , CameraUbo const & cameraUbo + , ShadowBuffer const & shadowBuffer + , crg::ImageViewId const & depthObj + , crg::ImageViewId const & nmlOcc + , ShadowMapResult const & directionalSmResult + , ShadowMapResult const & pointSmResult + , ShadowMapResult const & spotSmResult + , Texture const & result ); + C3D_API ~ReflectiveShadowMaps()noexcept; + + public: + C3D_API void initialise(); + C3D_API void cleanup(); + C3D_API void registerLight( Light * light ); + C3D_API void update( CpuUpdater & updater ); + C3D_API crg::SemaphoreWaitArray render( crg::SemaphoreWaitArray const & toWait + , ashes::Queue const & queue ); + C3D_API void accept( ConfigurationVisitorBase & visitor ); + + private: + crg::FramePass & doCreateClearPass(); + + private: + Scene const & m_scene; + RenderDevice const & m_device; + CameraUbo const & m_cameraUbo; + ShadowBuffer const & m_shadowBuffer; + crg::ImageViewId const & m_depthObj; + crg::ImageViewId const & m_nmlOcc; + ShadowMapResult const & m_directionalSmResult; + ShadowMapResult const & m_pointSmResult; + ShadowMapResult const & m_spotSmResult; + crg::FrameGraph m_graph; + bool m_initialised{ false }; + TextureArray m_intermediate; + Texture const & m_result; + struct LightRsm + { + LightRsm( crg::FrameGraph & graph + , crg::FramePassArray previousPasses + , RenderDevice const & device + , LightCache const & lightCache + , LightType lightType + , ShadowBuffer const & shadowBuffer + , CameraUbo const & cameraUbo + , crg::ImageViewId const & depthObj + , crg::ImageViewId const & nmlOcc + , ShadowMapResult const & smResult + , TextureArray const & intermediate + , Texture const & result ); + void update( CpuUpdater & updater ); + + LightCache const & lightCache; + RsmGIPassUPtr giPass; + RsmInterpolatePassUPtr interpolatePass; + crg::FramePass const * lastPass{}; + }; + using LightRsmPtr = std::unique_ptr< LightRsm >; + + crg::FramePass const & m_clearPass; + crg::FramePass const * m_lastPass; + std::unordered_map< Light *, LightRsmPtr > m_lightRsms; + crg::RunnableGraphPtr m_runnable; + }; +} + +#endif diff --git a/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapsModule.hpp b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapsModule.hpp new file mode 100644 index 0000000000..b84b466439 --- /dev/null +++ b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapsModule.hpp @@ -0,0 +1,76 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___C3D_ReflectiveShadowMapsModule_H___ +#define ___C3D_ReflectiveShadowMapsModule_H___ + +#include "Castor3D/Cache/CacheModule.hpp" +#include "Castor3D/Render/Opaque/OpaqueModule.hpp" +#include "Castor3D/Render/ShadowMap/ShadowMapModule.hpp" +#include "Castor3D/Scene/Light/LightModule.hpp" + +namespace castor3d +{ + /**@name Render */ + //@{ + /**@name Global Illumination */ + //@{ + /**@name Reflective Shadow Maps */ + //@{ + + /** + *\~english + *\brief + * Reflective Shadow Map shader helpers. + *\~french + *\brief + * classe d'aide pour les shaders de Reflective Shadow Map. + */ + class ReflectiveShadowMapping; + /** + *\~english + *\brief + * Reflective Shadow Maps configuration values. + *\~french + *\brief + * Valeurs de configuration des Reflective Shadow Maps. + */ + struct RsmConfig; + /** + *\~english + *\brief + * SSGI pass based on Reflective Shadow Maps. + *\~french + *\brief + * Passe de SSGI basée sur les Reflective Shadow Maps. + */ + class RsmGIPass; + /** + *\~english + *\brief + * RSM GI interpolation pass, used to optimise the algorithm. + *\~french + *\brief + * Passe d'interpolation du RSM GI, pour optimiser l'algorithme. + */ + class RsmInterpolatePass; + /** + *\~english + *\brief + * RSM full pass. + *\~french + *\brief + * Passe de RSM. + */ + class ReflectiveShadowMaps; + + CU_DeclareSmartPtr( castor3d, RsmGIPass, C3D_API ); + CU_DeclareSmartPtr( castor3d, RsmInterpolatePass, C3D_API ); + CU_DeclareSmartPtr( castor3d, ReflectiveShadowMaps, C3D_API ); + + //@} + //@} + //@} +} + +#endif diff --git a/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.hpp b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.hpp new file mode 100644 index 0000000000..0bf04f1f9c --- /dev/null +++ b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.hpp @@ -0,0 +1,37 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___C3D_RsmConfig_H___ +#define ___C3D_RsmConfig_H___ + +#include "ReflectiveShadowMapsModule.hpp" + +#include "Castor3D/Limits.hpp" + +#include "Castor3D/Miscellaneous/MiscellaneousModule.hpp" + +#include +#include +#include + +namespace castor3d +{ + struct RsmConfig + { + C3D_API void accept( ConfigurationVisitorBase & visitor ); + C3D_API static void addParsers( castor::AttributeParsers & result ); + + castor::ChangeTracked< float > intensity; + castor::ChangeTracked< float > maxRadius; + castor::ChangeTracked< castor::RangedValue< uint32_t > > sampleCount{ castor::makeRangedValue( 100u, 20u, MaxRsmRange ) }; + }; + + inline bool operator==( RsmConfig const & lhs, RsmConfig const & rhs )noexcept + { + return lhs.intensity == rhs.intensity + && lhs.maxRadius == rhs.maxRadius + && lhs.sampleCount == rhs.sampleCount; + } +} + +#endif diff --git a/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.hpp b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.hpp new file mode 100644 index 0000000000..0adc6af3f3 --- /dev/null +++ b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.hpp @@ -0,0 +1,100 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___C3D_RsmGIPass_HPP___ +#define ___C3D_RsmGIPass_HPP___ + +#include "ReflectiveShadowMapsModule.hpp" +#include "Castor3D/Cache/CacheModule.hpp" + +#include "Castor3D/Buffer/GpuBufferOffset.hpp" +#include "Castor3D/Material/Texture/TextureUnit.hpp" +#include "Castor3D/Miscellaneous/MiscellaneousModule.hpp" +#include "Castor3D/Render/ShadowMap/ShadowMapModule.hpp" +#include "Castor3D/Render/Opaque/OpaqueModule.hpp" +#include "Castor3D/Render/Passes/RenderQuad.hpp" +#include "Castor3D/Scene/Light/LightModule.hpp" +#include "Castor3D/Shader/Ubos/RsmConfigUbo.hpp" + +#include + +namespace castor3d +{ + class RsmGIPass + : public castor::Named + { + public: + /** + *\~english + *\brief Constructor. + *\param[in] pass The parent frame pass. + *\param[in] context The rendering context. + *\param[in] graph The runnable graph. + *\param[in] device The GPU device. + *\param[in] lightType The light source type. + *\param[in] size The render area dimensions. + *\param[in] gpInfo The GBuffer configuration UBO. + *\param[in] gpResult The GBuffer. + *\param[in] smResult The shadow map. + *\param[in] downscaleResult The downscaled result. + *\~french + *\brief Constructeur. + *\param[in] pass La frame pass parente. + *\param[in] context Le contexte de rendu. + *\param[in] graph Le runnable graph. + *\param[in] device Le device GPU. + *\param[in] size Les dimensions de la zone de rendu. + *\param[in] gpInfo L'UBO de configuration du GBuffer. + *\param[in] gpResult Le GBuffer. + *\param[in] smResult La shadow map. + *\param[in] downscaleResult Le résultat downscaled. + */ + C3D_API RsmGIPass( crg::FrameGraph & graph + , crg::FramePassArray const & previousPasses + , RenderDevice const & device + , LightType lightType + , ShadowBuffer const & shadowBuffer + , VkExtent3D const & size + , CameraUbo const & cameraUbo + , crg::ImageViewId const & depthObj + , crg::ImageViewId const & nmlOcc + , ShadowMapResult const & smResult + , TextureArray const & result ); + /** + *\copydoc castor3d::RenderTechniquePass::accept + */ + C3D_API void accept( ConfigurationVisitorBase & visitor ); + C3D_API void update( Light const & light ); + + RsmConfigUbo const & getConfigUbo()const + { + return m_rsmConfigUbo; + } + + GpuBufferOffsetT< castor::Point4f > const & getSamplesSsbo()const + { + return m_rsmSamplesSsbo; + } + + crg::FramePass const & getPass()const + { + return *m_pass; + } + + protected: + C3D_API void doSubInitialise(); + C3D_API void doSubRecordInto( crg::RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index ); + + private: + RsmConfigUbo m_rsmConfigUbo; + GpuBufferOffsetT< castor::Point4f > m_rsmSamplesSsbo; + ShaderModule m_vertexShader; + ShaderModule m_pixelShader; + ashes::PipelineShaderStageCreateInfoArray m_stages; + crg::FramePass const * m_pass; + }; +} + +#endif diff --git a/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.hpp b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.hpp new file mode 100644 index 0000000000..b877e5667c --- /dev/null +++ b/include/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.hpp @@ -0,0 +1,56 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___C3D_RsmInterpolatePass_HPP___ +#define ___C3D_RsmInterpolatePass_HPP___ + +#include "ReflectiveShadowMapsModule.hpp" +#include "Castor3D/Cache/CacheModule.hpp" + +#include "Castor3D/Miscellaneous/MiscellaneousModule.hpp" +#include "Castor3D/Render/ShadowMap/ShadowMapModule.hpp" +#include "Castor3D/Render/Opaque/OpaqueModule.hpp" +#include "Castor3D/Scene/Light/LightModule.hpp" +#include "Castor3D/Shader/Ubos/UbosModule.hpp" + +#include "Castor3D/Buffer/GpuBufferOffset.hpp" + +#include + +namespace castor3d +{ + class RsmInterpolatePass + : public castor::Named + { + public: + C3D_API RsmInterpolatePass( crg::FrameGraph & graph + , crg::FramePass const & previousPass + , RenderDevice const & device + , LightType lightType + , ShadowBuffer const & shadowBuffer + , VkExtent3D const & size + , CameraUbo const & cameraUbo + , crg::ImageViewId const & depthObj + , crg::ImageViewId const & nmlOcc + , ShadowMapResult const & smResult + , RsmConfigUbo const & rsmConfigUbo + , GpuBufferOffsetT< castor::Point4f > const & rsmSamplesSsbo + , Texture const & gi + , Texture const & nml + , Texture const & dst ); + C3D_API void accept( ConfigurationVisitorBase & visitor ); + + crg::FramePass const & getPass()const + { + return *m_pass; + } + + private: + ShaderModule m_vertexShader; + ShaderModule m_pixelShader; + ashes::PipelineShaderStageCreateInfoArray m_stages; + crg::FramePass const * m_pass{}; + }; +} + +#endif diff --git a/include/Core/Castor3D/Render/RenderTechnique.hpp b/include/Core/Castor3D/Render/RenderTechnique.hpp index 1a42111e30..a5f9b4e806 100644 --- a/include/Core/Castor3D/Render/RenderTechnique.hpp +++ b/include/Core/Castor3D/Render/RenderTechnique.hpp @@ -10,6 +10,7 @@ See LICENSE file in root folder #include "Castor3D/Render/Clustered/ClusteredModule.hpp" #include "Castor3D/Render/GlobalIllumination/GlobalIlluminationModule.hpp" #include "Castor3D/Render/GlobalIllumination/LightPropagationVolumes/LightPropagationVolumesModule.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapsModule.hpp" #include "Castor3D/Render/GlobalIllumination/VoxelConeTracing/VoxelizeModule.hpp" #include "Castor3D/Render/Opaque/OpaqueModule.hpp" #include "Castor3D/Render/Prepass/PrepassModule.hpp" @@ -375,13 +376,17 @@ namespace castor3d , crg::FramePass const * previousPass , crg::FramePassArray previousPasses = {} ); BackgroundRendererUPtr doCreateBackgroundPass( ProgressBar * progress ); + void doInitialiseRsm(); void doInitialiseLpv(); void doUpdateShadowMaps( CpuUpdater & updater ); void doUpdateShadowMaps( GpuUpdater & updater )const; + void doUpdateRsm( CpuUpdater & updater ); void doUpdateLpv( CpuUpdater & updater ); crg::SemaphoreWaitArray doRenderShadowMaps( crg::SemaphoreWaitArray const & semaphore , ashes::Queue const & queue )const; + crg::SemaphoreWaitArray doRenderRSM( crg::SemaphoreWaitArray const & semaphore + , ashes::Queue const & queue ); crg::SemaphoreWaitArray doRenderLPV( crg::SemaphoreWaitArray const & semaphore , ashes::Queue const & queue ); crg::SemaphoreWaitArray doRenderEnvironmentMaps( crg::SemaphoreWaitArray const & semaphore @@ -411,6 +416,7 @@ namespace castor3d ShadowMapUPtr m_pointShadowMap; ShadowMapUPtr m_spotShadowMap; VoxelizerUPtr m_voxelizer; + TextureUPtr m_rsmResult; LightVolumePassResultUPtr m_lpvResult; LightVolumePassResultArray m_llpvResult; IndirectLightingData m_indirectLighting; @@ -433,6 +439,7 @@ namespace castor3d LayeredLightPropagationVolumesLightType m_layeredLightPropagationVolumes; LightPropagationVolumesGLightType m_lightPropagationVolumesG; LayeredLightPropagationVolumesGLightType m_layeredLightPropagationVolumesG; + ReflectiveShadowMapsUPtr m_reflectiveShadowMaps; }; } diff --git a/include/Core/Castor3D/Scene/Light/Light.hpp b/include/Core/Castor3D/Scene/Light/Light.hpp index 0059c524b4..244888faf7 100644 --- a/include/Core/Castor3D/Scene/Light/Light.hpp +++ b/include/Core/Castor3D/Scene/Light/Light.hpp @@ -213,6 +213,11 @@ namespace castor3d return m_shadows.globalIllumination; } + RsmConfig const & getRsmConfig()const + { + return m_shadows.rsmConfig; + } + LpvConfig const & getLpvConfig()const { return m_shadows.lpvConfig; diff --git a/include/Core/Castor3D/Scene/Light/LightCategory.hpp b/include/Core/Castor3D/Scene/Light/LightCategory.hpp index a29cccd541..e551da27c0 100644 --- a/include/Core/Castor3D/Scene/Light/LightCategory.hpp +++ b/include/Core/Castor3D/Scene/Light/LightCategory.hpp @@ -6,6 +6,7 @@ See LICENSE file in root folder #include "LightModule.hpp" #include "Castor3D/Render/GlobalIllumination/LightPropagationVolumes/LightPropagationVolumesModule.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapsModule.hpp" #include "Castor3D/Shader/ShaderBuffers/LightBuffer.hpp" #include diff --git a/include/Core/Castor3D/Scene/Light/LightModule.hpp b/include/Core/Castor3D/Scene/Light/LightModule.hpp index 0427fe459d..0baa0d75f8 100644 --- a/include/Core/Castor3D/Scene/Light/LightModule.hpp +++ b/include/Core/Castor3D/Scene/Light/LightModule.hpp @@ -8,8 +8,6 @@ See LICENSE file in root folder #include "Castor3D/Scene/SceneModule.hpp" #include "Castor3D/Shader/ShaderBuffers/ShaderBuffersModule.hpp" -#include "Castor3D/Limits.hpp" - namespace castor3d { /**@name Scene */ @@ -197,14 +195,18 @@ namespace castor3d castor::Array< castor::Matrix4x4f, MaxDirectionalCascadesCount > transforms; }; + struct PointShadowData + : BaseShadowData + { + castor::Point4f position; + }; + struct SpotShadowData : BaseShadowData { castor::Matrix4x4f transform; }; - using PointShadowData = BaseShadowData; - struct AllShadowData { DirectionalShadowData directional; diff --git a/include/Core/Castor3D/Scene/Scene.hpp b/include/Core/Castor3D/Scene/Scene.hpp index 5ca956f86b..df72c45157 100644 --- a/include/Core/Castor3D/Scene/Scene.hpp +++ b/include/Core/Castor3D/Scene/Scene.hpp @@ -296,6 +296,7 @@ namespace castor3d C3D_API LightingModelID getDefaultLightingModel()const; C3D_API castor::String getDefaultLightingModelName()const; C3D_API bool needsGlobalIllumination()const; + C3D_API bool needsGlobalIllumination( GlobalIlluminationType giType )const; C3D_API bool needsGlobalIllumination( LightType ltType , GlobalIlluminationType giType )const; C3D_API crg::SemaphoreWaitArray getRenderTargetsSemaphores()const; diff --git a/include/Core/Castor3D/Scene/SceneFileParserData.hpp b/include/Core/Castor3D/Scene/SceneFileParserData.hpp index a68e55b0a0..0d843d5755 100644 --- a/include/Core/Castor3D/Scene/SceneFileParserData.hpp +++ b/include/Core/Castor3D/Scene/SceneFileParserData.hpp @@ -62,6 +62,7 @@ namespace castor3d eRaw = CU_MakeSectionName( 'R', 'A', 'W', 'S' ), ePcf = CU_MakeSectionName( 'P', 'C', 'F', 'S' ), eVsm = CU_MakeSectionName( 'V', 'S', 'M', 'S' ), + eRsm = CU_MakeSectionName( 'R', 'S', 'M', 'S' ), eTextureAnimation = CU_MakeSectionName( 'T', 'X', 'A', 'N' ), eVoxelConeTracing = CU_MakeSectionName( 'V', 'C', 'T', 'C' ), eTextureTransform = CU_MakeSectionName( 'T', 'X', 'T', 'R' ), diff --git a/include/Core/Castor3D/Scene/SceneModule.hpp b/include/Core/Castor3D/Scene/SceneModule.hpp index 3018abbc8c..74e50b50b1 100644 --- a/include/Core/Castor3D/Scene/SceneModule.hpp +++ b/include/Core/Castor3D/Scene/SceneModule.hpp @@ -129,17 +129,20 @@ namespace castor3d eShadowSpot = eShadowBegin << 2, eShadowEnd = eShadowSpot, eShadowAny = eShadowSpot | eShadowPoint | eShadowDirectional, + //!\~english Reflective Shadow Maps enabling. + //!\~french Activation des Reflective Shadow Maps. + eRsmGI = 0x0001 << 6, //!\~english Light Propagation Volumes enabling. //!\~french Activation des Light Propagation Volumes. - eLpvGI = 0x0001 << 6, - eLayeredLpvGI = 0x0001 << 7, + eLpvGI = 0x0001 << 7, + eLayeredLpvGI = 0x0001 << 8, //!\~english Voxel Cone Tracing enabling. //!\~french Activation du Voxel Cone Tracing. - eVoxelConeTracing = 0x0001 << 8, - eGIAny = eLpvGI | eLayeredLpvGI | eVoxelConeTracing, + eVoxelConeTracing = 0x0001 << 9, + eGIAny = eRsmGI | eLpvGI | eLayeredLpvGI | eVoxelConeTracing, //!\~english All flags. //!\~french Tous les indicateurs. - eAll = 0x01FF, + eAll = 0x03FF, }; CU_ImplementFlags( SceneFlag ) /** diff --git a/include/Core/Castor3D/Scene/Shadow.hpp b/include/Core/Castor3D/Scene/Shadow.hpp index 373529215b..25dae85362 100644 --- a/include/Core/Castor3D/Scene/Shadow.hpp +++ b/include/Core/Castor3D/Scene/Shadow.hpp @@ -8,6 +8,7 @@ See LICENSE file in root folder #include "Castor3D/Limits.hpp" #include "Castor3D/Render/GlobalIllumination/LightPropagationVolumes/LpvConfig.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.hpp" #include #include @@ -33,6 +34,7 @@ namespace castor3d castor::RangedValue< uint32_t > pcfFilterSize{ 4u, castor::makeRange( 0u, MaxPcfFilterSize ) }; castor::RangedValue< uint32_t > pcfSampleCount{ 8u, castor::makeRange( 0u, MaxPcfSampleCount ) }; LpvConfig lpvConfig; + RsmConfig rsmConfig; }; inline bool operator==( ShadowConfig const & lhs, ShadowConfig const & rhs )noexcept @@ -47,7 +49,8 @@ namespace castor3d && lhs.vsmLightBleedingReduction == rhs.vsmLightBleedingReduction && lhs.pcfFilterSize == rhs.pcfFilterSize && lhs.pcfSampleCount == rhs.pcfSampleCount - && lhs.lpvConfig == rhs.lpvConfig; + && lhs.lpvConfig == rhs.lpvConfig + && lhs.rsmConfig == rhs.rsmConfig; } } diff --git a/include/Core/Castor3D/Shader/Shaders/GlslGlobalIllumination.hpp b/include/Core/Castor3D/Shader/Shaders/GlslGlobalIllumination.hpp index 8432b0f7f4..b9247481d4 100644 --- a/include/Core/Castor3D/Shader/Shaders/GlslGlobalIllumination.hpp +++ b/include/Core/Castor3D/Shader/Shaders/GlslGlobalIllumination.hpp @@ -64,6 +64,8 @@ namespace castor3d::shader , uint32_t & texBindingIndex , uint32_t uboSetIndex = 0u , uint32_t texSetIndex = 0u ); + void declareRsm( uint32_t & texBindingIndex + , uint32_t texSetIndex = 0u ); void declareLpv( uint32_t & uboBindingIndex , uint32_t & texBindingIndex , uint32_t uboSetIndex = 0u @@ -80,6 +82,7 @@ namespace castor3d::shader , sdw::Float const & indirectOcclusion , sdw::Float const & indirectBlend , VoxelData const & voxelData ); + sdw::Vec4 computeRSMRadiance( sdw::Vec2 const & texcoord ); sdw::Vec4 computeLPVRadiance( LightSurface surface , LpvGridData lpvGridData ); sdw::Vec4 computeLLPVRadiance( LightSurface surface @@ -103,6 +106,8 @@ namespace castor3d::shader Utils & m_utils; sdw::Function< sdw::Vec4 , sdw::InVec3 > m_evalSH; + sdw::Function< sdw::Vec4 + , sdw::InVec2 > m_computeRSMRadiance; sdw::Function< sdw::Vec4 , sdw::InVec3 , sdw::InVec3 diff --git a/include/Core/Castor3D/Shader/Shaders/GlslLight.hpp b/include/Core/Castor3D/Shader/Shaders/GlslLight.hpp index 4df112fccd..7b444b9705 100644 --- a/include/Core/Castor3D/Shader/Shaders/GlslLight.hpp +++ b/include/Core/Castor3D/Shader/Shaders/GlslLight.hpp @@ -582,6 +582,12 @@ namespace castor3d::shader C3D_API sdw::Vec3 getCascadeFactors( DirectionalShadowData const light , sdw::Vec3 viewVertex , sdw::UInt maxCascadeCount ); + + C3D_API static sdw::Vec3 getCascadeFactors( sdw::ShaderWriter & writer + , sdw::Vec3 const & viewVertex + , sdw::Vec4Array const & splitDepths + , sdw::UInt const & cascadeCount + , sdw::UInt const & maxCascadeCount ); //\} Shadow & getShadowModel()const noexcept diff --git a/include/Core/Castor3D/Shader/Shaders/GlslShadow.hpp b/include/Core/Castor3D/Shader/Shaders/GlslShadow.hpp index a1c09a92f0..e7976d30b7 100644 --- a/include/Core/Castor3D/Shader/Shaders/GlslShadow.hpp +++ b/include/Core/Castor3D/Shader/Shaders/GlslShadow.hpp @@ -80,7 +80,8 @@ namespace castor3d::shader struct PointShadowData : public sdw::StructInstanceHelperT< "C3D_PointShadowData" , sdw::type::MemoryLayout::eStd140 - , sdw::StructFieldT< ShadowData, "base" > > + , sdw::StructFieldT< ShadowData, "base" > + , sdw::Vec4Field< "position" > > { PointShadowData( sdw::ShaderWriter & writer , ast::expr::ExprPtr expr @@ -90,6 +91,7 @@ namespace castor3d::shader } auto base()const { return getMember< "base" >(); } + auto position()const { return getMember< "position" >(); } }; struct SpotShadowData diff --git a/include/Core/Castor3D/Shader/Ubos/RsmConfigUbo.hpp b/include/Core/Castor3D/Shader/Ubos/RsmConfigUbo.hpp new file mode 100644 index 0000000000..92a49b339b --- /dev/null +++ b/include/Core/Castor3D/Shader/Ubos/RsmConfigUbo.hpp @@ -0,0 +1,109 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___C3D_VoxelizerUbo_H___ +#define ___C3D_VoxelizerUbo_H___ + +#include "UbosModule.hpp" + +#include "Castor3D/Buffer/UniformBufferOffset.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapsModule.hpp" + +#include +#include + +namespace castor3d +{ + namespace shader + { + struct RsmConfigData + : public sdw::StructInstance + { + C3D_API RsmConfigData( sdw::ShaderWriter & writer + , ast::expr::ExprPtr expr + , bool enabled ); + SDW_DeclStructInstance( C3D_API, RsmConfigData ); + + C3D_API static ast::type::BaseStructPtr makeType( ast::type::TypesCache & cache ); + C3D_API static castor::RawUniquePtr< sdw::Struct > declare( sdw::ShaderWriter & writer ); + + sdw::Float intensity; + sdw::Float maxRadius; + sdw::UInt32 sampleCount; + sdw::Int32 index; + + private: + using sdw::StructInstance::getMember; + using sdw::StructInstance::getMemberArray; + }; + } + + class RsmConfigUbo + { + public: + using Configuration = RsmUboConfiguration; + + public: + C3D_API RsmConfigUbo( RsmConfigUbo const & rhs ) = delete; + C3D_API RsmConfigUbo & operator=( RsmConfigUbo const & rhs ) = delete; + C3D_API RsmConfigUbo( RsmConfigUbo && rhs )noexcept = default; + C3D_API RsmConfigUbo & operator=( RsmConfigUbo && rhs )noexcept = delete; + C3D_API explicit RsmConfigUbo( RenderDevice const & device ); + C3D_API ~RsmConfigUbo()noexcept; + + C3D_API void cpuUpdate( RsmConfig const & rsmConfig + , uint32_t index ); + + void createPassBinding( crg::FramePass & pass + , uint32_t binding )const + { + m_ubo.createPassBinding( pass, "RsmCfg", binding ); + } + + void createSizedBinding( ashes::DescriptorSet & descriptorSet + , VkDescriptorSetLayoutBinding const & layoutBinding )const + { + return m_ubo.createSizedBinding( descriptorSet, layoutBinding ); + } + + ashes::WriteDescriptorSet getDescriptorWrite( uint32_t dstBinding + , uint32_t dstArrayElement = 0u )const + { + return m_ubo.getDescriptorWrite( dstBinding, dstArrayElement ); + } + + void addDescriptorWrite( ashes::WriteDescriptorSetArray & descriptorWrites + , uint32_t & dstBinding + , uint32_t dstArrayElement = 0u )const + { + descriptorWrites.emplace_back( getDescriptorWrite( dstBinding, dstArrayElement ) ); + ++dstBinding; + } + + UniformBufferOffsetT< Configuration > const & getUbo()const + { + return m_ubo; + } + + + private: + RenderDevice const & m_device; + UniformBufferOffsetT< Configuration > m_ubo{}; + }; +} + +#define C3D_RsmConfigEx( writer, binding, set, enable )\ + sdw::UniformBuffer rsmConfig{ writer\ + , "C3D_RsmConfig"\ + , "c3d_rsmConfig"\ + , uint32_t( binding )\ + , uint32_t( set )\ + , ast::type::MemoryLayout::eStd140\ + , enable };\ + auto c3d_rsmConfigData = rsmConfig.declMember< shader::RsmConfigData >( "c3d_rsmConfigData" );\ + rsmConfig.end() + +#define C3D_RsmConfig( writer, binding, set )\ + C3D_RsmConfigEx( writer, binding, set, true ) + +#endif diff --git a/source/Core/Castor3D/CMakeLists.txt b/source/Core/Castor3D/CMakeLists.txt index 16a9a50f7a..5eb5b7b432 100644 --- a/source/Core/Castor3D/CMakeLists.txt +++ b/source/Core/Castor3D/CMakeLists.txt @@ -1277,6 +1277,32 @@ set( ${PROJECT_NAME}_HDR_FILES source_group( "Header Files\\Render\\GlobalIllumination\\LightPropagationVolumes" FILES ${${PROJECT_NAME}_FOLDER_HDR_FILES} ) source_group( "Source Files\\Render\\GlobalIllumination\\LightPropagationVolumes" FILES ${${PROJECT_NAME}_FOLDER_SRC_FILES} ) +set( ${PROJECT_NAME}_FOLDER_SRC_FILES + ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.cpp + ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.cpp + ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.cpp + ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.cpp + ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.cpp +) +set( ${PROJECT_NAME}_FOLDER_HDR_FILES + ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.hpp + ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.hpp + ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapsModule.hpp + ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.hpp + ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.hpp + ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.hpp +) +set( ${PROJECT_NAME}_SRC_FILES + ${${PROJECT_NAME}_SRC_FILES} + ${${PROJECT_NAME}_FOLDER_SRC_FILES} +) +set( ${PROJECT_NAME}_HDR_FILES + ${${PROJECT_NAME}_HDR_FILES} + ${${PROJECT_NAME}_FOLDER_HDR_FILES} +) +source_group( "Header Files\\Render\\GlobalIllumination\\ReflectiveShadowMaps" FILES ${${PROJECT_NAME}_FOLDER_HDR_FILES} ) +source_group( "Source Files\\Render\\GlobalIllumination\\ReflectiveShadowMaps" FILES ${${PROJECT_NAME}_FOLDER_SRC_FILES} ) + set( ${PROJECT_NAME}_FOLDER_SRC_FILES ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/GlobalIllumination/VoxelConeTracing/VctConfig.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Render/GlobalIllumination/VoxelConeTracing/VoxelBufferToTexture.cpp @@ -2084,6 +2110,7 @@ set( ${PROJECT_NAME}_FOLDER_SRC_FILES ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Shader/Ubos/MorphingUbo.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Shader/Ubos/ObjectIdsUbo.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Shader/Ubos/OverlayUbo.cpp + ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Shader/Ubos/RsmConfigUbo.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Shader/Ubos/SceneUbo.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Shader/Ubos/ShadowMapUbo.cpp ${CASTOR_SOURCE_DIR}/source/Core/${PROJECT_NAME}/Shader/Ubos/SkinningUbo.cpp @@ -2103,6 +2130,7 @@ set( ${PROJECT_NAME}_FOLDER_HDR_FILES ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Shader/Ubos/MorphingUbo.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Shader/Ubos/ObjectIdsUbo.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Shader/Ubos/OverlayUbo.hpp + ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Shader/Ubos/RsmConfigUbo.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Shader/Ubos/SceneUbo.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Shader/Ubos/ShadowMapUbo.hpp ${CASTOR_SOURCE_DIR}/include/Core/${PROJECT_NAME}/Shader/Ubos/SkinningUbo.hpp diff --git a/source/Core/Castor3D/Render/GlobalIllumination/GlobalIlluminationModule.cpp b/source/Core/Castor3D/Render/GlobalIllumination/GlobalIlluminationModule.cpp index 85ad647236..0c07941046 100644 --- a/source/Core/Castor3D/Render/GlobalIllumination/GlobalIlluminationModule.cpp +++ b/source/Core/Castor3D/Render/GlobalIllumination/GlobalIlluminationModule.cpp @@ -8,8 +8,8 @@ namespace castor3d { { cuT( "none" ), - cuT( "rsm" ), cuT( "vct" ), + cuT( "rsm" ), cuT( "lpv" ), cuT( "lpv_geometry" ), cuT( "layered_lpv" ), diff --git a/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.cpp b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.cpp new file mode 100644 index 0000000000..abdb37ba06 --- /dev/null +++ b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.cpp @@ -0,0 +1,251 @@ +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.hpp" + +#include "Castor3D/DebugDefines.hpp" +#include "Castor3D/Render/ShadowMap/ShadowMapResult.hpp" +#include "Castor3D/Shader/Shaders/GlslLight.hpp" +#include "Castor3D/Shader/Shaders/GlslShadow.hpp" +#include "Castor3D/Shader/Ubos/RsmConfigUbo.hpp" + +#include + +#define C3D_RSMGIUseCascasdes 1 + +namespace castor3d +{ + namespace rsmvpl + { + template< typename ImageT, typename CoordT > + static sdw::Vec3 evaluateVPL( sdw::ShaderWriter & writer + , ImageT const & rsmNormalMap + , ImageT const & rsmPositionMap + , ImageT const & rsmFluxMap + , CoordT const & coords + , sdw::Vec3 const & worldPosition + , sdw::Vec3 const & worldNormal + , sdw::Float const & xi1 ) + { + auto vplWorldPosition = writer.declLocale( "vplWorldPosition" + , rsmPositionMap.lod( coords, 0.0_f ).xyz() ); + auto vplWorldNormal = writer.declLocale( "vplWorldNormal" + , rsmNormalMap.lod( coords, 0.0_f ).xyz() ); + auto vplFlux = writer.declLocale( "vplFlux" + , rsmFluxMap.lod( coords, 0.0_f ).xyz() ); + + auto diff = writer.declLocale( "diff" + , worldPosition - vplWorldPosition ); + auto dot1 = writer.declLocale( "dot1" + , max( 0.0_f, dot( vplWorldNormal, diff ) ) ); + auto dot2 = writer.declLocale( "dot2" + , max( 0.0_f, dot( worldNormal, -diff ) ) ); + auto sqlength = writer.declLocale( "sqlength" + , dot( diff, diff ) ); + + auto result = writer.declLocale( "result" + , vplFlux * ( dot1 * dot2 ) ); + result *= xi1 * xi1 / ( sqlength * sqlength ); + + return result; + } + } + + ReflectiveShadowMapping::ReflectiveShadowMapping( sdw::ShaderWriter & writer + , sdw::ArrayStorageBufferT< sdw::Vec4 > & rsmSamples ) + : m_writer{ writer } + , m_rsmSamples{ rsmSamples } + { + } + + sdw::Vec3 ReflectiveShadowMapping::directional( shader::DirectionalShadowData const & pshadowData + , sdw::Vec3 const & pviewPosition + , sdw::Vec3 const & pworldPosition + , sdw::Vec3 const & pworldNormal + , shader::RsmConfigData const & prsmData ) + { + if ( !m_directional ) + { + m_directional = m_writer.implementFunction< sdw::Vec3 >( "reflectiveShadowMapping" + , [&]( shader::DirectionalShadowData const & shadowData + , sdw::Vec3 const & viewPosition + , sdw::Vec3 const & worldPosition + , sdw::Vec3 const & worldNormal + , shader::RsmConfigData const & rsmData ) + { + auto c3d_rsmNormalMap = m_writer.getVariable< sdw::CombinedImage2DArrayRgba32 >( getTextureName( LightType::eDirectional, SmTexture::eNormal ) ); + auto c3d_rsmPositionMap = m_writer.getVariable< sdw::CombinedImage2DArrayRgba32 >( getTextureName( LightType::eDirectional, SmTexture::ePosition ) ); + auto c3d_rsmFluxMap = m_writer.getVariable< sdw::CombinedImage2DArrayRgba32 >( getTextureName( LightType::eDirectional, SmTexture::eFlux ) ); + auto maxCount = m_writer.declLocale( "maxCount" + , m_writer.cast< sdw::Int >( max( shadowData.cascadeCount(), 1_u ) - 1_u ) ); + auto cascadeFactors = m_writer.declLocale( "cascadeFactors" + , vec3( m_writer.cast< sdw::Float >( maxCount ), 1.0_f, 0.0_f ) ); + auto cascadeIndex = m_writer.declLocale( "cascadeIndex" + , m_writer.cast< sdw::UInt >( cascadeFactors.x() ) ); + auto rMax = m_writer.declLocale( "rMax" + , vec2( rsmData.maxRadius / shadowData.splitScales()[cascadeIndex / 4u][cascadeIndex % 4u] ) / vec2( c3d_rsmFluxMap.getSize( 0_i ).xy() ) ); + auto lightSpacePosition = m_writer.declLocale( "lightSpacePosition" + , shadowData.transforms()[cascadeIndex] * vec4( worldPosition, 1.0_f ) ); + lightSpacePosition.xyz() /= lightSpacePosition.w(); + lightSpacePosition.xy() = sdw::fma( lightSpacePosition.xy() + , vec2( 0.5_f ) + , vec2( 0.5_f ) ); + auto indirectIllumination = m_writer.declLocale( "indirectIllumination" + , vec3( 0.0_f ) ); + + FOR( m_writer, sdw::UInt, i, 0_u, i < rsmData.sampleCount, ++i ) + { + auto rnd = m_writer.declLocale( "rnd" + , m_rsmSamples[i] ); + auto coords = m_writer.declLocale( "coords" + , vec3( sdw::fma( rnd.xy(), rMax, lightSpacePosition.xy() ) + , m_writer.cast < sdw::Float > ( cascadeIndex ) ) ); + indirectIllumination += rsmvpl::evaluateVPL( m_writer + , c3d_rsmNormalMap + , c3d_rsmPositionMap + , c3d_rsmFluxMap + , coords + , worldPosition + , worldNormal + , rnd.z() ); + } + ROF + + m_writer.returnStmt( clamp( indirectIllumination * rsmData.intensity + , vec3( 0.0_f ) + , vec3( 1.0_f ) ) ); + } + , shader::InDirectionalShadowData{ m_writer, "shadowData" } + , sdw::InVec3{ m_writer, "viewPosition" } + , sdw::InVec3{ m_writer, "worldPosition" } + , sdw::InVec3{ m_writer, "worldNormal" } + , shader::InRsmConfigData{ m_writer, "rsmData" } ); + } + + return m_directional( pshadowData + , pviewPosition + , pworldPosition + , pworldNormal + , prsmData ); + } + + sdw::Vec3 ReflectiveShadowMapping::point( shader::PointShadowData const & pshadowData + , sdw::Vec3 const & plightPosition + , sdw::Vec3 const & pworldPosition + , sdw::Vec3 const & pworldNormal + , shader::RsmConfigData const & prsmData ) + { + if ( !m_point ) + { + m_point = m_writer.implementFunction< sdw::Vec3 >( "reflectiveShadowMapping" + , [&]( shader::PointShadowData const & shadowData + , sdw::Vec3 const & lightPosition + , sdw::Vec3 const & worldPosition + , sdw::Vec3 const & worldNormal + , shader::RsmConfigData const & rsmData ) + { + auto c3d_rsmNormalMap = m_writer.getVariable< sdw::CombinedImageCubeArrayRgba32 >( getTextureName( LightType::ePoint, SmTexture::eNormal ) ); + auto c3d_rsmPositionMap = m_writer.getVariable< sdw::CombinedImageCubeArrayRgba32 >( getTextureName( LightType::ePoint, SmTexture::ePosition ) ); + auto c3d_rsmFluxMap = m_writer.getVariable< sdw::CombinedImageCubeArrayRgba32 >( getTextureName( LightType::ePoint, SmTexture::eFlux ) ); + auto indirectIllumination = m_writer.declLocale( "indirectIllumination" + , vec3( 0.0_f ) ); + auto rMax = m_writer.declLocale( "rMax" + , vec2( rsmData.maxRadius ) / vec2( c3d_rsmFluxMap.getSize( 0_i ).xy() ) ); + auto lightSpacePosition = m_writer.declLocale( "lightSpacePosition" + , worldPosition - lightPosition ); + + FOR( m_writer, sdw::UInt, i, 0_u, i < rsmData.sampleCount, ++i ) + { + auto rnd = m_writer.declLocale( "rnd" + , m_rsmSamples[i] ); + auto coords = m_writer.declLocale( "coords" + , vec4( sdw::fma( rnd.xy(), rMax, lightSpacePosition.xy() ) + , lightSpacePosition.z() + , m_writer.cast< sdw::Float >( rsmData.index ) ) ); + indirectIllumination += rsmvpl::evaluateVPL( m_writer + , c3d_rsmNormalMap + , c3d_rsmPositionMap + , c3d_rsmFluxMap + , coords + , worldPosition + , worldNormal + , rnd.z() ); + } + ROF + + m_writer.returnStmt( clamp( indirectIllumination * rsmData.intensity + , vec3( 0.0_f ) + , vec3( 1.0_f ) ) ); + } + , shader::InPointShadowData{ m_writer, "shadowData" } + , sdw::InVec3{ m_writer, "lightPosition" } + , sdw::InVec3{ m_writer, "worldPosition" } + , sdw::InVec3{ m_writer, "worldNormal" } + , shader::InRsmConfigData{ m_writer, "rsmData" } ); + } + + return m_point( pshadowData + , plightPosition + , pworldPosition + , pworldNormal + , prsmData ); + } + + sdw::Vec3 ReflectiveShadowMapping::spot( shader::SpotShadowData const & pshadowData + , sdw::Vec3 const & pworldPosition + , sdw::Vec3 const & pworldNormal + , shader::RsmConfigData const & prsmData ) + { + if ( !m_spot ) + { + m_spot = m_writer.implementFunction< sdw::Vec3 >( "reflectiveShadowMapping" + , [&]( shader::SpotShadowData const & shadowData + , sdw::Vec3 const & worldPosition + , sdw::Vec3 const & worldNormal + , shader::RsmConfigData const & rsmData ) + { + auto c3d_rsmNormalMap = m_writer.getVariable< sdw::CombinedImage2DArrayRgba32 >( getTextureName( LightType::eSpot, SmTexture::eNormal ) ); + auto c3d_rsmPositionMap = m_writer.getVariable< sdw::CombinedImage2DArrayRgba32 >( getTextureName( LightType::eSpot, SmTexture::ePosition ) ); + auto c3d_rsmFluxMap = m_writer.getVariable< sdw::CombinedImage2DArrayRgba32 >( getTextureName( LightType::eSpot, SmTexture::eFlux ) ); + auto lightSpacePosition = m_writer.declLocale( "lightSpacePosition" + , shadowData.transform() * vec4( worldPosition, 1.0_f ) ); + lightSpacePosition.xyz() /= lightSpacePosition.w(); + lightSpacePosition.xy() = sdw::fma( lightSpacePosition.xy() + , vec2( 0.5_f ) + , vec2( 0.5_f ) ); + auto indirectIllumination = m_writer.declLocale( "indirectIllumination" + , vec3( 0.0_f ) ); + auto rMax = m_writer.declLocale( "rMax" + , vec2( rsmData.maxRadius ) / vec2( c3d_rsmFluxMap.getSize( 0_i ).xy() ) ); + + FOR( m_writer, sdw::UInt, i, 0_u, i < rsmData.sampleCount, ++i ) + { + auto rnd = m_writer.declLocale( "rnd" + , m_rsmSamples[i] ); + auto coords = m_writer.declLocale( "coords" + , vec3( sdw::fma( rnd.xy(), rMax, lightSpacePosition.xy() ) + , m_writer.cast< sdw::Float >( rsmData.index ) ) ); + indirectIllumination += rsmvpl::evaluateVPL( m_writer + , c3d_rsmNormalMap + , c3d_rsmPositionMap + , c3d_rsmFluxMap + , coords + , worldPosition + , worldNormal + , rnd.z() ); + } + ROF + + m_writer.returnStmt( clamp( indirectIllumination * rsmData.intensity + , vec3( 0.0_f ) + , vec3( 1.0_f ) ) ); + } + , shader::InSpotShadowData{ m_writer, "shadowData" } + , sdw::InVec3{ m_writer, "worldPosition" } + , sdw::InVec3{ m_writer, "worldNormal" } + , shader::InRsmConfigData{ m_writer, "rsmData" } ); + } + + return m_spot( pshadowData + , pworldPosition + , pworldNormal + , prsmData ); + } +} diff --git a/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.cpp b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.cpp new file mode 100644 index 0000000000..6719f6ea3a --- /dev/null +++ b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.cpp @@ -0,0 +1,344 @@ +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.hpp" + +#include "Castor3D/Engine.hpp" +#include "Castor3D/Cache/LightCache.hpp" +#include "Castor3D/Event/Frame/GpuFunctorEvent.hpp" +#include "Castor3D/Material/Texture/TextureLayout.hpp" +#include "Castor3D/Miscellaneous/ConfigurationVisitor.hpp" +#include "Castor3D/Render/RenderSystem.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.hpp" +#include "Castor3D/Render/ShadowMap/ShadowMapResult.hpp" +#include "Castor3D/Scene/Camera.hpp" +#include "Castor3D/Scene/Scene.hpp" +#include "Castor3D/Scene/SceneNode.hpp" +#include "Castor3D/Scene/Light/DirectionalLight.hpp" +#include "Castor3D/Scene/Light/Light.hpp" +#include "Castor3D/Scene/Light/PointLight.hpp" +#include "Castor3D/Scene/Light/SpotLight.hpp" + +#include + +#include +#include + +#include +#include +#include + +CU_ImplementSmartPtr( castor3d, ReflectiveShadowMaps ) + +namespace castor3d +{ + //********************************************************************************************* + + namespace rsm + { + class RsmClear + : public crg::RunnablePass + { + public: + RsmClear( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & graph ) + : crg::RunnablePass{ pass + , context + , graph + , Callbacks{ []( uint32_t ){} + , GetPipelineStateCallback( [](){ return crg::getPipelineState( VK_PIPELINE_STAGE_TRANSFER_BIT ); } ) + , [this]( crg::RecordContext & ctx, VkCommandBuffer cb, uint32_t i ){ doRecordInto( ctx, cb, i ); } } } + { + } + + protected: + void doRecordInto( crg::RecordContext & context + , VkCommandBuffer commandBuffer + , uint32_t index ) + { + auto clearValue = transparentBlackClearColor.color; + + for ( auto & attach : m_pass.images ) + { + auto view = attach.view(); + auto image = m_graph.createImage( view.data->image ); + assert( attach.isTransferOutputView() ); + m_context.vkCmdClearColorImage( commandBuffer + , image + , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL + , &clearValue + , 1u + , &view.data->info.subresourceRange ); + } + } + }; + + static Texture createImage( RenderDevice const & device + , crg::ResourcesCache & resources + , castor::String const & name + , VkFormat format + , VkExtent3D const & size ) + { + return Texture{ device + , resources + , name + , 0u + , VkExtent3D{ size.width / 4u, size.height / 4u, 1u } + , 1u + , 1u + , format + , ( VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT ) }; + } + + static TextureArray createImages( RenderDevice const & device + , crg::ResourcesCache & resources + , castor::String const & name + , VkExtent3D const & size ) + { + TextureArray result; + result.emplace_back( createImage( device, resources, name + "GI", VK_FORMAT_R16G16B16A16_SFLOAT, size ) ); + result.emplace_back( createImage( device, resources, name + "Normals", VK_FORMAT_R16G16B16A16_SFLOAT, size ) ); + return result; + } + } + + //********************************************************************************************* + + ReflectiveShadowMaps::LightRsm::LightRsm( crg::FrameGraph & graph + , crg::FramePassArray previousPasses + , RenderDevice const & device + , LightCache const & plightCache + , LightType lightType + , ShadowBuffer const & shadowBuffer + , CameraUbo const & cameraUbo + , crg::ImageViewId const & depthObj + , crg::ImageViewId const & nmlOcc + , ShadowMapResult const & smResult + , TextureArray const & intermediate + , Texture const & result ) + : lightCache{ plightCache } + , giPass{ castor::makeUnique< RsmGIPass >( graph + , std::move( previousPasses ) + , device + , lightType + , shadowBuffer + , intermediate[0].getExtent() + , cameraUbo + , depthObj + , nmlOcc + , smResult + , intermediate ) } + , interpolatePass{ castor::makeUnique< RsmInterpolatePass >( graph + , giPass->getPass() + , device + , lightType + , shadowBuffer + , result.getExtent() + , cameraUbo + , depthObj + , nmlOcc + , smResult + , giPass->getConfigUbo() + , giPass->getSamplesSsbo() + , intermediate[0] + , intermediate[1] + , result ) } + , lastPass{ &interpolatePass->getPass() } + { + } + + void ReflectiveShadowMaps::LightRsm::update( CpuUpdater & updater ) + { + auto & sceneObjs = updater.dirtyScenes[lightCache.getScene()]; + auto & light = *updater.light; + auto changed = sceneObjs.dirtyLights.end() != std::find( sceneObjs.dirtyLights.begin(), sceneObjs.dirtyLights.end(), &light ) + || light.getRsmConfig().intensity.isDirty() + || light.getRsmConfig().maxRadius.isDirty() + || light.getRsmConfig().sampleCount.isDirty(); + + if ( changed ) + { + giPass->update( light ); + } + } + + //********************************************************************************************* + + ReflectiveShadowMaps::ReflectiveShadowMaps( crg::ResourceHandler & handler + , Scene const & scene + , RenderDevice const & device + , CameraUbo const & cameraUbo + , ShadowBuffer const & shadowBuffer + , crg::ImageViewId const & depthObj + , crg::ImageViewId const & nmlOcc + , ShadowMapResult const & directionalSmResult + , ShadowMapResult const & pointSmResult + , ShadowMapResult const & spotSmResult + , Texture const & result ) + : castor::Named{ "RSM" } + , m_scene{ scene } + , m_device{ device } + , m_cameraUbo{ cameraUbo } + , m_shadowBuffer{ shadowBuffer } + , m_depthObj{ depthObj } + , m_nmlOcc{ nmlOcc } + , m_directionalSmResult{ directionalSmResult } + , m_pointSmResult{ pointSmResult } + , m_spotSmResult{ spotSmResult } + , m_graph{ handler, getName() } + , m_intermediate{ rsm::createImages( device + , *result.resources + , "RSMIntermediate" + , result.getExtent() ) } + , m_result{ result } + , m_clearPass{ doCreateClearPass() } + , m_lastPass{ &m_clearPass } + { + for ( auto & value : m_intermediate ) + { + value.create(); + } + } + + ReflectiveShadowMaps::~ReflectiveShadowMaps()noexcept + { + for ( auto & intermediate : m_intermediate ) + { + intermediate.destroy(); + } + } + + void ReflectiveShadowMaps::initialise() + { + if ( !m_initialised + && m_scene.needsGlobalIllumination( GlobalIlluminationType::eRsm ) ) + { + m_runnable = m_graph.compile( m_device.makeContext() ); + m_device.renderSystem.getEngine()->postEvent( makeGpuFunctorEvent( GpuEventType::ePreRender + , [this]( RenderDevice const & + , QueueData const & ) + { + m_runnable->record(); + } ) ); + m_initialised = true; + } + } + + void ReflectiveShadowMaps::cleanup() + { + m_initialised = false; + m_lightRsms.clear(); + } + + void ReflectiveShadowMaps::registerLight( Light * light ) + { + if ( auto lit = m_lightRsms.find( light ); + lit == m_lightRsms.end() ) + { + auto [it, res] = m_lightRsms.emplace( light + , std::make_unique< LightRsm >( m_graph + , crg::FramePassArray{ m_lastPass } + , m_device + , light->getScene()->getLightCache() + , light->getLightType() + , m_shadowBuffer + , m_cameraUbo + , m_depthObj + , m_nmlOcc + , ( light->getLightType() == LightType::eDirectional + ? m_directionalSmResult + : (light->getLightType() == LightType::ePoint + ? m_pointSmResult + : m_spotSmResult ) ) + , m_intermediate + , m_result ) ); + m_lastPass = it->second->lastPass; + m_graph.addOutput( m_result.wholeViewId + , crg::makeLayoutState( VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) ); + + if ( m_runnable ) + { + m_runnable.reset(); + m_runnable = m_graph.compile( m_device.makeContext() ); + auto runnable = m_runnable.get(); + m_device.renderSystem.getEngine()->postEvent( makeGpuFunctorEvent( GpuEventType::ePreRender + , [runnable]( RenderDevice const & device + , QueueData const & queueData ) + { + runnable->record(); + } ) ); + } + } + } + + void ReflectiveShadowMaps::update( CpuUpdater & updater ) + { + if ( !m_initialised + || !m_scene.needsGlobalIllumination( GlobalIlluminationType::eRsm ) ) + { + return; + } + + for ( auto & lightRsm : m_lightRsms ) + { + updater.light = lightRsm.first; + lightRsm.second->update( updater ); + } + } + + crg::SemaphoreWaitArray ReflectiveShadowMaps::render( crg::SemaphoreWaitArray const & toWait + , ashes::Queue const & queue ) + { + if ( !m_initialised + || !m_scene.needsGlobalIllumination( GlobalIlluminationType::eRsm ) + || m_lightRsms.empty() ) + { + return toWait; + } + + return m_runnable->run( toWait, queue ); + } + + void ReflectiveShadowMaps::accept( ConfigurationVisitorBase & visitor ) + { + if ( m_initialised ) + { + for ( auto & lightRsm : m_lightRsms ) + { + lightRsm.second->giPass->accept( visitor ); + lightRsm.second->interpolatePass->accept( visitor ); + } + + visitor.visit( getName() + " GI" + , m_intermediate[0] + , m_graph.getFinalLayoutState( m_intermediate[0].wholeViewId ).layout + , TextureFactors{}.invert( true ) ); + visitor.visit( getName() + " Normal" + , m_intermediate[1] + , m_graph.getFinalLayoutState( m_intermediate[1].wholeViewId ).layout + , TextureFactors{}.invert( true ) ); + visitor.visit( getName() + " Result" + , m_result + , VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL + , TextureFactors{}.invert( true ) ); + } + } + + crg::FramePass & ReflectiveShadowMaps::doCreateClearPass() + { + auto & result = m_graph.createPass( "RsmClear" + , []( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & graph ) + { + return std::make_unique< rsm::RsmClear >( pass + , context + , graph ); + } ); + result.addTransferOutputView( m_result.wholeViewId ); + return result; + } + + //********************************************************************************************* +} diff --git a/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.cpp b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.cpp new file mode 100644 index 0000000000..32b97b49da --- /dev/null +++ b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.cpp @@ -0,0 +1,82 @@ +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.hpp" + +#include "Castor3D/Miscellaneous/ConfigurationVisitor.hpp" +#include "Castor3D/Scene/SceneFileParserData.hpp" +#include "Castor3D/Scene/Light/Light.hpp" + +#include + +namespace castor3d +{ + namespace rsmcfg + { + static CU_ImplementAttributeParserBlock( parserConfig, LightContext ) + { + if ( !blockContext->shadowConfig ) + { + CU_ParsingError( cuT( "No shadow configuration initialised." ) ); + } + } + CU_EndAttributePushBlock( CSCNSection::eRsm, blockContext ) + + static CU_ImplementAttributeParserBlock( parserIntensity, LightContext ) + { + if ( !blockContext->shadowConfig ) + { + CU_ParsingError( cuT( "No shadow configuration initialised." ) ); + } + else + { + params[0]->get( *blockContext->shadowConfig->rsmConfig.intensity ); + } + } + CU_EndAttribute() + + static CU_ImplementAttributeParserBlock( parserMaxRadius, LightContext ) + { + if ( !blockContext->shadowConfig ) + { + CU_ParsingError( cuT( "No shadow configuration initialised." ) ); + } + else + { + params[0]->get( *blockContext->shadowConfig->rsmConfig.maxRadius ); + } + } + CU_EndAttribute() + + static CU_ImplementAttributeParserBlock( parserSampleCount, LightContext ) + { + if ( !blockContext->shadowConfig ) + { + CU_ParsingError( cuT( "No shadow configuration initialised." ) ); + } + else + { + *blockContext->shadowConfig->rsmConfig.sampleCount = params[0]->get< uint32_t >(); + } + } + CU_EndAttribute() + } + + void RsmConfig::accept( ConfigurationVisitorBase & visitor ) + { + auto block = visitor.visit( cuT( "Reflective Shadow Maps" ) ); + block.visit( cuT( "RSM Intensity" ), intensity ); + block.visit( cuT( "RSM Max Radius" ), maxRadius ); + block.visit( cuT( "RSM Sample Count" ), sampleCount ); + } + + void RsmConfig::addParsers( castor::AttributeParsers & result ) + { + using namespace castor; + BlockParserContextT< LightContext > shadowContext{ result, CSCNSection::eShadows, CSCNSection::eLight }; + BlockParserContextT< LightContext > rsmContext{ result, CSCNSection::eRsm, CSCNSection::eShadows }; + + shadowContext.addPushParser( cuT( "rsm_config" ), CSCNSection::eRsm, rsmcfg::parserConfig ); + rsmContext.addParser( cuT( "intensity" ), rsmcfg::parserIntensity, { makeParameter< ParameterType::eFloat >() } ); + rsmContext.addParser( cuT( "max_radius" ), rsmcfg::parserMaxRadius, { makeParameter< ParameterType::eFloat >() } ); + rsmContext.addParser( cuT( "sample_count" ), rsmcfg::parserSampleCount, { makeParameter< ParameterType::eUInt32 >( castor::makeRange( 20u, MaxRsmRange ) ) } ); + rsmContext.addDefaultPopParser(); + } +} diff --git a/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.cpp b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.cpp new file mode 100644 index 0000000000..52023eb76c --- /dev/null +++ b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.cpp @@ -0,0 +1,450 @@ +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmGIPass.hpp" + +#include "Castor3D/Engine.hpp" +#include "Castor3D/Buffer/GpuBufferPool.hpp" +#include "Castor3D/Buffer/UniformBufferPool.hpp" +#include "Castor3D/Cache/LightCache.hpp" +#include "Castor3D/Material/Pass/PassFactory.hpp" +#include "Castor3D/Material/Texture/Sampler.hpp" +#include "Castor3D/Material/Texture/TextureLayout.hpp" +#include "Castor3D/Material/Texture/TextureUnit.hpp" +#include "Castor3D/Miscellaneous/Parameter.hpp" +#include "Castor3D/Miscellaneous/ConfigurationVisitor.hpp" +#include "Castor3D/Model/Vertex.hpp" +#include "Castor3D/Render/RenderSystem.hpp" +#include "Castor3D/Render/RenderTarget.hpp" +#include "Castor3D/Render/Passes/LineariseDepthPass.hpp" +#include "Castor3D/Render/ShadowMap/ShadowMapResult.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmConfig.hpp" +#include "Castor3D/Scene/Light/Light.hpp" +#include "Castor3D/Scene/Light/DirectionalLight.hpp" +#include "Castor3D/Scene/Light/PointLight.hpp" +#include "Castor3D/Scene/Light/SpotLight.hpp" +#include "Castor3D/Shader/Program.hpp" +#include "Castor3D/Shader/ShaderBuffers/ShadowBuffer.hpp" +#include "Castor3D/Shader/Shaders/GlslFog.hpp" +#include "Castor3D/Shader/Shaders/GlslLight.hpp" +#include "Castor3D/Shader/Shaders/GlslLighting.hpp" +#include "Castor3D/Shader/Shaders/GlslMaterial.hpp" +#include "Castor3D/Shader/Shaders/GlslOutputComponents.hpp" +#include "Castor3D/Shader/Shaders/GlslShadow.hpp" +#include "Castor3D/Shader/Shaders/GlslUtils.hpp" +#include "Castor3D/Shader/Ubos/CameraUbo.hpp" +#include "Castor3D/Shader/Ubos/ModelDataUbo.hpp" +#include "Castor3D/Shader/Ubos/SceneUbo.hpp" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +CU_ImplementSmartPtr( castor3d, RsmGIPass ) + +namespace castor3d +{ + namespace rsmgi + { + enum Idx : uint32_t + { + RsmCfgUboIdx, + RsmSamplesIdx, + CameraUboIdx, + ShadowsIdx, + DepthObjMapIdx, + NmlOccMapIdx, + RsmNormalsIdx, + RsmPositionIdx, + RsmFluxIdx, + }; + + static std::unique_ptr< ast::Shader > getVertexProgram() + { + sdw::VertexWriter writer; + + // Shader inputs + auto position = writer.declInput< sdw::Vec2 >( "position", 0u ); + auto uv = writer.declInput< sdw::Vec2 >( "uv", 1u ); + + // Shader outputs + auto vtx_texture = writer.declOutput< sdw::Vec2 >( "vtx_texture", 0u ); + + writer.implementMain( [&]( sdw::VertexIn in + , sdw::VertexOut out ) + { + vtx_texture = uv; + out.vtx.position = vec4( position, 0.0_f, 1.0_f ); + } ); + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) ); + } + + static ShaderPtr getDirectionalPixelShaderSource( uint32_t width + , uint32_t height + , RenderSystem const & renderSystem ) + { + sdw::FragmentWriter writer; + + // Shader inputs + C3D_RsmConfig( writer, RsmCfgUboIdx, 0u ); + sdw::ArrayStorageBufferT< sdw::Vec4 > c3d_rsmSamples{ writer + , "c3d_rsmSamples" + , writer.getTypesCache().getVec4F() + , sdw::type::MemoryLayout::eStd430 + , RsmSamplesIdx + , 0u + , true }; + C3D_Camera( writer, CameraUboIdx, 0u ); + auto c3d_mapDepthObj = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapDepthObj", DepthObjMapIdx, 0u ); + auto c3d_mapNmlOcc = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapNmlOcc", NmlOccMapIdx, 0u ); + auto c3d_rsmNormalMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( LightType::eDirectional, SmTexture::eNormal ), RsmNormalsIdx, 0u ); + auto c3d_rsmPositionMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( LightType::eDirectional, SmTexture::ePosition ), RsmPositionIdx, 0u ); + auto c3d_rsmFluxMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( LightType::eDirectional, SmTexture::eFlux ), RsmFluxIdx, 0u ); + + auto vtx_texture = writer.declInput< sdw::Vec2 >( "vtx_texture", 0u ); + + // Shader outputs + auto pxl_rsmGI = writer.declOutput< sdw::Vec3 >( "pxl_rsmGI", 0 ); + auto pxl_rsmNormal = writer.declOutput< sdw::Vec3 >( "pxl_rsmNormal", 1 ); + + // Utility functions + shader::Utils utils{ writer }; + + shader::ShadowsBuffer shadows{ writer + , Idx::ShadowsIdx + , 0u }; + ReflectiveShadowMapping rsm{ writer + , c3d_rsmSamples }; + + writer.implementMain( [&]( sdw::FragmentIn in + , sdw::FragmentOut out ) + { + auto texCoord = writer.declLocale( "texCoord" + , vtx_texture ); + auto depthObj = writer.declLocale( "depthObj" + , c3d_mapDepthObj.lod( texCoord, 0.0_f ) ); + auto nodeId = writer.declLocale( "nodeId" + , writer.cast< sdw::UInt >( depthObj.z() ) ); + + IF( writer, nodeId == 0u ) + { + writer.demote(); + } + FI + + auto depth = writer.declLocale( "depth" + , depthObj.x() ); + auto nmlOcc = writer.declLocale( "nmlOcc" + , c3d_mapNmlOcc.lod( texCoord, 0.0_f ) ); + auto vsPosition = writer.declLocale( "vsPosition" + , c3d_cameraData.projToView( utils, texCoord, depth ) ); + auto wsPosition = writer.declLocale( "wsPosition" + , c3d_cameraData.curProjToWorld( utils, texCoord, depth ) ); + auto wsNormal = writer.declLocale( "wsNormal" + , nmlOcc.xyz() ); + auto shadowData = writer.declLocale( "shadowData" + , shadows.getDirectionalShadows() ); + pxl_rsmGI = rsm.directional( shadowData + , vsPosition + , wsPosition + , wsNormal + , c3d_rsmConfigData ); + pxl_rsmNormal = wsNormal; + } ); + + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) ); + } + + static ShaderPtr getSpotPixelShaderSource( uint32_t width + , uint32_t height + , RenderSystem const & renderSystem ) + { + sdw::FragmentWriter writer; + + // Shader inputs + C3D_RsmConfig( writer, RsmCfgUboIdx, 0u ); + sdw::ArrayStorageBufferT< sdw::Vec4 > c3d_rsmSamples{ writer + , "c3d_rsmSamples" + , writer.getTypesCache().getVec4F() + , sdw::type::MemoryLayout::eStd430 + , RsmSamplesIdx + , 0u + , true }; + C3D_Camera( writer, CameraUboIdx, 0u ); + auto c3d_mapDepthObj = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapDepthObj", DepthObjMapIdx, 0u ); + auto c3d_mapNmlOcc = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapNmlOcc", NmlOccMapIdx, 0u ); + auto c3d_rsmNormalMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( LightType::eSpot, SmTexture::eNormal ), RsmNormalsIdx, 0u ); + auto c3d_rsmPositionMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( LightType::eSpot, SmTexture::ePosition ), RsmPositionIdx, 0u ); + auto c3d_rsmFluxMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( LightType::eSpot, SmTexture::eFlux ), RsmFluxIdx, 0u ); + + auto vtx_texture = writer.declInput< sdw::Vec2 >( "vtx_texture", 0u ); + + // Shader outputs + auto pxl_rsmGI = writer.declOutput< sdw::Vec3 >( "pxl_rsmGI", 0 ); + auto pxl_rsmNormal = writer.declOutput< sdw::Vec3 >( "pxl_rsmNormal", 1 ); + + // Utility functions + shader::Utils utils{ writer }; + + shader::ShadowsBuffer shadows{ writer + , Idx::ShadowsIdx + , 0u }; + ReflectiveShadowMapping rsm{ writer + , c3d_rsmSamples }; + + writer.implementMain( [&]( sdw::FragmentIn in + , sdw::FragmentOut out ) + { + auto texCoord = writer.declLocale( "texCoord" + , vtx_texture ); + auto depthObj = writer.declLocale( "depthObj" + , c3d_mapDepthObj.lod( texCoord, 0.0_f ) ); + auto nodeId = writer.declLocale( "nodeId" + , writer.cast< sdw::UInt >( depthObj.z() ) ); + + IF( writer, nodeId == 0u ) + { + writer.demote(); + } + FI + + auto depth = writer.declLocale( "depth" + , depthObj.x() ); + auto nmlOcc = writer.declLocale( "nmlOcc" + , c3d_mapNmlOcc.lod( texCoord, 0.0_f ) ); + auto wsPosition = writer.declLocale( "wsPosition" + , c3d_cameraData.curProjToWorld( utils, texCoord, depth ) ); + auto wsNormal = writer.declLocale( "wsNormal" + , nmlOcc.xyz() ); + + IF( writer, dot( wsNormal, wsNormal ) == 0.0f ) + { + writer.demote(); + } + FI; + + auto shadowData = writer.declLocale( "shadowData" + , shadows.getSpotShadows( c3d_rsmConfigData.index ) ); + pxl_rsmGI = rsm.spot( shadowData + , wsPosition + , wsNormal + , c3d_rsmConfigData ); + pxl_rsmNormal = wsNormal; + } ); + + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) ); + } + + static ShaderPtr getPointPixelShaderSource( uint32_t width + , uint32_t height + , RenderSystem const & renderSystem ) + { + sdw::FragmentWriter writer; + + // Shader inputs + C3D_RsmConfig( writer, RsmCfgUboIdx, 0u ); + sdw::ArrayStorageBufferT< sdw::Vec4 > c3d_rsmSamples{ writer + , "c3d_rsmSamples" + , writer.getTypesCache().getVec4F() + , sdw::type::MemoryLayout::eStd430 + , RsmSamplesIdx + , 0u + , true }; + C3D_Camera( writer, CameraUboIdx, 0u ); + auto c3d_mapDepthObj = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapDepthObj", DepthObjMapIdx, 0u ); + auto c3d_mapNmlOcc = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapNmlOcc", NmlOccMapIdx, 0u ); + auto c3d_rsmNormalMap = writer.declCombinedImg< FImgCubeArrayRgba32 >( getTextureName( LightType::ePoint, SmTexture::eNormal ), RsmNormalsIdx, 0u ); + auto c3d_rsmPositionMap = writer.declCombinedImg< FImgCubeArrayRgba32 >( getTextureName( LightType::ePoint, SmTexture::ePosition ), RsmPositionIdx, 0u ); + auto c3d_rsmFluxMap = writer.declCombinedImg< FImgCubeArrayRgba32 >( getTextureName( LightType::ePoint, SmTexture::eFlux ), RsmFluxIdx, 0u ); + + auto vtx_texture = writer.declInput< sdw::Vec2 >( "vtx_texture", 0u ); + + // Shader outputs + auto pxl_rsmGI = writer.declOutput< sdw::Vec3 >( "pxl_rsmGI", 0 ); + auto pxl_rsmNormal = writer.declOutput< sdw::Vec3 >( "pxl_rsmNormal", 1 ); + + // Utility functions + shader::Utils utils{ writer }; + + shader::ShadowsBuffer shadows{ writer + , Idx::ShadowsIdx + , 0u }; + ReflectiveShadowMapping rsm{ writer + , c3d_rsmSamples }; + + writer.implementMain( [&]( sdw::FragmentIn in + , sdw::FragmentOut out ) + { + auto texCoord = writer.declLocale( "texCoord" + , vtx_texture ); + auto depthObj = writer.declLocale( "depthObj" + , c3d_mapDepthObj.lod( texCoord, 0.0_f ) ); + auto nodeId = writer.declLocale( "nodeId" + , writer.cast< sdw::UInt >( depthObj.z() ) ); + + IF( writer, nodeId == 0u ) + { + writer.demote(); + } + FI + + auto depth = writer.declLocale( "depth" + , depthObj.x() ); + auto nmlOcc = writer.declLocale( "nmlOcc" + , c3d_mapNmlOcc.lod( texCoord, 0.0_f ) ); + auto wsPosition = writer.declLocale( "wsPosition" + , c3d_cameraData.curProjToWorld( utils, texCoord, depth ) ); + auto wsNormal = writer.declLocale( "wsNormal" + , nmlOcc.xyz() ); + auto shadowData = writer.declLocale( "shadowData" + , shadows.getPointShadows( c3d_rsmConfigData.index ) ); + pxl_rsmGI = rsm.point( shadowData + , shadowData.position().xyz() + , wsPosition + , wsNormal + , c3d_rsmConfigData ); + pxl_rsmNormal = wsNormal; + } ); + + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) ); + } + + static std::unique_ptr< ast::Shader > getPixelProgram( LightType lightType + , uint32_t width + , uint32_t height + , RenderSystem const & renderSystem ) + { + switch ( lightType ) + { + case LightType::eDirectional: + return getDirectionalPixelShaderSource( width, height, renderSystem ); + case LightType::eSpot: + return getSpotPixelShaderSource( width, height, renderSystem ); + case LightType::ePoint: + return getPointPixelShaderSource( width, height, renderSystem ); + default: + CU_Failure( "Unexpected LightType" ); + return nullptr; + } + } + + static crg::rq::Config getConfig( VkExtent2D const & renderSize + , ashes::PipelineShaderStageCreateInfoArray const & stages ) + { + crg::rq::Config result; + result.texcoordConfig( {} ); + result.renderSize( renderSize ); + result.program( crg::makeVkArray< VkPipelineShaderStageCreateInfo >( stages ) ); + return result; + } + } + + //********************************************************************************************* + + RsmGIPass::RsmGIPass( crg::FrameGraph & graph + , crg::FramePassArray const & previousPasses + , RenderDevice const & device + , LightType lightType + , ShadowBuffer const & shadowBuffer + , VkExtent3D const & size + , CameraUbo const & cameraUbo + , crg::ImageViewId const & depthObj + , crg::ImageViewId const & nmlOcc + , ShadowMapResult const & smResult + , TextureArray const & result ) + : castor::Named{ castor3d::getName( lightType ) + "Rsm" } + , m_rsmConfigUbo{ device } + , m_rsmSamplesSsbo{ device.bufferPool->getBuffer< castor::Point4f >( VK_BUFFER_USAGE_STORAGE_BUFFER_BIT + , MaxRsmRange + , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ) } + , m_vertexShader{ VK_SHADER_STAGE_VERTEX_BIT, getName(), rsmgi::getVertexProgram() } + , m_pixelShader{ VK_SHADER_STAGE_FRAGMENT_BIT, getName(), rsmgi::getPixelProgram( lightType, size.width, size.height, device.renderSystem ) } + , m_stages{ makeShaderState( device, m_vertexShader ) + , makeShaderState( device, m_pixelShader ) } + { + std::random_device rd; + std::mt19937 rng( rd() ); + std::uniform_real_distribution< float > dist( 0.0f, 1.0f ); + + for ( auto & point : m_rsmSamplesSsbo.getData() ) + { + auto xi2 = dist( rng ); + auto twoPIy = castor::PiMult2< float > *xi2; + auto xi1 = dist( rng ); + point[0] = float( xi1 * sin( twoPIy ) ); + point[1] = float( xi1 * cos( twoPIy ) ); + point[2] = float( xi1 ); + point[3] = float( xi2 ); + } + + m_rsmSamplesSsbo.markDirty( VK_ACCESS_UNIFORM_READ_BIT + , VK_PIPELINE_STAGE_VERTEX_SHADER_BIT ); + + auto & pass = graph.createPass( getName() + , [this, &device, size]( crg::FramePass const & framePass + , crg::GraphContext & context + , crg::RunnableGraph & runnableGraph ) + { + auto result = std::make_unique< crg::RenderQuad >( framePass + , context + , runnableGraph + , crg::ru::Config{ 1u, false } + , rsmgi::getConfig( { size.width, size.height } + , m_stages ) ); + device.renderSystem.getEngine()->registerTimer( castor::makeString( framePass.getFullName() ) + , result->getTimer() ); + return result; + } ); + pass.addDependencies( previousPasses ); + pass.addUniformBuffer( { m_rsmConfigUbo.getUbo().getBuffer(), "RsmConfig" } + , rsmgi::RsmCfgUboIdx + , m_rsmConfigUbo.getUbo().getByteOffset() + , m_rsmConfigUbo.getUbo().getByteRange() ); + pass.addInputStorageBuffer( { m_rsmSamplesSsbo.getBuffer(), "RsmSample" } + , rsmgi::RsmSamplesIdx + , m_rsmSamplesSsbo.getOffset() + , m_rsmSamplesSsbo.getSize() ); + cameraUbo.createPassBinding( pass + , rsmgi::CameraUboIdx ); + shadowBuffer.createPassBinding( pass + , rsmgi::ShadowsIdx ); + pass.addSampledView( depthObj + , rsmgi::DepthObjMapIdx ); + pass.addSampledView( nmlOcc + , rsmgi::NmlOccMapIdx ); + pass.addSampledView( smResult[SmTexture::eNormal].sampledViewId + , rsmgi::RsmNormalsIdx ); + pass.addSampledView( smResult[SmTexture::ePosition].sampledViewId + , rsmgi::RsmPositionIdx ); + pass.addSampledView( smResult[SmTexture::eFlux].sampledViewId + , rsmgi::RsmFluxIdx ); + pass.addOutputColourView( result[0].targetViewId + , transparentBlackClearColor ); + pass.addOutputColourView( result[1].targetViewId + , transparentBlackClearColor ); + m_pass = &pass; + } + + void RsmGIPass::accept( ConfigurationVisitorBase & visitor ) + { + visitor.visit( m_vertexShader ); + visitor.visit( m_pixelShader ); + } + + void RsmGIPass::update( Light const & light ) + { + m_rsmConfigUbo.cpuUpdate( light.getRsmConfig() + , uint32_t( light.getShadowMapIndex() ) ); + } +} diff --git a/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.cpp b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.cpp new file mode 100644 index 0000000000..fb27f91d2f --- /dev/null +++ b/source/Core/Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.cpp @@ -0,0 +1,458 @@ +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/RsmInterpolatePass.hpp" + +#include "Castor3D/Engine.hpp" +#include "Castor3D/Buffer/GpuBufferOffset.hpp" +#include "Castor3D/Buffer/PoolUniformBuffer.hpp" +#include "Castor3D/Cache/LightCache.hpp" +#include "Castor3D/Material/Pass/PassFactory.hpp" +#include "Castor3D/Material/Texture/Sampler.hpp" +#include "Castor3D/Material/Texture/TextureLayout.hpp" +#include "Castor3D/Material/Texture/TextureUnit.hpp" +#include "Castor3D/Miscellaneous/ConfigurationVisitor.hpp" +#include "Castor3D/Render/RenderSystem.hpp" +#include "Castor3D/Render/ShadowMap/ShadowMapResult.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMapping.hpp" +#include "Castor3D/Shader/Program.hpp" +#include "Castor3D/Shader/ShaderBuffers/ShadowBuffer.hpp" +#include "Castor3D/Shader/Shaders/GlslLight.hpp" +#include "Castor3D/Shader/Shaders/GlslShadow.hpp" +#include "Castor3D/Shader/Shaders/GlslUtils.hpp" +#include "Castor3D/Shader/Ubos/CameraUbo.hpp" +#include "Castor3D/Shader/Ubos/RsmConfigUbo.hpp" + +#include +#include +#include +#include + +#include + +#include + +CU_ImplementSmartPtr( castor3d, RsmInterpolatePass ) + +namespace castor3d +{ + namespace rsminterp + { + enum Idx : uint32_t + { + RsmCfgUboIdx, + RsmSamplesIdx, + CameraIdx, + ShadowsIdx, + GiMapIdx, + NmlMapIdx, + DepthMapIdx, + NmlOccMapIdx, + RsmNormalsIdx, + RsmPositionIdx, + RsmFluxIdx, + }; + + static std::unique_ptr< ast::Shader > getVertexProgram() + { + sdw::VertexWriter writer; + + // Shader inputs + auto position = writer.declInput< sdw::Vec2 >( "position", 0u ); + auto uv = writer.declInput< sdw::Vec2 >( "uv", 1u ); + + // Shader outputs + auto vtx_texture = writer.declOutput< sdw::Vec2 >( "vtx_texture", 0u ); + + writer.implementMain( [&]( sdw::VertexIn in + , sdw::VertexOut out ) + { + vtx_texture = uv; + out.vtx.position = vec4( position, 0.0_f, 1.0_f ); + } ); + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) ); + } + + static ShaderPtr getDirectionalPixelShaderSource( LightType lightType + , uint32_t width + , uint32_t height + , RenderSystem const & renderSystem ) + { + sdw::FragmentWriter writer; + + // Shader inputs + C3D_RsmConfig( writer, RsmCfgUboIdx, 0u ); + sdw::ArrayStorageBufferT< sdw::Vec4 > c3d_rsmSamples{ writer + , "c3d_rsmSamples" + , writer.getTypesCache().getVec4F() + , sdw::type::MemoryLayout::eStd430 + , RsmSamplesIdx + , 0u + , true }; + C3D_Camera( writer, CameraIdx, 0u ); + auto c3d_mapGi = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapGi", GiMapIdx, 0u ); + auto c3d_mapNml = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapNml", NmlMapIdx, 0u ); + auto c3d_mapDepth = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapDepth", DepthMapIdx, 0u ); + auto c3d_mapNmlOcc = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapNmlOcc", NmlOccMapIdx, 0u ); + auto c3d_rsmNormalMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( lightType, SmTexture::eNormal ), RsmNormalsIdx, 0u ); + auto c3d_rsmPositionMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( lightType, SmTexture::ePosition ), RsmPositionIdx, 0u ); + auto c3d_rsmFluxMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( lightType, SmTexture::eFlux ), RsmFluxIdx, 0u ); + + auto vtx_texture = writer.declInput< sdw::Vec2 >( "vtx_texture", 0u ); + + // Shader outputs + auto pxl_rsmGI = writer.declOutput< sdw::Vec3 >( "pxl_rsmGI", 0 ); + + // Utility functions + shader::Utils utils{ writer }; + + shader::ShadowsBuffer shadows{ writer + , Idx::ShadowsIdx + , 0u }; + ReflectiveShadowMapping rsm{ writer + , c3d_rsmSamples }; + + writer.implementMain( [&]( sdw::FragmentIn in + , sdw::FragmentOut out ) + { + auto texCoord = writer.declLocale( "texCoord" + , vtx_texture ); + auto depth = writer.declLocale( "depth" + , c3d_mapDepth.lod( texCoord, 0.0_f ).x() ); + + IF( writer, depth == 1.0_f ) + { + writer.demote(); + } + FI; + + auto data1 = writer.declLocale( "data1" + , c3d_mapNmlOcc.lod( texCoord, 0.0_f ) ); + auto vsPosition = writer.declLocale( "vsPosition" + , c3d_cameraData.projToView( utils, texCoord, depth ) ); + auto wsPosition = writer.declLocale( "wsPosition" + , c3d_cameraData.curProjToWorld( utils, texCoord, depth ) ); + auto wsNormal = writer.declLocale( "wsNormal" + , data1.xyz() ); + auto giNormal = writer.declLocale( "giNormal" + , c3d_mapNml.lod( texCoord, 0.0_f ).xyz() ); + auto areEqual = writer.declLocale( "areEqual" + , giNormal == wsNormal ); + + IF( writer, areEqual.x() && areEqual.y() && areEqual.z() ) + { + auto offset = writer.declLocale( "offset" + , vec2( 1.0_f / float( width ), 1.0_f / float( height ) ) ); + pxl_rsmGI = c3d_mapGi.lod( texCoord, 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( offset.x(), offset.y() ), 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( offset.x(), -offset.y() ), 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( -offset.x(), offset.y() ), 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( -offset.x(), -offset.y() ), 0.0_f ).xyz(); + pxl_rsmGI /= 5.0_f; + } + ELSE + { + auto shadowData = writer.declLocale( "shadowData" + , shadows.getDirectionalShadows() ); + pxl_rsmGI = rsm.directional( shadowData + , vsPosition + , wsPosition + , wsNormal + , c3d_rsmConfigData ); + } + FI; + } ); + + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) ); + } + + static ShaderPtr getSpotPixelShaderSource( LightType lightType + , uint32_t width + , uint32_t height + , RenderSystem const & renderSystem ) + { + sdw::FragmentWriter writer; + + // Shader inputs + C3D_RsmConfig( writer, RsmCfgUboIdx, 0u ); + sdw::ArrayStorageBufferT< sdw::Vec4 > c3d_rsmSamples{ writer + , "c3d_rsmSamples" + , writer.getTypesCache().getVec4F() + , sdw::type::MemoryLayout::eStd430 + , RsmSamplesIdx + , 0u + , true }; + C3D_Camera( writer, CameraIdx, 0u ); + auto c3d_mapGi = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapGi", GiMapIdx, 0u ); + auto c3d_mapNml = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapNml", NmlMapIdx, 0u ); + auto c3d_mapDepth = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapDepth", DepthMapIdx, 0u ); + auto c3d_mapNmlOcc = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapNmlOcc", NmlOccMapIdx, 0u ); + auto c3d_rsmNormalMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( lightType, SmTexture::eNormal ), RsmNormalsIdx, 0u ); + auto c3d_rsmPositionMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( lightType, SmTexture::ePosition ), RsmPositionIdx, 0u ); + auto c3d_rsmFluxMap = writer.declCombinedImg< FImg2DArrayRgba32 >( getTextureName( lightType, SmTexture::eFlux ), RsmFluxIdx, 0u ); + + auto vtx_texture = writer.declInput< sdw::Vec2 >( "vtx_texture", 0u ); + + // Shader outputs + auto pxl_rsmGI = writer.declOutput< sdw::Vec3 >( "pxl_rsmGI", 0 ); + + // Utility functions + shader::Utils utils{ writer }; + + shader::ShadowsBuffer shadows{ writer + , Idx::ShadowsIdx + , 0u }; + ReflectiveShadowMapping rsm{ writer + , c3d_rsmSamples }; + + writer.implementMain( [&]( sdw::FragmentIn in + , sdw::FragmentOut out ) + { + auto texCoord = writer.declLocale( "texCoord" + , vtx_texture ); + auto depth = writer.declLocale( "depth" + , c3d_mapDepth.lod( texCoord, 0.0_f ).x() ); + + IF( writer, depth == 1.0_f ) + { + writer.demote(); + } + FI; + + auto data1 = writer.declLocale( "data1" + , c3d_mapNmlOcc.lod( texCoord, 0.0_f ) ); + auto wsPosition = writer.declLocale( "wsPosition" + , c3d_cameraData.curProjToWorld( utils, texCoord, depth ) ); + auto wsNormal = writer.declLocale( "wsNormal" + , data1.xyz() ); + + IF( writer, dot( wsNormal, wsNormal ) == 0.0f ) + { + writer.demote(); + } + FI; + + auto giNormal = writer.declLocale( "giNormal" + , c3d_mapNml.lod( texCoord, 0.0_f ).xyz() ); + + IF( writer, all( giNormal == wsNormal ) ) + { + auto offset = writer.declLocale( "offset" + , vec2( 1.0_f / float( width ), 1.0_f / float( height ) ) ); + pxl_rsmGI = c3d_mapGi.lod( texCoord, 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( offset.x(), offset.y() ), 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( offset.x(), -offset.y() ), 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( -offset.x(), offset.y() ), 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( -offset.x(), -offset.y() ), 0.0_f ).xyz(); + pxl_rsmGI /= 5.0_f; + } + ELSE + { + auto shadowData = writer.declLocale( "shadowData" + , shadows.getSpotShadows( 0_i ) ); + pxl_rsmGI = rsm.spot( shadowData + , wsPosition + , wsNormal + , c3d_rsmConfigData ); + } + FI; + } ); + + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) ); + } + + static ShaderPtr getPointPixelShaderSource( LightType lightType + , uint32_t width + , uint32_t height + , RenderSystem const & renderSystem ) + { + sdw::FragmentWriter writer; + + // Shader inputs + C3D_RsmConfig( writer, RsmCfgUboIdx, 0u ); + sdw::ArrayStorageBufferT< sdw::Vec4 > c3d_rsmSamples{ writer + , "c3d_rsmSamples" + , writer.getTypesCache().getVec4F() + , sdw::type::MemoryLayout::eStd430 + , RsmSamplesIdx + , 0u + , true }; + C3D_Camera( writer, CameraIdx, 0u ); + auto c3d_mapGi = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapGi", GiMapIdx, 0u ); + auto c3d_mapNml = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapNml", NmlMapIdx, 0u ); + auto c3d_mapDepth = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapDepth", DepthMapIdx, 0u ); + auto c3d_mapNmlOcc = writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapNmlOcc", NmlOccMapIdx, 0u ); + auto c3d_rsmNormalMap = writer.declCombinedImg< FImgCubeArrayRgba32 >( getTextureName( lightType, SmTexture::eNormal ), RsmNormalsIdx, 0u ); + auto c3d_rsmPositionMap = writer.declCombinedImg< FImgCubeArrayRgba32 >( getTextureName( lightType, SmTexture::ePosition ), RsmPositionIdx, 0u ); + auto c3d_rsmFluxMap = writer.declCombinedImg< FImgCubeArrayRgba32 >( getTextureName( lightType, SmTexture::eFlux ), RsmFluxIdx, 0u ); + + auto vtx_texture = writer.declInput< sdw::Vec2 >( "vtx_texture", 0u ); + + // Shader outputs + auto pxl_rsmGI = writer.declOutput< sdw::Vec3 >( "pxl_rsmGI", 0 ); + + // Utility functions + shader::Utils utils{ writer }; + + shader::ShadowsBuffer shadows{ writer + , Idx::ShadowsIdx + , 0u }; + ReflectiveShadowMapping rsm{ writer + , c3d_rsmSamples }; + + writer.implementMain( [&]( sdw::FragmentIn in + , sdw::FragmentOut out ) + { + auto texCoord = writer.declLocale( "texCoord" + , vtx_texture ); + auto data1 = writer.declLocale( "data1" + , c3d_mapNmlOcc.lod( texCoord, 0.0_f ) ); + auto depth = writer.declLocale( "depth" + , c3d_mapDepth.lod( texCoord, 0.0_f ).x() ); + auto wsPosition = writer.declLocale( "wsPosition" + , c3d_cameraData.curProjToWorld( utils, texCoord, depth ) ); + auto wsNormal = writer.declLocale( "wsNormal" + , data1.xyz() ); + + auto giNormal = writer.declLocale( "giNormal" + , c3d_mapNml.lod( texCoord, 0.0_f ).xyz() ); + auto areEqual = writer.declLocale( "areEqual" + , giNormal == wsNormal ); + + IF( writer, areEqual.x() && areEqual.y() && areEqual.z() ) + { + auto offset = writer.declLocale( "offset" + , vec2( 1.0_f / float( width ), 1.0_f / float( height ) ) ); + pxl_rsmGI = c3d_mapGi.lod( texCoord, 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( offset.x(), offset.y() ), 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( offset.x(), -offset.y() ), 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( -offset.x(), offset.y() ), 0.0_f ).xyz() + + c3d_mapGi.lod( texCoord + vec2( -offset.x(), -offset.y() ), 0.0_f ).xyz(); + pxl_rsmGI /= 5.0_f; + } + ELSE + { + auto shadowData = writer.declLocale( "shadowData" + , shadows.getPointShadows( 0_i ) ); + pxl_rsmGI = rsm.point( shadowData + , shadowData.position().xyz() + , wsPosition + , wsNormal + , c3d_rsmConfigData ); + } + FI; + } ); + + return std::make_unique< ast::Shader >( std::move( writer.getShader() ) ); + } + + static std::unique_ptr< ast::Shader > getPixelProgram( LightType lightType + , uint32_t width + , uint32_t height + , RenderSystem const & renderSystem ) + { + switch ( lightType ) + { + case LightType::eDirectional: + return getDirectionalPixelShaderSource( lightType, width, height, renderSystem ); + case LightType::eSpot: + return getSpotPixelShaderSource( lightType, width, height, renderSystem ); + case LightType::ePoint: + return getPointPixelShaderSource( lightType, width, height, renderSystem ); + default: + CU_Failure( "Unexpected LightType" ); + return nullptr; + } + } + + static crg::rq::Config getConfig( VkExtent2D const & renderSize + , ashes::PipelineShaderStageCreateInfoArray const & stages ) + { + crg::rq::Config result; + result.texcoordConfig( {} ); + result.renderSize( renderSize ); + result.program( crg::makeVkArray< VkPipelineShaderStageCreateInfo >( stages ) ); + return result; + } + } + + //********************************************************************************************* + + RsmInterpolatePass::RsmInterpolatePass( crg::FrameGraph & graph + , crg::FramePass const & previousPass + , RenderDevice const & device + , LightType lightType + , ShadowBuffer const & shadowBuffer + , VkExtent3D const & size + , CameraUbo const & cameraUbo + , crg::ImageViewId const & depthObj + , crg::ImageViewId const & nmlOcc + , ShadowMapResult const & smResult + , RsmConfigUbo const & rsmConfigUbo + , GpuBufferOffsetT< castor::Point4f > const & rsmSamplesSsbo + , Texture const & gi + , Texture const & nml + , Texture const & dst ) + : castor::Named{ "RsmInterpolate" } + , m_vertexShader{ VK_SHADER_STAGE_VERTEX_BIT, getName(), rsminterp::getVertexProgram() } + , m_pixelShader{ VK_SHADER_STAGE_FRAGMENT_BIT, getName(), rsminterp::getPixelProgram( lightType, gi.getExtent().width, gi.getExtent().height , device.renderSystem) } + , m_stages{ makeShaderState( device, m_vertexShader ) + , makeShaderState( device, m_pixelShader ) } + { + auto & pass = graph.createPass( getName() + , [this, &device, size]( crg::FramePass const & pass + , crg::GraphContext & context + , crg::RunnableGraph & graph ) + { + auto result = std::make_unique< crg::RenderQuad >( pass + , context + , graph + , crg::ru::Config{ 1u, false } + , rsminterp::getConfig( { size.width, size.height } + , m_stages ) ); + device.renderSystem.getEngine()->registerTimer( graph.getName() + "/RsmInterpolate" + , result->getTimer() ); + return result; + } ); + pass.addDependency( previousPass ); + pass.addUniformBuffer( { rsmConfigUbo.getUbo().getBuffer(), "RsmConfig" } + , rsminterp::RsmCfgUboIdx + , rsmConfigUbo.getUbo().getByteOffset() + , rsmConfigUbo.getUbo().getByteRange() ); + pass.addInputStorageBuffer( { rsmSamplesSsbo.getBuffer(), "RsmSample" } + , rsminterp::RsmSamplesIdx + , rsmSamplesSsbo.getOffset() + , rsmSamplesSsbo.getSize() ); + cameraUbo.createPassBinding( pass + , rsminterp::CameraIdx ); + shadowBuffer.createPassBinding( pass + , rsminterp::ShadowsIdx ); + pass.addSampledView( gi.sampledViewId + , rsminterp::GiMapIdx ); + pass.addSampledView( nml.sampledViewId + , rsminterp::NmlMapIdx ); + pass.addSampledView( depthObj + , rsminterp::DepthMapIdx ); + pass.addSampledView( nmlOcc + , rsminterp::NmlOccMapIdx ); + pass.addSampledView( smResult[SmTexture::eNormal].sampledViewId + , rsminterp::RsmNormalsIdx ); + pass.addSampledView( smResult[SmTexture::ePosition].sampledViewId + , rsminterp::RsmPositionIdx ); + pass.addSampledView( smResult[SmTexture::eFlux].sampledViewId + , rsminterp::RsmFluxIdx ); + pass.addInOutColourView( dst.targetViewId + , VkPipelineColorBlendAttachmentState{ VK_TRUE + , VK_BLEND_FACTOR_ONE + , VK_BLEND_FACTOR_ONE + , VK_BLEND_OP_ADD + , VK_BLEND_FACTOR_ONE + , VK_BLEND_FACTOR_ONE + , VK_BLEND_OP_ADD + , VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT } ); + m_pass = &pass; + } + + void RsmInterpolatePass::accept( ConfigurationVisitorBase & visitor ) + { + visitor.visit( m_vertexShader ); + visitor.visit( m_pixelShader ); + } +} diff --git a/source/Core/Castor3D/Render/GlobalIllumination/VoxelConeTracing/VoxelizePass.cpp b/source/Core/Castor3D/Render/GlobalIllumination/VoxelConeTracing/VoxelizePass.cpp index b98406b5b6..4156870395 100644 --- a/source/Core/Castor3D/Render/GlobalIllumination/VoxelConeTracing/VoxelizePass.cpp +++ b/source/Core/Castor3D/Render/GlobalIllumination/VoxelConeTracing/VoxelizePass.cpp @@ -187,6 +187,7 @@ namespace castor3d SceneFlags VoxelizePass::doAdjustSceneFlags( SceneFlags flags )const { + remFlag( flags, SceneFlag::eRsmGI ); remFlag( flags, SceneFlag::eLpvGI ); remFlag( flags, SceneFlag::eLayeredLpvGI ); remFlag( flags, SceneFlag::eFogLinear ); diff --git a/source/Core/Castor3D/Render/Prepass/DepthPass.cpp b/source/Core/Castor3D/Render/Prepass/DepthPass.cpp index 14b1b63de5..0cf8d76a30 100644 --- a/source/Core/Castor3D/Render/Prepass/DepthPass.cpp +++ b/source/Core/Castor3D/Render/Prepass/DepthPass.cpp @@ -78,6 +78,7 @@ namespace castor3d SceneFlags DepthPass::doAdjustSceneFlags( SceneFlags flags )const { + remFlag( flags, SceneFlag::eRsmGI ); remFlag( flags, SceneFlag::eLpvGI ); remFlag( flags, SceneFlag::eLayeredLpvGI ); remFlag( flags, SceneFlag::eVoxelConeTracing ); diff --git a/source/Core/Castor3D/Render/RenderNodesPass.cpp b/source/Core/Castor3D/Render/RenderNodesPass.cpp index 3ce7177e4b..40280e8ed2 100644 --- a/source/Core/Castor3D/Render/RenderNodesPass.cpp +++ b/source/Core/Castor3D/Render/RenderNodesPass.cpp @@ -597,6 +597,17 @@ namespace castor3d index += 3u; // VCT: UBO + FirstBounce + SecondBounce. } + if ( checkFlag( sceneFlags, SceneFlag::eRsmGI ) ) + { + addDescriptorSetLayoutBinding( bindings, index + , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER + , shaderStages ); + } + else if ( indirectLighting.rsmResult ) + { + ++index; // RSM: Result. + } + if ( checkFlag( sceneFlags, SceneFlag::eLpvGI ) ) { addDescriptorSetLayoutBinding( bindings, index @@ -799,6 +810,18 @@ namespace castor3d index += 3u; // VCT: UBO + FirstBounce + SecondBounce. } + if ( checkFlag( sceneFlags, SceneFlag::eRsmGI ) ) + { + bindTexture( indirectLighting.rsmResult->wholeView + , *indirectLighting.rsmResult->sampler + , descriptorWrites + , index ); + } + else if ( indirectLighting.rsmResult ) + { + ++index; // RSM: Result. + } + if ( checkFlag( sceneFlags, SceneFlag::eLpvGI ) ) { CU_Require( indirectLighting.lpvConfigUbo ); diff --git a/source/Core/Castor3D/Render/RenderTechnique.cpp b/source/Core/Castor3D/Render/RenderTechnique.cpp index 6c24e5e68e..56e739ca2b 100644 --- a/source/Core/Castor3D/Render/RenderTechnique.cpp +++ b/source/Core/Castor3D/Render/RenderTechnique.cpp @@ -21,6 +21,7 @@ #include "Castor3D/Render/GlobalIllumination/LightPropagationVolumes/LayeredLightPropagationVolumes.hpp" #include "Castor3D/Render/GlobalIllumination/LightPropagationVolumes/LightPropagationVolumes.hpp" #include "Castor3D/Render/GlobalIllumination/LightPropagationVolumes/LightVolumePassResult.hpp" +#include "Castor3D/Render/GlobalIllumination/ReflectiveShadowMaps/ReflectiveShadowMaps.hpp" #include "Castor3D/Render/GlobalIllumination/VoxelConeTracing/Voxelizer.hpp" #include "Castor3D/Render/Node/SubmeshRenderNode.hpp" #include "Castor3D/Render/Opaque/OpaqueRendering.hpp" @@ -113,6 +114,7 @@ namespace castor3d , LightPropagationVolumesGLightType const & lightPropagationVolumesG , LayeredLightPropagationVolumesLightType const & layeredLightPropagationVolumes , LayeredLightPropagationVolumesGLightType const & layeredLightPropagationVolumesG + , ReflectiveShadowMapsUPtr const & reflectiveShadowMaps , CpuUpdater & updater ) { auto lights = doSortLights( cache, type, *updater.camera ); @@ -137,6 +139,12 @@ namespace castor3d switch ( updater.light->getGlobalIlluminationType() ) { + case GlobalIlluminationType::eRsm: + if ( reflectiveShadowMaps ) + { + reflectiveShadowMaps->registerLight( updater.light ); + } + break; case GlobalIlluminationType::eLpv: if ( lightPropagationVolumes[size_t( type )] ) { @@ -404,6 +412,19 @@ namespace castor3d , m_renderTarget.getScene()->getVoxelConeTracingConfig() , previousPasses ) : nullptr ) } + , m_rsmResult{ ( m_shadowBuffer + ? castor::makeUnique< Texture >( m_device + , m_renderTarget.getResources() + , getName() + "RSMResult" + , 0u + , colour.getExtent() + , 1u + , 1u + , VK_FORMAT_R16G16B16A16_SFLOAT + , VkImageUsageFlags( VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT + | VK_IMAGE_USAGE_TRANSFER_DST_BIT ) ) + : nullptr ) } , m_lpvResult{ ( m_shadowBuffer ? castor::makeUnique< LightVolumePassResult >( m_renderTarget.getResources() , m_device @@ -419,6 +440,7 @@ namespace castor3d , m_indirectLighting{ ( ( m_renderTarget.isFullLoadingEnabled() || m_renderTarget.getScene()->needsGlobalIllumination() ) ? &m_lpvConfigUbo : nullptr ) , ( ( m_renderTarget.isFullLoadingEnabled() || m_renderTarget.getScene()->needsGlobalIllumination() ) ? &m_llpvConfigUbo : nullptr ) , ( m_voxelizer ? &m_vctConfigUbo : nullptr ) + , ( ( m_renderTarget.isFullLoadingEnabled() || m_renderTarget.getScene()->needsGlobalIllumination() ) ? m_rsmResult.get() : nullptr ) , ( ( m_renderTarget.isFullLoadingEnabled() || m_renderTarget.getScene()->needsGlobalIllumination() ) ? m_lpvResult.get() : nullptr ) , ( ( m_renderTarget.isFullLoadingEnabled() || m_renderTarget.getScene()->needsGlobalIllumination() ) ? &m_llpvResult : nullptr ) , ( m_voxelizer ? &m_voxelizer->getFirstBounce() : nullptr ) @@ -502,6 +524,7 @@ namespace castor3d m_allShadowMaps[size_t( LightType::ePoint )].emplace_back( castor::ref( *m_pointShadowMap ), UInt32Array{} ); } + doInitialiseRsm(); doInitialiseLpv(); #endif } @@ -516,6 +539,13 @@ namespace castor3d m_llpvResult.clear(); m_lpvResult.reset(); + + if ( m_rsmResult ) + { + m_rsmResult->destroy(); + m_rsmResult.reset(); + } + m_voxelizer.reset(); m_diffuse.destroy(); m_scattering.destroy(); @@ -560,6 +590,7 @@ namespace castor3d updater.debugIndex = debugConfig.intermediateShaderValueIndex; doUpdateShadowMaps( updater ); + doUpdateRsm( updater ); doUpdateLpv( updater ); if ( m_renderTarget.getTargetType() == TargetType::eWindow ) @@ -634,6 +665,7 @@ namespace castor3d auto & scene = *pscene; updater.voxelConeTracing = scene.getVoxelConeTracingConfig().enabled; + doInitialiseRsm(); doInitialiseLpv(); doUpdateShadowMaps( updater ); @@ -652,6 +684,7 @@ namespace castor3d { auto result = toWait; result = doRenderShadowMaps( result, queue ); + result = doRenderRSM( result, queue ); result = doRenderLPV( result, queue ); result = doRenderEnvironmentMaps( result, queue ); result = doRenderVCT( result, queue ); @@ -706,6 +739,11 @@ namespace castor3d renderPass.accept( visitor ); } ); + if ( m_reflectiveShadowMaps ) + { + m_reflectiveShadowMaps->accept( visitor ); + } + #if !C3D_DebugDisableShadowMaps if ( m_directionalShadowMap ) { @@ -875,6 +913,29 @@ namespace castor3d return result; } + void RenderTechnique::doInitialiseRsm() + { + auto & scene = *m_renderTarget.getScene(); + auto needRsm = scene.needsGlobalIllumination( GlobalIlluminationType::eRsm ); + + if ( needRsm && !m_reflectiveShadowMaps ) + { + m_rsmResult->create(); + m_reflectiveShadowMaps = castor::makeUnique< ReflectiveShadowMaps >( getOwner()->getGraphResourceHandler() + , scene + , m_device + , m_cameraUbo + , *m_shadowBuffer + , m_prepass.getDepthObj().sampledViewId + , m_normal.sampledViewId + , m_allShadowMaps[size_t( LightType::eDirectional )].front().first.get().getShadowPassResult( false ) + , m_allShadowMaps[size_t( LightType::ePoint )].front().first.get().getShadowPassResult( false ) + , m_allShadowMaps[size_t( LightType::eSpot )].front().first.get().getShadowPassResult( false ) + , *m_rsmResult ); + m_reflectiveShadowMaps->initialise(); + } + } + void RenderTechnique::doInitialiseLpv() { auto & scene = *m_renderTarget.getScene(); @@ -983,6 +1044,7 @@ namespace castor3d , m_lightPropagationVolumesG , m_layeredLightPropagationVolumes , m_layeredLightPropagationVolumesG + , m_reflectiveShadowMaps , updater ); } @@ -997,6 +1059,7 @@ namespace castor3d , m_lightPropagationVolumesG , m_layeredLightPropagationVolumes , m_layeredLightPropagationVolumesG + , m_reflectiveShadowMaps , updater ); } @@ -1011,6 +1074,7 @@ namespace castor3d , m_lightPropagationVolumesG , m_layeredLightPropagationVolumes , m_layeredLightPropagationVolumesG + , m_reflectiveShadowMaps , updater ); } } @@ -1033,6 +1097,14 @@ namespace castor3d } } + void RenderTechnique::doUpdateRsm( CpuUpdater & updater ) + { + if ( m_reflectiveShadowMaps ) + { + m_reflectiveShadowMaps->update( updater ); + } + } + void RenderTechnique::doUpdateLpv( CpuUpdater & updater ) { for ( auto i = uint32_t( LightType::eMin ); i < uint32_t( LightType::eCount ); ++i ) @@ -1059,6 +1131,20 @@ namespace castor3d } } + crg::SemaphoreWaitArray RenderTechnique::doRenderRSM( crg::SemaphoreWaitArray const & semaphore + , ashes::Queue const & queue ) + { + crg::SemaphoreWaitArray result = semaphore; + + if ( m_renderTarget.getScene()->needsGlobalIllumination( GlobalIlluminationType::eRsm ) + && m_reflectiveShadowMaps ) + { + result = m_reflectiveShadowMaps->render( result, queue ); + } + + return result; + } + crg::SemaphoreWaitArray RenderTechnique::doRenderLPV( crg::SemaphoreWaitArray const & semaphore , ashes::Queue const & queue ) { diff --git a/source/Core/Castor3D/Render/RenderTechniquePass.cpp b/source/Core/Castor3D/Render/RenderTechniquePass.cpp index 5def86541c..e32d124d47 100644 --- a/source/Core/Castor3D/Render/RenderTechniquePass.cpp +++ b/source/Core/Castor3D/Render/RenderTechniquePass.cpp @@ -271,6 +271,11 @@ namespace castor3d remFlag( flags, SceneFlag::eVoxelConeTracing ); } + if ( !m_indirectLighting.rsmResult ) + { + remFlag( flags, SceneFlag::eRsmGI ); + } + if ( !m_indirectLighting.lpvConfigUbo || !m_indirectLighting.lpvResult ) { remFlag( flags, SceneFlag::eLpvGI ); diff --git a/source/Core/Castor3D/Scene/Light/PointLight.cpp b/source/Core/Castor3D/Scene/Light/PointLight.cpp index 3e27735a4d..dd85ea95f8 100644 --- a/source/Core/Castor3D/Scene/Light/PointLight.cpp +++ b/source/Core/Castor3D/Scene/Light/PointLight.cpp @@ -147,6 +147,9 @@ namespace castor3d void PointLight::fillShadowBuffer( AllShadowData & data )const { auto & point = data.point[size_t( getLight().getShadowMapIndex() )]; + point.position->x = m_position.value()->x; + point.position->y = m_position.value()->y; + point.position->z = m_position.value()->z; LightCategory::doFillBaseShadowData( point ); } diff --git a/source/Core/Castor3D/Scene/Scene.cpp b/source/Core/Castor3D/Scene/Scene.cpp index 3bda6a0c58..7e92ccbbb1 100644 --- a/source/Core/Castor3D/Scene/Scene.cpp +++ b/source/Core/Castor3D/Scene/Scene.cpp @@ -582,6 +582,13 @@ namespace castor3d } else { + if ( needsGlobalIllumination( LightType::eDirectional, GlobalIlluminationType::eRsm ) + || needsGlobalIllumination( LightType::ePoint, GlobalIlluminationType::eRsm ) + || needsGlobalIllumination( LightType::eSpot, GlobalIlluminationType::eRsm ) ) + { + result |= SceneFlag::eRsmGI; + } + if ( needsGlobalIllumination( LightType::eDirectional, GlobalIlluminationType::eLpv ) || needsGlobalIllumination( LightType::eDirectional, GlobalIlluminationType::eLpvG ) || needsGlobalIllumination( LightType::ePoint, GlobalIlluminationType::eLpv ) @@ -793,6 +800,16 @@ namespace castor3d return m_needsGlobalIllumination; } + bool Scene::needsGlobalIllumination( GlobalIlluminationType giType )const + { + return std::any_of( m_giTypes.begin() + , m_giTypes.end() + , [&giType]( castor::Set< GlobalIlluminationType > const & lookup ) + { + return lookup.end() != lookup.find( giType ); + } ); + } + bool Scene::needsGlobalIllumination( LightType ltType , GlobalIlluminationType giType )const { diff --git a/source/Core/Castor3D/Scene/SceneFileParser_Parsers.cpp b/source/Core/Castor3D/Scene/SceneFileParser_Parsers.cpp index 2bda8e0c44..779ffa2060 100644 --- a/source/Core/Castor3D/Scene/SceneFileParser_Parsers.cpp +++ b/source/Core/Castor3D/Scene/SceneFileParser_Parsers.cpp @@ -5631,6 +5631,7 @@ namespace castor3d , { uint32_t( CSCNSection::eRaw ), cuT( "raw_config" ) } , { uint32_t( CSCNSection::ePcf ), cuT( "pcf_config" ) } , { uint32_t( CSCNSection::eVsm ), cuT( "vsm_config" ) } + , { uint32_t( CSCNSection::eRsm ), cuT( "rsm_config" ) } , { uint32_t( CSCNSection::eTextureAnimation ), cuT( "texture_animation" ) } , { uint32_t( CSCNSection::eVoxelConeTracing ), cuT( "voxel_cone_tracing" ) } , { uint32_t( CSCNSection::eTextureTransform ), cuT( "texture_transform" ) } diff --git a/source/Core/Castor3D/Scene/Shadow.cpp b/source/Core/Castor3D/Scene/Shadow.cpp index f612014f7f..c08b261c58 100644 --- a/source/Core/Castor3D/Scene/Shadow.cpp +++ b/source/Core/Castor3D/Scene/Shadow.cpp @@ -303,6 +303,26 @@ namespace castor3d { filterType = newV; } ) ); + if ( lightType == castor3d::LightType::eDirectional ) + { + baseBlock.visit( cuT( "GI Type" ) + , globalIllumination + , castor::StringArray{ cuT( "None" ), cuT( "VCT" ), cuT( "RSM" ), cuT( "LPV" ), cuT( "LPV (Geometry)" ), cuT( "Layered LPV" ), cuT( "Layered LPV (Geometry)" ) } + , ConfigurationVisitorBase::OnEnumValueChangeT< GlobalIlluminationType >( [this]( GlobalIlluminationType, GlobalIlluminationType newV ) + { + globalIllumination = GlobalIlluminationType( newV ); + } ) ); + } + else + { + baseBlock.visit( cuT( "GI Type" ) + , globalIllumination + , castor::StringArray{ cuT( "None" ), cuT( "VCT" ), cuT( "RSM" ), cuT( "LPV" ), cuT( "LPV (Geometry)" ) } + , ConfigurationVisitorBase::OnEnumValueChangeT< GlobalIlluminationType >( [this]( GlobalIlluminationType, GlobalIlluminationType newV ) + { + globalIllumination = GlobalIlluminationType( newV ); + } ) ); + } if ( lightType == castor3d::LightType::eDirectional ) { @@ -310,42 +330,23 @@ namespace castor3d baseBlock.visit( cuT( "Volumetric Scattering Factor" ), volumetricScattering ); } { - auto block = baseBlock.visit( cuT( "Raw:" ) ); + auto block = baseBlock.visit( cuT( "Raw" ) ); block.visit( cuT( "Raw Min. Offset" ), rawOffsets[0] ); block.visit( cuT( "Raw Max. Slope Offset" ), rawOffsets[1] ); } { - auto block = baseBlock.visit( cuT( "PCF: " ) ); + auto block = baseBlock.visit( cuT( "Percentage Closer Filtering" ) ); block.visit( cuT( "PCF Min. Offset" ), pcfOffsets[0] ); block.visit( cuT( "PCF Max. Slope Offset" ), pcfOffsets[1] ); block.visit( cuT( "PCF Filter Size" ), pcfFilterSize ); block.visit( cuT( "PCF Sample Count" ), pcfSampleCount ); } { - auto block = baseBlock.visit( cuT( "VSM:" ) ); + auto block = baseBlock.visit( cuT( "Variance Shadow Maps" ) ); block.visit( cuT( "Min. Variance" ), vsmMinVariance ); block.visit( cuT( "Light Bleeding Reduction" ), vsmLightBleedingReduction ); } - if ( lightType == castor3d::LightType::eDirectional ) - { - baseBlock.visit( cuT( "GI Type" ) - , globalIllumination - , castor::StringArray{ cuT( "None" ), cuT( "LPV" ), cuT( "LPV (Geometry)" ), cuT( "Layered LPV" ), cuT( "Layered LPV (Geometry)" ) } - , ConfigurationVisitorBase::OnEnumValueChangeT< GlobalIlluminationType >( [this]( GlobalIlluminationType, GlobalIlluminationType newV ) - { - globalIllumination = GlobalIlluminationType( newV ); - } ) ); - } - else - { - baseBlock.visit( cuT( "GI Type" ) - , globalIllumination - , castor::StringArray{ cuT( "None" ), cuT( "LPV" ), cuT( "LPV (Geometry)" ) } - , ConfigurationVisitorBase::OnEnumValueChangeT< GlobalIlluminationType >( [this]( GlobalIlluminationType, GlobalIlluminationType newV ) - { - globalIllumination = GlobalIlluminationType( newV ); - } ) ); - } + rsmConfig.accept( *baseBlock ); lpvConfig.accept( *baseBlock ); } @@ -386,5 +387,6 @@ namespace castor3d vsmContext.addDefaultPopParser(); LpvConfig::addParsers( result ); + RsmConfig::addParsers( result ); } } diff --git a/source/Core/Castor3D/Shader/Shaders/GlslGlobalIllumination.cpp b/source/Core/Castor3D/Shader/Shaders/GlslGlobalIllumination.cpp index 347e359d91..957d5f00e4 100644 --- a/source/Core/Castor3D/Shader/Shaders/GlslGlobalIllumination.cpp +++ b/source/Core/Castor3D/Shader/Shaders/GlslGlobalIllumination.cpp @@ -45,6 +45,15 @@ namespace castor3d bindingIndex += 3u; // VCT: UBO + FirstBounce + SecondBounce. } + if ( checkFlag( sceneFlags, SceneFlag::eRsmGI ) ) + { + declareRsm( bindingIndex, setIndex ); + } + else if ( indirectLighting.rsmResult ) + { + bindingIndex++; + } + if ( checkFlag( sceneFlags, SceneFlag::eLpvGI ) ) { declareLpv( bindingIndex, bindingIndex, setIndex, setIndex ); @@ -147,6 +156,11 @@ namespace castor3d } else { + if ( checkFlag( sceneFlags, SceneFlag::eRsmGI ) ) + { + indirectLighting.rawDiffuse() += computeRSMRadiance( lightSurface.clipPosition().xy() ); + } + if ( checkFlag( sceneFlags, SceneFlag::eLayeredLpvGI ) ) { auto llpvGridData = m_writer.getVariable< LayeredLpvGridData >( "c3d_llpvGridData" ); @@ -160,6 +174,7 @@ namespace castor3d } } + debugOutput.registerOutput( cuT( "Indirect" ), cuT( "Raw Diffuse" ), indirectLighting.rawDiffuse() ); debugOutput.registerOutput( cuT( "Indirect" ), cuT( "Diffuse Colour" ), indirectLighting.diffuseColour() ); debugOutput.registerOutput( cuT( "Indirect" ), cuT( "Diffuse Blend" ), indirectLighting.diffuseBlend() ); } @@ -183,6 +198,11 @@ namespace castor3d indirectLighting.ambient() = indirectLighting.diffuseColour() / lpvGridData.indirectAttenuation(); } + if ( checkFlag( sceneFlags, SceneFlag::eRsmGI ) ) + { + indirectLighting.ambient() = indirectLighting.diffuseColour(); + } + debugOutput.registerOutput( cuT( "Indirect" ), cuT( "Ambient" ), indirectLighting.ambient() ); } @@ -301,6 +321,19 @@ namespace castor3d m_writer.declCombinedImg< FImg3DRgba32 >( "c3d_mapVoxelsSecondaryBounce", texBindingIndex++, texSetIndex ); } + void GlobalIllumination::declareRsm( uint32_t & texBindingIndex + , uint32_t texSetIndex ) + { + auto c3d_mapRsmResult = m_writer.declCombinedImg< FImg2DRgba32 >( "c3d_mapRsmResult", texBindingIndex++, texSetIndex ); + + m_computeRSMRadiance = m_writer.implementFunction< sdw::Vec4 >( "computeRSMRadiance" + , [&]( sdw::Vec2 const & texcoord ) + { + m_writer.returnStmt( vec4( c3d_mapRsmResult.fetch( ivec2( texcoord ), 0_i ).xyz(), 1.0f ) ); + } + , sdw::InVec2{ m_writer, "texcoord" } ); + } + void GlobalIllumination::declareLpv( uint32_t & uboBindingIndex , uint32_t & texBindingIndex , uint32_t uboSetIndex @@ -502,6 +535,12 @@ namespace castor3d , vec3( vxlReflection.a() * indirectBlend * indirectOcclusion ) ); } + sdw::Vec4 GlobalIllumination::computeRSMRadiance( sdw::Vec2 const & texcoord ) + { + CU_Require( m_computeRSMRadiance ); + return m_computeRSMRadiance( texcoord ); + } + sdw::Vec4 GlobalIllumination::computeLPVRadiance( LightSurface lightSurface , LpvGridData lpvGridData ) { diff --git a/source/Core/Castor3D/Shader/Shaders/GlslLight.cpp b/source/Core/Castor3D/Shader/Shaders/GlslLight.cpp index 8bf6e09ac4..f3d654fe10 100644 --- a/source/Core/Castor3D/Shader/Shaders/GlslLight.cpp +++ b/source/Core/Castor3D/Shader/Shaders/GlslLight.cpp @@ -822,6 +822,55 @@ namespace castor3d::shader return m_lightsBuffer->getSpotLight( offset ); } + sdw::Vec3 Lights::getCascadeFactors( sdw::ShaderWriter & writer + , sdw::Vec3 const & viewVertex + , sdw::Vec4Array const & splitDepths + , sdw::UInt const & cascadeCount + , sdw::UInt const & maxCascadeCount ) + { + auto getSplitDepth = [&splitDepths]( sdw::UInt const & index ) + { + return splitDepths[index / 4u][index % 4u]; + }; + + auto maxCount = writer.declLocale( "maxCount" + , writer.cast< sdw::Int >( clamp( cascadeCount, 1_u, maxCascadeCount ) - 1_u ) ); + auto cascadeFactors = writer.declLocale( "cascadeFactors" + , vec3( writer.cast< sdw::Float >( maxCount ), 1.0_f, 0.0_f ) ); + + // Start at maxCount - 1 because the conditions inside the loop will never be true for maxCount. + FOR( writer, sdw::Int, i, maxCount - 1, i >= 0, --i ) + { + auto index = writer.declLocale( "index" + , writer.cast< sdw::UInt >( i ) ); + auto splitDepth = writer.declLocale( "splitDepth" + , getSplitDepth( index ) ); + auto splitDiff = writer.declLocale( "splitDiff" + , ( getSplitDepth( index + 1u ) - splitDepth ) / 16.0f ); + auto splitMax = writer.declLocale( "splitMax" + , splitDepth ); + auto splitMin = writer.declLocale( "splitMin" + , splitDepth - splitDiff ); + + IF( writer, viewVertex.z() > splitMin ) + { + cascadeFactors.x() = writer.cast< sdw::Float >( i ); + } + ELSEIF( viewVertex.z() > splitMax && viewVertex.z() <= splitMin ) + { + auto factor = writer.declLocale( "factor" + , ( viewVertex.z() - splitMin ) / splitDiff ); + cascadeFactors = vec3( writer.cast< sdw::Float >( i ) + , 1.0_f - factor + , factor ); + } + FI + } + ROF + + return cascadeFactors; + } + sdw::Vec3 Lights::getCascadeFactors( DirectionalShadowData const shadows , sdw::Vec3 pviewVertex , sdw::UInt pmaxCascadeCount ) @@ -834,47 +883,11 @@ namespace castor3d::shader , sdw::UInt const & cascadeCount , sdw::UInt const & maxCascadeCount ) { - auto getSplitDepth = [&splitDepths]( sdw::UInt const & index ) - { - return splitDepths[index / 4u][index % 4u]; - }; - - auto maxCount = m_writer.declLocale( "maxCount" - , m_writer.cast< sdw::Int >( clamp( cascadeCount, 1_u, maxCascadeCount ) - 1_u ) ); - auto cascadeFactors = m_writer.declLocale( "cascadeFactors" - , vec3( m_writer.cast< sdw::Float >( maxCount ), 1.0_f, 0.0_f)); - - // Start at maxCount - 1 because the conditions inside the loop will never be true for maxCount. - FOR( m_writer, sdw::Int, i, maxCount - 1, i >= 0, --i ) - { - auto index = m_writer.declLocale( "index" - , m_writer.cast< sdw::UInt >( i ) ); - auto splitDepth = m_writer.declLocale( "splitDepth" - , getSplitDepth( index ) ); - auto splitDiff = m_writer.declLocale( "splitDiff" - , ( getSplitDepth( index + 1u ) - splitDepth ) / 16.0f ); - auto splitMax = m_writer.declLocale( "splitMax" - , splitDepth ); - auto splitMin = m_writer.declLocale( "splitMin" - , splitDepth - splitDiff ); - - IF( m_writer, viewVertex.z() > splitMin ) - { - cascadeFactors.x() = m_writer.cast< sdw::Float >( i ); - } - ELSEIF( viewVertex.z() > splitMax && viewVertex.z() <= splitMin ) - { - auto factor = m_writer.declLocale( "factor" - , ( viewVertex.z() - splitMin ) / splitDiff ); - cascadeFactors = vec3( m_writer.cast< sdw::Float >( i ) - , 1.0_f - factor - , factor ); - } - FI - } - ROF - - m_writer.returnStmt( cascadeFactors ); + m_writer.returnStmt( getCascadeFactors( m_writer + , viewVertex + , splitDepths + , cascadeCount + , maxCascadeCount ) ); } , sdw::InVec3{ m_writer, "viewVertex" } , sdw::InVec4Array{ m_writer, "splitDepths", uint32_t( ashes::getAlignedSize( MaxDirectionalCascadesCount, 4u ) / 4u ) } diff --git a/source/Core/Castor3D/Shader/Ubos/RsmConfigUbo.cpp b/source/Core/Castor3D/Shader/Ubos/RsmConfigUbo.cpp new file mode 100644 index 0000000000..be4197b089 --- /dev/null +++ b/source/Core/Castor3D/Shader/Ubos/RsmConfigUbo.cpp @@ -0,0 +1,79 @@ +#include "Castor3D/Shader/Ubos/RsmConfigUbo.hpp" + +#include "Castor3D/Buffer/UniformBufferPool.hpp" +#include "Castor3D/Render/RenderDevice.hpp" +#include "Castor3D/Render/GlobalIllumination/VoxelConeTracing/VctConfig.hpp" +#include "Castor3D/Scene/Camera.hpp" +#include "Castor3D/Scene/Scene.hpp" +#include "Castor3D/Scene/SceneNode.hpp" + +#include + +#include + +namespace castor3d +{ + //********************************************************************************************* + + namespace shader + { + RsmConfigData::RsmConfigData( sdw::ShaderWriter & writer + , ast::expr::ExprPtr expr + , bool enabled ) + : StructInstance{ writer, castor::move( expr ), enabled } + , intensity{ getMember< sdw::Float >( "intensity" ) } + , maxRadius{ getMember< sdw::Float >( "maxRadius" ) } + , sampleCount{ getMember< sdw::UInt >( "sampleCount" ) } + , index{ getMember< sdw::Int >( "index" ) } + { + } + + ast::type::BaseStructPtr RsmConfigData::makeType( ast::type::TypesCache & cache ) + { + auto result = cache.getStruct( ast::type::MemoryLayout::eStd140 + , "C3D_RsmData" ); + + if ( result->empty() ) + { + result->declMember( "intensity", ast::type::Kind::eFloat ); + result->declMember( "maxRadius", ast::type::Kind::eFloat ); + result->declMember( "sampleCount", ast::type::Kind::eUInt32 ); + result->declMember( "index", ast::type::Kind::eInt32 ); + } + + return result; + } + + castor::RawUniquePtr< sdw::Struct > RsmConfigData::declare( sdw::ShaderWriter & writer ) + { + return castor::make_unique< sdw::Struct >( writer + , makeType( writer.getTypesCache() ) ); + } + } + + //********************************************************************************************* + + RsmConfigUbo::RsmConfigUbo( RenderDevice const & device ) + : m_device{ device } + , m_ubo{ m_device.uboPool->getBuffer< Configuration >( 0u ) } + { + } + + RsmConfigUbo::~RsmConfigUbo()noexcept + { + m_device.uboPool->putBuffer( m_ubo ); + } + + void RsmConfigUbo::cpuUpdate( RsmConfig const & rsmConfig + , uint32_t index ) + { + CU_Require( m_ubo ); + auto & rsmData = m_ubo.getData(); + rsmData.intensity = *rsmConfig.intensity; + rsmData.maxRadius = *rsmConfig.maxRadius; + rsmData.sampleCount = rsmConfig.sampleCount.value().value(); + rsmData.index = int32_t( index ); + } + + //********************************************************************************************* +} diff --git a/source/Core/SceneExporter/Text/TextRsmConfig.cpp b/source/Core/SceneExporter/Text/TextRsmConfig.cpp new file mode 100644 index 0000000000..59e02742c4 --- /dev/null +++ b/source/Core/SceneExporter/Text/TextRsmConfig.cpp @@ -0,0 +1,30 @@ +#include "TextRsmConfig.hpp" + +#include +#include + +namespace castor +{ + using namespace castor3d; + + TextWriter< RsmConfig >::TextWriter( String const & tabs ) + : castor::TextWriterT< RsmConfig >{ tabs } + { + } + + bool TextWriter< RsmConfig >::operator()( RsmConfig const & object + , StringStream & file ) + { + log::info << tabs() << cuT( "Writing RsmConfig" ) << std::endl; + auto result = false; + + if ( auto block{ beginBlock( file, cuT( "rsm_config" ) ) } ) + { + result = write( file, cuT( "intensity" ), object.intensity ) + && write( file, cuT( "max_radius" ), object.maxRadius ) + && write( file, cuT( "sample_count" ), object.sampleCount ); + } + + return result; + } +} diff --git a/source/Core/SceneExporter/Text/TextRsmConfig.hpp b/source/Core/SceneExporter/Text/TextRsmConfig.hpp new file mode 100644 index 0000000000..5783cfeb9f --- /dev/null +++ b/source/Core/SceneExporter/Text/TextRsmConfig.hpp @@ -0,0 +1,24 @@ +/* +See LICENSE file in root folder +*/ +#ifndef ___CSE_TextRsmConfig_H___ +#define ___CSE_TextRsmConfig_H___ + +#include + +#include + +namespace castor +{ + template<> + class TextWriter< castor3d::RsmConfig > + : public TextWriterT< castor3d::RsmConfig > + { + public: + explicit TextWriter( String const & tabs ); + bool operator()( castor3d::RsmConfig const & config + , castor::StringStream & file )override; + }; +} + +#endif diff --git a/tools/GuiCommon/Properties/TreeItems/LightTreeItemProperty.hpp b/tools/GuiCommon/Properties/TreeItems/LightTreeItemProperty.hpp index 5d8b125a3f..3be12a48cb 100644 --- a/tools/GuiCommon/Properties/TreeItems/LightTreeItemProperty.hpp +++ b/tools/GuiCommon/Properties/TreeItems/LightTreeItemProperty.hpp @@ -13,6 +13,7 @@ namespace GuiCommon enum class GIType { eNone, + eRSM, eLPV, eLPVG, eLLPV,