Add new Custom Lit shading model for custom lighting in materials (eg. Cel Shading)
This commit is contained in:
@@ -28,6 +28,13 @@ TextureCube SkyLightTexture : register(t__SRV__);
|
||||
Buffer<float4> ShadowsBuffer : register(t__SRV__);
|
||||
Texture2D<float> 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
/// </summary>
|
||||
Foliage = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
CustomLit = 5,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user