diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index 5920c2e..0d477b3 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -67,6 +67,8 @@ namespace Smuggler EffectParameter eyePositionParam; + EffectParameter shaderIndexParam; + Matrix world = Matrix.Identity; Matrix view = Matrix.Identity; Matrix projection = Matrix.Identity; @@ -77,6 +79,10 @@ namespace Smuggler float roughness; float ao; + bool albedoTextureEnabled = false; + bool metallicRoughnessMapEnabled = false; + bool normalMapEnabled = false; + // FIXME: lazily set properties for performance public Matrix World @@ -175,13 +181,22 @@ namespace Smuggler public Texture2D AlbedoTexture { get { return albedoTextureParam.GetValueTexture2D(); } - set { albedoTextureParam.SetValue(value); } + set + { + albedoTextureParam.SetValue(value); + albedoTextureEnabled = value != null; + System.Console.WriteLine(albedoTextureEnabled); + } } public Texture2D NormalTexture { get { return normalTextureParam.GetValueTexture2D(); } - set { normalTextureParam.SetValue(value); } + set + { + normalTextureParam.SetValue(value); + normalMapEnabled = value != null; + } } public Texture2D EmissionTexture @@ -199,7 +214,11 @@ namespace Smuggler public Texture2D MetallicRoughnessTexture { get { return metallicRoughnessTextureParam.GetValueTexture2D(); } - set { metallicRoughnessTextureParam.SetValue(value); } + set + { + metallicRoughnessTextureParam.SetValue(value); + metallicRoughnessMapEnabled = value != null; + } } public TextureCube EnvDiffuseTexture @@ -271,7 +290,40 @@ namespace Smuggler // FIXME: do param applications here for performance protected override void OnApply() { - base.OnApply(); + int shaderIndex = 0; + + if (albedoTextureEnabled && metallicRoughnessMapEnabled && normalMapEnabled) + { + System.Console.WriteLine("all enabled"); + shaderIndex = 7; + } + else if (metallicRoughnessMapEnabled && normalMapEnabled) + { + shaderIndex = 6; + } + else if (albedoTextureEnabled && normalMapEnabled) + { + shaderIndex = 5; + } + else if (albedoTextureEnabled && metallicRoughnessMapEnabled) + { + shaderIndex = 4; + } + else if (normalMapEnabled) + { + shaderIndex = 3; + } + else if (metallicRoughnessMapEnabled) + { + shaderIndex = 2; + } + else if (albedoTextureEnabled) + { + shaderIndex = 1; + } + + System.Console.WriteLine(shaderIndex); + shaderIndexParam.SetValue(shaderIndex); } void CacheEffectParameters(PBREffect cloneSource) @@ -298,6 +350,8 @@ namespace Smuggler aoParam = Parameters["AO"]; eyePositionParam = Parameters["EyePosition"]; + + shaderIndexParam = Parameters["ShaderIndex"]; } } } diff --git a/Effects/PBREffect.fx b/Effects/PBREffect.fx index 1ea26fa..08fabd7 100644 --- a/Effects/PBREffect.fx +++ b/Effects/PBREffect.fx @@ -121,15 +121,15 @@ float3 GetNormalFromMap(float3 worldPos, float2 texCoords, float3 normal) return normalize(mul(tangentNormal, TBN)); } -// The case where we have no texture maps for any PBR data -float4 None(PixelShaderInput input) : SV_TARGET0 -{ - float3 albedo = AlbedoValue; - float metallic = MetallicValue; - float roughness = RoughnessValue; - - float3 N = normalize(input.NormalWS); - float3 V = normalize(EyePosition - input.PositionWS); +float4 ComputeColor( + float3 worldPosition, + float3 worldNormal, + float3 albedo, + float metallic, + float roughness +) { + float3 V = normalize(EyePosition - worldPosition); + float3 N = worldNormal; float3 F0 = float3(0.04, 0.04, 0.04); F0 = lerp(F0, albedo, metallic); @@ -138,7 +138,7 @@ float4 None(PixelShaderInput input) : SV_TARGET0 for (int i = 0; i < 4; i++) { - float3 lightDir = LightPositions[i] - input.PositionWS; + float3 lightDir = LightPositions[i] - worldPosition; float3 L = normalize(lightDir); float3 H = normalize(V + L); @@ -173,166 +173,136 @@ float4 None(PixelShaderInput input) : SV_TARGET0 return float4(color, 1.0); } +// The case where we have no texture maps for any PBR data +float4 None(PixelShaderInput input) : SV_TARGET0 +{ + return ComputeColor( + input.PositionWS, + input.NormalWS, + AlbedoValue, + MetallicValue, + RoughnessValue + ); +} + float4 AlbedoMapPS(PixelShaderInput input) : SV_TARGET { - float3 albedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord).rgb; - float metallic = MetallicValue; - float roughness = RoughnessValue; + float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; - float3 N = normalize(input.NormalWS); - float3 V = normalize(EyePosition - input.PositionWS); + return ComputeColor( + input.PositionWS, + input.NormalWS, + albedo, + MetallicValue, + RoughnessValue + ); +} - float3 F0 = float3(0.04, 0.04, 0.04); - F0 = lerp(F0, albedo, metallic); +float4 MetallicRoughnessPS(PixelShaderInput input) : SV_TARGET +{ + float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - float3 Lo = float3(0.0, 0.0, 0.0); + return ComputeColor( + input.PositionWS, + input.NormalWS, + AlbedoValue, + metallicRoughness.r, + metallicRoughness.g + ); +} - for (int i = 0; i < 4; i++) - { - float3 lightDir = LightPositions[i] - input.PositionWS; - float3 L = normalize(lightDir); - float3 H = normalize(V + L); +float4 NormalPS(PixelShaderInput input) : SV_TARGET +{ + float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float distance = length(lightDir); - float attenuation = 1.0 / (distance * distance); - float3 radiance = LightColors[i] * attenuation; - - 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); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; - } - - 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); + return ComputeColor( + input.PositionWS, + normal, + AlbedoValue, + MetallicValue, + RoughnessValue + ); } float4 AlbedoMetallicRoughnessMapPS(PixelShaderInput input) : SV_TARGET { float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - float metallic = metallicRoughness.r; - float roughness = metallicRoughness.g; - float3 N = normalize(input.NormalWS); - float3 V = normalize(EyePosition - input.PositionWS); + return ComputeColor( + input.PositionWS, + input.NormalWS, + albedo, + metallicRoughness.r, + metallicRoughness.g + ); +} - float3 F0 = float3(0.04, 0.04, 0.04); - F0 = lerp(F0, albedo, metallic); +float4 AlbedoNormalPS(PixelShaderInput input) : SV_TARGET +{ + float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; + float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float3 Lo = float3(0.0, 0.0, 0.0); + return ComputeColor( + input.PositionWS, + normal, + albedo, + MetallicValue, + RoughnessValue + ); +} - for (int i = 0; i < 4; i++) - { - float3 lightDir = LightPositions[i] - input.PositionWS; - float3 L = normalize(lightDir); - float3 H = normalize(V + L); +float4 MetallicRoughnessNormalPS(PixelShaderInput input) : SV_TARGET +{ + float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; + float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float distance = length(lightDir); - float attenuation = 1.0 / (distance * distance); - float3 radiance = LightColors[i] * attenuation; - - 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); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; - } - - 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); + return ComputeColor( + input.PositionWS, + normal, + AlbedoValue, + metallicRoughness.r, + metallicRoughness.g + ); } float4 AlbedoMetallicRoughnessNormalMapPS(PixelShaderInput input) : SV_TARGET { float3 albedo = pow(SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord), 2.2).rgb; float2 metallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord).rg; - float metallic = metallicRoughness.r; - float roughness = metallicRoughness.g; + float3 normal = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float3 N = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS); - float3 V = normalize(EyePosition - input.PositionWS); - - float3 F0 = float3(0.04, 0.04, 0.04); - F0 = lerp(F0, albedo, metallic); - - float3 Lo = float3(0.0, 0.0, 0.0); - - for (int i = 0; i < 4; i++) - { - float3 lightDir = LightPositions[i] - input.PositionWS; - float3 L = normalize(lightDir); - float3 H = normalize(V + L); - - float distance = length(lightDir); - float attenuation = 1.0 / (distance * distance); - float3 radiance = LightColors[i] * attenuation; - - 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); - Lo += (kD * albedo / PI + specular) * radiance * NdotL; - } - - 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); + return ComputeColor( + input.PositionWS, + normal, + albedo, + metallicRoughness.r, + metallicRoughness.g + ); } +PixelShader PSArray[8] = +{ + compile ps_3_0 None(), + + compile ps_3_0 AlbedoMapPS(), + compile ps_3_0 MetallicRoughnessPS(), + compile ps_3_0 NormalPS(), + + compile ps_3_0 AlbedoMetallicRoughnessMapPS(), + compile ps_3_0 AlbedoNormalPS(), + compile ps_3_0 MetallicRoughnessNormalPS(), + + compile ps_3_0 AlbedoMetallicRoughnessNormalMapPS() +}; + +int ShaderIndex = 0; + Technique PBR { - Pass Pass1 + Pass { VertexShader = compile vs_3_0 main_vs(); - PixelShader = compile ps_3_0 AlbedoMetallicRoughnessNormalMapPS(); + PixelShader = (PSArray[ShaderIndex]); } } diff --git a/Effects/PBREffect.fxb b/Effects/PBREffect.fxb index f901f3e..a4ca2d7 100644 Binary files a/Effects/PBREffect.fxb and b/Effects/PBREffect.fxb differ