From 565be374bbb539ee652d0fa3b240bafb066bab18 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Thu, 1 Oct 2020 14:52:19 -0700 Subject: [PATCH] basic toon shading + controllable ambient light setting --- Effects/DeferredPBR_AmbientLightEffect.cs | 11 ++- Effects/Deferred_ToonEffect.cs | 47 +++++++++ .../FXB/DeferredPBR_AmbientLightEffect.fxb | 4 +- Effects/FXB/Deferred_ToonEffect.fxb | 3 + .../HLSL/DeferredPBR_AmbientLightEffect.fx | 8 +- Effects/HLSL/Deferred_ToonEffect.fx | 60 ++++++++++++ Kav.Core.csproj | 3 + Kav.Framework.csproj | 3 + Lights/AmbientLight.cs | 14 +++ Lights/DirectionalLight.cs | 6 +- Renderer.cs | 98 ++++++++++++++----- Resources.cs | 13 +++ 12 files changed, 240 insertions(+), 30 deletions(-) create mode 100644 Effects/Deferred_ToonEffect.cs create mode 100644 Effects/FXB/Deferred_ToonEffect.fxb create mode 100644 Effects/HLSL/Deferred_ToonEffect.fx create mode 100644 Lights/AmbientLight.cs diff --git a/Effects/DeferredPBR_AmbientLightEffect.cs b/Effects/DeferredPBR_AmbientLightEffect.cs index f1d5e31..8595426 100644 --- a/Effects/DeferredPBR_AmbientLightEffect.cs +++ b/Effects/DeferredPBR_AmbientLightEffect.cs @@ -1,3 +1,4 @@ +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace Kav @@ -8,9 +9,13 @@ namespace Kav EffectParameter gPositionParam; EffectParameter gAlbedoParam; + EffectParameter ambientColorParam; + public Texture2D GPosition { get; set; } public Texture2D GAlbedo { get; set; } + public Vector3 AmbientColor { get; set; } + public DeferredPBR_AmbientLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_AmbientLightEffect) { CacheEffectParameters(); @@ -20,12 +25,14 @@ namespace Kav { gPositionParam.SetValue(GPosition); gAlbedoParam.SetValue(GAlbedo); + ambientColorParam.SetValue(AmbientColor); } void CacheEffectParameters() { - gPositionParam = Parameters["gPosition"]; - gAlbedoParam = Parameters["gAlbedo"]; + gPositionParam = Parameters["gPosition"]; + gAlbedoParam = Parameters["gAlbedo"]; + ambientColorParam = Parameters["AmbientLightColor"]; } } } diff --git a/Effects/Deferred_ToonEffect.cs b/Effects/Deferred_ToonEffect.cs new file mode 100644 index 0000000..5b2cca3 --- /dev/null +++ b/Effects/Deferred_ToonEffect.cs @@ -0,0 +1,47 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Kav +{ + public class Deferred_ToonEffect : Effect + { + EffectParameter gPositionParam; + EffectParameter gAlbedoParam; + EffectParameter gNormalParam; + + EffectParameter eyePositionParam; + EffectParameter directionalLightDirectionParam; + + public Texture2D GPosition { get; set; } + public Texture2D GAlbedo { get; set; } + public Texture2D GNormal { get; set; } + + public Vector3 EyePosition { get; set; } + public Vector3 DirectionalLightDirection { get; set; } + + public Deferred_ToonEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.Deferred_ToonEffect) + { + CacheEffectParameters(); + } + + protected override void OnApply() + { + gPositionParam.SetValue(GPosition); + gAlbedoParam.SetValue(GAlbedo); + gNormalParam.SetValue(GNormal); + + eyePositionParam.SetValue(EyePosition); + directionalLightDirectionParam.SetValue(DirectionalLightDirection); + } + + void CacheEffectParameters() + { + gPositionParam = Parameters["gPosition"]; + gAlbedoParam = Parameters["gAlbedo"]; + gNormalParam = Parameters["gNormal"]; + + eyePositionParam = Parameters["EyePosition"]; + directionalLightDirectionParam = Parameters["DirectionalLightDirection"]; + } + } +} diff --git a/Effects/FXB/DeferredPBR_AmbientLightEffect.fxb b/Effects/FXB/DeferredPBR_AmbientLightEffect.fxb index 62de278..a439c6a 100644 --- a/Effects/FXB/DeferredPBR_AmbientLightEffect.fxb +++ b/Effects/FXB/DeferredPBR_AmbientLightEffect.fxb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0ea0cb071a1e53fec5058fae9919d376e408d33cd3de9485d42e1ebcbee85546 -size 1016 +oid sha256:244ded9c443bc10e538958075cabd14d2b066b9fd0743186ce620823380cb488 +size 1168 diff --git a/Effects/FXB/Deferred_ToonEffect.fxb b/Effects/FXB/Deferred_ToonEffect.fxb new file mode 100644 index 0000000..1dbb741 --- /dev/null +++ b/Effects/FXB/Deferred_ToonEffect.fxb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e49380a4f06e418f7056355d4b1426aa62d1025734c643c12ee9501c8a3d59b1 +size 1568 diff --git a/Effects/HLSL/DeferredPBR_AmbientLightEffect.fx b/Effects/HLSL/DeferredPBR_AmbientLightEffect.fx index 4144c8d..6c6e173 100644 --- a/Effects/HLSL/DeferredPBR_AmbientLightEffect.fx +++ b/Effects/HLSL/DeferredPBR_AmbientLightEffect.fx @@ -3,6 +3,12 @@ DECLARE_TEXTURE(gPosition, 0); DECLARE_TEXTURE(gAlbedo, 1); +BEGIN_CONSTANTS + +float3 AmbientLightColor _ps(c0) _cb(c0); + +END_CONSTANTS + struct VertexInput { float4 Position : POSITION; @@ -29,7 +35,7 @@ float4 ComputeColor( float3 worldPosition, float3 albedo ) { - float3 color = float3(0.03, 0.03, 0.03) * albedo; + float3 color = AmbientLightColor * albedo; return float4(color, 1.0); } diff --git a/Effects/HLSL/Deferred_ToonEffect.fx b/Effects/HLSL/Deferred_ToonEffect.fx new file mode 100644 index 0000000..7423236 --- /dev/null +++ b/Effects/HLSL/Deferred_ToonEffect.fx @@ -0,0 +1,60 @@ +#include "Macros.fxh" + +DECLARE_TEXTURE(gPosition, 0); +DECLARE_TEXTURE(gAlbedo, 1); +DECLARE_TEXTURE(gNormal, 2); + +BEGIN_CONSTANTS + +float3 EyePosition _ps(c0) _cb(c0); + +float3 DirectionalLightDirection _ps(c1) _cb(c1); +float3 AmbientLightColor _ps(c2) _cb(c2); + +END_CONSTANTS + +struct VertexInput +{ + float4 Position : POSITION; + float2 TexCoord : TEXCOORD; +}; + +struct PixelInput +{ + float4 Position : SV_POSITION; + float2 TexCoord : TEXCOORD0; +}; + +PixelInput main_vs(VertexInput input) +{ + PixelInput output; + + output.Position = input.Position; + output.TexCoord = input.TexCoord; + + return output; +} + +float4 main_ps(PixelInput input) : SV_TARGET0 +{ + float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb; + float3 normal = SAMPLE_TEXTURE(gNormal, input.TexCoord).xyz; + float3 albedo = SAMPLE_TEXTURE(gAlbedo, input.TexCoord).rgb; + + float3 V = normalize(EyePosition - worldPosition); + float3 L = normalize(DirectionalLightDirection); + float3 N = normalize(normal); + float NdotL = dot(N, L); + + float lightIntensity = (NdotL > 0.0) ? 1.0 : 0.0; + return float4(albedo * (lightIntensity, 1.0); +} + +Technique Deferred_Toon +{ + Pass + { + VertexShader = compile vs_3_0 main_vs(); + PixelShader = compile ps_3_0 main_ps(); + } +} diff --git a/Kav.Core.csproj b/Kav.Core.csproj index 327d7bb..b018e72 100644 --- a/Kav.Core.csproj +++ b/Kav.Core.csproj @@ -30,6 +30,9 @@ Kav.Resources.ToneMapEffect.fxb + + Kav.Resources.Deferred_ToonEffect.fxb + Kav.Resources.DeferredPBREffect.fxb diff --git a/Kav.Framework.csproj b/Kav.Framework.csproj index 2b2dd4f..c2d9079 100644 --- a/Kav.Framework.csproj +++ b/Kav.Framework.csproj @@ -30,6 +30,9 @@ Kav.Resources.ToneMapEffect.fxb + + Kav.Resources.Deferred_ToonEffect.fxb + Kav.Resources.DeferredPBREffect.fxb diff --git a/Lights/AmbientLight.cs b/Lights/AmbientLight.cs new file mode 100644 index 0000000..94bb42e --- /dev/null +++ b/Lights/AmbientLight.cs @@ -0,0 +1,14 @@ +using Microsoft.Xna.Framework; + +namespace Kav +{ + public struct AmbientLight + { + public Color Color { get; set; } + + public AmbientLight(Color color) + { + Color = color; + } + } +} diff --git a/Lights/DirectionalLight.cs b/Lights/DirectionalLight.cs index a22ab33..985745f 100644 --- a/Lights/DirectionalLight.cs +++ b/Lights/DirectionalLight.cs @@ -4,9 +4,9 @@ namespace Kav { public struct DirectionalLight { - public Vector3 Direction { get; set; } - public Color Color { get; set; } - public float Intensity { get; set; } + public Vector3 Direction { get; } + public Color Color { get; } + public float Intensity { get; } public Matrix View { diff --git a/Renderer.cs b/Renderer.cs index 63b34e5..5978274 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -24,6 +24,7 @@ namespace Kav private DeferredPBR_AmbientLightEffect DeferredAmbientLightEffect { get; } private DeferredPBR_PointLightEffect DeferredPointLightEffect { get; } private DeferredPBR_DirectionalLightEffect DeferredDirectionalLightEffect { get; } + private Deferred_ToonEffect Deferred_ToonEffect { get; } private SimpleDepthEffect SimpleDepthEffect { get; } private Effect ToneMapEffect { get; } @@ -136,6 +137,7 @@ namespace Kav DeferredDirectionalLightEffect = new DeferredPBR_DirectionalLightEffect(GraphicsDevice); DeferredDirectionalLightEffect.ShadowMapSize = ShadowMapSize; ToneMapEffect = new Effect(graphicsDevice, Resources.ToneMapEffect); + Deferred_ToonEffect = new Deferred_ToonEffect(GraphicsDevice); FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly); FullscreenTriangle.SetData(new VertexPositionTexture[3] { @@ -150,11 +152,62 @@ namespace Kav public void DeferredRender( PerspectiveCamera camera, IEnumerable<(Model, Matrix)> modelTransforms, + AmbientLight ambientLight, IEnumerable pointLights, DirectionalLight directionalLight ) { - // g-buffer pass + GBufferRender(camera, modelTransforms); + GraphicsDevice.SetRenderTarget(ColorRenderTarget); + GraphicsDevice.Clear(Color.Black); + + AmbientLightRender(ambientLight); + + DeferredPointLightEffect.EyePosition = camera.Position; + + foreach (var pointLight in pointLights) + { + PointLightRender(pointLight); + } + + DirectionalLightRender(camera, modelTransforms, directionalLight); + + GraphicsDevice.SetRenderTarget(null); + GraphicsDevice.Clear(Color.Black); + SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, ToneMapEffect); + SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White); + SpriteBatch.End(); + } + + public void DeferredToonRender( + PerspectiveCamera camera, + IEnumerable<(Model, Matrix)> modelTransforms, + AmbientLight ambientLight, + DirectionalLight directionalLight + ) { + GBufferRender(camera, modelTransforms); + + GraphicsDevice.SetRenderTarget(ColorRenderTarget); + GraphicsDevice.Clear(Color.Black); + + AmbientLightRender(ambientLight); + + Deferred_ToonEffect.GPosition = gPosition; + Deferred_ToonEffect.GAlbedo = gAlbedo; + Deferred_ToonEffect.GNormal = gNormal; + DirectionalLightToonRender(camera, directionalLight); + + GraphicsDevice.SetRenderTarget(null); + GraphicsDevice.Clear(Color.Black); + SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, ToneMapEffect); + SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White); + SpriteBatch.End(); + } + + private void GBufferRender( + PerspectiveCamera camera, + IEnumerable<(Model, Matrix)> modelTransforms + ) { GraphicsDevice.SetRenderTargets(GBuffer); GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); GraphicsDevice.DepthStencilState = DepthStencilState.Default; @@ -192,14 +245,17 @@ namespace Kav } } } + } + private void AmbientLightRender(AmbientLight ambientLight) + { GraphicsDevice.SetRenderTarget(ColorRenderTarget); - GraphicsDevice.Clear(Color.Black); GraphicsDevice.BlendState = BlendState.Additive; GraphicsDevice.DepthStencilState = DepthStencilState.None; DeferredAmbientLightEffect.GPosition = gPosition; DeferredAmbientLightEffect.GAlbedo = gAlbedo; + DeferredAmbientLightEffect.AmbientColor = ambientLight.Color.ToVector3(); foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes) { @@ -207,26 +263,6 @@ namespace Kav GraphicsDevice.SetVertexBuffer(FullscreenTriangle); GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); } - - DeferredPointLightEffect.EyePosition = camera.Position; - - foreach (var pointLight in pointLights) - { - PointLightRender(pointLight); - } - - DirectionalLightRender(camera, modelTransforms, directionalLight); - // return; - // GraphicsDevice.SetRenderTarget(null); - // SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied); - // SpriteBatch.Draw(DirectionalRenderTarget, Vector2.Zero, Color.White); - // SpriteBatch.End(); - - GraphicsDevice.SetRenderTarget(null); - GraphicsDevice.Clear(Color.Black); - SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, ToneMapEffect); - SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White); - SpriteBatch.End(); } private void PointLightRender(PointLight pointLight) @@ -313,6 +349,24 @@ namespace Kav } } + private void DirectionalLightToonRender( + PerspectiveCamera camera, + DirectionalLight directionalLight + ) { + Deferred_ToonEffect.EyePosition = camera.Position; + Deferred_ToonEffect.DirectionalLightDirection = directionalLight.Direction; + + GraphicsDevice.SetRenderTarget(ColorRenderTarget); + GraphicsDevice.BlendState = BlendState.Additive; + + foreach (EffectPass pass in Deferred_ToonEffect.CurrentTechnique.Passes) + { + pass.Apply(); + GraphicsDevice.SetVertexBuffer(FullscreenTriangle); + GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); + } + } + private void RenderShadowMap( PerspectiveCamera camera, IEnumerable<(Model, Matrix)> modelTransforms, diff --git a/Resources.cs b/Resources.cs index 7791eaa..9badc01 100644 --- a/Resources.cs +++ b/Resources.cs @@ -63,6 +63,18 @@ namespace Kav } } + public static byte[] Deferred_ToonEffect + { + get + { + if (deferredToonEffect == null) + { + deferredToonEffect = GetResource("Deferred_ToonEffect"); + } + return deferredToonEffect; + } + } + public static byte[] DeferredPBREffect { get @@ -104,6 +116,7 @@ namespace Kav private static byte[] directionalLightEffect; private static byte[] gBufferEffect; private static byte[] toneMapEffect; + private static byte[] deferredToonEffect; private static byte[] deferredPBREffect; private static byte[] pbrEffect; private static byte[] simpleDepthEffect;