using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace Smuggler { public struct PBRLight { public Vector3 direction; public Vector3 radiance; public PBRLight(Vector3 direction, Vector3 radiance) { this.direction = direction; this.radiance = radiance; } } public class PBRLightCollection { readonly EffectParameter directionParam; readonly EffectParameter radianceParam; private readonly Vector3[] directions = new Vector3[PBREffect.NUM_LIGHTS]; private readonly Vector3[] radiances = new Vector3[PBREffect.NUM_LIGHTS]; public PBRLightCollection(EffectParameter directionParam, EffectParameter radianceParam) { this.directionParam = directionParam; this.radianceParam = radianceParam; } public PBRLightCollection(PBRLightCollection other) { for (int i = 0; i < PBREffect.NUM_LIGHTS; i++) { directions[i] = other.directions[i]; radiances[i] = other.radiances[i]; } } public PBRLight this[int index] { get { return new PBRLight(directions[index], radiances[index]); } set { directions[index] = value.direction; radiances[index] = value.radiance; directionParam.SetValue(directions); radianceParam.SetValue(radiances); } } } public class PBREffect : Effect { public static readonly int NUM_LIGHTS = 3; readonly EffectParameter viewProjectionParam; readonly EffectParameter sceneRotationParam; readonly EffectParameter eyePositionParam; readonly EffectParameter specularTextureLevelsParam; readonly EffectParameter albedoTextureParam; Matrix world = Matrix.Identity; Matrix view = Matrix.Identity; Matrix projection = Matrix.Identity; Vector3 eyePosition = Vector3.Zero; int specularTextureLevels = 0; public Matrix World { get { return world; } set { world = value; sceneRotationParam.SetValue(world); } } public Matrix View { get { return view; } set { view = value; viewProjectionParam.SetValue(projection * view); eyePositionParam.SetValue(Matrix.Invert(view).Backward); } } public Matrix Projection { get { return projection; } set { projection = value; viewProjectionParam.SetValue(projection * view); } } public PBRLightCollection Lights { get; } public int SpecularTextureLevels { get { return specularTextureLevels; } set { specularTextureLevels = value; specularTextureLevelsParam.SetValue(specularTextureLevels); } } public Texture2D AlbedoTexture { get { return albedoTextureParam.GetValueTexture2D(); } set { albedoTextureParam.SetValue(value); } } public PBREffect(GraphicsDevice graphicsDevice, byte[] effectCode) : base(graphicsDevice, effectCode) { viewProjectionParam = Parameters["viewProjectionMatrix"]; sceneRotationParam = Parameters["sceneRotationMatrix"]; eyePositionParam = Parameters["eyePosition"]; specularTextureLevelsParam = Parameters["specularTextureLevels"]; Lights = new PBRLightCollection(Parameters["directions"], Parameters["radiance"]); } protected PBREffect(PBREffect cloneSource) : base(cloneSource) { viewProjectionParam = Parameters["viewProjectionMatrix"]; sceneRotationParam = Parameters["sceneRotationMatrix"]; eyePositionParam = Parameters["eyePosition"]; specularTextureLevelsParam = Parameters["specularTextureLevels"]; World = cloneSource.World; View = cloneSource.View; Projection = cloneSource.Projection; Lights = new PBRLightCollection(cloneSource.Lights); } public override Effect Clone() { return new PBREffect(this); } // FIXME: do param applications here for performance protected override void OnApply() { base.OnApply(); } } }