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; | ||||
| 
 | ||||
| namespace Kav | ||||
|  | @ -8,9 +9,13 @@ namespace Kav | |||
|         EffectParameter gPositionParam; | ||||
|         EffectParameter gAlbedoParam; | ||||
| 
 | ||||
|         EffectParameter ambientColorParam; | ||||
| 
 | ||||
|         public Texture2D GPosition { get; set; } | ||||
|         public Texture2D GAlbedo { get; set; } | ||||
| 
 | ||||
|         public Vector3 AmbientColor { get; set; } | ||||
| 
 | ||||
|         public DeferredPBR_AmbientLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_AmbientLightEffect) | ||||
|         { | ||||
|             CacheEffectParameters(); | ||||
|  | @ -20,12 +25,14 @@ namespace Kav | |||
|         { | ||||
|             gPositionParam.SetValue(GPosition); | ||||
|             gAlbedoParam.SetValue(GAlbedo); | ||||
|             ambientColorParam.SetValue(AmbientColor); | ||||
|         } | ||||
| 
 | ||||
|         void CacheEffectParameters() | ||||
|         { | ||||
|             gPositionParam    = Parameters["gPosition"]; | ||||
|             gAlbedoParam      = Parameters["gAlbedo"]; | ||||
|             ambientColorParam = Parameters["AmbientLightColor"]; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics; | |||
| 
 | ||||
| namespace Kav | ||||
| { | ||||
|     public class DeferredPBR_DirectionalLightEffect : Effect | ||||
|     public class DeferredPBR_DirectionalLightEffect : Effect, ShadowCascadeEffect | ||||
|     { | ||||
|         EffectParameter gPositionParam; | ||||
|         EffectParameter gAlbedoParam; | ||||
|  | @ -46,7 +46,7 @@ namespace Kav | |||
|         public Vector3 DirectionalLightDirection { get; set; } | ||||
|         public Vector3 DirectionalLightColor { get; set; } | ||||
| 
 | ||||
|         public readonly float[] CascadeFarPlanes; | ||||
|         public float[] CascadeFarPlanes { get; } | ||||
| 
 | ||||
|         public int ShadowMapSize { get; set; } | ||||
| 
 | ||||
|  | @ -147,7 +147,6 @@ namespace Kav | |||
|             directionalLightColorParam     = Parameters["DirectionalLightColor"]; | ||||
| 
 | ||||
|             cascadeFarPlanesParam          = Parameters["CascadeFarPlanes"]; | ||||
| 
 | ||||
|             shadowMapSizeParam             = Parameters["ShadowMapSize"]; | ||||
| 
 | ||||
|             lightSpaceMatrixOneParam       = Parameters["LightSpaceMatrixOne"]; | ||||
|  |  | |||
|  | @ -9,22 +9,28 @@ namespace Kav | |||
|         EffectParameter gAlbedoParam; | ||||
|         EffectParameter gNormalParam; | ||||
|         EffectParameter gMetallicRoughnessParam; | ||||
|         EffectParameter shadowMapParam; | ||||
| 
 | ||||
|         EffectParameter eyePositionParam; | ||||
| 
 | ||||
|         EffectParameter pointLightColorParam; | ||||
|         EffectParameter pointLightPositionParam; | ||||
| 
 | ||||
|         EffectParameter farPlaneParam; | ||||
| 
 | ||||
|         public Texture2D GPosition { get; set; } | ||||
|         public Texture2D GAlbedo { get; set; } | ||||
|         public Texture2D GNormal { get; set; } | ||||
|         public Texture2D GMetallicRoughness { get; set; } | ||||
|         public TextureCube ShadowMap { get; set; } | ||||
| 
 | ||||
|         public Vector3 EyePosition { get; set; } | ||||
| 
 | ||||
|         public Vector3 PointLightPosition { get; set; } | ||||
|         public Vector3 PointLightColor { get; set; } | ||||
| 
 | ||||
|         public float FarPlane { get; set; } | ||||
| 
 | ||||
|         public DeferredPBR_PointLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_PointLightEffect) | ||||
|         { | ||||
|             CacheEffectParameters(); | ||||
|  | @ -32,15 +38,20 @@ namespace Kav | |||
| 
 | ||||
|         public DeferredPBR_PointLightEffect(DeferredPBR_PointLightEffect cloneSource) : base(cloneSource) | ||||
|         { | ||||
|             CacheEffectParameters(); | ||||
|              | ||||
|             GPosition = cloneSource.GPosition; | ||||
|             GAlbedo = cloneSource.GAlbedo; | ||||
|             GNormal = cloneSource.GNormal; | ||||
|             GMetallicRoughness = cloneSource.GMetallicRoughness; | ||||
|             ShadowMap = cloneSource.ShadowMap; | ||||
| 
 | ||||
|             EyePosition = cloneSource.EyePosition; | ||||
| 
 | ||||
|             PointLightPosition = cloneSource.PointLightPosition; | ||||
|             PointLightColor = cloneSource.PointLightColor; | ||||
| 
 | ||||
|             FarPlane = cloneSource.FarPlane; | ||||
|         } | ||||
| 
 | ||||
|         public override Effect Clone() | ||||
|  | @ -54,11 +65,14 @@ namespace Kav | |||
|             gAlbedoParam.SetValue(GAlbedo); | ||||
|             gNormalParam.SetValue(GNormal); | ||||
|             gMetallicRoughnessParam.SetValue(GMetallicRoughness); | ||||
|             shadowMapParam.SetValue(ShadowMap); | ||||
| 
 | ||||
|             eyePositionParam.SetValue(EyePosition); | ||||
| 
 | ||||
|             pointLightPositionParam.SetValue(PointLightPosition); | ||||
|             pointLightColorParam.SetValue(PointLightColor); | ||||
| 
 | ||||
|             farPlaneParam.SetValue(FarPlane); | ||||
|         } | ||||
| 
 | ||||
|         void CacheEffectParameters() | ||||
|  | @ -67,11 +81,14 @@ namespace Kav | |||
|             gAlbedoParam                   = Parameters["gAlbedo"]; | ||||
|             gNormalParam                   = Parameters["gNormal"]; | ||||
|             gMetallicRoughnessParam        = Parameters["gMetallicRoughness"]; | ||||
|             shadowMapParam                 = Parameters["shadowMap"]; | ||||
| 
 | ||||
|             eyePositionParam               = Parameters["EyePosition"]; | ||||
| 
 | ||||
|             pointLightPositionParam        = Parameters["PointLightPosition"]; | ||||
|             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(gAlbedo, 1); | ||||
| 
 | ||||
| BEGIN_CONSTANTS | ||||
| 
 | ||||
| float3 AmbientLightColor _ps(c0)   _cb(c0); | ||||
| 
 | ||||
| END_CONSTANTS | ||||
| 
 | ||||
| struct VertexInput | ||||
| { | ||||
|     float4 Position : POSITION; | ||||
|  | @ -29,7 +35,7 @@ float4 ComputeColor( | |||
|     float3 worldPosition, | ||||
|     float3 albedo | ||||
| ) { | ||||
|     float3 color = float3(0.03, 0.03, 0.03) * albedo; | ||||
|     float3 color = AmbientLightColor * albedo; | ||||
|     return float4(color, 1.0); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| #include "Macros.fxh" //from FNA | ||||
| #include "Lighting.fxh" | ||||
| #include "Shadow.fxh" | ||||
| 
 | ||||
| static const int NUM_SHADOW_CASCADES = 4; | ||||
| 
 | ||||
|  | @ -35,26 +36,6 @@ MATRIX_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 | ||||
| { | ||||
|     float4 Position : POSITION; | ||||
|  | @ -79,35 +60,8 @@ PixelInput main_vs(VertexInput input) | |||
| 
 | ||||
| // 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 bias = 0.005 * tan(acos(dot(N, L))); | ||||
|     bias = clamp(bias, 0, 0.01); | ||||
| 
 | ||||
|     float4 positionCameraSpace = mul(float4(positionWorldSpace, 1.0), ViewMatrix); | ||||
| 
 | ||||
|     int shadowCascadeIndex = 0; // 0 is closest | ||||
|  | @ -139,69 +93,52 @@ float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L) | |||
|         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 | ||||
|     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) | ||||
|     { | ||||
|         visibility = PoissonCoord(SAMPLER(shadowMapOne), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias); | ||||
|         return PoissonShadow( | ||||
|             positionWorldSpace, | ||||
|             N, | ||||
|             L, | ||||
|             lightSpaceMatrix, | ||||
|             SAMPLER(shadowMapOne), | ||||
|             ShadowMapSize | ||||
|         ); | ||||
|     } | ||||
|     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) | ||||
|     { | ||||
|         visibility = PoissonCoord(SAMPLER(shadowMapThree), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias); | ||||
|         return PoissonShadow( | ||||
|             positionWorldSpace, | ||||
|             N, | ||||
|             L, | ||||
|             lightSpaceMatrix, | ||||
|             SAMPLER(shadowMapThree), | ||||
|             ShadowMapSize | ||||
|         ); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         visibility = PoissonCoord(SAMPLER(shadowMapFour), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias); | ||||
|         return PoissonShadow( | ||||
|             positionWorldSpace, | ||||
|             N, | ||||
|             L, | ||||
|             lightSpaceMatrix, | ||||
|             SAMPLER(shadowMapFour), | ||||
|             ShadowMapSize | ||||
|         ); | ||||
|     } | ||||
| 
 | ||||
|     return visibility; | ||||
| } | ||||
| 
 | ||||
| float4 ComputeColor( | ||||
|  |  | |||
|  | @ -1,10 +1,12 @@ | |||
| #include "Macros.fxh" //from FNA | ||||
| #include "Lighting.fxh"  | ||||
| #include "Shadow.fxh" | ||||
| 
 | ||||
| DECLARE_TEXTURE(gPosition, 0); | ||||
| DECLARE_TEXTURE(gAlbedo, 1); | ||||
| DECLARE_TEXTURE(gNormal, 2); | ||||
| DECLARE_TEXTURE(gMetallicRoughness, 3); | ||||
| DECLARE_CUBEMAP(shadowMap, 4); | ||||
| 
 | ||||
| BEGIN_CONSTANTS | ||||
| 
 | ||||
|  | @ -13,6 +15,8 @@ BEGIN_CONSTANTS | |||
|     float3 PointLightPosition               _ps(c1)     _cb(c1); | ||||
|     float3 PointLightColor                  _ps(c2)     _cb(c2); | ||||
| 
 | ||||
|     float FarPlane                          _ps(c3)     _cb(c3); | ||||
| 
 | ||||
| MATRIX_CONSTANTS | ||||
| 
 | ||||
| END_CONSTANTS | ||||
|  | @ -60,9 +64,11 @@ float4 ComputeColor( | |||
|     float attenuation = 1.0 / (distance * distance); | ||||
|     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(shadow, shadow, shadow, 1.0); | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
|     output.Position = mul(input.Position, ModelViewProjection); | ||||
|     output.Depth = output.Position.z; | ||||
|     output.Depth = output.Position.z / output.Position.w; | ||||
| 
 | ||||
|     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 Triangle[] Triangles { 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; | ||||
|             IndexBuffer = indexBuffer; | ||||
|             Positions = positions; | ||||
|             Triangles = triangles; | ||||
|             Effect = effect; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -6,9 +6,84 @@ namespace Kav | |||
|     { | ||||
|         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) | ||||
|         { | ||||
|             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"> | ||||
|       <LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName> | ||||
|     </EmbeddedResource> | ||||
|     <EmbeddedResource Include="Effects\FXB\Deferred_ToonEffect.fxb"> | ||||
|       <LogicalName>Kav.Resources.Deferred_ToonEffect.fxb</LogicalName> | ||||
|     </EmbeddedResource> | ||||
|     <EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb"> | ||||
|       <LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName> | ||||
|     </EmbeddedResource> | ||||
|  | @ -39,6 +42,15 @@ | |||
|     <EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb"> | ||||
|       <LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName> | ||||
| 		</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> | ||||
| 
 | ||||
| </Project> | ||||
|  |  | |||
|  | @ -30,6 +30,9 @@ | |||
|     <EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb"> | ||||
|       <LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName> | ||||
|     </EmbeddedResource> | ||||
|     <EmbeddedResource Include="Effects\FXB\Deferred_ToonEffect.fxb"> | ||||
|       <LogicalName>Kav.Resources.Deferred_ToonEffect.fxb</LogicalName> | ||||
|     </EmbeddedResource> | ||||
|     <EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb"> | ||||
|       <LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName> | ||||
|     </EmbeddedResource> | ||||
|  | @ -39,6 +42,15 @@ | |||
|     <EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb"> | ||||
|       <LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName> | ||||
| 		</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> | ||||
| 
 | ||||
| </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 Vector3 Direction { get; set; } | ||||
|         public Color Color { get; set; } | ||||
|         public float Intensity { get; set; } | ||||
|         public Vector3 Direction { get; } | ||||
|         public Color Color { get; } | ||||
|         public float Intensity { get; } | ||||
| 
 | ||||
|         public Matrix View | ||||
|         { | ||||
|  |  | |||
|  | @ -15,19 +15,6 @@ namespace Kav | |||
| 
 | ||||
|                 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]; | ||||
|                     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.IndexBuffer, | ||||
|                         meshPartData.Positions, | ||||
|                         triangles, | ||||
|                         effect | ||||
|                     )); | ||||
|                         triangles | ||||
|                     ); | ||||
| 
 | ||||
|                     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())); | ||||
|  |  | |||
										
											Binary file not shown.
										
									
								
							|  | @ -15,9 +15,9 @@ Essential | |||
| - [x] Tone map shader | ||||
| - [x] Poisson soft shadowing | ||||
| - [ ] Frustum culling | ||||
| - [ ] Shadow-casting point lights | ||||
| - [x] Shadow-casting point lights | ||||
| - [ ] Parabolic lights | ||||
| - [ ] Skyboxes | ||||
| - [x] Skyboxes | ||||
| - [ ] Screen-space reflection | ||||
| 
 | ||||
| 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.Graphics; | ||||
| 
 | ||||
|  | @ -21,19 +23,27 @@ namespace Kav | |||
|         private RenderTarget2D[] ShadowRenderTargets { 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_PointLightEffect DeferredPointLightEffect { get; } | ||||
|         private DeferredPBR_DirectionalLightEffect DeferredDirectionalLightEffect { get; } | ||||
|         private Deferred_ToonEffect Deferred_ToonEffect { get; } | ||||
|         private SimpleDepthEffect SimpleDepthEffect { get; } | ||||
|         private LinearDepthEffect LinearDepthEffect { get; } | ||||
|         private Effect ToneMapEffect { get; } | ||||
|         private SkyboxEffect SkyboxEffect { get; } | ||||
| 
 | ||||
|         private RenderTarget2D gPosition { get; } | ||||
|         private RenderTarget2D gNormal { get; } | ||||
|         private RenderTarget2D gAlbedo { get; } | ||||
|         private RenderTarget2D gMetallicRoughness { get; } | ||||
|         private RenderTargetCube PointShadowCubeMap { get; } | ||||
| 
 | ||||
|         private RenderTargetBinding[] GBuffer { get; } | ||||
| 
 | ||||
|         private Kav.Model UnitCube { get; } | ||||
| 
 | ||||
|         private SpriteBatch SpriteBatch { get; } | ||||
| 
 | ||||
|         public Renderer( | ||||
|  | @ -70,7 +80,7 @@ namespace Kav | |||
|                 renderDimensionsY, | ||||
|                 false, | ||||
|                 SurfaceFormat.Color, | ||||
|                 DepthFormat.None, | ||||
|                 DepthFormat.Depth24, | ||||
|                 0, | ||||
|                 RenderTargetUsage.PreserveContents | ||||
|             ); | ||||
|  | @ -129,13 +139,26 @@ namespace Kav | |||
|                 new RenderTargetBinding(gMetallicRoughness) | ||||
|             }; | ||||
| 
 | ||||
|             PointShadowCubeMap = new RenderTargetCube( | ||||
|                 GraphicsDevice, | ||||
|                 shadowMapSize, | ||||
|                 false, | ||||
|                 SurfaceFormat.Single, | ||||
|                 DepthFormat.Depth24 | ||||
|             ); | ||||
| 
 | ||||
|             SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice); | ||||
|             LinearDepthEffect = new LinearDepthEffect(GraphicsDevice); | ||||
|             DeferredPBREffect = new DeferredPBREffect(GraphicsDevice); | ||||
| 
 | ||||
|             Deferred_GBufferEffect = new DeferredPBR_GBufferEffect(GraphicsDevice); | ||||
|             DeferredAmbientLightEffect = new DeferredPBR_AmbientLightEffect(GraphicsDevice); | ||||
|             DeferredPointLightEffect = new DeferredPBR_PointLightEffect(GraphicsDevice); | ||||
|             DeferredDirectionalLightEffect = new DeferredPBR_DirectionalLightEffect(GraphicsDevice); | ||||
|             DeferredDirectionalLightEffect.ShadowMapSize = ShadowMapSize; | ||||
|             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.SetData(new VertexPositionTexture[3] { | ||||
|  | @ -144,39 +167,93 @@ namespace Kav | |||
|                 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); | ||||
|         } | ||||
| 
 | ||||
|         public void DeferredRender( | ||||
|             PerspectiveCamera camera, | ||||
|             IEnumerable<(Model, Matrix)> modelTransforms, | ||||
|             AmbientLight ambientLight, | ||||
|             IEnumerable<PointLight> pointLights, | ||||
|             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.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 modelMesh in model.Meshes) | ||||
|                 { | ||||
|                     foreach (var meshPart in modelMesh.MeshParts) | ||||
|                     { | ||||
|                         SimpleDepthEffect.Model = transform; | ||||
|                         SimpleDepthEffect.View = camera.View; | ||||
|                         SimpleDepthEffect.Projection = camera.Projection; | ||||
| 
 | ||||
|                         GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); | ||||
|                         GraphicsDevice.Indices = meshPart.IndexBuffer; | ||||
| 
 | ||||
|                         if (meshPart.Effect is TransformEffect transformEffect) | ||||
|                         { | ||||
|                             transformEffect.World = transform; | ||||
|                             transformEffect.View = camera.View; | ||||
|                             transformEffect.Projection = camera.Projection; | ||||
|                         } | ||||
| 
 | ||||
|                         foreach (var pass in meshPart.Effect.CurrentTechnique.Passes) | ||||
|                         foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes) | ||||
|                         { | ||||
|                             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.Clear(Color.Black); | ||||
|             GraphicsDevice.BlendState = BlendState.Additive; | ||||
|             GraphicsDevice.DepthStencilState = DepthStencilState.None; | ||||
|             GraphicsDevice.BlendState = BlendState.Opaque; | ||||
| 
 | ||||
|             DeferredAmbientLightEffect.GPosition = gPosition; | ||||
|             DeferredAmbientLightEffect.GAlbedo = gAlbedo; | ||||
|             DeferredAmbientLightEffect.AmbientColor = ambientLight.Color.ToVector3(); | ||||
| 
 | ||||
|             foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes) | ||||
|             { | ||||
|  | @ -207,39 +366,31 @@ namespace Kav | |||
|                 GraphicsDevice.SetVertexBuffer(FullscreenTriangle); | ||||
|                 GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); | ||||
|             } | ||||
| 
 | ||||
|             DeferredPointLightEffect.EyePosition = camera.Position; | ||||
| 
 | ||||
|             foreach (var pointLight in pointLights) | ||||
|             { | ||||
|                 PointLightRender(pointLight); | ||||
|         } | ||||
| 
 | ||||
|             DirectionalLightRender(camera, modelTransforms, directionalLight); | ||||
|             // return; | ||||
|             // GraphicsDevice.SetRenderTarget(null); | ||||
|             // SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied); | ||||
|             // SpriteBatch.Draw(DirectionalRenderTarget, Vector2.Zero, Color.White); | ||||
|             // SpriteBatch.End(); | ||||
|         private void PointLightRender( | ||||
|             PerspectiveCamera camera, | ||||
|             IEnumerable<(Model, Matrix)> modelTransforms, | ||||
|             PointLight pointLight | ||||
|         ) { | ||||
|             RenderPointShadows(camera, modelTransforms, pointLight); | ||||
| 
 | ||||
|             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(); | ||||
|         } | ||||
|             GraphicsDevice.SetRenderTarget(ColorRenderTarget); | ||||
|             GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; | ||||
|             GraphicsDevice.BlendState = BlendState.Additive; | ||||
| 
 | ||||
|         private void PointLightRender(PointLight pointLight)  | ||||
|         { | ||||
|             DeferredPointLightEffect.GPosition = gPosition; | ||||
|             DeferredPointLightEffect.GAlbedo = gAlbedo; | ||||
|             DeferredPointLightEffect.GNormal = gNormal; | ||||
|             DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness;     | ||||
|             DeferredPointLightEffect.ShadowMap = PointShadowCubeMap; | ||||
| 
 | ||||
|             DeferredPointLightEffect.PointLightPosition = pointLight.Position; | ||||
|             DeferredPointLightEffect.PointLightColor =  | ||||
|                 pointLight.Color.ToVector3() * pointLight.Intensity; | ||||
| 
 | ||||
|             DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value | ||||
| 
 | ||||
|             foreach (var pass in DeferredPointLightEffect.CurrentTechnique.Passes) | ||||
|             { | ||||
|                 pass.Apply(); | ||||
|  | @ -253,28 +404,7 @@ namespace Kav | |||
|             IEnumerable<(Model, Matrix)> modelTransforms, | ||||
|             DirectionalLight directionalLight | ||||
|         ) { | ||||
|             // 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 | ||||
|                 RenderShadowMap(shadowCamera, modelTransforms, directionalLight, i); | ||||
| 
 | ||||
|                 previousFarPlane = farPlane; | ||||
|             } | ||||
|             RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect); | ||||
| 
 | ||||
|             DeferredDirectionalLightEffect.GPosition = gPosition; | ||||
|             DeferredDirectionalLightEffect.GAlbedo = gAlbedo; | ||||
|  | @ -300,7 +430,7 @@ namespace Kav | |||
|                 directionalLight.Color.ToVector3() * directionalLight.Intensity; | ||||
|              | ||||
|             DeferredDirectionalLightEffect.ViewMatrix = camera.View; | ||||
|             DeferredDirectionalLightEffect.EyePosition = Matrix.Invert(camera.View).Translation; | ||||
|             DeferredDirectionalLightEffect.EyePosition = camera.Position; | ||||
| 
 | ||||
|             GraphicsDevice.SetRenderTarget(ColorRenderTarget); | ||||
|             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, | ||||
|             IEnumerable<(Model, Matrix)> modelTransforms, | ||||
|             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 | ||||
|         ) { | ||||
|             GraphicsDevice.SetRenderTarget(ShadowRenderTargets[shadowCascadeIndex]); | ||||
|  | @ -357,23 +566,21 @@ namespace Kav | |||
| 
 | ||||
|             if (shadowCascadeIndex == 0) | ||||
|             { | ||||
|                 DeferredDirectionalLightEffect.LightSpaceMatrixOne = lightSpaceMatrix; | ||||
|                 effect.LightSpaceMatrixOne = lightSpaceMatrix; | ||||
|             } | ||||
|             else if (shadowCascadeIndex == 1) | ||||
|             { | ||||
|                 DeferredDirectionalLightEffect.LightSpaceMatrixTwo = lightSpaceMatrix; | ||||
|                 effect.LightSpaceMatrixTwo = lightSpaceMatrix; | ||||
|             } | ||||
|             else if (shadowCascadeIndex == 2) | ||||
|             { | ||||
|                 DeferredDirectionalLightEffect.LightSpaceMatrixThree = lightSpaceMatrix; | ||||
|                 effect.LightSpaceMatrixThree = lightSpaceMatrix; | ||||
|             } | ||||
|             else if (shadowCascadeIndex == 3) | ||||
|             { | ||||
|                 DeferredDirectionalLightEffect.LightSpaceMatrixFour = lightSpaceMatrix; | ||||
|                 effect.LightSpaceMatrixFour = lightSpaceMatrix; | ||||
|             } | ||||
| 
 | ||||
|             DeferredDirectionalLightEffect.CascadeFarPlanes[shadowCascadeIndex] = camera.FarPlane; | ||||
| 
 | ||||
|             foreach (var (model, transform) in modelTransforms) | ||||
|             { | ||||
|                 foreach (var modelMesh in model.Meshes) | ||||
|  | @ -403,22 +610,73 @@ namespace Kav | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public void Render( | ||||
|         private void RenderPointShadows( | ||||
|             PerspectiveCamera camera, | ||||
|             IEnumerable<(Model, Matrix)> modelTransforms, | ||||
|             IEnumerable<PointLight> pointLights, | ||||
|             IEnumerable<DirectionalLight> directionalLights | ||||
|             PointLight pointLight | ||||
|         ) { | ||||
|             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( | ||||
|             Matrix view, | ||||
|             Matrix projection, | ||||
|             IEnumerable<(Model, Matrix)> modelTransforms, | ||||
|             IEnumerable<PointLight> pointLights, | ||||
|             IEnumerable<DirectionalLight> directionalLights | ||||
|         ) { | ||||
|                 LinearDepthEffect.View = Matrix.CreateLookAt( | ||||
|                     pointLight.Position, | ||||
|                     pointLight.Position + targetDirection, | ||||
|                     targetUpDirection | ||||
|                 ); | ||||
| 
 | ||||
|                 foreach (var (model, transform) in modelTransforms) | ||||
|                 { | ||||
|                     foreach (var modelMesh in model.Meshes) | ||||
|  | @ -428,25 +686,9 @@ namespace Kav | |||
|                             GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); | ||||
|                             GraphicsDevice.Indices = meshPart.IndexBuffer; | ||||
| 
 | ||||
|                         if (meshPart.Effect is TransformEffect transformEffect) | ||||
|                         { | ||||
|                             transformEffect.World = transform; | ||||
|                             transformEffect.View = view; | ||||
|                             transformEffect.Projection = projection; | ||||
|                         } | ||||
|                             LinearDepthEffect.Model = transform; | ||||
| 
 | ||||
|                         if (meshPart.Effect is PointLightEffect pointLightEffect) | ||||
|                         { | ||||
|                             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) | ||||
|                             foreach (var pass in LinearDepthEffect.CurrentTechnique.Passes) | ||||
|                             { | ||||
|                                 pass.Apply(); | ||||
| 
 | ||||
|  | @ -464,4 +706,5 @@ namespace Kav | |||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										71
									
								
								Resources.cs
								
								
								
								
							
							
						
						
									
										71
									
								
								Resources.cs
								
								
								
								
							|  | @ -10,7 +10,7 @@ namespace Kav | |||
|             { | ||||
|                 if (ambientLightEffect == null) | ||||
|                 { | ||||
|                     ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect"); | ||||
|                     ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect.fxb"); | ||||
|                 } | ||||
|                 return ambientLightEffect; | ||||
|             } | ||||
|  | @ -21,7 +21,7 @@ namespace Kav | |||
|             { | ||||
|                 if (pointLightEffect == null) | ||||
|                 { | ||||
|                     pointLightEffect = GetResource("DeferredPBR_PointLightEffect"); | ||||
|                     pointLightEffect = GetResource("DeferredPBR_PointLightEffect.fxb"); | ||||
|                 } | ||||
|                 return pointLightEffect; | ||||
|             } | ||||
|  | @ -33,7 +33,7 @@ namespace Kav | |||
|             { | ||||
|                 if (directionalLightEffect == null) | ||||
|                 { | ||||
|                     directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect"); | ||||
|                     directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect.fxb"); | ||||
|                 } | ||||
|                 return directionalLightEffect; | ||||
|             } | ||||
|  | @ -45,7 +45,7 @@ namespace Kav | |||
|             { | ||||
|                 if (gBufferEffect == null) | ||||
|                 { | ||||
|                     gBufferEffect = GetResource("DeferredPBR_GBufferEffect"); | ||||
|                     gBufferEffect = GetResource("DeferredPBR_GBufferEffect.fxb"); | ||||
|                 } | ||||
|                 return gBufferEffect; | ||||
|             } | ||||
|  | @ -57,19 +57,31 @@ namespace Kav | |||
|             { | ||||
|                 if (toneMapEffect == null) | ||||
|                 { | ||||
|                     toneMapEffect = GetResource("ToneMapEffect"); | ||||
|                     toneMapEffect = GetResource("ToneMapEffect.fxb"); | ||||
|                 } | ||||
|                 return toneMapEffect; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static byte[] Deferred_ToonEffect | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 if (deferredToonEffect == null) | ||||
|                 { | ||||
|                     deferredToonEffect = GetResource("Deferred_ToonEffect.fxb"); | ||||
|                 } | ||||
|                 return deferredToonEffect; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         public static byte[] DeferredPBREffect | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 if (deferredPBREffect == null) | ||||
|                 { | ||||
|                     deferredPBREffect = GetResource("DeferredPBREffect"); | ||||
|                     deferredPBREffect = GetResource("DeferredPBREffect.fxb"); | ||||
|                 } | ||||
|                 return deferredPBREffect; | ||||
|             } | ||||
|  | @ -81,7 +93,7 @@ namespace Kav | |||
|             { | ||||
|                 if (pbrEffect == null) | ||||
|                 { | ||||
|                     pbrEffect = GetResource("PBREffect"); | ||||
|                     pbrEffect = GetResource("PBREffect.fxb"); | ||||
|                 } | ||||
|                 return pbrEffect; | ||||
|             } | ||||
|  | @ -93,25 +105,66 @@ namespace Kav | |||
|             { | ||||
|                 if (simpleDepthEffect == null) | ||||
|                 { | ||||
|                     simpleDepthEffect = GetResource("SimpleDepthEffect"); | ||||
|                     simpleDepthEffect = GetResource("SimpleDepthEffect.fxb"); | ||||
|                 } | ||||
|                 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[] pointLightEffect; | ||||
|         private static byte[] directionalLightEffect; | ||||
|         private static byte[] gBufferEffect; | ||||
|         private static byte[] toneMapEffect; | ||||
|         private static byte[] deferredToonEffect; | ||||
|         private static byte[] deferredPBREffect; | ||||
|         private static byte[] pbrEffect; | ||||
|         private static byte[] simpleDepthEffect; | ||||
|         private static byte[] linearDepthEffect; | ||||
|         private static byte[] skyboxEffect; | ||||
| 
 | ||||
|         private static byte[] unitCubeModel; | ||||
| 
 | ||||
|         private static byte[] GetResource(string name) | ||||
|         { | ||||
|             Stream stream = typeof(Resources).Assembly.GetManifestResourceStream( | ||||
|                 "Kav.Resources." + name + ".fxb" | ||||
|                 "Kav.Resources." + name | ||||
|             ); | ||||
|             using (MemoryStream ms = new MemoryStream()) | ||||
|             { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue