Toon Shading + Point Shadows #3
			
				
			
		
		
		
	|  | @ -0,0 +1,14 @@ | ||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  | 
 | ||||||
|  | namespace Kav | ||||||
|  | { | ||||||
|  |     public interface ShadowCascadeEffect | ||||||
|  |     { | ||||||
|  |         Matrix LightSpaceMatrixOne { get; set; } | ||||||
|  |         Matrix LightSpaceMatrixTwo { get; set; } | ||||||
|  |         Matrix LightSpaceMatrixThree { get; set; } | ||||||
|  |         Matrix LightSpaceMatrixFour { get; set; } | ||||||
|  | 
 | ||||||
|  |         float[] CascadeFarPlanes { get; } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
|  | using Microsoft.Xna.Framework; | ||||||
| using Microsoft.Xna.Framework.Graphics; | using Microsoft.Xna.Framework.Graphics; | ||||||
| 
 | 
 | ||||||
| namespace Kav | namespace Kav | ||||||
|  | @ -8,9 +9,13 @@ namespace Kav | ||||||
|         EffectParameter gPositionParam; |         EffectParameter gPositionParam; | ||||||
|         EffectParameter gAlbedoParam; |         EffectParameter gAlbedoParam; | ||||||
| 
 | 
 | ||||||
|  |         EffectParameter ambientColorParam; | ||||||
|  | 
 | ||||||
|         public Texture2D GPosition { get; set; } |         public Texture2D GPosition { get; set; } | ||||||
|         public Texture2D GAlbedo { get; set; } |         public Texture2D GAlbedo { get; set; } | ||||||
| 
 | 
 | ||||||
|  |         public Vector3 AmbientColor { get; set; } | ||||||
|  | 
 | ||||||
|         public DeferredPBR_AmbientLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_AmbientLightEffect) |         public DeferredPBR_AmbientLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_AmbientLightEffect) | ||||||
|         { |         { | ||||||
|             CacheEffectParameters(); |             CacheEffectParameters(); | ||||||
|  | @ -20,12 +25,14 @@ namespace Kav | ||||||
|         { |         { | ||||||
|             gPositionParam.SetValue(GPosition); |             gPositionParam.SetValue(GPosition); | ||||||
|             gAlbedoParam.SetValue(GAlbedo); |             gAlbedoParam.SetValue(GAlbedo); | ||||||
|  |             ambientColorParam.SetValue(AmbientColor); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void CacheEffectParameters() |         void CacheEffectParameters() | ||||||
|         { |         { | ||||||
|             gPositionParam    = Parameters["gPosition"]; |             gPositionParam    = Parameters["gPosition"]; | ||||||
|             gAlbedoParam      = Parameters["gAlbedo"]; |             gAlbedoParam      = Parameters["gAlbedo"]; | ||||||
|  |             ambientColorParam = Parameters["AmbientLightColor"]; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics; | ||||||
| 
 | 
 | ||||||
| namespace Kav | namespace Kav | ||||||
| { | { | ||||||
|     public class DeferredPBR_DirectionalLightEffect : Effect |     public class DeferredPBR_DirectionalLightEffect : Effect, ShadowCascadeEffect | ||||||
|     { |     { | ||||||
|         EffectParameter gPositionParam; |         EffectParameter gPositionParam; | ||||||
|         EffectParameter gAlbedoParam; |         EffectParameter gAlbedoParam; | ||||||
|  | @ -46,7 +46,7 @@ namespace Kav | ||||||
|         public Vector3 DirectionalLightDirection { get; set; } |         public Vector3 DirectionalLightDirection { get; set; } | ||||||
|         public Vector3 DirectionalLightColor { get; set; } |         public Vector3 DirectionalLightColor { get; set; } | ||||||
| 
 | 
 | ||||||
|         public readonly float[] CascadeFarPlanes; |         public float[] CascadeFarPlanes { get; } | ||||||
| 
 | 
 | ||||||
|         public int ShadowMapSize { get; set; } |         public int ShadowMapSize { get; set; } | ||||||
| 
 | 
 | ||||||
|  | @ -147,7 +147,6 @@ namespace Kav | ||||||
|             directionalLightColorParam     = Parameters["DirectionalLightColor"]; |             directionalLightColorParam     = Parameters["DirectionalLightColor"]; | ||||||
| 
 | 
 | ||||||
|             cascadeFarPlanesParam          = Parameters["CascadeFarPlanes"]; |             cascadeFarPlanesParam          = Parameters["CascadeFarPlanes"]; | ||||||
| 
 |  | ||||||
|             shadowMapSizeParam             = Parameters["ShadowMapSize"]; |             shadowMapSizeParam             = Parameters["ShadowMapSize"]; | ||||||
| 
 | 
 | ||||||
|             lightSpaceMatrixOneParam       = Parameters["LightSpaceMatrixOne"]; |             lightSpaceMatrixOneParam       = Parameters["LightSpaceMatrixOne"]; | ||||||
|  |  | ||||||
|  | @ -9,22 +9,28 @@ namespace Kav | ||||||
|         EffectParameter gAlbedoParam; |         EffectParameter gAlbedoParam; | ||||||
|         EffectParameter gNormalParam; |         EffectParameter gNormalParam; | ||||||
|         EffectParameter gMetallicRoughnessParam; |         EffectParameter gMetallicRoughnessParam; | ||||||
|  |         EffectParameter shadowMapParam; | ||||||
| 
 | 
 | ||||||
|         EffectParameter eyePositionParam; |         EffectParameter eyePositionParam; | ||||||
| 
 | 
 | ||||||
|         EffectParameter pointLightColorParam; |         EffectParameter pointLightColorParam; | ||||||
|         EffectParameter pointLightPositionParam; |         EffectParameter pointLightPositionParam; | ||||||
| 
 | 
 | ||||||
|  |         EffectParameter farPlaneParam; | ||||||
|  | 
 | ||||||
|         public Texture2D GPosition { get; set; } |         public Texture2D GPosition { get; set; } | ||||||
|         public Texture2D GAlbedo { get; set; } |         public Texture2D GAlbedo { get; set; } | ||||||
|         public Texture2D GNormal { get; set; } |         public Texture2D GNormal { get; set; } | ||||||
|         public Texture2D GMetallicRoughness { get; set; } |         public Texture2D GMetallicRoughness { get; set; } | ||||||
|  |         public TextureCube ShadowMap { get; set; } | ||||||
| 
 | 
 | ||||||
|         public Vector3 EyePosition { get; set; } |         public Vector3 EyePosition { get; set; } | ||||||
| 
 | 
 | ||||||
|         public Vector3 PointLightPosition { get; set; } |         public Vector3 PointLightPosition { get; set; } | ||||||
|         public Vector3 PointLightColor { get; set; } |         public Vector3 PointLightColor { get; set; } | ||||||
| 
 | 
 | ||||||
|  |         public float FarPlane { get; set; } | ||||||
|  | 
 | ||||||
|         public DeferredPBR_PointLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_PointLightEffect) |         public DeferredPBR_PointLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_PointLightEffect) | ||||||
|         { |         { | ||||||
|             CacheEffectParameters(); |             CacheEffectParameters(); | ||||||
|  | @ -32,15 +38,20 @@ namespace Kav | ||||||
| 
 | 
 | ||||||
|         public DeferredPBR_PointLightEffect(DeferredPBR_PointLightEffect cloneSource) : base(cloneSource) |         public DeferredPBR_PointLightEffect(DeferredPBR_PointLightEffect cloneSource) : base(cloneSource) | ||||||
|         { |         { | ||||||
|  |             CacheEffectParameters(); | ||||||
|  |              | ||||||
|             GPosition = cloneSource.GPosition; |             GPosition = cloneSource.GPosition; | ||||||
|             GAlbedo = cloneSource.GAlbedo; |             GAlbedo = cloneSource.GAlbedo; | ||||||
|             GNormal = cloneSource.GNormal; |             GNormal = cloneSource.GNormal; | ||||||
|             GMetallicRoughness = cloneSource.GMetallicRoughness; |             GMetallicRoughness = cloneSource.GMetallicRoughness; | ||||||
|  |             ShadowMap = cloneSource.ShadowMap; | ||||||
| 
 | 
 | ||||||
|             EyePosition = cloneSource.EyePosition; |             EyePosition = cloneSource.EyePosition; | ||||||
| 
 | 
 | ||||||
|             PointLightPosition = cloneSource.PointLightPosition; |             PointLightPosition = cloneSource.PointLightPosition; | ||||||
|             PointLightColor = cloneSource.PointLightColor; |             PointLightColor = cloneSource.PointLightColor; | ||||||
|  | 
 | ||||||
|  |             FarPlane = cloneSource.FarPlane; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public override Effect Clone() |         public override Effect Clone() | ||||||
|  | @ -54,11 +65,14 @@ namespace Kav | ||||||
|             gAlbedoParam.SetValue(GAlbedo); |             gAlbedoParam.SetValue(GAlbedo); | ||||||
|             gNormalParam.SetValue(GNormal); |             gNormalParam.SetValue(GNormal); | ||||||
|             gMetallicRoughnessParam.SetValue(GMetallicRoughness); |             gMetallicRoughnessParam.SetValue(GMetallicRoughness); | ||||||
|  |             shadowMapParam.SetValue(ShadowMap); | ||||||
| 
 | 
 | ||||||
|             eyePositionParam.SetValue(EyePosition); |             eyePositionParam.SetValue(EyePosition); | ||||||
| 
 | 
 | ||||||
|             pointLightPositionParam.SetValue(PointLightPosition); |             pointLightPositionParam.SetValue(PointLightPosition); | ||||||
|             pointLightColorParam.SetValue(PointLightColor); |             pointLightColorParam.SetValue(PointLightColor); | ||||||
|  | 
 | ||||||
|  |             farPlaneParam.SetValue(FarPlane); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         void CacheEffectParameters() |         void CacheEffectParameters() | ||||||
|  | @ -67,11 +81,14 @@ namespace Kav | ||||||
|             gAlbedoParam                   = Parameters["gAlbedo"]; |             gAlbedoParam                   = Parameters["gAlbedo"]; | ||||||
|             gNormalParam                   = Parameters["gNormal"]; |             gNormalParam                   = Parameters["gNormal"]; | ||||||
|             gMetallicRoughnessParam        = Parameters["gMetallicRoughness"]; |             gMetallicRoughnessParam        = Parameters["gMetallicRoughness"]; | ||||||
|  |             shadowMapParam                 = Parameters["shadowMap"]; | ||||||
| 
 | 
 | ||||||
|             eyePositionParam               = Parameters["EyePosition"]; |             eyePositionParam               = Parameters["EyePosition"]; | ||||||
| 
 | 
 | ||||||
|             pointLightPositionParam        = Parameters["PointLightPosition"]; |             pointLightPositionParam        = Parameters["PointLightPosition"]; | ||||||
|             pointLightColorParam           = Parameters["PointLightColor"]; |             pointLightColorParam           = Parameters["PointLightColor"]; | ||||||
|  | 
 | ||||||
|  |             farPlaneParam                  = Parameters["FarPlane"]; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,147 @@ | ||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  | using Microsoft.Xna.Framework.Graphics; | ||||||
|  | 
 | ||||||
|  | namespace Kav | ||||||
|  | { | ||||||
|  |     public class Deferred_ToonEffect : Effect, ShadowCascadeEffect | ||||||
|  |     { | ||||||
|  |         EffectParameter gPositionParam; | ||||||
|  |         EffectParameter gAlbedoParam; | ||||||
|  |         EffectParameter gNormalParam; | ||||||
|  |         EffectParameter gMetallicRoughnessParam; | ||||||
|  | 
 | ||||||
|  |         EffectParameter shadowMapOneParam; | ||||||
|  |         EffectParameter shadowMapTwoParam; | ||||||
|  |         EffectParameter shadowMapThreeParam; | ||||||
|  |         EffectParameter shadowMapFourParam; | ||||||
|  | 
 | ||||||
|  |         EffectParameter eyePositionParam; | ||||||
|  |         EffectParameter directionalLightDirectionParam; | ||||||
|  |         EffectParameter directionalLightColorParam; | ||||||
|  | 
 | ||||||
|  |         EffectParameter cascadeFarPlanesParam; | ||||||
|  |         EffectParameter shadowMapSizeParam; | ||||||
|  | 
 | ||||||
|  |         EffectParameter lightSpaceMatrixOneParam; | ||||||
|  |         EffectParameter lightSpaceMatrixTwoParam; | ||||||
|  |         EffectParameter lightSpaceMatrixThreeParam; | ||||||
|  |         EffectParameter lightSpaceMatrixFourParam; | ||||||
|  | 
 | ||||||
|  |         EffectParameter viewMatrixParam; | ||||||
|  | 
 | ||||||
|  |         EffectParameter shaderIndexParam; | ||||||
|  | 
 | ||||||
|  |         public Texture2D GPosition { get; set; } | ||||||
|  |         public Texture2D GAlbedo { get; set; } | ||||||
|  |         public Texture2D GNormal { get; set; } | ||||||
|  |         public Texture2D GMetallicRoughness { get; set; } | ||||||
|  | 
 | ||||||
|  |         public Texture2D ShadowMapOne { get; set; } | ||||||
|  |         public Texture2D ShadowMapTwo { get; set; } | ||||||
|  |         public Texture2D ShadowMapThree { get; set; } | ||||||
|  |         public Texture2D ShadowMapFour { get; set; } | ||||||
|  | 
 | ||||||
|  |         public Vector3 EyePosition { get; set; } | ||||||
|  |         public Vector3 DirectionalLightDirection { get; set; } | ||||||
|  |         public Vector3 DirectionalLightColor { get; set; } | ||||||
|  | 
 | ||||||
|  |         public float[] CascadeFarPlanes { get; } | ||||||
|  |         public float ShadowMapSize { get; set; } | ||||||
|  | 
 | ||||||
|  |         public Matrix LightSpaceMatrixOne { get; set; } | ||||||
|  |         public Matrix LightSpaceMatrixTwo { get; set; } | ||||||
|  |         public Matrix LightSpaceMatrixThree { get; set; } | ||||||
|  |         public Matrix LightSpaceMatrixFour { get; set; } | ||||||
|  | 
 | ||||||
|  |         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]; | ||||||
|  |             CacheEffectParameters();    | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         protected override void OnApply() | ||||||
|  |         { | ||||||
|  |             gPositionParam.SetValue(GPosition); | ||||||
|  |             gAlbedoParam.SetValue(GAlbedo); | ||||||
|  |             gNormalParam.SetValue(GNormal); | ||||||
|  |             gMetallicRoughnessParam.SetValue(GMetallicRoughness); | ||||||
|  | 
 | ||||||
|  |             shadowMapOneParam.SetValue(ShadowMapOne); | ||||||
|  |             shadowMapTwoParam.SetValue(ShadowMapTwo); | ||||||
|  |             shadowMapThreeParam.SetValue(ShadowMapThree); | ||||||
|  |             shadowMapFourParam.SetValue(ShadowMapFour); | ||||||
|  | 
 | ||||||
|  |             eyePositionParam.SetValue(EyePosition); | ||||||
|  |             directionalLightDirectionParam.SetValue(DirectionalLightDirection); | ||||||
|  |             directionalLightColorParam.SetValue(DirectionalLightColor); | ||||||
|  | 
 | ||||||
|  |             cascadeFarPlanesParam.SetValue(CascadeFarPlanes); | ||||||
|  |             shadowMapSizeParam.SetValue(ShadowMapSize); | ||||||
|  | 
 | ||||||
|  |             lightSpaceMatrixOneParam.SetValue(LightSpaceMatrixOne); | ||||||
|  |             lightSpaceMatrixTwoParam.SetValue(LightSpaceMatrixTwo); | ||||||
|  |             lightSpaceMatrixThreeParam.SetValue(LightSpaceMatrixThree); | ||||||
|  |             lightSpaceMatrixFourParam.SetValue(LightSpaceMatrixFour); | ||||||
|  | 
 | ||||||
|  |             viewMatrixParam.SetValue(ViewMatrix); | ||||||
|  | 
 | ||||||
|  |             shaderIndexParam.SetValue(shaderIndex); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         void CacheEffectParameters() | ||||||
|  |         { | ||||||
|  |             gPositionParam                 = Parameters["gPosition"]; | ||||||
|  |             gAlbedoParam                   = Parameters["gAlbedo"]; | ||||||
|  |             gNormalParam                   = Parameters["gNormal"]; | ||||||
|  |             gMetallicRoughnessParam        = Parameters["gMetallicRoughness"]; | ||||||
|  | 
 | ||||||
|  |             shadowMapOneParam              = Parameters["shadowMapOne"]; | ||||||
|  |             shadowMapTwoParam              = Parameters["shadowMapTwo"]; | ||||||
|  |             shadowMapThreeParam            = Parameters["shadowMapThree"]; | ||||||
|  |             shadowMapFourParam             = Parameters["shadowMapFour"]; | ||||||
|  | 
 | ||||||
|  |             eyePositionParam               = Parameters["EyePosition"]; | ||||||
|  |             directionalLightDirectionParam = Parameters["DirectionalLightDirection"]; | ||||||
|  |             directionalLightColorParam     = Parameters["DirectionalLightColor"]; | ||||||
|  | 
 | ||||||
|  |             cascadeFarPlanesParam          = Parameters["CascadeFarPlanes"]; | ||||||
|  |             shadowMapSizeParam             = Parameters["ShadowMapSize"]; | ||||||
|  | 
 | ||||||
|  |             lightSpaceMatrixOneParam       = Parameters["LightSpaceMatrixOne"]; | ||||||
|  |             lightSpaceMatrixTwoParam       = Parameters["LightSpaceMatrixTwo"]; | ||||||
|  |             lightSpaceMatrixThreeParam     = Parameters["LightSpaceMatrixThree"]; | ||||||
|  |             lightSpaceMatrixFourParam      = Parameters["LightSpaceMatrixFour"]; | ||||||
|  | 
 | ||||||
|  |             viewMatrixParam                = Parameters["ViewMatrix"]; | ||||||
|  | 
 | ||||||
|  |             shaderIndexParam               = Parameters["ShaderIndex"]; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private void CalculateShaderIndex() | ||||||
|  |         { | ||||||
|  |             if (ditheredShadowValue) | ||||||
|  |             { | ||||||
|  |                 shaderIndex = 1; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 shaderIndex = 0; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										
											BIN
										
									
								
								Effects/FXB/DeferredPBR_AmbientLightEffect.fxb (Stored with Git LFS)
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								Effects/FXB/DeferredPBR_AmbientLightEffect.fxb (Stored with Git LFS)
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Effects/FXB/DeferredPBR_DirectionalLightEffect.fxb (Stored with Git LFS)
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								Effects/FXB/DeferredPBR_DirectionalLightEffect.fxb (Stored with Git LFS)
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Effects/FXB/DeferredPBR_PointLightEffect.fxb (Stored with Git LFS)
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								Effects/FXB/DeferredPBR_PointLightEffect.fxb (Stored with Git LFS)
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								Effects/FXB/SimpleDepthEffect.fxb (Stored with Git LFS)
								
								
								
								
							
							
						
						
									
										
											BIN
										
									
								
								Effects/FXB/SimpleDepthEffect.fxb (Stored with Git LFS)
								
								
								
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | float3 HUEtoRGB(in float H) | ||||||
|  | { | ||||||
|  |     float R = abs(H * 6 - 3) - 1; | ||||||
|  |     float G = 2 - abs(H * 6 - 2); | ||||||
|  |     float B = 2 - abs(H * 6 - 4); | ||||||
|  |     return saturate(float3(R,G,B)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float Epsilon = 1e-10; | ||||||
|  | 
 | ||||||
|  | float3 RGBtoHCV(in float3 RGB) | ||||||
|  | { | ||||||
|  |     // Based on work by Sam Hocevar and Emil Persson | ||||||
|  |     float4 P = (RGB.g < RGB.b) ? float4(RGB.bg, -1.0, 2.0/3.0) : float4(RGB.gb, 0.0, -1.0/3.0); | ||||||
|  |     float4 Q = (RGB.r < P.x) ? float4(P.xyw, RGB.r) : float4(RGB.r, P.yzx); | ||||||
|  |     float C = Q.x - min(Q.w, Q.y); | ||||||
|  |     float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z); | ||||||
|  |     return float3(H, C, Q.x); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float3 RGBtoHSL(float3 RGB) | ||||||
|  | { | ||||||
|  |     float3 HCV = RGBtoHCV(RGB); | ||||||
|  |     float L = HCV.z - HCV.y * 0.5; | ||||||
|  |     float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon); | ||||||
|  |     return float3(HCV.x, S, L); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float3 HSLtoRGB(float3 HSL) | ||||||
|  | { | ||||||
|  |     float3 RGB = HUEtoRGB(HSL.x); | ||||||
|  |     float C = (1 - abs(2 * HSL.z - 1)) * HSL.y; | ||||||
|  |     return (RGB - 0.5) * C + HSL.z; | ||||||
|  | } | ||||||
|  | @ -3,6 +3,12 @@ | ||||||
| DECLARE_TEXTURE(gPosition, 0); | DECLARE_TEXTURE(gPosition, 0); | ||||||
| DECLARE_TEXTURE(gAlbedo, 1); | DECLARE_TEXTURE(gAlbedo, 1); | ||||||
| 
 | 
 | ||||||
|  | BEGIN_CONSTANTS | ||||||
|  | 
 | ||||||
|  | float3 AmbientLightColor _ps(c0)   _cb(c0); | ||||||
|  | 
 | ||||||
|  | END_CONSTANTS | ||||||
|  | 
 | ||||||
| struct VertexInput | struct VertexInput | ||||||
| { | { | ||||||
|     float4 Position : POSITION; |     float4 Position : POSITION; | ||||||
|  | @ -29,7 +35,7 @@ float4 ComputeColor( | ||||||
|     float3 worldPosition, |     float3 worldPosition, | ||||||
|     float3 albedo |     float3 albedo | ||||||
| ) { | ) { | ||||||
|     float3 color = float3(0.03, 0.03, 0.03) * albedo; |     float3 color = AmbientLightColor * albedo; | ||||||
|     return float4(color, 1.0); |     return float4(color, 1.0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| #include "Macros.fxh" //from FNA | #include "Macros.fxh" //from FNA | ||||||
| #include "Lighting.fxh" | #include "Lighting.fxh" | ||||||
|  | #include "Shadow.fxh" | ||||||
| 
 | 
 | ||||||
| static const int NUM_SHADOW_CASCADES = 4; | static const int NUM_SHADOW_CASCADES = 4; | ||||||
| 
 | 
 | ||||||
|  | @ -35,26 +36,6 @@ MATRIX_CONSTANTS | ||||||
| 
 | 
 | ||||||
| END_CONSTANTS | END_CONSTANTS | ||||||
| 
 | 
 | ||||||
| static float2 poissonDisk[16] =  |  | ||||||
| { |  | ||||||
|    float2( -0.94201624, -0.39906216 ),  |  | ||||||
|    float2( 0.94558609, -0.76890725 ),  |  | ||||||
|    float2( -0.094184101, -0.92938870 ),  |  | ||||||
|    float2( 0.34495938, 0.29387760 ),  |  | ||||||
|    float2( -0.91588581, 0.45771432 ),  |  | ||||||
|    float2( -0.81544232, -0.87912464 ),  |  | ||||||
|    float2( -0.38277543, 0.27676845 ),  |  | ||||||
|    float2( 0.97484398, 0.75648379 ),  |  | ||||||
|    float2( 0.44323325, -0.97511554 ),  |  | ||||||
|    float2( 0.53742981, -0.47373420 ),  |  | ||||||
|    float2( -0.26496911, -0.41893023 ),  |  | ||||||
|    float2( 0.79197514, 0.19090188 ),  |  | ||||||
|    float2( -0.24188840, 0.99706507 ),  |  | ||||||
|    float2( -0.81409955, 0.91437590 ),  |  | ||||||
|    float2( 0.19984126, 0.78641367 ),  |  | ||||||
|    float2( 0.14383161, -0.14100790 )  |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct VertexInput | struct VertexInput | ||||||
| { | { | ||||||
|     float4 Position : POSITION; |     float4 Position : POSITION; | ||||||
|  | @ -79,35 +60,8 @@ PixelInput main_vs(VertexInput input) | ||||||
| 
 | 
 | ||||||
| // Pixel Shader | // Pixel Shader | ||||||
| 
 | 
 | ||||||
| // Returns a random number based on a vec3 and an int. |  | ||||||
| float random(float3 seed, int i){ |  | ||||||
| 	float4 seed4 = float4(seed, i); |  | ||||||
| 	float dot_product = dot(seed4, float4(12.9898,78.233,45.164,94.673)); |  | ||||||
| 	return frac(sin(dot_product) * 43758.5453); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| float PoissonCoord(sampler shadowMap, float3 worldPosition, float2 texCoord, float fragmentDepth, float bias) |  | ||||||
| { |  | ||||||
|     float visibility = 1.0; |  | ||||||
| 
 |  | ||||||
|     for (int i = 0; i < 16; i++) |  | ||||||
|     { |  | ||||||
|         int index = int(16.0 * random(floor(worldPosition * 1000.0), i)) % 16; |  | ||||||
| 
 |  | ||||||
|         if (tex2D(shadowMap, texCoord + poissonDisk[index] / 1024.0).r < fragmentDepth - bias) |  | ||||||
|         { |  | ||||||
|             visibility -= 0.05; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return visibility; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L) | float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L) | ||||||
| { | { | ||||||
|     float bias = 0.005 * tan(acos(dot(N, L))); |  | ||||||
|     bias = clamp(bias, 0, 0.01); |  | ||||||
| 
 |  | ||||||
|     float4 positionCameraSpace = mul(float4(positionWorldSpace, 1.0), ViewMatrix); |     float4 positionCameraSpace = mul(float4(positionWorldSpace, 1.0), ViewMatrix); | ||||||
| 
 | 
 | ||||||
|     int shadowCascadeIndex = 0; // 0 is closest |     int shadowCascadeIndex = 0; // 0 is closest | ||||||
|  | @ -139,69 +93,52 @@ float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L) | ||||||
|         lightSpaceMatrix = LightSpaceMatrixFour; |         lightSpaceMatrix = LightSpaceMatrixFour; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     float4 positionLightSpace = mul(float4(positionWorldSpace, 1.0), lightSpaceMatrix); |  | ||||||
|     |  | ||||||
|     // maps to [-1, 1] |  | ||||||
|     float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w; |  | ||||||
| 
 |  | ||||||
|     // maps to [0, 1] |  | ||||||
|     projectionCoords.x = (projectionCoords.x * 0.5) + 0.5; |  | ||||||
|     projectionCoords.y = (projectionCoords.y * 0.5) + 0.5; |  | ||||||
|     projectionCoords.y *= -1; |  | ||||||
|     // in XNA clip z is 0 to 1 already |  | ||||||
| 
 |  | ||||||
|     if (projectionCoords.z > 1.0) |  | ||||||
|     { |  | ||||||
|         return 1.0; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     float inc = 1.0 / ShadowMapSize; // TODO: shadow map size uniform |  | ||||||
| 
 |  | ||||||
|     // PCF + Poisson soft shadows |     // PCF + Poisson soft shadows | ||||||
|     float visibility = 0.0; |  | ||||||
|     // for (int row = -1; row <= 1; row++) |  | ||||||
|     // { |  | ||||||
|     //     for (int col = -1; col <= 1; col++) |  | ||||||
|     //     { |  | ||||||
|     //         if (shadowCascadeIndex == 0) |  | ||||||
|     //         { |  | ||||||
|     //             visibility += PoissonCoord(SAMPLER(shadowMapOne), positionWorldSpace, projectionCoords.xy + float2(row, col) * inc, projectionCoords.z, bias); |  | ||||||
|     //         } |  | ||||||
|     //         else if (shadowCascadeIndex == 1) |  | ||||||
|     //         { |  | ||||||
|     //             visibility += PoissonCoord(SAMPLER(shadowMapTwo), positionWorldSpace, projectionCoords.xy + float2(row, col) * inc, projectionCoords.z, bias); |  | ||||||
|     //         } |  | ||||||
|     //         else if (shadowCascadeIndex == 2) |  | ||||||
|     //         { |  | ||||||
|     //             visibility += PoissonCoord(SAMPLER(shadowMapThree), positionWorldSpace, projectionCoords.xy + float2(row, col) * inc, projectionCoords.z, bias); |  | ||||||
|     //         } |  | ||||||
|     //         else |  | ||||||
|     //         { |  | ||||||
|     //             visibility += PoissonCoord(SAMPLER(shadowMapFour), positionWorldSpace, projectionCoords.xy + float2(row, col) * inc, projectionCoords.z, bias); |  | ||||||
|     //         } |  | ||||||
|     //     } |  | ||||||
|     // } |  | ||||||
| 
 |  | ||||||
|     // visibility /= 9.0; |  | ||||||
| 
 | 
 | ||||||
|     if (shadowCascadeIndex == 0) |     if (shadowCascadeIndex == 0) | ||||||
|     { |     { | ||||||
|         visibility = PoissonCoord(SAMPLER(shadowMapOne), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias); |         return PoissonShadow( | ||||||
|  |             positionWorldSpace, | ||||||
|  |             N, | ||||||
|  |             L, | ||||||
|  |             lightSpaceMatrix, | ||||||
|  |             SAMPLER(shadowMapOne), | ||||||
|  |             ShadowMapSize | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|     else if (shadowCascadeIndex == 1) |     else if (shadowCascadeIndex == 1) | ||||||
|     { |     { | ||||||
|         visibility = PoissonCoord(SAMPLER(shadowMapTwo), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias); |         return PoissonShadow( | ||||||
|  |             positionWorldSpace, | ||||||
|  |             N, | ||||||
|  |             L, | ||||||
|  |             lightSpaceMatrix, | ||||||
|  |             SAMPLER(shadowMapTwo), | ||||||
|  |             ShadowMapSize | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|     else if (shadowCascadeIndex == 2) |     else if (shadowCascadeIndex == 2) | ||||||
|     { |     { | ||||||
|         visibility = PoissonCoord(SAMPLER(shadowMapThree), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias); |         return PoissonShadow( | ||||||
|  |             positionWorldSpace, | ||||||
|  |             N, | ||||||
|  |             L, | ||||||
|  |             lightSpaceMatrix, | ||||||
|  |             SAMPLER(shadowMapThree), | ||||||
|  |             ShadowMapSize | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
|     { |     { | ||||||
|         visibility = PoissonCoord(SAMPLER(shadowMapFour), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias); |         return PoissonShadow( | ||||||
|  |             positionWorldSpace, | ||||||
|  |             N, | ||||||
|  |             L, | ||||||
|  |             lightSpaceMatrix, | ||||||
|  |             SAMPLER(shadowMapFour), | ||||||
|  |             ShadowMapSize | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     return visibility; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float4 ComputeColor( | float4 ComputeColor( | ||||||
|  |  | ||||||
|  | @ -1,10 +1,12 @@ | ||||||
| #include "Macros.fxh" //from FNA | #include "Macros.fxh" //from FNA | ||||||
| #include "Lighting.fxh"  | #include "Lighting.fxh"  | ||||||
|  | #include "Shadow.fxh" | ||||||
| 
 | 
 | ||||||
| DECLARE_TEXTURE(gPosition, 0); | DECLARE_TEXTURE(gPosition, 0); | ||||||
| DECLARE_TEXTURE(gAlbedo, 1); | DECLARE_TEXTURE(gAlbedo, 1); | ||||||
| DECLARE_TEXTURE(gNormal, 2); | DECLARE_TEXTURE(gNormal, 2); | ||||||
| DECLARE_TEXTURE(gMetallicRoughness, 3); | DECLARE_TEXTURE(gMetallicRoughness, 3); | ||||||
|  | DECLARE_CUBEMAP(shadowMap, 4); | ||||||
| 
 | 
 | ||||||
| BEGIN_CONSTANTS | BEGIN_CONSTANTS | ||||||
| 
 | 
 | ||||||
|  | @ -13,6 +15,8 @@ BEGIN_CONSTANTS | ||||||
|     float3 PointLightPosition               _ps(c1)     _cb(c1); |     float3 PointLightPosition               _ps(c1)     _cb(c1); | ||||||
|     float3 PointLightColor                  _ps(c2)     _cb(c2); |     float3 PointLightColor                  _ps(c2)     _cb(c2); | ||||||
| 
 | 
 | ||||||
|  |     float FarPlane                          _ps(c3)     _cb(c3); | ||||||
|  | 
 | ||||||
| MATRIX_CONSTANTS | MATRIX_CONSTANTS | ||||||
| 
 | 
 | ||||||
| END_CONSTANTS | END_CONSTANTS | ||||||
|  | @ -60,9 +64,11 @@ float4 ComputeColor( | ||||||
|     float attenuation = 1.0 / (distance * distance); |     float attenuation = 1.0 / (distance * distance); | ||||||
|     float3 radiance = PointLightColor * attenuation; |     float3 radiance = PointLightColor * attenuation; | ||||||
| 
 | 
 | ||||||
|     float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, 1.0); |     float shadow = HardPointShadow(worldPosition, N, L, PointLightPosition, SAMPLER(shadowMap), FarPlane); | ||||||
|  |     float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, shadow); | ||||||
| 
 | 
 | ||||||
|     return float4(color, 1.0); |     return float4(color, 1.0); | ||||||
|  |     //return float4(shadow, shadow, shadow, 1.0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| float4 main_ps(PixelInput input) : SV_TARGET0 | float4 main_ps(PixelInput input) : SV_TARGET0 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,285 @@ | ||||||
|  | #include "Macros.fxh" | ||||||
|  | #include "Shadow.fxh" | ||||||
|  | #include "Dither.fxh" | ||||||
|  | 
 | ||||||
|  | static const int NUM_SHADOW_CASCADES = 4; | ||||||
|  | 
 | ||||||
|  | DECLARE_TEXTURE(gPosition, 0); | ||||||
|  | DECLARE_TEXTURE(gAlbedo, 1); | ||||||
|  | DECLARE_TEXTURE(gNormal, 2); | ||||||
|  | DECLARE_TEXTURE(gMetallicRoughness, 3); | ||||||
|  | DECLARE_TEXTURE(shadowMapOne, 4); | ||||||
|  | DECLARE_TEXTURE(shadowMapTwo, 5); | ||||||
|  | DECLARE_TEXTURE(shadowMapThree, 6); | ||||||
|  | DECLARE_TEXTURE(shadowMapFour, 7); | ||||||
|  | 
 | ||||||
|  | BEGIN_CONSTANTS | ||||||
|  | 
 | ||||||
|  | float3 EyePosition                           _ps(c0)     _cb(c0); | ||||||
|  | 
 | ||||||
|  | float3 DirectionalLightDirection             _ps(c1)     _cb(c1); | ||||||
|  | float3 DirectionalLightColor                 _ps(c2)     _cb(c2); | ||||||
|  | 
 | ||||||
|  | float CascadeFarPlanes[NUM_SHADOW_CASCADES]  _ps(c4)     _cb(c4); | ||||||
|  | 
 | ||||||
|  | float ShadowMapSize                          _ps(c8)     _cb(c8); | ||||||
|  | 
 | ||||||
|  | MATRIX_CONSTANTS | ||||||
|  | 
 | ||||||
|  | float4x4 LightSpaceMatrixOne                 _ps(c9)     _cb(c9); | ||||||
|  | float4x4 LightSpaceMatrixTwo                 _ps(c13)    _cb(c13); | ||||||
|  | float4x4 LightSpaceMatrixThree               _ps(c17)    _cb(c17); | ||||||
|  | float4x4 LightSpaceMatrixFour                _ps(c21)    _cb(c21); | ||||||
|  | 
 | ||||||
|  | float4x4 ViewMatrix                          _ps(c25)    _cb(c25); | ||||||
|  | 
 | ||||||
|  | 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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L) | ||||||
|  | { | ||||||
|  |     float4 positionCameraSpace = mul(float4(positionWorldSpace, 1.0), ViewMatrix); | ||||||
|  | 
 | ||||||
|  |     int shadowCascadeIndex = 0; // 0 is closest | ||||||
|  |     for (int i = 0; i < NUM_SHADOW_CASCADES; i++) | ||||||
|  |     { | ||||||
|  |         if (abs(positionCameraSpace.z) < CascadeFarPlanes[i]) | ||||||
|  |         { | ||||||
|  |             shadowCascadeIndex = i; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     float4x4 lightSpaceMatrix; | ||||||
|  | 
 | ||||||
|  |     if (shadowCascadeIndex == 0) | ||||||
|  |     { | ||||||
|  |         lightSpaceMatrix = LightSpaceMatrixOne; | ||||||
|  |     } | ||||||
|  |     else if (shadowCascadeIndex == 1) | ||||||
|  |     { | ||||||
|  |         lightSpaceMatrix = LightSpaceMatrixTwo; | ||||||
|  |     } | ||||||
|  |     else if (shadowCascadeIndex == 2) | ||||||
|  |     { | ||||||
|  |         lightSpaceMatrix = LightSpaceMatrixThree; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         lightSpaceMatrix = LightSpaceMatrixFour; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (shadowCascadeIndex == 0) | ||||||
|  |     { | ||||||
|  |         return HardShadow( | ||||||
|  |             positionWorldSpace, | ||||||
|  |             N, | ||||||
|  |             L, | ||||||
|  |             lightSpaceMatrix, | ||||||
|  |             SAMPLER(shadowMapOne), | ||||||
|  |             ShadowMapSize | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     else if (shadowCascadeIndex == 1) | ||||||
|  |     { | ||||||
|  |         return HardShadow( | ||||||
|  |             positionWorldSpace, | ||||||
|  |             N, | ||||||
|  |             L, | ||||||
|  |             lightSpaceMatrix, | ||||||
|  |             SAMPLER(shadowMapTwo), | ||||||
|  |             ShadowMapSize | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     else if (shadowCascadeIndex == 2) | ||||||
|  |     { | ||||||
|  |         return HardShadow( | ||||||
|  |             positionWorldSpace, | ||||||
|  |             N, | ||||||
|  |             L, | ||||||
|  |             lightSpaceMatrix, | ||||||
|  |             SAMPLER(shadowMapThree), | ||||||
|  |             ShadowMapSize | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         return HardShadow( | ||||||
|  |             positionWorldSpace, | ||||||
|  |             N, | ||||||
|  |             L, | ||||||
|  |             lightSpaceMatrix, | ||||||
|  |             SAMPLER(shadowMapFour), | ||||||
|  |             ShadowMapSize | ||||||
|  |         ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float IntensityBanding(float NdotL) | ||||||
|  | { | ||||||
|  |     // if (NdotL > 0.5) | ||||||
|  |     // { | ||||||
|  |     //     return 1.0; | ||||||
|  |     // } | ||||||
|  |     // else if (NdotL > 0.25) | ||||||
|  |     // { | ||||||
|  |     //     return 0.5; | ||||||
|  |     // } | ||||||
|  |     // else if (NdotL > 0.0) | ||||||
|  |     // { | ||||||
|  |     //     return 0.25; | ||||||
|  |     // } | ||||||
|  |     // else | ||||||
|  |     // { | ||||||
|  |     //     return 0.0; | ||||||
|  |     // } | ||||||
|  |     if (NdotL > 0) | ||||||
|  |     { | ||||||
|  |         return 1.0; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         return 0.25; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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 DitheredShadow(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; | ||||||
|  |     float3 light = DirectionalLightColor; | ||||||
|  | 
 | ||||||
|  |     if (lightIntensity < 1) | ||||||
|  |     { | ||||||
|  |         light *= dither(lightIntensity, screenPosition); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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; | ||||||
|  | 
 | ||||||
|  |     if (shadow < 1) | ||||||
|  |     { | ||||||
|  |         color *= dither(shadow, screenPosition); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     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 = (PSArray[PSIndices[ShaderIndex]]); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,89 @@ | ||||||
|  | #include "Conversion.fxh" | ||||||
|  | 
 | ||||||
|  | // technique from http://alex-charlton.com/posts/Dithering_on_the_GPU/ | ||||||
|  | 
 | ||||||
|  | uniform float3 palette[8]; | ||||||
|  | static const int paletteSize = 8; | ||||||
|  | 
 | ||||||
|  | static const int indexMatrix4x4[16] = | ||||||
|  | { | ||||||
|  |      0,  8,  2, 10, | ||||||
|  |     12,  4, 14,  6, | ||||||
|  |      3, 11,  1,  9, | ||||||
|  |     15,  7, 13,  5 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | float indexValue(float2 screenCoords) | ||||||
|  | { | ||||||
|  |     int x = int(screenCoords.x % 4); | ||||||
|  |     int y = int(screenCoords.y % 4); | ||||||
|  | 
 | ||||||
|  |     return indexMatrix4x4[(x + y * 4)] / 16.0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float hueDistance(float h1, float h2) | ||||||
|  | { | ||||||
|  |     float diff = abs(h1 - h2); | ||||||
|  |     return min(abs(1.0 - diff), diff); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void closestColors(float hue, out float3 ret[2]) | ||||||
|  | { | ||||||
|  |     float3 closest = float3(-2, 0, 0); | ||||||
|  |     float3 secondClosest = float3(-2, 0, 0); | ||||||
|  |     float3 temp; | ||||||
|  | 
 | ||||||
|  |     for (int i = 0; i < paletteSize; i++) | ||||||
|  |     { | ||||||
|  |         temp = palette[i]; | ||||||
|  |         float tempDistance = hueDistance(temp.x, hue); | ||||||
|  |         if (tempDistance < hueDistance(closest.x, hue)) | ||||||
|  |         { | ||||||
|  |             secondClosest = closest; | ||||||
|  |             closest = temp; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             if (tempDistance < hueDistance(secondClosest.x, hue)) | ||||||
|  |             { | ||||||
|  |                 secondClosest = temp; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ret[0] = closest; | ||||||
|  |     ret[1] = secondClosest; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float3 dither(float3 color, float2 screenCoords) | ||||||
|  | { | ||||||
|  |     float3 colors[2]; | ||||||
|  |     float3 hsl = RGBtoHSL(color); | ||||||
|  |     closestColors(hsl.x, colors); | ||||||
|  |     float3 closestColor = colors[0]; | ||||||
|  |     float3 secondClosestColor = colors[1]; | ||||||
|  |     float d = indexValue(screenCoords); | ||||||
|  |     float hueDiff = hueDistance(hsl.x, closestColor.x) / hueDistance(secondClosestColor.x, secondClosestColor.x); | ||||||
|  |     return HSLtoRGB(hueDiff < d ? closestColor : secondClosestColor); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // brightColor refers to undithered max color | ||||||
|  | // float3 dither(float3 color, float3 brightColor, float2 screenCoords) | ||||||
|  | // { | ||||||
|  | //     float brightHue = RGBtoHSL(brightColor.x); | ||||||
|  | //     float colorHue = RGBtoHSL(color.x); | ||||||
|  | //     float halfDistance = hueDistance(0.0, brightHue) / 2.0; | ||||||
|  | //     float3 closestColor = (colorHue < halfDistance) ? float3(0.0, 0.0, 0.0) : brightColor; | ||||||
|  | //     float3 secondClosestColor = brightColor - closestColor; | ||||||
|  | //     float d = indexValue(screenCoords); | ||||||
|  | //     float distance = abs(closestColor - color); | ||||||
|  | //     return (distance < d) ? closestColor : secondClosestColor; | ||||||
|  | // } | ||||||
|  | 
 | ||||||
|  | float3 dither(float color, float2 screenCoords) { | ||||||
|  |     float closestColor = (color < 0.5) ? 0 : 1; | ||||||
|  |     float secondClosestColor = 1 - closestColor; | ||||||
|  |     float d = indexValue(screenCoords); | ||||||
|  |     float distance = abs(closestColor - color); | ||||||
|  |     return (distance < d) ? closestColor : secondClosestColor; | ||||||
|  | } | ||||||
|  | @ -0,0 +1,47 @@ | ||||||
|  | #include "Macros.fxh" | ||||||
|  | 
 | ||||||
|  | BEGIN_CONSTANTS | ||||||
|  | 
 | ||||||
|  |     float4x4 Model                  _vs(c0)             _cb(c0); | ||||||
|  |     float4x4 ModelViewProjection    _vs(c4)             _cb(c4); | ||||||
|  | 
 | ||||||
|  |     float3 LightPosition                      _ps(c0)   _cb(c8); | ||||||
|  |     float FarPlane                            _ps(c1)   _cb(c9); | ||||||
|  | 
 | ||||||
|  | END_CONSTANTS | ||||||
|  | 
 | ||||||
|  | struct VertexShaderInput | ||||||
|  | { | ||||||
|  |     float4 Position : POSITION; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct VertexShaderOutput | ||||||
|  | { | ||||||
|  |     float4 Position : SV_Position; | ||||||
|  |     float3 PositionWorld : TEXCOORD0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | VertexShaderOutput main_vs(VertexShaderInput input) | ||||||
|  | { | ||||||
|  |     VertexShaderOutput output; | ||||||
|  |     output.Position = mul(input.Position, ModelViewProjection); | ||||||
|  |     output.Position.x *= -1; // otherwise cube map render will be horizontally flipped | ||||||
|  |     output.PositionWorld = mul(input.Position, Model); | ||||||
|  |     return output; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float4 main_ps(VertexShaderOutput input) : SV_TARGET0 | ||||||
|  | { | ||||||
|  |     float lightDistance = length(input.PositionWorld - LightPosition); | ||||||
|  |     lightDistance /= FarPlane; | ||||||
|  |     return float4(lightDistance, 0.0, 0.0, 0.0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Technique SimpleDepth | ||||||
|  | { | ||||||
|  |     Pass | ||||||
|  |     { | ||||||
|  |         VertexShader = compile vs_3_0 main_vs(); | ||||||
|  |         PixelShader  = compile ps_3_0 main_ps(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,141 @@ | ||||||
|  | static float2 poissonDisk[16] =  | ||||||
|  | { | ||||||
|  |    float2( -0.94201624, -0.39906216 ),  | ||||||
|  |    float2( 0.94558609, -0.76890725 ),  | ||||||
|  |    float2( -0.094184101, -0.92938870 ),  | ||||||
|  |    float2( 0.34495938, 0.29387760 ),  | ||||||
|  |    float2( -0.91588581, 0.45771432 ),  | ||||||
|  |    float2( -0.81544232, -0.87912464 ),  | ||||||
|  |    float2( -0.38277543, 0.27676845 ),  | ||||||
|  |    float2( 0.97484398, 0.75648379 ),  | ||||||
|  |    float2( 0.44323325, -0.97511554 ),  | ||||||
|  |    float2( 0.53742981, -0.47373420 ),  | ||||||
|  |    float2( -0.26496911, -0.41893023 ),  | ||||||
|  |    float2( 0.79197514, 0.19090188 ),  | ||||||
|  |    float2( -0.24188840, 0.99706507 ),  | ||||||
|  |    float2( -0.81409955, 0.91437590 ),  | ||||||
|  |    float2( 0.19984126, 0.78641367 ),  | ||||||
|  |    float2( 0.14383161, -0.14100790 )  | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // TODO: this should probably sample a noise texture instead | ||||||
|  | // Returns a random number based on a vec3 and an int. | ||||||
|  | float random(float3 seed, int i){ | ||||||
|  | 	float4 seed4 = float4(seed, i); | ||||||
|  | 	float dot_product = dot(seed4, float4(12.9898,78.233,45.164,94.673)); | ||||||
|  | 	return frac(sin(dot_product) * 43758.5453); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float PoissonCoord(sampler shadowMap, float3 worldPosition, float2 texCoord, float fragmentDepth, float bias) | ||||||
|  | { | ||||||
|  |     float visibility = 1.0; | ||||||
|  | 
 | ||||||
|  |     for (int i = 0; i < 16; i++) | ||||||
|  |     { | ||||||
|  |         int index = int(16.0 * random(floor(worldPosition * 1000.0), i)) % 16; | ||||||
|  | 
 | ||||||
|  |         if (tex2D(shadowMap, texCoord + poissonDisk[index] / 1024.0).r < fragmentDepth - bias) | ||||||
|  |         { | ||||||
|  |             visibility -= 0.05; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return visibility; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float PoissonShadow( | ||||||
|  |     float3 positionWorldSpace,  | ||||||
|  |     float3 N,  | ||||||
|  |     float3 L, | ||||||
|  |     float4x4 lightSpaceMatrix, | ||||||
|  |     sampler shadowMap, | ||||||
|  |     int shadowMapSize | ||||||
|  | ) { | ||||||
|  |     float bias = 0.005 * tan(acos(dot(N, L))); | ||||||
|  |     bias = clamp(bias, 0, 0.01); | ||||||
|  | 
 | ||||||
|  |     float4 positionLightSpace = mul(float4(positionWorldSpace, 1.0), lightSpaceMatrix); | ||||||
|  | 
 | ||||||
|  |     // maps to [-1, 1] | ||||||
|  |     float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w; | ||||||
|  | 
 | ||||||
|  |     // maps to [0, 1] | ||||||
|  |     // NOTE: In XNA, clip space z is [0, 1] range | ||||||
|  |     projectionCoords.x = (projectionCoords.x * 0.5) + 0.5; | ||||||
|  |     projectionCoords.y = (projectionCoords.y * 0.5) + 0.5; | ||||||
|  |     projectionCoords.y *= -1; | ||||||
|  | 
 | ||||||
|  |     if (projectionCoords.z > 1.0) | ||||||
|  |     { | ||||||
|  |         return 1.0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     float inc = 1.0 / shadowMapSize; | ||||||
|  | 
 | ||||||
|  |     // Poisson soft shadows | ||||||
|  |     float visibility = 0.0; | ||||||
|  | 
 | ||||||
|  |     visibility = PoissonCoord( | ||||||
|  |         shadowMap,  | ||||||
|  |         positionWorldSpace, | ||||||
|  |         projectionCoords.xy, | ||||||
|  |         projectionCoords.z, | ||||||
|  |         bias | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     return visibility; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float HardShadow( | ||||||
|  |     float3 positionWorldSpace,  | ||||||
|  |     float3 N,  | ||||||
|  |     float3 L, | ||||||
|  |     float4x4 lightSpaceMatrix, | ||||||
|  |     sampler shadowMap, | ||||||
|  |     int shadowMapSize | ||||||
|  | ) { | ||||||
|  |     // float bias = 0.005 * tan(acos(dot(N, L))); | ||||||
|  |     // bias = clamp(bias, 0, 0.01); | ||||||
|  | 
 | ||||||
|  |     float bias = max(0.05 * (1.0 - dot(N, L)), 0.005);   | ||||||
|  | 
 | ||||||
|  |     float4 positionLightSpace = mul(float4(positionWorldSpace, 1.0), lightSpaceMatrix); | ||||||
|  | 
 | ||||||
|  |     // maps to [-1, 1] | ||||||
|  |     float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w; | ||||||
|  | 
 | ||||||
|  |     // maps to [0, 1] | ||||||
|  |     // NOTE: In XNA, clip space z is [0, 1] range | ||||||
|  |     projectionCoords.x = (projectionCoords.x * 0.5) + 0.5; | ||||||
|  |     projectionCoords.y = (projectionCoords.y * 0.5) + 0.5; | ||||||
|  |     projectionCoords.y *= -1; | ||||||
|  | 
 | ||||||
|  |     if (projectionCoords.z > 1.0) | ||||||
|  |     { | ||||||
|  |         return 1.0; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     float closestDepth = tex2D(shadowMap, projectionCoords.xy); | ||||||
|  |     float currentDepth = projectionCoords.z; | ||||||
|  | 
 | ||||||
|  |     return (currentDepth - bias > closestDepth ? 0.25 : 1.0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float HardPointShadow( | ||||||
|  |     float3 positionWorldSpace,  | ||||||
|  |     float3 N,  | ||||||
|  |     float3 L, | ||||||
|  |     float3 lightPosition, | ||||||
|  |     sampler shadowMap, | ||||||
|  |     float farPlane | ||||||
|  | ) { | ||||||
|  |     float3 lightToFrag = positionWorldSpace - lightPosition; | ||||||
|  |     float closestDepth = texCUBE(shadowMap, lightToFrag).r; | ||||||
|  |     closestDepth *= farPlane; | ||||||
|  | 
 | ||||||
|  |     float currentDepth = length(lightToFrag); | ||||||
|  | 
 | ||||||
|  |     float bias = max(0.05 * (1.0 - dot(N, L)), 0.005);   | ||||||
|  | 
 | ||||||
|  |     return (currentDepth - bias > closestDepth ? 0 : 1.0); | ||||||
|  | } | ||||||
|  | @ -24,7 +24,7 @@ VertexShaderOutput main_vs(VertexShaderInput input) | ||||||
|     VertexShaderOutput output; |     VertexShaderOutput output; | ||||||
| 
 | 
 | ||||||
|     output.Position = mul(input.Position, ModelViewProjection); |     output.Position = mul(input.Position, ModelViewProjection); | ||||||
|     output.Depth = output.Position.z; |     output.Depth = output.Position.z / output.Position.w; | ||||||
| 
 | 
 | ||||||
|     return output; |     return output; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,45 @@ | ||||||
|  | #include "Macros.fxh" | ||||||
|  | 
 | ||||||
|  | DECLARE_CUBEMAP(skybox, 0); | ||||||
|  | 
 | ||||||
|  | BEGIN_CONSTANTS | ||||||
|  | 
 | ||||||
|  |     float4x4 ViewProjection _vs(c0)    _cb(c0); | ||||||
|  | 
 | ||||||
|  | END_CONSTANTS | ||||||
|  | 
 | ||||||
|  | struct VertexShaderInput | ||||||
|  | { | ||||||
|  |     float3 Position : POSITION; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct VertexShaderOutput | ||||||
|  | { | ||||||
|  |     float4 Position : SV_POSITION; | ||||||
|  |     float3 TexCoord : TEXCOORD; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | VertexShaderOutput main_vs(VertexShaderInput input) | ||||||
|  | { | ||||||
|  |     VertexShaderOutput output; | ||||||
|  | 
 | ||||||
|  |     output.Position = mul(float4(input.Position, 1.0), ViewProjection); | ||||||
|  |     output.Position = output.Position.xyww; | ||||||
|  |     output.TexCoord = input.Position; | ||||||
|  | 
 | ||||||
|  |     return output; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | float4 main_ps(VertexShaderOutput input) : SV_TARGET0 | ||||||
|  | { | ||||||
|  |     return SAMPLE_CUBEMAP(skybox, input.TexCoord); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Technique Skybox | ||||||
|  | { | ||||||
|  |     Pass | ||||||
|  |     { | ||||||
|  |         VertexShader = compile vs_3_0 main_vs(); | ||||||
|  |         PixelShader  = compile ps_3_0 main_ps(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,90 @@ | ||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  | using Microsoft.Xna.Framework.Graphics; | ||||||
|  | 
 | ||||||
|  | namespace Kav | ||||||
|  | { | ||||||
|  |     public class LinearDepthEffect : Effect | ||||||
|  |     { | ||||||
|  |         EffectParameter modelParam; | ||||||
|  |         EffectParameter modelViewProjectionParam; | ||||||
|  |         EffectParameter lightPositionParam; | ||||||
|  |         EffectParameter farPlaneParam; | ||||||
|  | 
 | ||||||
|  |         EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; | ||||||
|  | 
 | ||||||
|  |         Matrix model; | ||||||
|  |         Matrix view; | ||||||
|  |         Matrix projection; | ||||||
|  | 
 | ||||||
|  |         public Vector3 LightPosition { get; set; } | ||||||
|  |         public float FarPlane { get; set; } | ||||||
|  | 
 | ||||||
|  |         public Matrix Model | ||||||
|  |         { | ||||||
|  |             get { return model; } | ||||||
|  |             set | ||||||
|  |             { | ||||||
|  |                 model = value; | ||||||
|  |                 dirtyFlags |= EffectDirtyFlags.World; | ||||||
|  |                 dirtyFlags |= EffectDirtyFlags.WorldViewProj; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Matrix View | ||||||
|  |         { | ||||||
|  |             get { return view; } | ||||||
|  |             set | ||||||
|  |             { | ||||||
|  |                 view = value; | ||||||
|  |                 dirtyFlags |= EffectDirtyFlags.WorldViewProj; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Matrix Projection | ||||||
|  |         { | ||||||
|  |             get { return projection; } | ||||||
|  |             set | ||||||
|  |             { | ||||||
|  |                 projection = value; | ||||||
|  |                 dirtyFlags |= EffectDirtyFlags.WorldViewProj; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public LinearDepthEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.LinearDepthEffect) | ||||||
|  |         { | ||||||
|  |             CacheEffectParameters(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         protected override void OnApply() | ||||||
|  |         { | ||||||
|  |             if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) | ||||||
|  |             { | ||||||
|  |                 Matrix.Multiply(ref view, ref projection, out Matrix viewProjection); | ||||||
|  |                 Matrix.Multiply(ref model, ref viewProjection, out Matrix worldViewProj); | ||||||
|  | 
 | ||||||
|  |                 modelViewProjectionParam.SetValue(worldViewProj); | ||||||
|  | 
 | ||||||
|  |                 dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if ((dirtyFlags & EffectDirtyFlags.World) != 0) | ||||||
|  |             { | ||||||
|  |                 modelParam.SetValue(model); | ||||||
|  |                  | ||||||
|  |                 dirtyFlags &= ~EffectDirtyFlags.World; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             lightPositionParam.SetValue(LightPosition); | ||||||
|  |             farPlaneParam.SetValue(FarPlane); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private void CacheEffectParameters() | ||||||
|  |         { | ||||||
|  |             modelParam               = Parameters["Model"]; | ||||||
|  |             modelViewProjectionParam = Parameters["ModelViewProjection"]; | ||||||
|  | 
 | ||||||
|  |             lightPositionParam       = Parameters["LightPosition"]; | ||||||
|  |             farPlaneParam            = Parameters["FarPlane"]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,77 @@ | ||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  | using Microsoft.Xna.Framework.Graphics; | ||||||
|  | 
 | ||||||
|  | namespace Kav | ||||||
|  | { | ||||||
|  |     public class SkyboxEffect : Effect | ||||||
|  |     { | ||||||
|  |         EffectParameter viewProjectionParam; | ||||||
|  |         EffectParameter skyboxParam; | ||||||
|  | 
 | ||||||
|  |         Matrix view; | ||||||
|  |         Matrix projection; | ||||||
|  |         TextureCube skybox; | ||||||
|  | 
 | ||||||
|  |         EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; | ||||||
|  | 
 | ||||||
|  |         public Matrix View | ||||||
|  |         { | ||||||
|  |             get { return view; } | ||||||
|  |             set  | ||||||
|  |             { | ||||||
|  |                 view = value; | ||||||
|  |                 dirtyFlags |= EffectDirtyFlags.WorldViewProj; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Matrix Projection | ||||||
|  |         { | ||||||
|  |             get { return projection; } | ||||||
|  |             set | ||||||
|  |             { | ||||||
|  |                 projection = value; | ||||||
|  |                 dirtyFlags |= EffectDirtyFlags.WorldViewProj; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public TextureCube Skybox | ||||||
|  |         { | ||||||
|  |             get { return skybox; } | ||||||
|  |             set | ||||||
|  |             { | ||||||
|  |                 skybox = value; | ||||||
|  |                 dirtyFlags |= EffectDirtyFlags.World; // hack flag but whatever | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public SkyboxEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SkyboxEffect) | ||||||
|  |         { | ||||||
|  |             CacheEffectParameters(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         protected override void OnApply() | ||||||
|  |         { | ||||||
|  |             if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) | ||||||
|  |             { | ||||||
|  |                 Matrix.Multiply(ref view, ref projection, out Matrix viewProjection); | ||||||
|  | 
 | ||||||
|  |                 viewProjectionParam.SetValue(viewProjection); | ||||||
|  | 
 | ||||||
|  |                 dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if ((dirtyFlags & EffectDirtyFlags.World) != 0) | ||||||
|  |             { | ||||||
|  |                 skyboxParam.SetValue(skybox); | ||||||
|  | 
 | ||||||
|  |                 dirtyFlags &= ~EffectDirtyFlags.World; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private void CacheEffectParameters() | ||||||
|  |         { | ||||||
|  |             viewProjectionParam = Parameters["ViewProjection"]; | ||||||
|  |             skyboxParam = Parameters["skybox"]; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -9,15 +9,47 @@ namespace Kav | ||||||
|         public VertexBuffer VertexBuffer { get; } |         public VertexBuffer VertexBuffer { get; } | ||||||
|         public Triangle[] Triangles { get; } |         public Triangle[] Triangles { get; } | ||||||
|         public Vector3[] Positions { get; } |         public Vector3[] Positions { get; } | ||||||
|         public Effect Effect { get; } |  | ||||||
|          |          | ||||||
|         public MeshPart(VertexBuffer vertexBuffer, IndexBuffer indexBuffer, Vector3[] positions, Triangle[] triangles, Effect effect) |         private Texture2D albedoTexture = null; | ||||||
|  |         private Texture2D normalTexture = null; | ||||||
|  |         private Texture2D metallicRoughnessTexture = null; | ||||||
|  | 
 | ||||||
|  |         public Texture2D AlbedoTexture  | ||||||
|         {  |         {  | ||||||
|  |             get { return DisableAlbedoMap ? null : albedoTexture; } | ||||||
|  |             set { albedoTexture = value; } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Texture2D NormalTexture  | ||||||
|  |         {  | ||||||
|  |             get { return DisableNormalMap ? null : normalTexture; }  | ||||||
|  |             set { normalTexture = value; } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Texture2D MetallicRoughnessTexture  | ||||||
|  |         {  | ||||||
|  |             get { return DisableMetallicRoughnessMap ? null : metallicRoughnessTexture; } | ||||||
|  |             set { metallicRoughnessTexture = value; }  | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public Vector3 Albedo { get; set; } = Vector3.One; | ||||||
|  |         public float Metallic { get; set; } = 0.5f; | ||||||
|  |         public float Roughness { get; set; } = 0.5f; | ||||||
|  | 
 | ||||||
|  |         public bool DisableAlbedoMap { get; set; } = false; | ||||||
|  |         public bool DisableNormalMap { get; set; } = false; | ||||||
|  |         public bool DisableMetallicRoughnessMap { get; set; } = false; | ||||||
|  | 
 | ||||||
|  |         public MeshPart( | ||||||
|  |             VertexBuffer vertexBuffer, | ||||||
|  |             IndexBuffer indexBuffer, | ||||||
|  |             Vector3[] positions, | ||||||
|  |             Triangle[] triangles | ||||||
|  |         ) { | ||||||
|             VertexBuffer = vertexBuffer; |             VertexBuffer = vertexBuffer; | ||||||
|             IndexBuffer = indexBuffer; |             IndexBuffer = indexBuffer; | ||||||
|             Positions = positions; |             Positions = positions; | ||||||
|             Triangles = triangles; |             Triangles = triangles; | ||||||
|             Effect = effect; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -6,9 +6,84 @@ namespace Kav | ||||||
|     { |     { | ||||||
|         public Mesh[] Meshes { get; } |         public Mesh[] Meshes { get; } | ||||||
| 
 | 
 | ||||||
|  |         public Color Albedo  | ||||||
|  |         {  | ||||||
|  |             set  | ||||||
|  |             { | ||||||
|  |                 foreach (var mesh in Meshes) | ||||||
|  |                 { | ||||||
|  |                     foreach (var meshPart in mesh.MeshParts) | ||||||
|  |                     { | ||||||
|  |                         meshPart.Albedo = value.ToVector3(); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public float Metallic | ||||||
|  |         { | ||||||
|  |             set | ||||||
|  |             { | ||||||
|  |                 foreach (var mesh in Meshes) | ||||||
|  |                 { | ||||||
|  |                     foreach (var meshPart in mesh.MeshParts) | ||||||
|  |                     { | ||||||
|  |                         meshPart.Metallic = value; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }    | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public float Roughness | ||||||
|  |         { | ||||||
|  |             set | ||||||
|  |             { | ||||||
|  |                 foreach (var mesh in Meshes) | ||||||
|  |                 { | ||||||
|  |                     foreach (var meshPart in mesh.MeshParts) | ||||||
|  |                     { | ||||||
|  |                         meshPart.Roughness = value; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             }    | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         public Model(Mesh[] meshes) |         public Model(Mesh[] meshes) | ||||||
|         { |         { | ||||||
|             Meshes = meshes; |             Meshes = meshes; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         public void DisableAlbedoMaps() | ||||||
|  |         { | ||||||
|  |             foreach (var mesh in Meshes) | ||||||
|  |             { | ||||||
|  |                 foreach (var meshPart in mesh.MeshParts) | ||||||
|  |                 { | ||||||
|  |                     meshPart.DisableAlbedoMap = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void DisableNormalMaps() | ||||||
|  |         { | ||||||
|  |             foreach (var mesh in Meshes) | ||||||
|  |             { | ||||||
|  |                 foreach (var meshPart in mesh.MeshParts) | ||||||
|  |                 { | ||||||
|  |                     meshPart.DisableNormalMap = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         public void DisableMetallicRoughnessMaps() | ||||||
|  |         { | ||||||
|  |             foreach (var mesh in Meshes) | ||||||
|  |             { | ||||||
|  |                 foreach (var meshPart in mesh.MeshParts) | ||||||
|  |                 { | ||||||
|  |                     meshPart.DisableMetallicRoughnessMap = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -30,6 +30,9 @@ | ||||||
|     <EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb"> |     <EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb"> | ||||||
|       <LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName> |       <LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName> | ||||||
|     </EmbeddedResource> |     </EmbeddedResource> | ||||||
|  |     <EmbeddedResource Include="Effects\FXB\Deferred_ToonEffect.fxb"> | ||||||
|  |       <LogicalName>Kav.Resources.Deferred_ToonEffect.fxb</LogicalName> | ||||||
|  |     </EmbeddedResource> | ||||||
|     <EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb"> |     <EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb"> | ||||||
|       <LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName> |       <LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName> | ||||||
|     </EmbeddedResource> |     </EmbeddedResource> | ||||||
|  | @ -39,6 +42,15 @@ | ||||||
|     <EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb"> |     <EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb"> | ||||||
|       <LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName> |       <LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName> | ||||||
| 		</EmbeddedResource> | 		</EmbeddedResource> | ||||||
|  |     <EmbeddedResource Include="Effects\FXB\LinearDepthEffect.fxb"> | ||||||
|  |       <LogicalName>Kav.Resources.LinearDepthEffect.fxb</LogicalName> | ||||||
|  | 		</EmbeddedResource> | ||||||
|  |     <EmbeddedResource Include="Effects\FXB\SkyboxEffect.fxb"> | ||||||
|  |       <LogicalName>Kav.Resources.SkyboxEffect.fxb</LogicalName> | ||||||
|  | 		</EmbeddedResource> | ||||||
|  |     <EmbeddedResource Include="Models\UnitCube.glb"> | ||||||
|  |       <LogicalName>Kav.Resources.UnitCube.glb</LogicalName> | ||||||
|  | 		</EmbeddedResource> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
| </Project> | </Project> | ||||||
|  |  | ||||||
|  | @ -30,6 +30,9 @@ | ||||||
|     <EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb"> |     <EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb"> | ||||||
|       <LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName> |       <LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName> | ||||||
|     </EmbeddedResource> |     </EmbeddedResource> | ||||||
|  |     <EmbeddedResource Include="Effects\FXB\Deferred_ToonEffect.fxb"> | ||||||
|  |       <LogicalName>Kav.Resources.Deferred_ToonEffect.fxb</LogicalName> | ||||||
|  |     </EmbeddedResource> | ||||||
|     <EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb"> |     <EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb"> | ||||||
|       <LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName> |       <LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName> | ||||||
|     </EmbeddedResource> |     </EmbeddedResource> | ||||||
|  | @ -39,6 +42,15 @@ | ||||||
|     <EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb"> |     <EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb"> | ||||||
|       <LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName> |       <LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName> | ||||||
| 		</EmbeddedResource> | 		</EmbeddedResource> | ||||||
|  |     <EmbeddedResource Include="Effects\FXB\LinearDepthEffect.fxb"> | ||||||
|  |       <LogicalName>Kav.Resources.LinearDepthEffect.fxb</LogicalName> | ||||||
|  | 		</EmbeddedResource> | ||||||
|  |     <EmbeddedResource Include="Effects\FXB\SkyboxEffect.fxb"> | ||||||
|  |       <LogicalName>Kav.Resources.SkyboxEffect.fxb</LogicalName> | ||||||
|  | 		</EmbeddedResource> | ||||||
|  |     <EmbeddedResource Include="Models\UnitCube.glb"> | ||||||
|  |       <LogicalName>Kav.Resources.UnitCube.glb</LogicalName> | ||||||
|  | 		</EmbeddedResource> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| 
 | 
 | ||||||
| </Project> | </Project> | ||||||
|  |  | ||||||
|  | @ -0,0 +1,14 @@ | ||||||
|  | using Microsoft.Xna.Framework; | ||||||
|  | 
 | ||||||
|  | namespace Kav | ||||||
|  | { | ||||||
|  |     public struct AmbientLight | ||||||
|  |     { | ||||||
|  |         public Color Color { get; set; } | ||||||
|  | 
 | ||||||
|  |         public AmbientLight(Color color) | ||||||
|  |         { | ||||||
|  |             Color = color; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -4,9 +4,9 @@ namespace Kav | ||||||
| { | { | ||||||
|     public struct DirectionalLight |     public struct DirectionalLight | ||||||
|     { |     { | ||||||
|         public Vector3 Direction { get; set; } |         public Vector3 Direction { get; } | ||||||
|         public Color Color { get; set; } |         public Color Color { get; } | ||||||
|         public float Intensity { get; set; } |         public float Intensity { get; } | ||||||
| 
 | 
 | ||||||
|         public Matrix View |         public Matrix View | ||||||
|         { |         { | ||||||
|  |  | ||||||
|  | @ -15,19 +15,6 @@ namespace Kav | ||||||
| 
 | 
 | ||||||
|                 foreach (var meshPartData in meshData.MeshParts) |                 foreach (var meshPartData in meshData.MeshParts) | ||||||
|                 { |                 { | ||||||
|                     var effect = new Kav.DeferredPBR_GBufferEffect( |  | ||||||
|                         graphicsDevice |  | ||||||
|                     ) |  | ||||||
|                     { |  | ||||||
|                         Albedo = meshPartData.Albedo, |  | ||||||
|                         Metallic = meshPartData.Metallic, |  | ||||||
|                         Roughness = meshPartData.Roughness, |  | ||||||
| 
 |  | ||||||
|                         AlbedoTexture = meshPartData.AlbedoTexture, |  | ||||||
|                         NormalTexture = meshPartData.NormalTexture, |  | ||||||
|                         MetallicRoughnessTexture = meshPartData.MetallicRoughnessTexture |  | ||||||
|                     }; |  | ||||||
| 
 |  | ||||||
|                     var triangles = new Kav.Triangle[meshPartData.Triangles.Length]; |                     var triangles = new Kav.Triangle[meshPartData.Triangles.Length]; | ||||||
|                     for (int i = 0; i < meshPartData.Triangles.Length; i++) |                     for (int i = 0; i < meshPartData.Triangles.Length; i++) | ||||||
|                     { |                     { | ||||||
|  | @ -40,13 +27,22 @@ namespace Kav | ||||||
|                         ); |                         ); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     meshParts.Add(new Kav.MeshPart( |                     var meshPart = new Kav.MeshPart( | ||||||
|                         meshPartData.VertexBuffer, |                         meshPartData.VertexBuffer, | ||||||
|                         meshPartData.IndexBuffer, |                         meshPartData.IndexBuffer, | ||||||
|                         meshPartData.Positions, |                         meshPartData.Positions, | ||||||
|                         triangles, |                         triangles | ||||||
|                         effect |                     ); | ||||||
|                     )); | 
 | ||||||
|  |                     meshPart.Albedo = meshPartData.Albedo; | ||||||
|  |                     meshPart.Metallic = meshPartData.Metallic; | ||||||
|  |                     meshPart.Roughness = meshPartData.Roughness; | ||||||
|  | 
 | ||||||
|  |                     meshPart.AlbedoTexture = meshPartData.AlbedoTexture; | ||||||
|  |                     meshPart.NormalTexture = meshPartData.NormalTexture; | ||||||
|  |                     meshPart.MetallicRoughnessTexture = meshPartData.MetallicRoughnessTexture; | ||||||
|  | 
 | ||||||
|  |                     meshParts.Add(meshPart); | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 meshes.Add(new Kav.Mesh(meshParts.ToArray())); |                 meshes.Add(new Kav.Mesh(meshParts.ToArray())); | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							|  | @ -15,9 +15,9 @@ Essential | ||||||
| - [x] Tone map shader | - [x] Tone map shader | ||||||
| - [x] Poisson soft shadowing | - [x] Poisson soft shadowing | ||||||
| - [ ] Frustum culling | - [ ] Frustum culling | ||||||
| - [ ] Shadow-casting point lights | - [x] Shadow-casting point lights | ||||||
| - [ ] Parabolic lights | - [ ] Parabolic lights | ||||||
| - [ ] Skyboxes | - [x] Skyboxes | ||||||
| - [ ] Screen-space reflection | - [ ] Screen-space reflection | ||||||
| 
 | 
 | ||||||
| Nice-To-Haves | Nice-To-Haves | ||||||
|  |  | ||||||
							
								
								
									
										433
									
								
								Renderer.cs
								
								
								
								
							
							
						
						
									
										433
									
								
								Renderer.cs
								
								
								
								
							|  | @ -1,4 +1,6 @@ | ||||||
| using System.Collections.Generic; | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.IO; | ||||||
| using Microsoft.Xna.Framework; | using Microsoft.Xna.Framework; | ||||||
| using Microsoft.Xna.Framework.Graphics; | using Microsoft.Xna.Framework.Graphics; | ||||||
| 
 | 
 | ||||||
|  | @ -21,19 +23,27 @@ namespace Kav | ||||||
|         private RenderTarget2D[] ShadowRenderTargets { get; } |         private RenderTarget2D[] ShadowRenderTargets { get; } | ||||||
| 
 | 
 | ||||||
|         private DeferredPBREffect DeferredPBREffect { get; } |         private DeferredPBREffect DeferredPBREffect { get; } | ||||||
|  |         /* FIXME: these next two dont actually have anything to do with PBR */ | ||||||
|  |         private DeferredPBR_GBufferEffect Deferred_GBufferEffect { get; } | ||||||
|         private DeferredPBR_AmbientLightEffect DeferredAmbientLightEffect { get; } |         private DeferredPBR_AmbientLightEffect DeferredAmbientLightEffect { get; } | ||||||
|         private DeferredPBR_PointLightEffect DeferredPointLightEffect { get; } |         private DeferredPBR_PointLightEffect DeferredPointLightEffect { get; } | ||||||
|         private DeferredPBR_DirectionalLightEffect DeferredDirectionalLightEffect { get; } |         private DeferredPBR_DirectionalLightEffect DeferredDirectionalLightEffect { get; } | ||||||
|  |         private Deferred_ToonEffect Deferred_ToonEffect { get; } | ||||||
|         private SimpleDepthEffect SimpleDepthEffect { get; } |         private SimpleDepthEffect SimpleDepthEffect { get; } | ||||||
|  |         private LinearDepthEffect LinearDepthEffect { get; } | ||||||
|         private Effect ToneMapEffect { get; } |         private Effect ToneMapEffect { get; } | ||||||
|  |         private SkyboxEffect SkyboxEffect { get; } | ||||||
| 
 | 
 | ||||||
|         private RenderTarget2D gPosition { get; } |         private RenderTarget2D gPosition { get; } | ||||||
|         private RenderTarget2D gNormal { get; } |         private RenderTarget2D gNormal { get; } | ||||||
|         private RenderTarget2D gAlbedo { get; } |         private RenderTarget2D gAlbedo { get; } | ||||||
|         private RenderTarget2D gMetallicRoughness { get; } |         private RenderTarget2D gMetallicRoughness { get; } | ||||||
|  |         private RenderTargetCube PointShadowCubeMap { get; } | ||||||
| 
 | 
 | ||||||
|         private RenderTargetBinding[] GBuffer { get; } |         private RenderTargetBinding[] GBuffer { get; } | ||||||
| 
 | 
 | ||||||
|  |         private Kav.Model UnitCube { get; } | ||||||
|  | 
 | ||||||
|         private SpriteBatch SpriteBatch { get; } |         private SpriteBatch SpriteBatch { get; } | ||||||
| 
 | 
 | ||||||
|         public Renderer( |         public Renderer( | ||||||
|  | @ -70,7 +80,7 @@ namespace Kav | ||||||
|                 renderDimensionsY, |                 renderDimensionsY, | ||||||
|                 false, |                 false, | ||||||
|                 SurfaceFormat.Color, |                 SurfaceFormat.Color, | ||||||
|                 DepthFormat.None, |                 DepthFormat.Depth24, | ||||||
|                 0, |                 0, | ||||||
|                 RenderTargetUsage.PreserveContents |                 RenderTargetUsage.PreserveContents | ||||||
|             ); |             ); | ||||||
|  | @ -129,13 +139,26 @@ namespace Kav | ||||||
|                 new RenderTargetBinding(gMetallicRoughness) |                 new RenderTargetBinding(gMetallicRoughness) | ||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|  |             PointShadowCubeMap = new RenderTargetCube( | ||||||
|  |                 GraphicsDevice, | ||||||
|  |                 shadowMapSize, | ||||||
|  |                 false, | ||||||
|  |                 SurfaceFormat.Single, | ||||||
|  |                 DepthFormat.Depth24 | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|             SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice); |             SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice); | ||||||
|  |             LinearDepthEffect = new LinearDepthEffect(GraphicsDevice); | ||||||
|             DeferredPBREffect = new DeferredPBREffect(GraphicsDevice); |             DeferredPBREffect = new DeferredPBREffect(GraphicsDevice); | ||||||
|  | 
 | ||||||
|  |             Deferred_GBufferEffect = new DeferredPBR_GBufferEffect(GraphicsDevice); | ||||||
|             DeferredAmbientLightEffect = new DeferredPBR_AmbientLightEffect(GraphicsDevice); |             DeferredAmbientLightEffect = new DeferredPBR_AmbientLightEffect(GraphicsDevice); | ||||||
|             DeferredPointLightEffect = new DeferredPBR_PointLightEffect(GraphicsDevice); |             DeferredPointLightEffect = new DeferredPBR_PointLightEffect(GraphicsDevice); | ||||||
|             DeferredDirectionalLightEffect = new DeferredPBR_DirectionalLightEffect(GraphicsDevice); |             DeferredDirectionalLightEffect = new DeferredPBR_DirectionalLightEffect(GraphicsDevice); | ||||||
|             DeferredDirectionalLightEffect.ShadowMapSize = ShadowMapSize; |             DeferredDirectionalLightEffect.ShadowMapSize = ShadowMapSize; | ||||||
|             ToneMapEffect = new Effect(graphicsDevice, Resources.ToneMapEffect); |             ToneMapEffect = new Effect(graphicsDevice, Resources.ToneMapEffect); | ||||||
|  |             Deferred_ToonEffect = new Deferred_ToonEffect(GraphicsDevice); | ||||||
|  |             SkyboxEffect = new SkyboxEffect(GraphicsDevice); | ||||||
| 
 | 
 | ||||||
|             FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly); |             FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly); | ||||||
|             FullscreenTriangle.SetData(new VertexPositionTexture[3] { |             FullscreenTriangle.SetData(new VertexPositionTexture[3] { | ||||||
|  | @ -144,39 +167,93 @@ namespace Kav | ||||||
|                 new VertexPositionTexture(new Vector3(3, 1, 0), new Vector2(2, 0)) |                 new VertexPositionTexture(new Vector3(3, 1, 0), new Vector2(2, 0)) | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
|  |             UnitCube = Kav.ModelLoader.Load( | ||||||
|  |                 GraphicsDevice, | ||||||
|  |                 Smuggler.Importer.ImportGLB(GraphicsDevice, new MemoryStream(Resources.UnitCubeModel)) | ||||||
|  |             ); | ||||||
|  | 
 | ||||||
|             SpriteBatch = new SpriteBatch(graphicsDevice); |             SpriteBatch = new SpriteBatch(graphicsDevice); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void DeferredRender( |         public void DeferredRender( | ||||||
|             PerspectiveCamera camera, |             PerspectiveCamera camera, | ||||||
|             IEnumerable<(Model, Matrix)> modelTransforms, |             IEnumerable<(Model, Matrix)> modelTransforms, | ||||||
|  |             AmbientLight ambientLight, | ||||||
|             IEnumerable<PointLight> pointLights, |             IEnumerable<PointLight> pointLights, | ||||||
|             DirectionalLight directionalLight |             DirectionalLight directionalLight | ||||||
|         ) { |         ) { | ||||||
|             // g-buffer pass |             GBufferRender(camera, modelTransforms); | ||||||
| 
 | 
 | ||||||
|             GraphicsDevice.SetRenderTargets(GBuffer); |             GraphicsDevice.SetRenderTarget(ColorRenderTarget); | ||||||
|  |             GraphicsDevice.Clear(Color.Black); | ||||||
|  | 
 | ||||||
|  |             AmbientLightRender(ambientLight); | ||||||
|  | 
 | ||||||
|  |             DeferredPointLightEffect.EyePosition = camera.Position; | ||||||
|  | 
 | ||||||
|  |             foreach (var pointLight in pointLights) | ||||||
|  |             { | ||||||
|  |                 PointLightRender(camera, modelTransforms, 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, | ||||||
|  |             IEnumerable<PointLight> pointLights, | ||||||
|  |             DirectionalLight directionalLight, | ||||||
|  |             TextureCube skybox | ||||||
|  |         ) {             | ||||||
|  |             GBufferRender(camera, modelTransforms); | ||||||
|  | 
 | ||||||
|  |             GraphicsDevice.SetRenderTarget(ColorRenderTarget); | ||||||
|             GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); |             GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); | ||||||
|             GraphicsDevice.DepthStencilState = DepthStencilState.Default; |             GraphicsDevice.DepthStencilState = DepthStencilState.Default; | ||||||
|             GraphicsDevice.BlendState = BlendState.Opaque; |  | ||||||
| 
 | 
 | ||||||
|  |             DepthRender(camera, modelTransforms); | ||||||
|  |             GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; | ||||||
|  | 
 | ||||||
|  |             AmbientLightRender(ambientLight); | ||||||
|  |             foreach (var pointLight in pointLights) | ||||||
|  |             { | ||||||
|  |                 PointLightRender(camera, modelTransforms, pointLight); | ||||||
|  |             } | ||||||
|  |             DirectionalLightToonRender(camera, modelTransforms, directionalLight); | ||||||
|  |             SkyboxRender(camera, skybox); | ||||||
|  | 
 | ||||||
|  |             GraphicsDevice.SetRenderTarget(null); | ||||||
|  |             SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, null); | ||||||
|  |             SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White); | ||||||
|  |             SpriteBatch.End(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private void DepthRender( | ||||||
|  |             PerspectiveCamera camera, | ||||||
|  |             IEnumerable<(Model, Matrix)> modelTransforms | ||||||
|  |         ) { | ||||||
|             foreach (var (model, transform) in modelTransforms) |             foreach (var (model, transform) in modelTransforms) | ||||||
|             { |             { | ||||||
|                 foreach (var modelMesh in model.Meshes) |                 foreach (var modelMesh in model.Meshes) | ||||||
|                 { |                 { | ||||||
|                     foreach (var meshPart in modelMesh.MeshParts) |                     foreach (var meshPart in modelMesh.MeshParts) | ||||||
|                     { |                     { | ||||||
|  |                         SimpleDepthEffect.Model = transform; | ||||||
|  |                         SimpleDepthEffect.View = camera.View; | ||||||
|  |                         SimpleDepthEffect.Projection = camera.Projection; | ||||||
|  | 
 | ||||||
|                         GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); |                         GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); | ||||||
|                         GraphicsDevice.Indices = meshPart.IndexBuffer; |                         GraphicsDevice.Indices = meshPart.IndexBuffer; | ||||||
| 
 | 
 | ||||||
|                         if (meshPart.Effect is TransformEffect transformEffect) |                         foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes) | ||||||
|                         { |  | ||||||
|                             transformEffect.World = transform; |  | ||||||
|                             transformEffect.View = camera.View; |  | ||||||
|                             transformEffect.Projection = camera.Projection; |  | ||||||
|                         } |  | ||||||
| 
 |  | ||||||
|                         foreach (var pass in meshPart.Effect.CurrentTechnique.Passes) |  | ||||||
|                         { |                         { | ||||||
|                             pass.Apply(); |                             pass.Apply(); | ||||||
| 
 | 
 | ||||||
|  | @ -192,14 +269,96 @@ namespace Kav | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|  |         private void SkyboxRender( | ||||||
|  |             PerspectiveCamera camera, | ||||||
|  |             TextureCube skybox | ||||||
|  |         ) { | ||||||
|  |             GraphicsDevice.RasterizerState.CullMode = CullMode.CullClockwiseFace; | ||||||
|  |             SkyboxEffect.Skybox = skybox; | ||||||
|  | 
 | ||||||
|  |             var view = camera.View; | ||||||
|  |             view.Translation = Vector3.Zero; | ||||||
|  |             SkyboxEffect.View = view; | ||||||
|  | 
 | ||||||
|  |             SkyboxEffect.Projection = camera.Projection; | ||||||
|  | 
 | ||||||
|  |             GraphicsDevice.SetVertexBuffer(UnitCube.Meshes[0].MeshParts[0].VertexBuffer); | ||||||
|  |             GraphicsDevice.Indices = UnitCube.Meshes[0].MeshParts[0].IndexBuffer; | ||||||
|  | 
 | ||||||
|  |             foreach (var pass in SkyboxEffect.CurrentTechnique.Passes) | ||||||
|  |             { | ||||||
|  |                 pass.Apply(); | ||||||
|  | 
 | ||||||
|  |                 GraphicsDevice.DrawIndexedPrimitives( | ||||||
|  |                     PrimitiveType.TriangleList, | ||||||
|  |                     0, | ||||||
|  |                     0, | ||||||
|  |                     UnitCube.Meshes[0].MeshParts[0].VertexBuffer.VertexCount, | ||||||
|  |                     0, | ||||||
|  |                     UnitCube.Meshes[0].MeshParts[0].Triangles.Length | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             GraphicsDevice.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         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; | ||||||
|  |             GraphicsDevice.BlendState = BlendState.Opaque; | ||||||
|  | 
 | ||||||
|  |             foreach (var (model, transform) in modelTransforms) | ||||||
|  |             { | ||||||
|  |                 foreach (var modelMesh in model.Meshes) | ||||||
|  |                 { | ||||||
|  |                     foreach (var meshPart in modelMesh.MeshParts) | ||||||
|  |                     { | ||||||
|  |                         Deferred_GBufferEffect.World = transform; | ||||||
|  |                         Deferred_GBufferEffect.View = camera.View; | ||||||
|  |                         Deferred_GBufferEffect.Projection = camera.Projection; | ||||||
|  | 
 | ||||||
|  |                         Deferred_GBufferEffect.Albedo = meshPart.Albedo; | ||||||
|  |                         Deferred_GBufferEffect.Metallic = meshPart.Metallic; | ||||||
|  |                         Deferred_GBufferEffect.Roughness = meshPart.Roughness; | ||||||
|  | 
 | ||||||
|  |                         Deferred_GBufferEffect.AlbedoTexture = meshPart.AlbedoTexture; | ||||||
|  |                         Deferred_GBufferEffect.NormalTexture = meshPart.NormalTexture; | ||||||
|  |                         Deferred_GBufferEffect.MetallicRoughnessTexture = meshPart.MetallicRoughnessTexture; | ||||||
|  | 
 | ||||||
|  |                         GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); | ||||||
|  |                         GraphicsDevice.Indices = meshPart.IndexBuffer; | ||||||
|  | 
 | ||||||
|  |                         foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes) | ||||||
|  |                         { | ||||||
|  |                             pass.Apply(); | ||||||
|  | 
 | ||||||
|  |                             GraphicsDevice.DrawIndexedPrimitives( | ||||||
|  |                                 PrimitiveType.TriangleList, | ||||||
|  |                                 0, | ||||||
|  |                                 0, | ||||||
|  |                                 meshPart.VertexBuffer.VertexCount, | ||||||
|  |                                 0, | ||||||
|  |                                 meshPart.Triangles.Length | ||||||
|  |                             ); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private void AmbientLightRender(AmbientLight ambientLight) | ||||||
|  |         { | ||||||
|             GraphicsDevice.SetRenderTarget(ColorRenderTarget); |             GraphicsDevice.SetRenderTarget(ColorRenderTarget); | ||||||
|             GraphicsDevice.Clear(Color.Black); |             GraphicsDevice.BlendState = BlendState.Opaque; | ||||||
|             GraphicsDevice.BlendState = BlendState.Additive; |  | ||||||
|             GraphicsDevice.DepthStencilState = DepthStencilState.None; |  | ||||||
| 
 | 
 | ||||||
|             DeferredAmbientLightEffect.GPosition = gPosition; |             DeferredAmbientLightEffect.GPosition = gPosition; | ||||||
|             DeferredAmbientLightEffect.GAlbedo = gAlbedo; |             DeferredAmbientLightEffect.GAlbedo = gAlbedo; | ||||||
|  |             DeferredAmbientLightEffect.AmbientColor = ambientLight.Color.ToVector3(); | ||||||
| 
 | 
 | ||||||
|             foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes) |             foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes) | ||||||
|             { |             { | ||||||
|  | @ -207,39 +366,31 @@ namespace Kav | ||||||
|                 GraphicsDevice.SetVertexBuffer(FullscreenTriangle); |                 GraphicsDevice.SetVertexBuffer(FullscreenTriangle); | ||||||
|                 GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); |                 GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); | ||||||
|             } |             } | ||||||
| 
 |  | ||||||
|             DeferredPointLightEffect.EyePosition = camera.Position; |  | ||||||
| 
 |  | ||||||
|             foreach (var pointLight in pointLights) |  | ||||||
|             { |  | ||||||
|                 PointLightRender(pointLight); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|             DirectionalLightRender(camera, modelTransforms, directionalLight); |         private void PointLightRender( | ||||||
|             // return; |             PerspectiveCamera camera, | ||||||
|             // GraphicsDevice.SetRenderTarget(null); |             IEnumerable<(Model, Matrix)> modelTransforms, | ||||||
|             // SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied); |             PointLight pointLight | ||||||
|             // SpriteBatch.Draw(DirectionalRenderTarget, Vector2.Zero, Color.White); |         ) { | ||||||
|             // SpriteBatch.End(); |             RenderPointShadows(camera, modelTransforms, pointLight); | ||||||
| 
 | 
 | ||||||
|             GraphicsDevice.SetRenderTarget(null); |             GraphicsDevice.SetRenderTarget(ColorRenderTarget); | ||||||
|             GraphicsDevice.Clear(Color.Black); |             GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; | ||||||
|             SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, ToneMapEffect); |             GraphicsDevice.BlendState = BlendState.Additive; | ||||||
|             SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White); |  | ||||||
|             SpriteBatch.End(); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         private void PointLightRender(PointLight pointLight)  |  | ||||||
|         { |  | ||||||
|             DeferredPointLightEffect.GPosition = gPosition; |             DeferredPointLightEffect.GPosition = gPosition; | ||||||
|             DeferredPointLightEffect.GAlbedo = gAlbedo; |             DeferredPointLightEffect.GAlbedo = gAlbedo; | ||||||
|             DeferredPointLightEffect.GNormal = gNormal; |             DeferredPointLightEffect.GNormal = gNormal; | ||||||
|             DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness;     |             DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness;     | ||||||
|  |             DeferredPointLightEffect.ShadowMap = PointShadowCubeMap; | ||||||
| 
 | 
 | ||||||
|             DeferredPointLightEffect.PointLightPosition = pointLight.Position; |             DeferredPointLightEffect.PointLightPosition = pointLight.Position; | ||||||
|             DeferredPointLightEffect.PointLightColor =  |             DeferredPointLightEffect.PointLightColor =  | ||||||
|                 pointLight.Color.ToVector3() * pointLight.Intensity; |                 pointLight.Color.ToVector3() * pointLight.Intensity; | ||||||
| 
 | 
 | ||||||
|  |             DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value | ||||||
|  | 
 | ||||||
|             foreach (var pass in DeferredPointLightEffect.CurrentTechnique.Passes) |             foreach (var pass in DeferredPointLightEffect.CurrentTechnique.Passes) | ||||||
|             { |             { | ||||||
|                 pass.Apply(); |                 pass.Apply(); | ||||||
|  | @ -253,28 +404,7 @@ namespace Kav | ||||||
|             IEnumerable<(Model, Matrix)> modelTransforms, |             IEnumerable<(Model, Matrix)> modelTransforms, | ||||||
|             DirectionalLight directionalLight |             DirectionalLight directionalLight | ||||||
|         ) { |         ) { | ||||||
|             // render the individual shadow cascades |             RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect); | ||||||
|             var previousFarPlane = camera.NearPlane; |  | ||||||
|             for (var i = 0; i < NumShadowCascades; i++) |  | ||||||
|             { |  | ||||||
|                 var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f)); |  | ||||||
| 
 |  | ||||||
|                 // divide the view frustum  |  | ||||||
|                 var shadowCamera = new PerspectiveCamera( |  | ||||||
|                     camera.Position, |  | ||||||
|                     camera.Forward, |  | ||||||
|                     camera.Up, |  | ||||||
|                     camera.FieldOfView, |  | ||||||
|                     camera.AspectRatio, |  | ||||||
|                     previousFarPlane, |  | ||||||
|                     farPlane |  | ||||||
|                 ); |  | ||||||
|                  |  | ||||||
|                 // TODO: This is tightly coupled to the effect and it sucks |  | ||||||
|                 RenderShadowMap(shadowCamera, modelTransforms, directionalLight, i); |  | ||||||
| 
 |  | ||||||
|                 previousFarPlane = farPlane; |  | ||||||
|             } |  | ||||||
| 
 | 
 | ||||||
|             DeferredDirectionalLightEffect.GPosition = gPosition; |             DeferredDirectionalLightEffect.GPosition = gPosition; | ||||||
|             DeferredDirectionalLightEffect.GAlbedo = gAlbedo; |             DeferredDirectionalLightEffect.GAlbedo = gAlbedo; | ||||||
|  | @ -300,7 +430,7 @@ namespace Kav | ||||||
|                 directionalLight.Color.ToVector3() * directionalLight.Intensity; |                 directionalLight.Color.ToVector3() * directionalLight.Intensity; | ||||||
|              |              | ||||||
|             DeferredDirectionalLightEffect.ViewMatrix = camera.View; |             DeferredDirectionalLightEffect.ViewMatrix = camera.View; | ||||||
|             DeferredDirectionalLightEffect.EyePosition = Matrix.Invert(camera.View).Translation; |             DeferredDirectionalLightEffect.EyePosition = camera.Position; | ||||||
| 
 | 
 | ||||||
|             GraphicsDevice.SetRenderTarget(ColorRenderTarget); |             GraphicsDevice.SetRenderTarget(ColorRenderTarget); | ||||||
|             GraphicsDevice.BlendState = BlendState.Additive; |             GraphicsDevice.BlendState = BlendState.Additive; | ||||||
|  | @ -313,10 +443,89 @@ namespace Kav | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private void RenderShadowMap( |         private void DirectionalLightToonRender( | ||||||
|  |             PerspectiveCamera camera, | ||||||
|  |             IEnumerable<(Model, Matrix)> modelTransforms, | ||||||
|  |             DirectionalLight directionalLight | ||||||
|  |         ) { | ||||||
|  |             RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect); | ||||||
|  | 
 | ||||||
|  |             GraphicsDevice.SetRenderTarget(ColorRenderTarget); | ||||||
|  |             GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; | ||||||
|  |             GraphicsDevice.BlendState = BlendState.Additive; | ||||||
|  | 
 | ||||||
|  |             Deferred_ToonEffect.GPosition = gPosition; | ||||||
|  |             Deferred_ToonEffect.GAlbedo = gAlbedo; | ||||||
|  |             Deferred_ToonEffect.GNormal = gNormal; | ||||||
|  |             Deferred_ToonEffect.GMetallicRoughness = gMetallicRoughness; | ||||||
|  | 
 | ||||||
|  |             Deferred_ToonEffect.DitheredShadows = false; | ||||||
|  | 
 | ||||||
|  |             Deferred_ToonEffect.EyePosition = camera.Position; | ||||||
|  |             Deferred_ToonEffect.DirectionalLightDirection = directionalLight.Direction; | ||||||
|  |             Deferred_ToonEffect.DirectionalLightColor =  | ||||||
|  |                 directionalLight.Color.ToVector3() * directionalLight.Intensity; | ||||||
|  | 
 | ||||||
|  |             Deferred_ToonEffect.ShadowMapOne = ShadowRenderTargets[0]; | ||||||
|  |             if (NumShadowCascades > 1) | ||||||
|  |             { | ||||||
|  |                 Deferred_ToonEffect.ShadowMapTwo = ShadowRenderTargets[1]; | ||||||
|  |             } | ||||||
|  |             if (NumShadowCascades > 2) | ||||||
|  |             { | ||||||
|  |                 Deferred_ToonEffect.ShadowMapThree = ShadowRenderTargets[2]; | ||||||
|  |             } | ||||||
|  |             if (NumShadowCascades > 3) | ||||||
|  |             { | ||||||
|  |                 Deferred_ToonEffect.ShadowMapFour = ShadowRenderTargets[3]; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             Deferred_ToonEffect.ViewMatrix = camera.View; | ||||||
|  | 
 | ||||||
|  |             foreach (EffectPass pass in Deferred_ToonEffect.CurrentTechnique.Passes) | ||||||
|  |             { | ||||||
|  |                 pass.Apply(); | ||||||
|  |                 GraphicsDevice.SetVertexBuffer(FullscreenTriangle); | ||||||
|  |                 GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private void RenderDirectionalShadows( | ||||||
|             PerspectiveCamera camera, |             PerspectiveCamera camera, | ||||||
|             IEnumerable<(Model, Matrix)> modelTransforms, |             IEnumerable<(Model, Matrix)> modelTransforms, | ||||||
|             DirectionalLight directionalLight, |             DirectionalLight directionalLight, | ||||||
|  |             ShadowCascadeEffect effect | ||||||
|  |         ) { | ||||||
|  |             // render the individual shadow cascades | ||||||
|  |             var previousFarPlane = camera.NearPlane; | ||||||
|  |             for (var i = 0; i < NumShadowCascades; i++) | ||||||
|  |             { | ||||||
|  |                 var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f)); | ||||||
|  | 
 | ||||||
|  |                 // divide the view frustum  | ||||||
|  |                 var shadowCamera = new PerspectiveCamera( | ||||||
|  |                     camera.Position, | ||||||
|  |                     camera.Forward, | ||||||
|  |                     camera.Up, | ||||||
|  |                     camera.FieldOfView, | ||||||
|  |                     camera.AspectRatio, | ||||||
|  |                     previousFarPlane, | ||||||
|  |                     farPlane | ||||||
|  |                 ); | ||||||
|  |                  | ||||||
|  |                 // TODO: This is tightly coupled to the effect and it sucks | ||||||
|  |                 RenderDirectionalShadowMap(shadowCamera, modelTransforms, directionalLight, effect, i); | ||||||
|  | 
 | ||||||
|  |                 effect.CascadeFarPlanes[i] = farPlane; | ||||||
|  |                 previousFarPlane = farPlane; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private void RenderDirectionalShadowMap( | ||||||
|  |             PerspectiveCamera camera,  | ||||||
|  |             IEnumerable<(Model, Matrix)> modelTransforms,  | ||||||
|  |             DirectionalLight directionalLight, | ||||||
|  |             ShadowCascadeEffect effect, | ||||||
|             int shadowCascadeIndex |             int shadowCascadeIndex | ||||||
|         ) { |         ) { | ||||||
|             GraphicsDevice.SetRenderTarget(ShadowRenderTargets[shadowCascadeIndex]); |             GraphicsDevice.SetRenderTarget(ShadowRenderTargets[shadowCascadeIndex]); | ||||||
|  | @ -357,23 +566,21 @@ namespace Kav | ||||||
| 
 | 
 | ||||||
|             if (shadowCascadeIndex == 0) |             if (shadowCascadeIndex == 0) | ||||||
|             { |             { | ||||||
|                 DeferredDirectionalLightEffect.LightSpaceMatrixOne = lightSpaceMatrix; |                 effect.LightSpaceMatrixOne = lightSpaceMatrix; | ||||||
|             } |             } | ||||||
|             else if (shadowCascadeIndex == 1) |             else if (shadowCascadeIndex == 1) | ||||||
|             { |             { | ||||||
|                 DeferredDirectionalLightEffect.LightSpaceMatrixTwo = lightSpaceMatrix; |                 effect.LightSpaceMatrixTwo = lightSpaceMatrix; | ||||||
|             } |             } | ||||||
|             else if (shadowCascadeIndex == 2) |             else if (shadowCascadeIndex == 2) | ||||||
|             { |             { | ||||||
|                 DeferredDirectionalLightEffect.LightSpaceMatrixThree = lightSpaceMatrix; |                 effect.LightSpaceMatrixThree = lightSpaceMatrix; | ||||||
|             } |             } | ||||||
|             else if (shadowCascadeIndex == 3) |             else if (shadowCascadeIndex == 3) | ||||||
|             { |             { | ||||||
|                 DeferredDirectionalLightEffect.LightSpaceMatrixFour = lightSpaceMatrix; |                 effect.LightSpaceMatrixFour = lightSpaceMatrix; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             DeferredDirectionalLightEffect.CascadeFarPlanes[shadowCascadeIndex] = camera.FarPlane; |  | ||||||
| 
 |  | ||||||
|             foreach (var (model, transform) in modelTransforms) |             foreach (var (model, transform) in modelTransforms) | ||||||
|             { |             { | ||||||
|                 foreach (var modelMesh in model.Meshes) |                 foreach (var modelMesh in model.Meshes) | ||||||
|  | @ -403,22 +610,73 @@ namespace Kav | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Render( |         private void RenderPointShadows( | ||||||
|             PerspectiveCamera camera, |             PerspectiveCamera camera, | ||||||
|             IEnumerable<(Model, Matrix)> modelTransforms, |             IEnumerable<(Model, Matrix)> modelTransforms, | ||||||
|             IEnumerable<PointLight> pointLights, |             PointLight pointLight | ||||||
|             IEnumerable<DirectionalLight> directionalLights |  | ||||||
|         ) { |         ) { | ||||||
|             Render(camera.View, camera.Projection, modelTransforms, pointLights, directionalLights); |             GraphicsDevice.DepthStencilState = DepthStencilState.Default; | ||||||
|  |             GraphicsDevice.BlendState = BlendState.Opaque; | ||||||
|  | 
 | ||||||
|  |             LinearDepthEffect.Projection = Matrix.CreatePerspectiveFieldOfView( | ||||||
|  |                 MathHelper.PiOver2, | ||||||
|  |                 1, | ||||||
|  |                 0.1f, | ||||||
|  |                 25f // FIXME: magic value | ||||||
|  |             ); | ||||||
|  |             LinearDepthEffect.FarPlane = 25f; | ||||||
|  |             LinearDepthEffect.LightPosition = pointLight.Position; | ||||||
|  | 
 | ||||||
|  |             foreach (CubeMapFace face in Enum.GetValues(typeof(CubeMapFace))) | ||||||
|  |             { | ||||||
|  |                 GraphicsDevice.SetRenderTarget(PointShadowCubeMap, face); | ||||||
|  | 
 | ||||||
|  |                 Vector3 targetDirection; | ||||||
|  |                 Vector3 targetUpDirection; | ||||||
|  |                 switch(face) | ||||||
|  |                 { | ||||||
|  |                     case CubeMapFace.PositiveX: | ||||||
|  |                         targetDirection = Vector3.Right; | ||||||
|  |                         targetUpDirection = Vector3.Up; | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                     case CubeMapFace.NegativeX: | ||||||
|  |                         targetDirection = Vector3.Left; | ||||||
|  |                         targetUpDirection = Vector3.Up; | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                     case CubeMapFace.PositiveY: | ||||||
|  |                         targetDirection = Vector3.Up; | ||||||
|  |                         targetUpDirection = Vector3.Forward; | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                     case CubeMapFace.NegativeY: | ||||||
|  |                         targetDirection = Vector3.Down; | ||||||
|  |                         targetUpDirection = Vector3.Backward; | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                     case CubeMapFace.PositiveZ: | ||||||
|  |                         targetDirection = Vector3.Backward; | ||||||
|  |                         targetUpDirection = Vector3.Up; | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                     case CubeMapFace.NegativeZ: | ||||||
|  |                         targetDirection = Vector3.Forward; | ||||||
|  |                         targetUpDirection = Vector3.Up; | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                     default: | ||||||
|  |                         targetDirection = Vector3.Right; | ||||||
|  |                         targetUpDirection = Vector3.Up; | ||||||
|  |                         break; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|         private void Render( |                 LinearDepthEffect.View = Matrix.CreateLookAt( | ||||||
|             Matrix view, |                     pointLight.Position, | ||||||
|             Matrix projection, |                     pointLight.Position + targetDirection, | ||||||
|             IEnumerable<(Model, Matrix)> modelTransforms, |                     targetUpDirection | ||||||
|             IEnumerable<PointLight> pointLights, |                 ); | ||||||
|             IEnumerable<DirectionalLight> directionalLights | 
 | ||||||
|         ) { |  | ||||||
|                 foreach (var (model, transform) in modelTransforms) |                 foreach (var (model, transform) in modelTransforms) | ||||||
|                 { |                 { | ||||||
|                     foreach (var modelMesh in model.Meshes) |                     foreach (var modelMesh in model.Meshes) | ||||||
|  | @ -428,25 +686,9 @@ namespace Kav | ||||||
|                             GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); |                             GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); | ||||||
|                             GraphicsDevice.Indices = meshPart.IndexBuffer; |                             GraphicsDevice.Indices = meshPart.IndexBuffer; | ||||||
| 
 | 
 | ||||||
|                         if (meshPart.Effect is TransformEffect transformEffect) |                             LinearDepthEffect.Model = transform; | ||||||
|                         { |  | ||||||
|                             transformEffect.World = transform; |  | ||||||
|                             transformEffect.View = view; |  | ||||||
|                             transformEffect.Projection = projection; |  | ||||||
|                         } |  | ||||||
| 
 | 
 | ||||||
|                         if (meshPart.Effect is PointLightEffect pointLightEffect) |                             foreach (var pass in LinearDepthEffect.CurrentTechnique.Passes) | ||||||
|                         { |  | ||||||
|                             int i = 0; |  | ||||||
|                             foreach (var pointLight in pointLights) |  | ||||||
|                             { |  | ||||||
|                                 if (i > pointLightEffect.MaxPointLights) { break; } |  | ||||||
|                                 pointLightEffect.PointLights[i] = pointLight; |  | ||||||
|                                 i++; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
| 
 |  | ||||||
|                         foreach (var pass in meshPart.Effect.CurrentTechnique.Passes) |  | ||||||
|                             { |                             { | ||||||
|                                 pass.Apply(); |                                 pass.Apply(); | ||||||
| 
 | 
 | ||||||
|  | @ -465,3 +707,4 @@ namespace Kav | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										71
									
								
								Resources.cs
								
								
								
								
							
							
						
						
									
										71
									
								
								Resources.cs
								
								
								
								
							|  | @ -10,7 +10,7 @@ namespace Kav | ||||||
|             { |             { | ||||||
|                 if (ambientLightEffect == null) |                 if (ambientLightEffect == null) | ||||||
|                 { |                 { | ||||||
|                     ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect"); |                     ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect.fxb"); | ||||||
|                 } |                 } | ||||||
|                 return ambientLightEffect; |                 return ambientLightEffect; | ||||||
|             } |             } | ||||||
|  | @ -21,7 +21,7 @@ namespace Kav | ||||||
|             { |             { | ||||||
|                 if (pointLightEffect == null) |                 if (pointLightEffect == null) | ||||||
|                 { |                 { | ||||||
|                     pointLightEffect = GetResource("DeferredPBR_PointLightEffect"); |                     pointLightEffect = GetResource("DeferredPBR_PointLightEffect.fxb"); | ||||||
|                 } |                 } | ||||||
|                 return pointLightEffect; |                 return pointLightEffect; | ||||||
|             } |             } | ||||||
|  | @ -33,7 +33,7 @@ namespace Kav | ||||||
|             { |             { | ||||||
|                 if (directionalLightEffect == null) |                 if (directionalLightEffect == null) | ||||||
|                 { |                 { | ||||||
|                     directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect"); |                     directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect.fxb"); | ||||||
|                 } |                 } | ||||||
|                 return directionalLightEffect; |                 return directionalLightEffect; | ||||||
|             } |             } | ||||||
|  | @ -45,7 +45,7 @@ namespace Kav | ||||||
|             { |             { | ||||||
|                 if (gBufferEffect == null) |                 if (gBufferEffect == null) | ||||||
|                 { |                 { | ||||||
|                     gBufferEffect = GetResource("DeferredPBR_GBufferEffect"); |                     gBufferEffect = GetResource("DeferredPBR_GBufferEffect.fxb"); | ||||||
|                 } |                 } | ||||||
|                 return gBufferEffect; |                 return gBufferEffect; | ||||||
|             } |             } | ||||||
|  | @ -57,19 +57,31 @@ namespace Kav | ||||||
|             { |             { | ||||||
|                 if (toneMapEffect == null) |                 if (toneMapEffect == null) | ||||||
|                 { |                 { | ||||||
|                     toneMapEffect = GetResource("ToneMapEffect"); |                     toneMapEffect = GetResource("ToneMapEffect.fxb"); | ||||||
|                 } |                 } | ||||||
|                 return toneMapEffect; |                 return toneMapEffect; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         public static byte[] Deferred_ToonEffect | ||||||
|  |         { | ||||||
|  |             get | ||||||
|  |             { | ||||||
|  |                 if (deferredToonEffect == null) | ||||||
|  |                 { | ||||||
|  |                     deferredToonEffect = GetResource("Deferred_ToonEffect.fxb"); | ||||||
|  |                 } | ||||||
|  |                 return deferredToonEffect; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         public static byte[] DeferredPBREffect |         public static byte[] DeferredPBREffect | ||||||
|         { |         { | ||||||
|             get |             get | ||||||
|             { |             { | ||||||
|                 if (deferredPBREffect == null) |                 if (deferredPBREffect == null) | ||||||
|                 { |                 { | ||||||
|                     deferredPBREffect = GetResource("DeferredPBREffect"); |                     deferredPBREffect = GetResource("DeferredPBREffect.fxb"); | ||||||
|                 } |                 } | ||||||
|                 return deferredPBREffect; |                 return deferredPBREffect; | ||||||
|             } |             } | ||||||
|  | @ -81,7 +93,7 @@ namespace Kav | ||||||
|             { |             { | ||||||
|                 if (pbrEffect == null) |                 if (pbrEffect == null) | ||||||
|                 { |                 { | ||||||
|                     pbrEffect = GetResource("PBREffect"); |                     pbrEffect = GetResource("PBREffect.fxb"); | ||||||
|                 } |                 } | ||||||
|                 return pbrEffect; |                 return pbrEffect; | ||||||
|             } |             } | ||||||
|  | @ -93,25 +105,66 @@ namespace Kav | ||||||
|             { |             { | ||||||
|                 if (simpleDepthEffect == null) |                 if (simpleDepthEffect == null) | ||||||
|                 { |                 { | ||||||
|                     simpleDepthEffect = GetResource("SimpleDepthEffect"); |                     simpleDepthEffect = GetResource("SimpleDepthEffect.fxb"); | ||||||
|                 } |                 } | ||||||
|                 return simpleDepthEffect; |                 return simpleDepthEffect; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         public static byte[] LinearDepthEffect | ||||||
|  |         { | ||||||
|  |             get | ||||||
|  |             { | ||||||
|  |                 if (linearDepthEffect == null) | ||||||
|  |                 { | ||||||
|  |                     linearDepthEffect = GetResource("LinearDepthEffect.fxb"); | ||||||
|  |                 } | ||||||
|  |                 return linearDepthEffect; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public static byte[] SkyboxEffect | ||||||
|  |         { | ||||||
|  |             get | ||||||
|  |             { | ||||||
|  |                 if (skyboxEffect == null) | ||||||
|  |                 { | ||||||
|  |                     skyboxEffect = GetResource("SkyboxEffect.fxb"); | ||||||
|  |                 } | ||||||
|  |                 return skyboxEffect; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public static byte[] UnitCubeModel | ||||||
|  |         { | ||||||
|  |             get | ||||||
|  |             { | ||||||
|  |                 if (unitCubeModel == null) | ||||||
|  |                 { | ||||||
|  |                     unitCubeModel = GetResource("UnitCube.glb"); | ||||||
|  |                 } | ||||||
|  |                 return unitCubeModel; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         private static byte[] ambientLightEffect; |         private static byte[] ambientLightEffect; | ||||||
|         private static byte[] pointLightEffect; |         private static byte[] pointLightEffect; | ||||||
|         private static byte[] directionalLightEffect; |         private static byte[] directionalLightEffect; | ||||||
|         private static byte[] gBufferEffect; |         private static byte[] gBufferEffect; | ||||||
|         private static byte[] toneMapEffect; |         private static byte[] toneMapEffect; | ||||||
|  |         private static byte[] deferredToonEffect; | ||||||
|         private static byte[] deferredPBREffect; |         private static byte[] deferredPBREffect; | ||||||
|         private static byte[] pbrEffect; |         private static byte[] pbrEffect; | ||||||
|         private static byte[] simpleDepthEffect; |         private static byte[] simpleDepthEffect; | ||||||
|  |         private static byte[] linearDepthEffect; | ||||||
|  |         private static byte[] skyboxEffect; | ||||||
|  | 
 | ||||||
|  |         private static byte[] unitCubeModel; | ||||||
| 
 | 
 | ||||||
|         private static byte[] GetResource(string name) |         private static byte[] GetResource(string name) | ||||||
|         { |         { | ||||||
|             Stream stream = typeof(Resources).Assembly.GetManifestResourceStream( |             Stream stream = typeof(Resources).Assembly.GetManifestResourceStream( | ||||||
|                 "Kav.Resources." + name + ".fxb" |                 "Kav.Resources." + name | ||||||
|             ); |             ); | ||||||
|             using (MemoryStream ms = new MemoryStream()) |             using (MemoryStream ms = new MemoryStream()) | ||||||
|             { |             { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue