diff --git a/Effects/Deferred_ToonEffect.cs b/Effects/Deferred_ToonEffect.cs index 1b1deea..031f8e7 100644 --- a/Effects/Deferred_ToonEffect.cs +++ b/Effects/Deferred_ToonEffect.cs @@ -29,6 +29,8 @@ namespace Kav EffectParameter viewMatrixParam; + EffectParameter shaderIndexParam; + public Texture2D GPosition { get; set; } public Texture2D GAlbedo { get; set; } public Texture2D GNormal { get; set; } @@ -53,6 +55,19 @@ namespace Kav public Matrix ViewMatrix { get; set; } + private bool ditheredShadowValue = false; + public bool DitheredShadows + { + get { return ditheredShadowValue; } + set + { + ditheredShadowValue = value; + CalculateShaderIndex(); + } + } + + private int shaderIndex = 0; + public Deferred_ToonEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.Deferred_ToonEffect) { CascadeFarPlanes = new float[4]; @@ -84,6 +99,8 @@ namespace Kav lightSpaceMatrixFourParam.SetValue(LightSpaceMatrixFour); viewMatrixParam.SetValue(ViewMatrix); + + shaderIndexParam.SetValue(shaderIndex); } void CacheEffectParameters() @@ -111,6 +128,20 @@ namespace Kav lightSpaceMatrixFourParam = Parameters["LightSpaceMatrixFour"]; viewMatrixParam = Parameters["ViewMatrix"]; + + shaderIndexParam = Parameters["ShaderIndex"]; + } + + private void CalculateShaderIndex() + { + if (ditheredShadowValue) + { + shaderIndex = 1; + } + else + { + shaderIndex = 0; + } } } } diff --git a/Effects/FXB/Deferred_ToonEffect.fxb b/Effects/FXB/Deferred_ToonEffect.fxb index 685bdea..529d086 100644 --- a/Effects/FXB/Deferred_ToonEffect.fxb +++ b/Effects/FXB/Deferred_ToonEffect.fxb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1d94e2b3520ef29a3de94389bb42b949f07af8e19cbac1fdd170e6ae116f4142 -size 7344 +oid sha256:78552dce830d09b83694863355e51d4b2eaa31fafb11a16a207f8b42a6d004e5 +size 10964 diff --git a/Effects/HLSL/Deferred_ToonEffect.fx b/Effects/HLSL/Deferred_ToonEffect.fx index 3d8ac3f..62fbcad 100644 --- a/Effects/HLSL/Deferred_ToonEffect.fx +++ b/Effects/HLSL/Deferred_ToonEffect.fx @@ -164,8 +164,51 @@ float IntensityBanding(float NdotL) } } +float4 FlatShadow(PixelInput input) : SV_TARGET0 +{ + float2 screenPosition = input.Position.xy; + float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb; + float3 normal = SAMPLE_TEXTURE(gNormal, input.TexCoord).xyz; + float3 albedo = SAMPLE_TEXTURE(gAlbedo, input.TexCoord).rgb; + float2 metallicRoughness = SAMPLE_TEXTURE(gMetallicRoughness, input.TexCoord).rg; + + // the lower the glossiness, the sharper the specular highlight + float glossiness = lerp(64, 16, 1.0 - metallicRoughness.r); + + float3 V = normalize(EyePosition - worldPosition); + float3 L = normalize(DirectionalLightDirection); + float3 N = normalize(normal); + float3 H = normalize(V + L); + + float NdotL = dot(N, L); + float NdotH = max(dot(N, H), 0.0); + + float lightIntensity = IntensityBanding(NdotL); + float3 light = lightIntensity * DirectionalLightColor; + + float specularIntensity = pow(NdotH * lightIntensity, glossiness * glossiness); + float specularSmooth = smoothstep(0.005, 0.01, specularIntensity); + + float3 specular = specularSmooth * float3(1.0, 1.0, 1.0); + + if (metallicRoughness.r == 0.0) { specular = float3(0.0, 0.0, 0.0); } + + float3 rimColor = float3(1.0, 1.0, 1.0); + float rimThreshold = 0.1; + float rimAmount = 1 - metallicRoughness.g; + float rimDot = 1 - dot(V, N); + float rimIntensity = rimDot * pow(max(NdotL, 0.0), rimThreshold); + rimIntensity = smoothstep(rimAmount - 0.01, rimAmount + 0.01, rimIntensity); + float3 rim = rimIntensity * rimColor; + + float shadow = ComputeShadow(worldPosition, N, L); + float3 color = albedo * (light + specular + rim) * shadow; + + return float4(color, 1.0); +} + // FIXME: organize this -float4 main_ps(PixelInput input) : SV_TARGET0 +float4 DitheredShadow(PixelInput input) : SV_TARGET0 { float2 screenPosition = input.Position.xy; float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb; @@ -219,11 +262,24 @@ float4 main_ps(PixelInput input) : SV_TARGET0 return float4(color, 1.0); } +PixelShader PSArray[2] = +{ + compile ps_3_0 FlatShadow(), + compile ps_3_0 DitheredShadow() +}; + +int PSIndices[2] = +{ + 0, 1 +}; + +int ShaderIndex = 0; + Technique Deferred_Toon { Pass { VertexShader = compile vs_3_0 main_vs(); - PixelShader = compile ps_3_0 main_ps(); + PixelShader = (PSArray[PSIndices[ShaderIndex]]); } } diff --git a/Renderer.cs b/Renderer.cs index 747d88b..d48a36a 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -348,6 +348,8 @@ namespace Kav Deferred_ToonEffect.GNormal = gNormal; Deferred_ToonEffect.GMetallicRoughness = gMetallicRoughness; + Deferred_ToonEffect.DitheredShadows = true; + Deferred_ToonEffect.EyePosition = camera.Position; Deferred_ToonEffect.DirectionalLightDirection = directionalLight.Direction; Deferred_ToonEffect.DirectionalLightColor =