From 7bc1f522a51b15e87ad40c786f6868295261970d Mon Sep 17 00:00:00 2001 From: Panos Karabelas Date: Fri, 1 Dec 2023 04:32:56 +0000 Subject: [PATCH] [Forest] Enabled subsurface scattering for vegetation (a very basic version for now) --- data/shaders/brdf.hlsl | 4 +-- data/shaders/common.hlsl | 6 ++-- data/shaders/common_structs.hlsl | 3 +- data/shaders/light.hlsl | 49 +++++++++++++++++-------------- editor/Widgets/Properties.cpp | 2 +- readme.md | 28 ++++++++---------- runtime/RHI/RHI_Implemenation.cpp | 2 +- runtime/Rendering/Material.cpp | 2 +- runtime/Rendering/Renderer.cpp | 34 +++++++++++---------- runtime/World/Entity.cpp | 3 +- 10 files changed, 69 insertions(+), 64 deletions(-) diff --git a/data/shaders/brdf.hlsl b/data/shaders/brdf.hlsl index 6817ac788..f87c0fe2f 100644 --- a/data/shaders/brdf.hlsl +++ b/data/shaders/brdf.hlsl @@ -165,12 +165,12 @@ float3 BRDF_Specular_Isotropic(inout Surface surface, AngularInfo angular_info) float3 BRDF_Specular_Anisotropic(inout Surface surface, AngularInfo angular_info) { - // Construct TBN from the normal + // construct TBN from the normal float3 t, b; find_best_axis_vectors(surface.normal, t, b); float3x3 TBN = float3x3(t, b, surface.normal); - // Rotate tangent and bitagent + // rotate tangent and bitagent float rotation = max(surface.anisotropic_rotation * PI2, FLT_MIN); // convert material property to a full rotation float2 direction = float2(cos(rotation), sin(rotation)); // convert rotation to direction t = normalize(mul(float3(direction, 0.0f), TBN).xyz); // compute direction derived tangent diff --git a/data/shaders/common.hlsl b/data/shaders/common.hlsl index bd4b43a64..40a674be5 100644 --- a/data/shaders/common.hlsl +++ b/data/shaders/common.hlsl @@ -565,9 +565,9 @@ float draw_circle_view_space(float3 origin, float radius, float2 uv) ------------------------------------------------------------------------------*/ float3 compute_diffuse_energy(float3 F, float metallic) { - float3 kS = F; // The energy of light that gets reflected - Equal to Fresnel - float3 kD = 1.0f - kS; // Remaining energy, light that gets refracted - kD *= 1.0f - metallic; // Multiply kD by the inverse metalness such that only non-metals have diffuse lighting + float3 kS = F; // the energy of light that gets reflected - equal to fresnel + float3 kD = 1.0f - kS; // remaining energy, light that gets refracted + kD *= 1.0f - metallic; // multiply kD by the inverse metalness such that only non-metals have diffuse lighting return kD; } diff --git a/data/shaders/common_structs.hlsl b/data/shaders/common_structs.hlsl index 6c5dd2deb..a83f5261d 100644 --- a/data/shaders/common_structs.hlsl +++ b/data/shaders/common_structs.hlsl @@ -101,8 +101,7 @@ struct Surface specular_energy = 1.0f; diffuse_energy = 1.0f; - // Roughness is authored as perceptual roughness; as is convention, - // convert to material roughness by squaring the perceptual roughness. + // roughness is authored as perceptual roughness, as is convention roughness_alpha = roughness * roughness; roughness_alpha_squared = roughness_alpha * roughness_alpha; diff --git a/data/shaders/light.hlsl b/data/shaders/light.hlsl index d24c0c586..c631141d7 100644 --- a/data/shaders/light.hlsl +++ b/data/shaders/light.hlsl @@ -26,16 +26,22 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "fog.hlsl" //============================ -float3 SubsurfaceScattering(Surface surface, AngularInfo angular_info) +float3 subsurface_scattering(Surface surface, Light light) { - float sss_strength = 0.2f * surface.subsurface_scattering; - float sss_width = 0.5 * surface.subsurface_scattering; + float sss_strength = 0.05f * surface.subsurface_scattering; + float sss_width = 4.0f; - float backlit = max(dot(surface.normal, angular_info.l), 0); + // calculate backlit effect - light penetrating through the surface + float backlit = max(dot(surface.normal, -light.to_pixel), 0); float sss_effect = exp(-backlit * sss_width) * sss_strength; - float3 sss_color = float3(0.8, 1.0, 0.7); // green-yellow color - vegetation - return surface.albedo * sss_color * sss_effect; + // angle based color + float3 color_a = float3(0.6, 0.8, 0.5); + float3 color_b = float3(0.3, 0.6, 0.2); + float angle_factor = pow(backlit, 1.5f); + float3 sss_color = lerp(color_a, color_b, angle_factor); + + return surface.albedo * sss_color * sss_effect * light.color * light.intensity; } [numthreads(THREAD_GROUP_COUNT_X, THREAD_GROUP_COUNT_Y, 1)] @@ -88,56 +94,55 @@ void mainCS(uint3 thread_id : SV_DispatchThreadID) float3 light_specular = 0.0f; // reflectance equation + float3 light_subsurface = 0.0f; if (!surface.is_sky()) { AngularInfo angular_info; angular_info.Build(light, surface); // specular - if (surface.anisotropic == 0.0f) + if (surface.anisotropic > 0.0f) { - light_specular += BRDF_Specular_Isotropic(surface, angular_info); + light_specular += BRDF_Specular_Anisotropic(surface, angular_info); } else { - light_specular += BRDF_Specular_Anisotropic(surface, angular_info); + light_specular += BRDF_Specular_Isotropic(surface, angular_info); } // specular clearcoat - if (surface.clearcoat != 0.0f) + if (surface.clearcoat > 0.0f) { light_specular += BRDF_Specular_Clearcoat(surface, angular_info); } // sheen - if (surface.sheen != 0.0f) + if (surface.sheen > 0.0f) { light_specular += BRDF_Specular_Sheen(surface, angular_info); } // subsurface scattering - if (surface.subsurface_scattering != 0.0f) + if (surface.subsurface_scattering > 0.0f) { - light_diffuse += SubsurfaceScattering(surface, angular_info); + light_subsurface += subsurface_scattering(surface, light); } // diffuse light_diffuse += BRDF_Diffuse(surface, angular_info); - // tone down diffuse such as that only non metals have it + // energy conservation - only non metals have diffuse light_diffuse *= surface.diffuse_energy; } float3 emissive = surface.emissive * surface.albedo; // diffuse and specular - tex_uav[thread_id.xy] += float4(saturate_11(light_diffuse * light.radiance + emissive), 1.0f); + tex_uav[thread_id.xy] += float4(saturate_11(light_diffuse * light.radiance + emissive + light_subsurface), 1.0f); tex_uav2[thread_id.xy] += float4(saturate_11(light_specular * light.radiance), 1.0f); - - // volumetric - //if (light_is_volumetric() && is_fog_volumetric_enabled()) - //{ - // float3 light_fog = VolumetricLighting(surface, light); - // tex_uav3[thread_id.xy] += float4(saturate_11(light_fog), 1.0f); - //} } + + + + + diff --git a/editor/Widgets/Properties.cpp b/editor/Widgets/Properties.cpp index db6f1df0f..d44ffbf77 100644 --- a/editor/Widgets/Properties.cpp +++ b/editor/Widgets/Properties.cpp @@ -777,7 +777,7 @@ void Properties::ShowMaterial(Material* material) const show_property("Sheen", "Amount of soft velvet like reflection near edges", MaterialTexture::Undefined, MaterialProperty::Sheen); show_property("Sheen tint", "Mix between white and using base color for sheen reflection", MaterialTexture::Undefined, MaterialProperty::SheenTint); show_property("Subsurface scattering","Amount of translucency", MaterialTexture::Undefined, MaterialProperty::MultiplierSubsurfaceScattering); - show_property("IOR", "Index of refraction", MaterialTexture::Undefined, MaterialProperty::Ior); + show_property("IOR", "Index of refraction, color must be transparent for this have any effect", MaterialTexture::Undefined, MaterialProperty::Ior); } // UV diff --git a/readme.md b/readme.md index 06d2441d7..a4e1c2195 100644 --- a/readme.md +++ b/readme.md @@ -40,29 +40,27 @@ Upon launching the engine, you'll be greeted with a selection of default worlds # Features #### Rendering - 128-byte push constant buffer for lightning fast CPU to GPU data transfer. -- AMD FidelityFX suite for enhanced visuals and performance. -- Bloom effect inspired by Resident Evil 2's RE Engine. -- Unified deferred rendering with transparency (BSDF with same render path and shaders). -- Camera-controlled depth of field, motion blur and chromatic aberration. +- On the fly GPU-based mip generation - with only one dispatch. +- Unified deferred rendering with transparency (BSDF with same render path). +- Vulkan and DirectX 12 (WIP) backends with universal HLSL shaders. +- Advanced shadow features with penumbra and colored translucency. +- Screen space global illumination, reflections, and shadows. +- Physical light units (intensity from lumens and color from kelvin). - Comprehensive debug rendering options. - Frustum culling. -- Physical light units (intensity from lumens and color from kelvin). - Physically based camera. - Atmospheric scattering. -- GPU-based mip generation (single dispatch). -- Advanced shadow features with penumbra and colored translucency. -- Screen space global illumination, reflections, and shadows. - Temporal anti-aliasing for smooth visuals. -- Vulkan and DirectX 12 backends with universal HLSL shaders. -- Volumetric lighting for atmospheric effects. -#### System -- One-click build for easy setup. -- Entity-component and event systems for flexible architecture. +- Post-process effects like fxaa, bloom, motion-blur, depth of field, chromatic aberration etc. +- AMD FidelityFX features like FSR 2, SPD, etc. +#### General +- One-click project generation for easy setup. - Universal input support, including mouse, keyboard, and controllers (tested with a PS5 controller). - Comprehensive physics features. -- CPU & GPU profiling for performance tuning. +- CPU & GPU profiling. - XML support for data handling. -- Thread pool for efficient multitasking. +- Thread pool for that can consume any workload. +- Entity-component, event systems and most things you'll expect to find in a modern engine. #### Formats - Wide file format support: 10+ for fonts, 20+ for audio, 30+ for images, and 40+ for models. diff --git a/runtime/RHI/RHI_Implemenation.cpp b/runtime/RHI/RHI_Implemenation.cpp index 60733ffd4..821038831 100644 --- a/runtime/RHI/RHI_Implemenation.cpp +++ b/runtime/RHI/RHI_Implemenation.cpp @@ -55,7 +55,7 @@ namespace Spartan bool RHI_Context::validation = true; bool RHI_Context::gpu_markers = true; bool RHI_Context::gpu_profiling = true; - bool RHI_Context::renderdoc = true; + bool RHI_Context::renderdoc = false; #else bool RHI_Context::validation = false; bool RHI_Context::gpu_markers = false; diff --git a/runtime/Rendering/Material.cpp b/runtime/Rendering/Material.cpp index 47e468012..0c45e320a 100644 --- a/runtime/Rendering/Material.cpp +++ b/runtime/Rendering/Material.cpp @@ -80,7 +80,7 @@ namespace Spartan } } } - } + } Material::Material() : IResource(ResourceType::Material) { diff --git a/runtime/Rendering/Renderer.cpp b/runtime/Rendering/Renderer.cpp index 57302faee..7b9988312 100644 --- a/runtime/Rendering/Renderer.cpp +++ b/runtime/Rendering/Renderer.cpp @@ -123,23 +123,23 @@ namespace Spartan // are set into a this array of structs, which is then accessed as a structured buffer from the GPU namespace material_properties { - array properties; + array data; bool is_dirty = true; void update(const Material* material) { - Sb_MaterialProperties mat = {}; - mat.anisotropic = material->GetProperty(MaterialProperty::Anisotropic); - mat.anisotropic_rotation = material->GetProperty(MaterialProperty::AnisotropicRotation); - mat.clearcoat = material->GetProperty(MaterialProperty::Clearcoat); - mat.clearcoat_roughness = material->GetProperty(MaterialProperty::Clearcoat_Roughness); - mat.sheen = material->GetProperty(MaterialProperty::Sheen); - mat.sheen_tint = material->GetProperty(MaterialProperty::SheenTint); - mat.subsurface_scattering = material->GetProperty(MaterialProperty::MultiplierSubsurfaceScattering); - mat.ior = material->GetProperty(MaterialProperty::Ior); - - uint32_t index = static_cast(material->GetObjectId() % properties.size()); - properties[index] = mat; + Sb_MaterialProperties properties = {}; + properties.anisotropic = material->GetProperty(MaterialProperty::Anisotropic); + properties.anisotropic_rotation = material->GetProperty(MaterialProperty::AnisotropicRotation); + properties.clearcoat = material->GetProperty(MaterialProperty::Clearcoat); + properties.clearcoat_roughness = material->GetProperty(MaterialProperty::Clearcoat_Roughness); + properties.sheen = material->GetProperty(MaterialProperty::Sheen); + properties.sheen_tint = material->GetProperty(MaterialProperty::SheenTint); + properties.subsurface_scattering = material->GetProperty(MaterialProperty::MultiplierSubsurfaceScattering); + properties.ior = material->GetProperty(MaterialProperty::Ior); + + uint32_t index = static_cast(material->GetObjectId() % data.size()); + data[index] = properties; } void update(vector>& entities) @@ -158,9 +158,13 @@ namespace Spartan void refresh(unordered_map>>& renderables) { - properties.fill(Sb_MaterialProperties{}); + data.fill(Sb_MaterialProperties{}); + update(renderables[Renderer_Entity::Geometry]); + update(renderables[Renderer_Entity::GeometryInstanced]); update(renderables[Renderer_Entity::GeometryTransparent]); + update(renderables[Renderer_Entity::GeometryTransparentInstanced]); + is_dirty = true; } } @@ -958,7 +962,7 @@ namespace Spartan // update material array if (material_properties::is_dirty) { - GetStructuredBuffer(Renderer_StructuredBuffer::Material)->Update(&material_properties::properties[0]); + GetStructuredBuffer(Renderer_StructuredBuffer::Material)->Update(&material_properties::data[0]); material_properties::is_dirty = false; } diff --git a/runtime/World/Entity.cpp b/runtime/World/Entity.cpp index 402ed8dc8..da915776f 100644 --- a/runtime/World/Entity.cpp +++ b/runtime/World/Entity.cpp @@ -613,10 +613,9 @@ namespace Spartan // this is a recursive function, the children will also find their own children and so on void Entity::AcquireChildren() { - m_child_mutex.lock(); + lock_guard lock(m_child_mutex); m_children.clear(); m_children.shrink_to_fit(); - m_child_mutex.unlock(); auto entities = World::GetAllEntities(); for (const auto& entity : entities)