304 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			HLSL
		
	
	
			
		
		
	
	
			304 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			HLSL
		
	
	
| #include "Macros.fxh" //from FNA
 | |
| 
 | |
| static const float PI = 3.141592653589793;
 | |
| static const int MAX_POINT_LIGHTS = 64;
 | |
| 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 PointLightPositions[MAX_POINT_LIGHTS]               _ps(c1)      _cb(c1);
 | |
|     float3 PointLightColors[MAX_POINT_LIGHTS]                  _ps(c65)     _cb(c65);
 | |
| 
 | |
|     float3 DirectionalLightDirection                           _ps(c129)   _cb(c129);
 | |
|     float3 DirectionalLightColor                               _ps(c130)   _cb(c130);
 | |
| 
 | |
|     float CascadeFarPlanes[NUM_SHADOW_CASCADES]                _ps(c131)   _cb(c131);
 | |
| 
 | |
| MATRIX_CONSTANTS
 | |
| 
 | |
|     float4x4 LightSpaceMatrixOne                               _ps(c135)   _cb(c135);
 | |
|     float4x4 LightSpaceMatrixTwo                               _ps(c139)   _cb(c139);
 | |
|     float4x4 LightSpaceMatrixThree                             _ps(c143)   _cb(c143);
 | |
|     float4x4 LightSpaceMatrixFour                              _ps(c147)   _cb(c147);
 | |
| 
 | |
|     // used to select shadow cascade
 | |
|     float4x4 ViewMatrix                                        _ps(c151)   _cb(c151);
 | |
| 
 | |
| 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;
 | |
| }
 | |
| 
 | |
| // Pixel Shader
 | |
| 
 | |
| float3 FresnelSchlick(float cosTheta, float3 F0)
 | |
| {
 | |
|     return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
 | |
| }
 | |
| 
 | |
| float DistributionGGX(float3 N, float3 H, float roughness)
 | |
| {
 | |
|     float a = roughness * roughness;
 | |
|     float a2 = a * a;
 | |
|     float NdotH = max(dot(N, H), 0.0);
 | |
|     float NdotH2 = NdotH * NdotH;
 | |
| 
 | |
|     float num = a2;
 | |
|     float denom = (NdotH2 * (a2 - 1.0) + 1.0);
 | |
|     denom = PI * denom * denom;
 | |
| 
 | |
|     return num / denom;
 | |
| }
 | |
| 
 | |
| float GeometrySchlickGGX(float NdotV, float roughness)
 | |
| {
 | |
|     float r = (roughness + 1.0);
 | |
|     float k = (r * r) / 8.0;
 | |
| 
 | |
|     float num = NdotV;
 | |
|     float denom = NdotV * (1.0 - k) + k;
 | |
| 
 | |
|     return num / denom;
 | |
| }
 | |
| 
 | |
| float GeometrySmith(float3 N, float3 V, float3 L, float roughness)
 | |
| {
 | |
|     float NdotV = max(dot(N, V), 0.0);
 | |
|     float NdotL = max(dot(N, L), 0.0);
 | |
|     float ggx2 = GeometrySchlickGGX(NdotV, roughness);
 | |
|     float ggx1 = GeometrySchlickGGX(NdotL, roughness);
 | |
| 
 | |
|     return ggx1 * ggx2;
 | |
| }
 | |
| 
 | |
| float ComputeShadow(float3 positionWorldSpace, float3 N, float 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
 | |
|     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;
 | |
|     }
 | |
| 
 | |
|     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
 | |
| 
 | |
|     float inc = 1.0 / 1024.0;
 | |
| 
 | |
|     float shadowFactor = 0;
 | |
|     for (int row = -1; row <= 1; row++)
 | |
|     {
 | |
|         for (int col = -1; col <= 1; col++)
 | |
|         {
 | |
|             float closestDepth;
 | |
|             if (shadowCascadeIndex == 0)
 | |
|             {
 | |
|                 closestDepth = SAMPLE_TEXTURE(shadowMapOne, projectionCoords.xy + float2(row, col) * inc).r;
 | |
|             }
 | |
|             else if (shadowCascadeIndex == 1)
 | |
|             {
 | |
|                 closestDepth = SAMPLE_TEXTURE(shadowMapTwo, projectionCoords.xy + float2(row, col) * inc).r;
 | |
|             }
 | |
|             else if (shadowCascadeIndex == 2)
 | |
|             {
 | |
|                 closestDepth = SAMPLE_TEXTURE(shadowMapThree, projectionCoords.xy + float2(row, col) * inc).r;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 closestDepth = SAMPLE_TEXTURE(shadowMapFour, projectionCoords.xy + float2(row, col) * inc).r;
 | |
|             }
 | |
|             shadowFactor += projectionCoords.z - bias > closestDepth ? 1.0 : 0.0;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     shadowFactor /= 9.0;
 | |
| 
 | |
|     if (projectionCoords.z > 1.0)
 | |
|     {
 | |
|         shadowFactor = 1.0;
 | |
|     }
 | |
| 
 | |
|     return shadowFactor;
 | |
| 
 | |
| 
 | |
|     // float currentDepth = projectionCoords.z;
 | |
| 
 | |
|     // if (currentDepth > 1.0)
 | |
|     // {
 | |
|     //     return 0.0;
 | |
|     // }
 | |
| 
 | |
|     // if (currentDepth - bias > closestDepth)
 | |
|     // {
 | |
|     //     return 1.0;
 | |
|     // }
 | |
|     // else
 | |
|     // {
 | |
|     //     return 0.0;
 | |
|     // }
 | |
| }
 | |
| 
 | |
| float3 ComputeLight(
 | |
|     float3 L,
 | |
|     float3 radiance,
 | |
|     float3 F0,
 | |
|     float3 V,
 | |
|     float3 N,
 | |
|     float3 albedo,
 | |
|     float metallic,
 | |
|     float roughness,
 | |
|     float shadow
 | |
| ) {
 | |
|     float3 H = normalize(V + L);
 | |
| 
 | |
|     float NDF = DistributionGGX(N, H, roughness);
 | |
|     float G = GeometrySmith(N, V, L, roughness);
 | |
|     float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0);
 | |
| 
 | |
|     float3 numerator = NDF * G * F;
 | |
|     float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
 | |
|     float3 specular = numerator / max(denominator, 0.001);
 | |
| 
 | |
|     float3 kS = F;
 | |
|     float3 kD = float3(1.0, 1.0, 1.0) - kS;
 | |
| 
 | |
|     kD *= 1.0 - metallic;
 | |
| 
 | |
|     float NdotL = max(dot(N, L), 0.0);
 | |
|     return (kD * albedo / PI + specular) * radiance * NdotL * shadow;
 | |
| }
 | |
| 
 | |
| float4 ComputeColor(
 | |
|     float3 worldPosition,
 | |
|     float3 worldNormal,
 | |
|     float3 albedo,
 | |
|     float metallic,
 | |
|     float roughness
 | |
| ) {
 | |
|     float3 V = normalize(EyePosition - worldPosition);
 | |
|     float3 N = normalize(worldNormal);
 | |
| 
 | |
|     float3 F0 = float3(0.04, 0.04, 0.04);
 | |
|     F0 = lerp(F0, albedo, metallic);
 | |
| 
 | |
|     float3 Lo = float3(0.0, 0.0, 0.0);
 | |
| 
 | |
|     // point light
 | |
|     for (int i = 0; i < MAX_POINT_LIGHTS; i++)
 | |
|     {
 | |
|         float3 lightDir = PointLightPositions[i] - worldPosition;
 | |
|         float3 L = normalize(lightDir);
 | |
|         float distance = length(lightDir);
 | |
|         float attenuation = 1.0 / (distance * distance);
 | |
|         float3 radiance = PointLightColors[i] * attenuation;
 | |
| 
 | |
|         Lo += ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, 1.0);
 | |
|     }
 | |
| 
 | |
|     // directional light
 | |
|     float3 L = normalize(DirectionalLightDirection);
 | |
|     float3 radiance = DirectionalLightColor;
 | |
| 
 | |
|     float shadow = ComputeShadow(worldPosition, N, L);
 | |
|     Lo += ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, (1.0 - shadow));
 | |
| 
 | |
|     float3 ambient = float3(0.03, 0.03, 0.03) * albedo; // * AO;
 | |
|     float3 color = ambient + Lo;
 | |
| 
 | |
|     color = color / (color + float3(1.0, 1.0, 1.0));
 | |
|     float exposureConstant = 1.0 / 2.2;
 | |
|     color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant));
 | |
| 
 | |
|     return float4(color, 1.0);
 | |
| }
 | |
| 
 | |
| float4 main_ps(PixelInput input) : SV_TARGET0
 | |
| {
 | |
|     float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb;
 | |
|     float3 normal = SAMPLE_TEXTURE(gNormal, input.TexCoord).xyz;
 | |
|     float3 albedo = SAMPLE_TEXTURE(gAlbedo, input.TexCoord).rgb;
 | |
|     float2 metallicRoughness = SAMPLE_TEXTURE(gMetallicRoughness, input.TexCoord).rg;
 | |
| 
 | |
|     return ComputeColor(
 | |
|         worldPosition,
 | |
|         normal,
 | |
|         albedo,
 | |
|         metallicRoughness.r,
 | |
|         metallicRoughness.g
 | |
|     );
 | |
| }
 | |
| 
 | |
| Technique DeferredPBR
 | |
| {
 | |
|     Pass
 | |
|     {
 | |
|         VertexShader = compile vs_3_0 main_vs();
 | |
|         PixelShader = compile ps_3_0 main_ps();
 | |
|     }
 | |
| }
 |