diff --git a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl index 2db55111b..263859075 100644 --- a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl +++ b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl @@ -28,6 +28,13 @@ TextureCube SkyLightTexture : register(t__SRV__); Buffer ShadowsBuffer : register(t__SRV__); Texture2D ShadowMap : register(t__SRV__); @4// Forward Shading: Utilities +// Public accessors for lighting data, use them as data binding might change but those methods will remain. +LightData GetDirectionalLight() { return DirectionalLight; } +LightData GetSkyLight() { return SkyLight; } +ProbeData GetEnvironmentProbe() { return EnvironmentProbe; } +ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; } +uint GetLocalLightsCount() { return LocalLightsCount; } +LightData GetLocalLight(uint i) { return LocalLights[i]; } @5// Forward Shading: Shaders // Pixel Shader function for Forward Pass @@ -76,9 +83,8 @@ void PS_Forward( gBuffer.ShadingModel = MATERIAL_SHADING_MODEL; // Calculate lighting from a single directional light - float4 shadowMask = 1.0f; ShadowSample shadow = SampleDirectionalLightShadow(DirectionalLight, ShadowsBuffer, ShadowMap, gBuffer); - shadowMask = GetShadowMask(shadow); + float4 shadowMask = GetShadowMask(shadow); float4 light = GetLighting(ViewPos, DirectionalLight, gBuffer, shadowMask, false, false); // Calculate lighting from sky light diff --git a/Source/Editor/Surface/Archetypes/Material.cs b/Source/Editor/Surface/Archetypes/Material.cs index c9066eaa5..e46038639 100644 --- a/Source/Editor/Surface/Archetypes/Material.cs +++ b/Source/Editor/Surface/Archetypes/Material.cs @@ -124,7 +124,8 @@ namespace FlaxEditor.Surface.Archetypes case MaterialDomain.Particle: case MaterialDomain.Deformable: { - bool isNotUnlit = info.ShadingModel != MaterialShadingModel.Unlit; + bool isNotUnlit = info.ShadingModel != MaterialShadingModel.Unlit && info.ShadingModel != MaterialShadingModel.CustomLit; + bool isOpaque = info.BlendMode == MaterialBlendMode.Opaque; bool withTess = info.TessellationMode != TessellationMethod.None; GetBox(MaterialNodeBoxes.Color).IsActive = isNotUnlit; @@ -135,8 +136,8 @@ namespace FlaxEditor.Surface.Archetypes GetBox(MaterialNodeBoxes.Roughness).IsActive = isNotUnlit; GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = isNotUnlit; GetBox(MaterialNodeBoxes.Normal).IsActive = isNotUnlit; - GetBox(MaterialNodeBoxes.Opacity).IsActive = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage || info.BlendMode != MaterialBlendMode.Opaque; - GetBox(MaterialNodeBoxes.Refraction).IsActive = info.BlendMode != MaterialBlendMode.Opaque; + GetBox(MaterialNodeBoxes.Opacity).IsActive = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage || !isOpaque; + GetBox(MaterialNodeBoxes.Refraction).IsActive = !isOpaque; GetBox(MaterialNodeBoxes.PositionOffset).IsActive = true; GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = withTess; GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = withTess; diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp index ce457c862..1e36b36ae 100644 --- a/Source/Engine/Content/Assets/Material.cpp +++ b/Source/Engine/Content/Assets/Material.cpp @@ -414,16 +414,18 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options) // Prepare auto& info = _shaderHeader.Material.Info; const bool isSurfaceOrTerrainOrDeformable = info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Terrain || info.Domain == MaterialDomain::Deformable; + const bool isOpaque = info.BlendMode == MaterialBlendMode::Opaque; const bool useCustomData = info.ShadingModel == MaterialShadingModel::Subsurface || info.ShadingModel == MaterialShadingModel::Foliage; - const bool useForward = ((info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable) && info.BlendMode != MaterialBlendMode::Opaque) || info.Domain == MaterialDomain::Particle; + const bool useForward = ((info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable) && !isOpaque) || info.Domain == MaterialDomain::Particle; const bool useTess = info.TessellationMode != TessellationMethod::None && RenderTools::CanSupportTessellation(options.Profile) && isSurfaceOrTerrainOrDeformable; const bool useDistortion = (info.Domain == MaterialDomain::Surface || info.Domain == MaterialDomain::Deformable || info.Domain == MaterialDomain::Particle) && - info.BlendMode != MaterialBlendMode::Opaque && + !isOpaque && EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseRefraction) && (info.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == MaterialFeaturesFlags::None; + const MaterialShadingModel shadingModel = info.ShadingModel == MaterialShadingModel::CustomLit ? MaterialShadingModel::Unlit : info.ShadingModel; // @formatter:off static const char* Numbers[] = @@ -435,7 +437,7 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options) // Setup shader macros options.Macros.Add({ "MATERIAL_DOMAIN", Numbers[(int32)info.Domain] }); options.Macros.Add({ "MATERIAL_BLEND", Numbers[(int32)info.BlendMode] }); - options.Macros.Add({ "MATERIAL_SHADING_MODEL", Numbers[(int32)info.ShadingModel] }); + options.Macros.Add({ "MATERIAL_SHADING_MODEL", Numbers[(int32)shadingModel] }); options.Macros.Add({ "MATERIAL_MASKED", Numbers[EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseMask) ? 1 : 0] }); options.Macros.Add({ "DECAL_BLEND_MODE", Numbers[(int32)info.DecalBlendingMode] }); options.Macros.Add({ "USE_EMISSIVE", Numbers[EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseEmissive) ? 1 : 0] }); @@ -492,7 +494,7 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options) options.Macros.Add({ "IS_PARTICLE", Numbers[info.Domain == MaterialDomain::Particle ? 1 : 0] }); options.Macros.Add({ "IS_DEFORMABLE", Numbers[info.Domain == MaterialDomain::Deformable ? 1 : 0] }); options.Macros.Add({ "USE_FORWARD", Numbers[useForward ? 1 : 0] }); - options.Macros.Add({ "USE_DEFERRED", Numbers[isSurfaceOrTerrainOrDeformable && info.BlendMode == MaterialBlendMode::Opaque ? 1 : 0] }); + options.Macros.Add({ "USE_DEFERRED", Numbers[isSurfaceOrTerrainOrDeformable && isOpaque ? 1 : 0] }); options.Macros.Add({ "USE_DISTORTION", Numbers[useDistortion ? 1 : 0] }); #endif } diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index c15ff5ef2..4e9622a01 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -42,6 +42,8 @@ void DeferredMaterialShader::Bind(BindParameters& params) // Setup features const bool useLightmap = _info.BlendMode == MaterialBlendMode::Opaque && LightmapFeature::Bind(params, cb, srv); + if (_info.ShadingModel == MaterialShadingModel::CustomLit) + ForwardShadingFeature::Bind(params, cb, srv); // Setup parameters MaterialParameter::BindMeta bindMeta; diff --git a/Source/Engine/Graphics/Materials/MaterialInfo.h b/Source/Engine/Graphics/Materials/MaterialInfo.h index 2a57b5f3d..69a9bd0a6 100644 --- a/Source/Engine/Graphics/Materials/MaterialInfo.h +++ b/Source/Engine/Graphics/Materials/MaterialInfo.h @@ -103,6 +103,11 @@ API_ENUM() enum class MaterialShadingModel : byte /// The foliage material. Intended for foliage materials like leaves and grass that need light scattering to transport simulation through the thin object. /// Foliage = 3, + + /// + /// The custom lit shader that calculates own lighting such as Cel Shading. It has access to the scene lights data during both GBuffer and Forward pass rendering. + /// + CustomLit = 5, }; /// diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp index 5950676a3..2aea40c94 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp @@ -184,28 +184,29 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo return true; \ } \ } + const bool isOpaque = materialInfo.BlendMode == MaterialBlendMode::Opaque; switch (baseLayer->Domain) { case MaterialDomain::Surface: if (materialInfo.TessellationMode != TessellationMethod::None) ADD_FEATURE(TessellationFeature); - if (materialInfo.BlendMode == MaterialBlendMode::Opaque) + if (isOpaque) ADD_FEATURE(MotionVectorsFeature); - if (materialInfo.BlendMode == MaterialBlendMode::Opaque) + if (isOpaque) ADD_FEATURE(LightmapFeature); - if (materialInfo.BlendMode == MaterialBlendMode::Opaque) + if (isOpaque) ADD_FEATURE(DeferredShadingFeature); - if (materialInfo.BlendMode != MaterialBlendMode::Opaque && (materialInfo.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == MaterialFeaturesFlags::None) + if (!isOpaque && (materialInfo.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == MaterialFeaturesFlags::None) ADD_FEATURE(DistortionFeature); - if (materialInfo.BlendMode != MaterialBlendMode::Opaque && EnumHasAnyFlags(materialInfo.FeaturesFlags, MaterialFeaturesFlags::GlobalIllumination)) + if (!isOpaque && EnumHasAnyFlags(materialInfo.FeaturesFlags, MaterialFeaturesFlags::GlobalIllumination)) { ADD_FEATURE(GlobalIlluminationFeature); - // SDF Reflections is only valid when both GI and SSR is enabled - if (materialInfo.BlendMode != MaterialBlendMode::Opaque && EnumHasAnyFlags(materialInfo.FeaturesFlags, MaterialFeaturesFlags::ScreenSpaceReflections)) + // SDF Reflections is only valid when both GI and SSR are enabled + if (EnumHasAnyFlags(materialInfo.FeaturesFlags, MaterialFeaturesFlags::ScreenSpaceReflections)) ADD_FEATURE(SDFReflectionsFeature); } - if (materialInfo.BlendMode != MaterialBlendMode::Opaque) + if (materialInfo.BlendMode != MaterialBlendMode::Opaque || materialInfo.ShadingModel == MaterialShadingModel::CustomLit) ADD_FEATURE(ForwardShadingFeature); break; case MaterialDomain::Terrain: @@ -215,16 +216,16 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo ADD_FEATURE(DeferredShadingFeature); break; case MaterialDomain::Particle: - if (materialInfo.BlendMode != MaterialBlendMode::Opaque && (materialInfo.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == MaterialFeaturesFlags::None) + if (!isOpaque && (materialInfo.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == MaterialFeaturesFlags::None) ADD_FEATURE(DistortionFeature); - if (materialInfo.BlendMode != MaterialBlendMode::Opaque && EnumHasAnyFlags(materialInfo.FeaturesFlags, MaterialFeaturesFlags::GlobalIllumination)) + if (!isOpaque && EnumHasAnyFlags(materialInfo.FeaturesFlags, MaterialFeaturesFlags::GlobalIllumination)) ADD_FEATURE(GlobalIlluminationFeature); ADD_FEATURE(ForwardShadingFeature); break; case MaterialDomain::Deformable: if (materialInfo.TessellationMode != TessellationMethod::None) ADD_FEATURE(TessellationFeature); - if (materialInfo.BlendMode == MaterialBlendMode::Opaque) + if (isOpaque) ADD_FEATURE(DeferredShadingFeature); if (materialInfo.BlendMode != MaterialBlendMode::Opaque) ADD_FEATURE(ForwardShadingFeature); diff --git a/Source/Shaders/LightingCommon.hlsl b/Source/Shaders/LightingCommon.hlsl index 807d6a71d..f09572310 100644 --- a/Source/Shaders/LightingCommon.hlsl +++ b/Source/Shaders/LightingCommon.hlsl @@ -62,8 +62,8 @@ void GetRadialLightAttenuation( float distanceBiasSqr, float3 toLight, float3 L, - inout float NoL, - inout float attenuation) + out float NoL, + out float attenuation) { // Distance attenuation if (lightData.InverseSquared) @@ -104,6 +104,20 @@ void GetRadialLightAttenuation( } } +// Calculates radial light (point or spot) attenuation factors (distance, spot and radius mask) +void GetRadialLightAttenuation( + LightData lightData, + bool isSpotLight, + float3 toLight, + float3 N, + out float NoL, + out float attenuation) +{ + float distanceSqr = dot(toLight, toLight); + float3 L = toLight * rsqrt(distanceSqr); + GetRadialLightAttenuation(lightData, isSpotLight, N, distanceSqr, 1, toLight, L, NoL, attenuation); +} + // Find representative incoming light direction and energy modification float AreaLightSpecular(LightData lightData, float roughness, inout float3 toLight, inout float3 L, float3 V, half3 N) {