using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace Kav { public class DeferredPBR_GBufferEffect : Effect, TransformEffect { EffectParameter worldParam; EffectParameter worldViewProjectionParam; EffectParameter worldInverseTransposeParam; EffectParameter albedoTextureParam; EffectParameter normalTextureParam; EffectParameter metallicRoughnessTextureParam; EffectParameter albedoParam; EffectParameter metallicParam; EffectParameter roughnessParam; EffectParameter vertexShaderIndexParam; EffectParameter shaderIndexParam; Matrix world = Matrix.Identity; Matrix view = Matrix.Identity; Matrix projection = Matrix.Identity; Vector3 albedo; float metallic; float roughness; bool albedoTextureEnabled = false; bool metallicRoughnessMapEnabled = false; bool normalMapEnabled = false; bool hardwareInstancingEnabled = false; EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; public Matrix World { get { return world; } set { world = value; dirtyFlags |= EffectDirtyFlags.World | EffectDirtyFlags.WorldViewProj; } } public Matrix View { get { return view; } set { view = value; dirtyFlags |= EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.EyePosition; } } public Matrix Projection { get { return projection; } set { projection = value; dirtyFlags |= EffectDirtyFlags.WorldViewProj; } } public Vector3 Albedo { get { return albedo; } set { albedo = value; albedoParam.SetValue(albedo); } } public float Metallic { get { return metallic; } set { metallic = value; metallicParam.SetValue(metallic); } } public float Roughness { get { return roughness; } set { roughness = value; roughnessParam.SetValue(roughness); } } public Texture2D AlbedoTexture { get { return albedoTextureParam.GetValueTexture2D(); } set { albedoTextureParam.SetValue(value); albedoTextureEnabled = value != null; dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; } } public Texture2D NormalTexture { get { return normalTextureParam.GetValueTexture2D(); } set { normalTextureParam.SetValue(value); normalMapEnabled = value != null; dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; } } public Texture2D MetallicRoughnessTexture { get { return metallicRoughnessTextureParam.GetValueTexture2D(); } set { metallicRoughnessTextureParam.SetValue(value); metallicRoughnessMapEnabled = value != null; dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; } } public bool HardwareInstancingEnabled { get { return hardwareInstancingEnabled; } set { if (value != hardwareInstancingEnabled) { hardwareInstancingEnabled = value; dirtyFlags |= EffectDirtyFlags.VertexShaderIndex; } } } public DeferredPBR_GBufferEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_GBufferEffect) { CacheEffectParameters(); } protected DeferredPBR_GBufferEffect(DeferredPBR_GBufferEffect cloneSource) : base(cloneSource) { CacheEffectParameters(); World = cloneSource.World; View = cloneSource.View; Projection = cloneSource.Projection; AlbedoTexture = cloneSource.AlbedoTexture; NormalTexture = cloneSource.NormalTexture; MetallicRoughnessTexture = cloneSource.MetallicRoughnessTexture; Albedo = cloneSource.Albedo; Metallic = cloneSource.Metallic; Roughness = cloneSource.Roughness; } public override Effect Clone() { return new DeferredPBR_GBufferEffect(this); } protected override void OnApply() { if ((dirtyFlags & EffectDirtyFlags.World) != 0) { worldParam.SetValue(world); Matrix.Invert(ref world, out Matrix worldInverse); Matrix.Transpose(ref worldInverse, out Matrix worldInverseTranspose); worldInverseTransposeParam.SetValue(worldInverseTranspose); dirtyFlags &= ~EffectDirtyFlags.World; } if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) { Matrix.Multiply(ref world, ref view, out Matrix worldView); Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); worldViewProjectionParam.SetValue(worldViewProj); dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; } if ((dirtyFlags & EffectDirtyFlags.VertexShaderIndex) != 0) { int vertexShaderIndex = 0; if (hardwareInstancingEnabled) { vertexShaderIndex = 1; } vertexShaderIndexParam.SetValue(vertexShaderIndex); } if ((dirtyFlags & EffectDirtyFlags.PixelShaderIndex) != 0) { int shaderIndex = 0; if (albedoTextureEnabled && metallicRoughnessMapEnabled && normalMapEnabled) { 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; } shaderIndexParam.SetValue(shaderIndex); dirtyFlags &= ~EffectDirtyFlags.PixelShaderIndex; } } void CacheEffectParameters() { worldParam = Parameters["World"]; worldViewProjectionParam = Parameters["WorldViewProjection"]; worldInverseTransposeParam = Parameters["WorldInverseTranspose"]; albedoTextureParam = Parameters["AlbedoTexture"]; normalTextureParam = Parameters["NormalTexture"]; metallicRoughnessTextureParam = Parameters["MetallicRoughnessTexture"]; albedoParam = Parameters["AlbedoValue"]; metallicParam = Parameters["MetallicValue"]; roughnessParam = Parameters["RoughnessValue"]; shaderIndexParam = Parameters["PixelShaderIndex"]; vertexShaderIndexParam = Parameters["VertexShaderIndex"]; } } }