Skip to content

Commit

Permalink
[Forest] Enabled subsurface scattering for vegetation (a very basic v…
Browse files Browse the repository at this point in the history
…ersion for now)
  • Loading branch information
PanosK92 committed Dec 1, 2023
1 parent 8b77de1 commit 7bc1f52
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 64 deletions.
4 changes: 2 additions & 2 deletions data/shaders/brdf.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions data/shaders/common.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 1 addition & 2 deletions data/shaders/common_structs.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
49 changes: 27 additions & 22 deletions data/shaders/light.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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);
//}
}





2 changes: 1 addition & 1 deletion editor/Widgets/Properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 13 additions & 15 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
2 changes: 1 addition & 1 deletion runtime/RHI/RHI_Implemenation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion runtime/Rendering/Material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ namespace Spartan
}
}
}
}
}

Material::Material() : IResource(ResourceType::Material)
{
Expand Down
34 changes: 19 additions & 15 deletions runtime/Rendering/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Sb_MaterialProperties, 1024> properties;
array<Sb_MaterialProperties, 1024> 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<uint32_t>(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<uint32_t>(material->GetObjectId() % data.size());
data[index] = properties;
}

void update(vector<shared_ptr<Entity>>& entities)
Expand All @@ -158,9 +158,13 @@ namespace Spartan

void refresh(unordered_map<Renderer_Entity, vector<shared_ptr<Entity>>>& 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;
}
}
Expand Down Expand Up @@ -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;
}

Expand Down
3 changes: 1 addition & 2 deletions runtime/World/Entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 7bc1f52

Please sign in to comment.