Directional Light + Shadows + Tone Mapping + One Pass Per Light (#2)
parent
4095b7eda5
commit
66d4e5bf6e
|
@ -0,0 +1 @@
|
|||
*.fxb filter=lfs diff=lfs merge=lfs -text
|
|
@ -2,22 +2,32 @@ using Microsoft.Xna.Framework;
|
|||
|
||||
namespace Kav
|
||||
{
|
||||
public struct Camera
|
||||
public struct PerspectiveCamera
|
||||
{
|
||||
public Matrix Transform { get; }
|
||||
public Matrix View
|
||||
{
|
||||
get
|
||||
{
|
||||
return Matrix.CreateLookAt(Transform.Translation, Transform.Translation + Transform.Forward, Transform.Up);
|
||||
}
|
||||
}
|
||||
public Matrix View { get; }
|
||||
public Matrix Projection { get; }
|
||||
|
||||
public Camera(Matrix transform, Matrix projection)
|
||||
public Vector3 Position { get; }
|
||||
public Vector3 Forward { get; }
|
||||
public Vector3 Up { get; }
|
||||
|
||||
public float FieldOfView { get; }
|
||||
public float AspectRatio { get; }
|
||||
public float NearPlane { get; }
|
||||
public float FarPlane { get; }
|
||||
|
||||
public PerspectiveCamera(Vector3 position, Vector3 forward, Vector3 up, float fieldOfView, float aspectRatio, float nearPlane, float farPlane)
|
||||
{
|
||||
Transform = transform;
|
||||
Projection = projection;
|
||||
Position = position;
|
||||
Forward = forward;
|
||||
Up = up;
|
||||
View = Matrix.CreateLookAt(Position, Position + Forward, Up);
|
||||
|
||||
FieldOfView = fieldOfView;
|
||||
AspectRatio = aspectRatio;
|
||||
NearPlane = nearPlane;
|
||||
FarPlane = farPlane;
|
||||
Projection = Matrix.CreatePerspectiveFieldOfView(FieldOfView, AspectRatio, NearPlane, FarPlane);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
namespace Kav
|
||||
{
|
||||
public interface DirectionalLightEffect
|
||||
{
|
||||
int MaxDirectionalLights { get; }
|
||||
DirectionalLightCollection DirectionalLights { get; }
|
||||
}
|
||||
}
|
|
@ -10,15 +10,47 @@ namespace Kav
|
|||
EffectParameter gNormalParam;
|
||||
EffectParameter gMetallicRoughnessParam;
|
||||
|
||||
EffectParameter shadowMapOneParam;
|
||||
EffectParameter shadowMapTwoParam;
|
||||
EffectParameter shadowMapThreeParam;
|
||||
EffectParameter shadowMapFourParam;
|
||||
|
||||
EffectParameter lightSpaceMatrixOneParam;
|
||||
EffectParameter lightSpaceMatrixTwoParam;
|
||||
EffectParameter lightSpaceMatrixThreeParam;
|
||||
EffectParameter lightSpaceMatrixFourParam;
|
||||
|
||||
EffectParameter viewMatrixParam;
|
||||
EffectParameter cascadeFarPlanesParam;
|
||||
|
||||
EffectParameter directionalLightColorParam;
|
||||
EffectParameter directionalLightDirectionParam;
|
||||
|
||||
EffectParameter eyePositionParam;
|
||||
|
||||
PointLightCollection pointLightCollection;
|
||||
DirectionalLightCollection directionalLightCollection;
|
||||
|
||||
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 Matrix LightSpaceMatrixOne { get; set; }
|
||||
public Matrix LightSpaceMatrixTwo { get; set; }
|
||||
public Matrix LightSpaceMatrixThree { get; set; }
|
||||
public Matrix LightSpaceMatrixFour { get; set; }
|
||||
|
||||
public Matrix ViewMatrix { get; set; }
|
||||
public readonly float[] CascadeFarPlanes;
|
||||
|
||||
public Vector3 DirectionalLightColor { get; set; }
|
||||
public Vector3 DirectionalLightDirection { get; set; }
|
||||
|
||||
public Vector3 EyePosition { get; set; }
|
||||
|
||||
public int MaxPointLights { get; } = 64;
|
||||
|
@ -29,16 +61,10 @@ namespace Kav
|
|||
private set { pointLightCollection = value; }
|
||||
}
|
||||
|
||||
public int MaxDirectionalLights { get; } = 4;
|
||||
|
||||
public DirectionalLightCollection DirectionalLights
|
||||
{
|
||||
get { return directionalLightCollection; }
|
||||
private set { directionalLightCollection = value; }
|
||||
}
|
||||
|
||||
public DeferredPBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBREffect)
|
||||
{
|
||||
CascadeFarPlanes = new float[4];
|
||||
|
||||
CacheEffectParameters();
|
||||
|
||||
pointLightCollection = new PointLightCollection(
|
||||
|
@ -46,11 +72,6 @@ namespace Kav
|
|||
Parameters["PointLightColors"],
|
||||
MaxPointLights
|
||||
);
|
||||
|
||||
DirectionalLights = new DirectionalLightCollection(
|
||||
Parameters["DirectionalLightDirections"],
|
||||
Parameters["DirectionalLightColors"]
|
||||
);
|
||||
}
|
||||
|
||||
protected DeferredPBREffect(DeferredPBREffect cloneSource) : base(cloneSource)
|
||||
|
@ -72,16 +93,6 @@ namespace Kav
|
|||
{
|
||||
PointLights[i] = cloneSource.PointLights[i];
|
||||
}
|
||||
|
||||
DirectionalLights = new DirectionalLightCollection(
|
||||
Parameters["DirectionalLightDirections"],
|
||||
Parameters["DirectionalLightColors"]
|
||||
);
|
||||
|
||||
for (int i = 0; i < MaxDirectionalLights; i++)
|
||||
{
|
||||
DirectionalLights[i] = cloneSource.DirectionalLights[i];
|
||||
}
|
||||
}
|
||||
|
||||
public override Effect Clone()
|
||||
|
@ -96,6 +107,22 @@ namespace Kav
|
|||
gNormalParam.SetValue(GNormal);
|
||||
gMetallicRoughnessParam.SetValue(GMetallicRoughness);
|
||||
|
||||
shadowMapOneParam.SetValue(ShadowMapOne);
|
||||
shadowMapTwoParam.SetValue(ShadowMapTwo);
|
||||
shadowMapThreeParam.SetValue(ShadowMapThree);
|
||||
shadowMapFourParam.SetValue(ShadowMapFour);
|
||||
|
||||
lightSpaceMatrixOneParam.SetValue(LightSpaceMatrixOne);
|
||||
lightSpaceMatrixTwoParam.SetValue(LightSpaceMatrixTwo);
|
||||
lightSpaceMatrixThreeParam.SetValue(LightSpaceMatrixThree);
|
||||
lightSpaceMatrixFourParam.SetValue(LightSpaceMatrixFour);
|
||||
|
||||
viewMatrixParam.SetValue(ViewMatrix);
|
||||
cascadeFarPlanesParam.SetValue(CascadeFarPlanes);
|
||||
|
||||
directionalLightColorParam.SetValue(DirectionalLightColor);
|
||||
directionalLightDirectionParam.SetValue(DirectionalLightDirection);
|
||||
|
||||
eyePositionParam.SetValue(EyePosition);
|
||||
}
|
||||
|
||||
|
@ -106,6 +133,22 @@ namespace Kav
|
|||
gNormalParam = Parameters["gNormal"];
|
||||
gMetallicRoughnessParam = Parameters["gMetallicRoughness"];
|
||||
|
||||
shadowMapOneParam = Parameters["shadowMapOne"];
|
||||
shadowMapTwoParam = Parameters["shadowMapTwo"];
|
||||
shadowMapThreeParam = Parameters["shadowMapThree"];
|
||||
shadowMapFourParam = Parameters["shadowMapFour"];
|
||||
|
||||
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];
|
||||
lightSpaceMatrixTwoParam = Parameters["LightSpaceMatrixTwo"];
|
||||
lightSpaceMatrixThreeParam = Parameters["LightSpaceMatrixThree"];
|
||||
lightSpaceMatrixFourParam = Parameters["LightSpaceMatrixFour"];
|
||||
|
||||
viewMatrixParam = Parameters["ViewMatrix"];
|
||||
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
|
||||
|
||||
directionalLightDirectionParam = Parameters["DirectionalLightDirection"];
|
||||
directionalLightColorParam = Parameters["DirectionalLightColor"];
|
||||
|
||||
eyePositionParam = Parameters["EyePosition"];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
|
||||
public class DeferredPBR_AmbientLightEffect : Effect
|
||||
{
|
||||
EffectParameter gPositionParam;
|
||||
EffectParameter gAlbedoParam;
|
||||
|
||||
public Texture2D GPosition { get; set; }
|
||||
public Texture2D GAlbedo { get; set; }
|
||||
|
||||
public DeferredPBR_AmbientLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_AmbientLightEffect)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
{
|
||||
gPositionParam.SetValue(GPosition);
|
||||
gAlbedoParam.SetValue(GAlbedo);
|
||||
}
|
||||
|
||||
void CacheEffectParameters()
|
||||
{
|
||||
gPositionParam = Parameters["gPosition"];
|
||||
gAlbedoParam = Parameters["gAlbedo"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class DeferredPBR_DirectionalLightEffect : Effect
|
||||
{
|
||||
EffectParameter gPositionParam;
|
||||
EffectParameter gAlbedoParam;
|
||||
EffectParameter gNormalParam;
|
||||
EffectParameter gMetallicRoughnessParam;
|
||||
|
||||
EffectParameter shadowMapOneParam;
|
||||
EffectParameter shadowMapTwoParam;
|
||||
EffectParameter shadowMapThreeParam;
|
||||
EffectParameter shadowMapFourParam;
|
||||
|
||||
EffectParameter eyePositionParam;
|
||||
|
||||
EffectParameter directionalLightColorParam;
|
||||
EffectParameter directionalLightDirectionParam;
|
||||
|
||||
EffectParameter cascadeFarPlanesParam;
|
||||
|
||||
EffectParameter shadowMapSizeParam;
|
||||
|
||||
EffectParameter lightSpaceMatrixOneParam;
|
||||
EffectParameter lightSpaceMatrixTwoParam;
|
||||
EffectParameter lightSpaceMatrixThreeParam;
|
||||
EffectParameter lightSpaceMatrixFourParam;
|
||||
|
||||
EffectParameter viewMatrixParam;
|
||||
|
||||
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 readonly float[] CascadeFarPlanes;
|
||||
|
||||
public int 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; }
|
||||
|
||||
public DeferredPBR_DirectionalLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_DirectionalLightEffect)
|
||||
{
|
||||
CascadeFarPlanes = new float[4];
|
||||
CacheEffectParameters();
|
||||
}
|
||||
|
||||
public DeferredPBR_DirectionalLightEffect(DeferredPBR_DirectionalLightEffect cloneSource) : base(cloneSource)
|
||||
{
|
||||
GPosition = cloneSource.GPosition;
|
||||
GAlbedo = cloneSource.GAlbedo;
|
||||
GNormal = cloneSource.GNormal;
|
||||
GMetallicRoughness = cloneSource.GMetallicRoughness;
|
||||
|
||||
ShadowMapOne = cloneSource.ShadowMapOne;
|
||||
ShadowMapTwo = cloneSource.ShadowMapTwo;
|
||||
ShadowMapThree = cloneSource.ShadowMapThree;
|
||||
ShadowMapFour = cloneSource.ShadowMapFour;
|
||||
|
||||
EyePosition = cloneSource.EyePosition;
|
||||
|
||||
DirectionalLightDirection = cloneSource.DirectionalLightDirection;
|
||||
DirectionalLightColor = cloneSource.DirectionalLightColor;
|
||||
|
||||
CascadeFarPlanes = new float[4];
|
||||
for (int i = 0 ; i < 4; i++)
|
||||
{
|
||||
CascadeFarPlanes[i] = cloneSource.CascadeFarPlanes[i];
|
||||
}
|
||||
|
||||
ShadowMapSize = cloneSource.ShadowMapSize;
|
||||
|
||||
LightSpaceMatrixOne = cloneSource.LightSpaceMatrixOne;
|
||||
LightSpaceMatrixTwo = cloneSource.LightSpaceMatrixTwo;
|
||||
LightSpaceMatrixThree = cloneSource.LightSpaceMatrixThree;
|
||||
LightSpaceMatrixFour = cloneSource.LightSpaceMatrixFour;
|
||||
|
||||
ViewMatrix = cloneSource.ViewMatrix;
|
||||
}
|
||||
|
||||
public override Effect Clone()
|
||||
{
|
||||
return new DeferredPBR_DirectionalLightEffect(this);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class DeferredPBR_PointLightEffect : Effect
|
||||
{
|
||||
EffectParameter gPositionParam;
|
||||
EffectParameter gAlbedoParam;
|
||||
EffectParameter gNormalParam;
|
||||
EffectParameter gMetallicRoughnessParam;
|
||||
|
||||
EffectParameter eyePositionParam;
|
||||
|
||||
EffectParameter pointLightColorParam;
|
||||
EffectParameter pointLightPositionParam;
|
||||
|
||||
public Texture2D GPosition { get; set; }
|
||||
public Texture2D GAlbedo { get; set; }
|
||||
public Texture2D GNormal { get; set; }
|
||||
public Texture2D GMetallicRoughness { get; set; }
|
||||
|
||||
public Vector3 EyePosition { get; set; }
|
||||
|
||||
public Vector3 PointLightPosition { get; set; }
|
||||
public Vector3 PointLightColor { get; set; }
|
||||
|
||||
public DeferredPBR_PointLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_PointLightEffect)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
}
|
||||
|
||||
public DeferredPBR_PointLightEffect(DeferredPBR_PointLightEffect cloneSource) : base(cloneSource)
|
||||
{
|
||||
GPosition = cloneSource.GPosition;
|
||||
GAlbedo = cloneSource.GAlbedo;
|
||||
GNormal = cloneSource.GNormal;
|
||||
GMetallicRoughness = cloneSource.GMetallicRoughness;
|
||||
|
||||
EyePosition = cloneSource.EyePosition;
|
||||
|
||||
PointLightPosition = cloneSource.PointLightPosition;
|
||||
PointLightColor = cloneSource.PointLightColor;
|
||||
}
|
||||
|
||||
public override Effect Clone()
|
||||
{
|
||||
return new DeferredPBR_PointLightEffect(this);
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
{
|
||||
gPositionParam.SetValue(GPosition);
|
||||
gAlbedoParam.SetValue(GAlbedo);
|
||||
gNormalParam.SetValue(GNormal);
|
||||
gMetallicRoughnessParam.SetValue(GMetallicRoughness);
|
||||
|
||||
eyePositionParam.SetValue(EyePosition);
|
||||
|
||||
pointLightPositionParam.SetValue(PointLightPosition);
|
||||
pointLightColorParam.SetValue(PointLightColor);
|
||||
}
|
||||
|
||||
void CacheEffectParameters()
|
||||
{
|
||||
gPositionParam = Parameters["gPosition"];
|
||||
gAlbedoParam = Parameters["gAlbedo"];
|
||||
gNormalParam = Parameters["gNormal"];
|
||||
gMetallicRoughnessParam = Parameters["gMetallicRoughness"];
|
||||
|
||||
eyePositionParam = Parameters["EyePosition"];
|
||||
|
||||
pointLightPositionParam = Parameters["PointLightPosition"];
|
||||
pointLightColorParam = Parameters["PointLightColor"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class DirectionalLightCollection
|
||||
{
|
||||
private readonly Vector3[] directions = new Vector3[4];
|
||||
private readonly Vector3[] colors = new Vector3[4];
|
||||
private readonly float[] intensities = new float[4];
|
||||
|
||||
readonly EffectParameter lightDirectionsParam;
|
||||
readonly EffectParameter lightColorsParam;
|
||||
|
||||
public DirectionalLightCollection(EffectParameter lightDirectionsParam, EffectParameter lightColorsParam)
|
||||
{
|
||||
this.lightDirectionsParam = lightDirectionsParam;
|
||||
this.lightColorsParam = lightColorsParam;
|
||||
}
|
||||
|
||||
public DirectionalLight this[int i]
|
||||
{
|
||||
get
|
||||
{
|
||||
var color = colors[i] / intensities[i];
|
||||
return new DirectionalLight(
|
||||
directions[i],
|
||||
new Color(
|
||||
color.X,
|
||||
color.Y,
|
||||
color.Z,
|
||||
1f
|
||||
),
|
||||
intensities[i]
|
||||
);
|
||||
}
|
||||
set
|
||||
{
|
||||
directions[i] = value.Direction;
|
||||
colors[i] = value.Color.ToVector3() * value.Intensity;
|
||||
intensities[i] = value.Intensity;
|
||||
lightDirectionsParam.SetValue(directions);
|
||||
lightColorsParam.SetValue(colors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,12 +2,16 @@
|
|||
|
||||
static const float PI = 3.141592653589793;
|
||||
static const int MAX_POINT_LIGHTS = 64;
|
||||
static const int MAX_DIRECTIONAL_LIGHTS = 4;
|
||||
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
|
||||
|
||||
|
@ -16,19 +20,45 @@ BEGIN_CONSTANTS
|
|||
float3 PointLightPositions[MAX_POINT_LIGHTS] _ps(c1) _cb(c1);
|
||||
float3 PointLightColors[MAX_POINT_LIGHTS] _ps(c65) _cb(c65);
|
||||
|
||||
float3 DirectionalLightDirections[MAX_DIRECTIONAL_LIGHTS] _ps(c129) _cb(c129);
|
||||
float3 DirectionalLightColors[MAX_DIRECTIONAL_LIGHTS] _ps(c133) _cb(c133);
|
||||
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)
|
||||
|
@ -71,17 +101,119 @@ float GeometrySmith(float3 N, float3 V, float3 L, float 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 lightDir,
|
||||
float3 L,
|
||||
float3 radiance,
|
||||
float3 F0,
|
||||
float3 V,
|
||||
float3 N,
|
||||
float3 albedo,
|
||||
float metallic,
|
||||
float roughness
|
||||
float roughness,
|
||||
float shadow
|
||||
) {
|
||||
float3 L = normalize(lightDir);
|
||||
float3 H = normalize(V + L);
|
||||
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
|
@ -98,7 +230,7 @@ float3 ComputeLight(
|
|||
kD *= 1.0 - metallic;
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
return (kD * albedo / PI + specular) * radiance * NdotL;
|
||||
return (kD * albedo / PI + specular) * radiance * NdotL * shadow;
|
||||
}
|
||||
|
||||
float4 ComputeColor(
|
||||
|
@ -120,21 +252,20 @@ float4 ComputeColor(
|
|||
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(lightDir, radiance, F0, V, N, albedo, metallic, roughness);
|
||||
Lo += ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, 1.0);
|
||||
}
|
||||
|
||||
// directional light
|
||||
for (int i = 0; i < MAX_DIRECTIONAL_LIGHTS; i++)
|
||||
{
|
||||
float3 lightDir = DirectionalLightDirections[i];
|
||||
float3 radiance = DirectionalLightColors[i];
|
||||
float3 L = normalize(DirectionalLightDirection);
|
||||
float3 radiance = DirectionalLightColor;
|
||||
|
||||
Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness);
|
||||
}
|
||||
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;
|
||||
|
@ -148,13 +279,13 @@ float4 ComputeColor(
|
|||
|
||||
float4 main_ps(PixelInput input) : SV_TARGET0
|
||||
{
|
||||
float3 fragPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb;
|
||||
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(
|
||||
fragPosition,
|
||||
worldPosition,
|
||||
normal,
|
||||
albedo,
|
||||
metallicRoughness.r,
|
||||
|
@ -166,6 +297,7 @@ Technique DeferredPBR
|
|||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#include "Macros.fxh" // from FNA
|
||||
|
||||
DECLARE_TEXTURE(gPosition, 0);
|
||||
DECLARE_TEXTURE(gAlbedo, 1);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
float4 ComputeColor(
|
||||
float3 worldPosition,
|
||||
float3 albedo
|
||||
) {
|
||||
float3 color = float3(0.03, 0.03, 0.03) * albedo;
|
||||
return float4(color, 1.0);
|
||||
}
|
||||
|
||||
float4 main_ps(PixelInput input) : SV_TARGET0
|
||||
{
|
||||
float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb;
|
||||
float3 albedo = SAMPLE_TEXTURE(gAlbedo, input.TexCoord).rgb;
|
||||
|
||||
return ComputeColor(
|
||||
worldPosition,
|
||||
albedo
|
||||
);
|
||||
}
|
||||
|
||||
Technique DeferredPBR_Ambient
|
||||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
#include "Macros.fxh" //from FNA
|
||||
#include "Lighting.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(c3) _cb(c3);
|
||||
|
||||
float ShadowMapSize _ps(c7) _cb(c7);
|
||||
|
||||
MATRIX_CONSTANTS
|
||||
|
||||
float4x4 LightSpaceMatrixOne _ps(c8) _cb(c8);
|
||||
float4x4 LightSpaceMatrixTwo _ps(c12) _cb(c12);
|
||||
float4x4 LightSpaceMatrixThree _ps(c16) _cb(c16);
|
||||
float4x4 LightSpaceMatrixFour _ps(c20) _cb(c20);
|
||||
|
||||
// used to select shadow cascade
|
||||
float4x4 ViewMatrix _ps(c24) _cb(c24);
|
||||
|
||||
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;
|
||||
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
|
||||
|
||||
// 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
|
||||
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
|
||||
|
||||
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);
|
||||
}
|
||||
else if (shadowCascadeIndex == 1)
|
||||
{
|
||||
visibility = PoissonCoord(SAMPLER(shadowMapTwo), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
||||
}
|
||||
else if (shadowCascadeIndex == 2)
|
||||
{
|
||||
visibility = PoissonCoord(SAMPLER(shadowMapThree), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
||||
}
|
||||
else
|
||||
{
|
||||
visibility = PoissonCoord(SAMPLER(shadowMapFour), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
||||
}
|
||||
|
||||
return visibility;
|
||||
}
|
||||
|
||||
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 L = normalize(DirectionalLightDirection);
|
||||
float3 radiance = DirectionalLightColor;
|
||||
|
||||
float shadow = ComputeShadow(worldPosition, N, L);
|
||||
float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, shadow);
|
||||
|
||||
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_Directional
|
||||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -79,10 +79,10 @@ PixelOutput NonePS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 1.0);
|
||||
output.gAlbedo = float4(AlbedoValue, 1.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 0.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 1.0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -91,10 +91,10 @@ PixelOutput AlbedoPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 1.0);
|
||||
output.gAlbedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 0.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 1.0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -103,8 +103,8 @@ PixelOutput MetallicRoughnessPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 1.0);
|
||||
output.gAlbedo = float4(AlbedoValue, 1.0);
|
||||
output.gMetallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord);
|
||||
|
||||
|
@ -115,10 +115,10 @@ PixelOutput NormalPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 1.0);
|
||||
output.gAlbedo = float4(AlbedoValue, 1.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 0.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 1.0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -127,8 +127,8 @@ PixelOutput AlbedoMetallicRoughnessPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 1.0);
|
||||
output.gAlbedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord);
|
||||
output.gMetallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord);
|
||||
|
||||
|
@ -139,10 +139,10 @@ PixelOutput AlbedoNormalPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 1.0);
|
||||
output.gAlbedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 0.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 1.0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -151,8 +151,8 @@ PixelOutput MetallicRoughnessNormalPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 1.0);
|
||||
output.gAlbedo = float4(AlbedoValue, 1.0);
|
||||
output.gMetallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord);
|
||||
|
||||
|
@ -163,8 +163,8 @@ PixelOutput AlbedoMetallicRoughnessNormalMapPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 1.0);
|
||||
output.gAlbedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord);
|
||||
output.gMetallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord);
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
#include "Macros.fxh" //from FNA
|
||||
#include "Lighting.fxh"
|
||||
|
||||
DECLARE_TEXTURE(gPosition, 0);
|
||||
DECLARE_TEXTURE(gAlbedo, 1);
|
||||
DECLARE_TEXTURE(gNormal, 2);
|
||||
DECLARE_TEXTURE(gMetallicRoughness, 3);
|
||||
|
||||
BEGIN_CONSTANTS
|
||||
|
||||
float3 EyePosition _ps(c0) _cb(c0);
|
||||
|
||||
float3 PointLightPosition _ps(c1) _cb(c1);
|
||||
float3 PointLightColor _ps(c2) _cb(c2);
|
||||
|
||||
MATRIX_CONSTANTS
|
||||
|
||||
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
|
||||
|
||||
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 lightDir = PointLightPosition - worldPosition;
|
||||
float3 L = normalize(lightDir);
|
||||
float distance = length(lightDir);
|
||||
float attenuation = 1.0 / (distance * distance);
|
||||
float3 radiance = PointLightColor * attenuation;
|
||||
|
||||
float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, 1.0);
|
||||
|
||||
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_Point
|
||||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
static const float PI = 3.141592653589793;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
float3 ComputeLight(
|
||||
float3 L,
|
||||
float3 radiance,
|
||||
float3 F0,
|
||||
float3 V,
|
||||
float3 N,
|
||||
float3 albedo,
|
||||
float metallic,
|
||||
float roughness,
|
||||
float visibility
|
||||
) {
|
||||
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 * visibility;
|
||||
}
|
|
@ -54,4 +54,5 @@
|
|||
#define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord)
|
||||
#define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name##Sampler, texCoord)
|
||||
#define SAMPLE_CUBEMAP_LOD(Name, texCoord) texCUBElod(Name##Sampler, texCoord)
|
||||
#define SAMPLER(Name) Name##Sampler
|
||||
#endif
|
||||
|
|
|
@ -16,21 +16,29 @@ struct VertexShaderInput
|
|||
struct VertexShaderOutput
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float Depth : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertexShaderOutput main_vs(VertexShaderInput input)
|
||||
{
|
||||
VertexShaderOutput output;
|
||||
|
||||
output.Position = mul(float4(input.Position.xyz, 1.0), ModelViewProjection);
|
||||
output.Position = mul(input.Position, ModelViewProjection);
|
||||
output.Depth = output.Position.z;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 main_ps(VertexShaderOutput input) : SV_TARGET0
|
||||
{
|
||||
return float4(input.Depth, 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,20 @@
|
|||
sampler TextureSampler : register(s0);
|
||||
|
||||
float4 main_ps(float2 texCoord : TEXCOORD0) : COLOR0
|
||||
{
|
||||
float3 color = tex2D(TextureSampler, texCoord).xyz;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Technique DeferredPBR
|
||||
{
|
||||
Pass
|
||||
{
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
|
|||
|
||||
namespace Kav
|
||||
{
|
||||
public class PBREffect : Effect, TransformEffect, PointLightEffect, DirectionalLightEffect
|
||||
public class PBREffect : Effect, TransformEffect, PointLightEffect
|
||||
{
|
||||
EffectParameter worldParam;
|
||||
EffectParameter worldViewProjectionParam;
|
||||
|
@ -31,7 +31,6 @@ namespace Kav
|
|||
Matrix view = Matrix.Identity;
|
||||
Matrix projection = Matrix.Identity;
|
||||
PointLightCollection pointLightCollection;
|
||||
DirectionalLightCollection directionalLightCollection;
|
||||
|
||||
Vector3 albedo;
|
||||
float metallic;
|
||||
|
@ -84,14 +83,6 @@ namespace Kav
|
|||
private set { pointLightCollection = value; }
|
||||
}
|
||||
|
||||
public int MaxDirectionalLights { get; } = 4;
|
||||
|
||||
public DirectionalLightCollection DirectionalLights
|
||||
{
|
||||
get { return directionalLightCollection; }
|
||||
private set { directionalLightCollection = value; }
|
||||
}
|
||||
|
||||
public Vector3 Albedo
|
||||
{
|
||||
get { return albedo; }
|
||||
|
@ -204,11 +195,6 @@ namespace Kav
|
|||
Parameters["PositionLightColors"],
|
||||
MaxPointLights
|
||||
);
|
||||
|
||||
directionalLightCollection = new DirectionalLightCollection(
|
||||
Parameters["LightDirections"],
|
||||
Parameters["DirectionLightColors"]
|
||||
);
|
||||
}
|
||||
|
||||
protected PBREffect(PBREffect cloneSource) : base(cloneSource)
|
||||
|
@ -230,16 +216,6 @@ namespace Kav
|
|||
PointLights[i] = cloneSource.PointLights[i];
|
||||
}
|
||||
|
||||
DirectionalLights = new DirectionalLightCollection(
|
||||
Parameters["LightDirections"],
|
||||
Parameters["DirectionLightColors"]
|
||||
);
|
||||
|
||||
for (int i = 0; i < MaxDirectionalLights; i++)
|
||||
{
|
||||
DirectionalLights[i] = cloneSource.DirectionalLights[i];
|
||||
}
|
||||
|
||||
AlbedoTexture = cloneSource.AlbedoTexture;
|
||||
NormalTexture = cloneSource.NormalTexture;
|
||||
EmissionTexture = cloneSource.EmissionTexture;
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace Kav
|
|||
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleDepthEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SimpleDepthEffect)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
|
@ -51,8 +52,8 @@ namespace Kav
|
|||
{
|
||||
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
|
||||
{
|
||||
Matrix.Multiply(ref model, ref view, out Matrix modelView);
|
||||
Matrix.Multiply(ref modelView, ref projection, out Matrix worldViewProj);
|
||||
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection);
|
||||
Matrix.Multiply(ref model, ref viewProjection, out Matrix worldViewProj);
|
||||
|
||||
modelViewProjectionParam.SetValue(worldViewProj);
|
||||
|
||||
|
|
|
@ -15,9 +15,21 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_AmbientLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_AmbientLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_PointLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_PointLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_DirectionalLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_DirectionalLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_GBufferEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_GBufferEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb">
|
||||
<LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -15,9 +15,21 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_AmbientLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_AmbientLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_PointLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_PointLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_DirectionalLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_DirectionalLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_GBufferEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_GBufferEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb">
|
||||
<LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace Kav
|
|||
{
|
||||
get
|
||||
{
|
||||
return Matrix.CreateLookAt(-Direction * 100f, Vector3.Zero, Vector3.Up);
|
||||
return Matrix.CreateLookAt(Direction * 100f, Vector3.Zero, Vector3.Up);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
# Kav
|
||||
|
||||
A 3D renderer built on top of FNA.
|
||||
|
||||
## Roadmap
|
||||
|
||||
Essential
|
||||
|
||||
- [x] PBR shading
|
||||
- [x] Deferred rendering
|
||||
- [x] Point lighting
|
||||
- [x] Directional lighting
|
||||
- [x] Directional shadow maps
|
||||
- [x] Cascading shadow maps
|
||||
- [x] Tone map shader
|
||||
- [x] Poisson soft shadowing
|
||||
- [ ] Frustum culling
|
||||
- [ ] Shadow-casting point lights
|
||||
- [ ] Parabolic lights
|
||||
- [ ] Skyboxes
|
||||
- [ ] Screen-space reflection
|
||||
|
||||
Nice-To-Haves
|
||||
|
||||
- [ ] Anti-aliasing
|
||||
- [ ] Image-based lighting
|
||||
- [ ] Volumetric lighting
|
||||
- [ ] Volumetric smoke
|
||||
- [ ]
|
311
Renderer.cs
311
Renderer.cs
|
@ -6,38 +6,84 @@ namespace Kav
|
|||
{
|
||||
public class Renderer
|
||||
{
|
||||
private const int MAX_SHADOW_CASCADES = 4;
|
||||
private int ShadowMapSize { get; }
|
||||
|
||||
private GraphicsDevice GraphicsDevice { get; }
|
||||
private int RenderDimensionsX { get; }
|
||||
private int RenderDimensionsY { get; }
|
||||
|
||||
private RenderTarget2D DepthRenderTarget { get; }
|
||||
private VertexBuffer FullscreenTriangle { get; }
|
||||
private int NumShadowCascades { get; }
|
||||
|
||||
private RenderTarget2D ColorRenderTarget { get; }
|
||||
private RenderTarget2D DirectionalRenderTarget { get; }
|
||||
private RenderTarget2D[] ShadowRenderTargets { get; }
|
||||
|
||||
private DeferredPBREffect DeferredPBREffect { get; }
|
||||
private DeferredPBR_AmbientLightEffect DeferredAmbientLightEffect { get; }
|
||||
private DeferredPBR_PointLightEffect DeferredPointLightEffect { get; }
|
||||
private DeferredPBR_DirectionalLightEffect DeferredDirectionalLightEffect { get; }
|
||||
private SimpleDepthEffect SimpleDepthEffect { get; }
|
||||
private Effect ToneMapEffect { get; }
|
||||
|
||||
private RenderTarget2D gPosition { get; }
|
||||
private RenderTarget2D gNormal { get; }
|
||||
private RenderTarget2D gAlbedo { get; }
|
||||
private RenderTarget2D gMetallicRoughness { get; }
|
||||
private RenderTarget2D deferredRenderTarget { get; }
|
||||
|
||||
private RenderTargetBinding[] GBuffer { get; }
|
||||
|
||||
private DeferredPBREffect DeferredPBREffect { get; }
|
||||
|
||||
private SpriteBatch SpriteBatch { get; }
|
||||
|
||||
public Renderer(GraphicsDevice graphicsDevice, int renderDimensionsX, int renderDimensionsY)
|
||||
{
|
||||
public Renderer(
|
||||
GraphicsDevice graphicsDevice,
|
||||
int renderDimensionsX,
|
||||
int renderDimensionsY,
|
||||
int numShadowCascades,
|
||||
int shadowMapSize
|
||||
) {
|
||||
GraphicsDevice = graphicsDevice;
|
||||
RenderDimensionsX = renderDimensionsX;
|
||||
RenderDimensionsY = renderDimensionsY;
|
||||
|
||||
DepthRenderTarget = new RenderTarget2D(
|
||||
ShadowMapSize = shadowMapSize;
|
||||
|
||||
NumShadowCascades = (int)MathHelper.Clamp(numShadowCascades, 1, MAX_SHADOW_CASCADES);
|
||||
ShadowRenderTargets = new RenderTarget2D[numShadowCascades];
|
||||
|
||||
for (var i = 0; i < numShadowCascades; i++)
|
||||
{
|
||||
ShadowRenderTargets[i] = new RenderTarget2D(
|
||||
GraphicsDevice,
|
||||
ShadowMapSize,
|
||||
ShadowMapSize,
|
||||
false,
|
||||
SurfaceFormat.Single,
|
||||
DepthFormat.Depth24
|
||||
);
|
||||
}
|
||||
|
||||
ColorRenderTarget = new RenderTarget2D(
|
||||
graphicsDevice,
|
||||
renderDimensionsX,
|
||||
renderDimensionsY,
|
||||
false,
|
||||
SurfaceFormat.HalfSingle, // unused
|
||||
DepthFormat.Depth24
|
||||
SurfaceFormat.Color,
|
||||
DepthFormat.None,
|
||||
0,
|
||||
RenderTargetUsage.PreserveContents
|
||||
);
|
||||
|
||||
DirectionalRenderTarget = new RenderTarget2D(
|
||||
graphicsDevice,
|
||||
renderDimensionsX,
|
||||
renderDimensionsY,
|
||||
false,
|
||||
SurfaceFormat.Color,
|
||||
DepthFormat.None,
|
||||
0,
|
||||
RenderTargetUsage.PreserveContents
|
||||
);
|
||||
|
||||
gPosition = new RenderTarget2D(
|
||||
|
@ -83,28 +129,32 @@ namespace Kav
|
|||
new RenderTargetBinding(gMetallicRoughness)
|
||||
};
|
||||
|
||||
deferredRenderTarget = new RenderTarget2D(
|
||||
GraphicsDevice,
|
||||
renderDimensionsX,
|
||||
renderDimensionsY
|
||||
);
|
||||
|
||||
SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice);
|
||||
DeferredPBREffect = new DeferredPBREffect(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);
|
||||
|
||||
SpriteBatch = new SpriteBatch(GraphicsDevice);
|
||||
FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly);
|
||||
FullscreenTriangle.SetData(new VertexPositionTexture[3] {
|
||||
new VertexPositionTexture(new Vector3(-1, -3, 0), new Vector2(0, 2)),
|
||||
new VertexPositionTexture(new Vector3(-1, 1, 0), new Vector2(0, 0)),
|
||||
new VertexPositionTexture(new Vector3(3, 1, 0), new Vector2(2, 0))
|
||||
});
|
||||
|
||||
GraphicsDevice.SetRenderTarget(deferredRenderTarget);
|
||||
graphicsDevice.Clear(Color.White);
|
||||
GraphicsDevice.SetRenderTarget(null);
|
||||
SpriteBatch = new SpriteBatch(graphicsDevice);
|
||||
}
|
||||
|
||||
public void DeferredRender(
|
||||
Camera camera,
|
||||
PerspectiveCamera camera,
|
||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||
IEnumerable<PointLight> pointLights,
|
||||
IEnumerable<DirectionalLight> directionalLights
|
||||
DirectionalLight directionalLight
|
||||
) {
|
||||
// g-buffer pass
|
||||
|
||||
GraphicsDevice.SetRenderTargets(GBuffer);
|
||||
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
|
||||
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||
|
@ -143,53 +193,186 @@ namespace Kav
|
|||
}
|
||||
}
|
||||
|
||||
GraphicsDevice.SetRenderTarget(null);
|
||||
GraphicsDevice.Clear(Color.CornflowerBlue);
|
||||
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||
GraphicsDevice.Clear(Color.Black);
|
||||
GraphicsDevice.BlendState = BlendState.Additive;
|
||||
GraphicsDevice.DepthStencilState = DepthStencilState.None;
|
||||
|
||||
DeferredPBREffect.GPosition = gPosition;
|
||||
DeferredPBREffect.GAlbedo = gAlbedo;
|
||||
DeferredPBREffect.GNormal = gNormal;
|
||||
DeferredPBREffect.GMetallicRoughness = gMetallicRoughness;
|
||||
DeferredPBREffect.EyePosition = Matrix.Invert(camera.View).Translation;
|
||||
DeferredAmbientLightEffect.GPosition = gPosition;
|
||||
DeferredAmbientLightEffect.GAlbedo = gAlbedo;
|
||||
|
||||
foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes)
|
||||
{
|
||||
pass.Apply();
|
||||
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
|
||||
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
|
||||
}
|
||||
|
||||
DeferredPointLightEffect.EyePosition = camera.Position;
|
||||
|
||||
int i = 0;
|
||||
foreach (var pointLight in pointLights)
|
||||
{
|
||||
if (i > DeferredPBREffect.MaxPointLights) { break; }
|
||||
DeferredPBREffect.PointLights[i] = pointLight;
|
||||
i++;
|
||||
PointLightRender(pointLight);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
foreach (var directionalLight in directionalLights)
|
||||
{
|
||||
if (i > DeferredPBREffect.MaxDirectionalLights) { break; }
|
||||
DeferredPBREffect.DirectionalLights[i] = directionalLight;
|
||||
i++;
|
||||
}
|
||||
DirectionalLightRender(camera, modelTransforms, directionalLight);
|
||||
// return;
|
||||
// GraphicsDevice.SetRenderTarget(null);
|
||||
// SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
|
||||
// SpriteBatch.Draw(DirectionalRenderTarget, Vector2.Zero, Color.White);
|
||||
// SpriteBatch.End();
|
||||
|
||||
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, null, null, DeferredPBREffect);
|
||||
SpriteBatch.Draw(deferredRenderTarget, Vector2.Zero, Color.White);
|
||||
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 Render(
|
||||
Camera camera,
|
||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||
IEnumerable<PointLight> pointLights,
|
||||
IEnumerable<DirectionalLight> directionalLights
|
||||
) {
|
||||
Render(camera.View, camera.Projection, modelTransforms, pointLights, directionalLights);
|
||||
private void PointLightRender(PointLight pointLight)
|
||||
{
|
||||
DeferredPointLightEffect.GPosition = gPosition;
|
||||
DeferredPointLightEffect.GAlbedo = gAlbedo;
|
||||
DeferredPointLightEffect.GNormal = gNormal;
|
||||
DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness;
|
||||
|
||||
DeferredPointLightEffect.PointLightPosition = pointLight.Position;
|
||||
DeferredPointLightEffect.PointLightColor =
|
||||
pointLight.Color.ToVector3() * pointLight.Intensity;
|
||||
|
||||
foreach (var pass in DeferredPointLightEffect.CurrentTechnique.Passes)
|
||||
{
|
||||
pass.Apply();
|
||||
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
|
||||
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// for shadow mapping
|
||||
public void DepthRender(IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight)
|
||||
private void DirectionalLightRender(
|
||||
PerspectiveCamera camera,
|
||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||
DirectionalLight directionalLight
|
||||
) {
|
||||
// render the individual shadow cascades
|
||||
var previousFarPlane = camera.NearPlane;
|
||||
for (var i = 0; i < NumShadowCascades; i++)
|
||||
{
|
||||
GraphicsDevice.SetRenderTarget(DepthRenderTarget);
|
||||
GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1, 0);
|
||||
var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f));
|
||||
|
||||
SimpleDepthEffect.View = directionalLight.View;
|
||||
SimpleDepthEffect.Projection = directionalLight.Projection;
|
||||
// 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;
|
||||
}
|
||||
|
||||
DeferredDirectionalLightEffect.GPosition = gPosition;
|
||||
DeferredDirectionalLightEffect.GAlbedo = gAlbedo;
|
||||
DeferredDirectionalLightEffect.GNormal = gNormal;
|
||||
DeferredDirectionalLightEffect.GMetallicRoughness = gMetallicRoughness;
|
||||
|
||||
DeferredDirectionalLightEffect.ShadowMapOne = ShadowRenderTargets[0];
|
||||
if (NumShadowCascades > 1)
|
||||
{
|
||||
DeferredDirectionalLightEffect.ShadowMapTwo = ShadowRenderTargets[1];
|
||||
}
|
||||
if (NumShadowCascades > 2)
|
||||
{
|
||||
DeferredDirectionalLightEffect.ShadowMapThree = ShadowRenderTargets[2];
|
||||
}
|
||||
if (NumShadowCascades > 3)
|
||||
{
|
||||
DeferredDirectionalLightEffect.ShadowMapFour = ShadowRenderTargets[3];
|
||||
}
|
||||
|
||||
DeferredDirectionalLightEffect.DirectionalLightDirection = directionalLight.Direction;
|
||||
DeferredDirectionalLightEffect.DirectionalLightColor =
|
||||
directionalLight.Color.ToVector3() * directionalLight.Intensity;
|
||||
|
||||
DeferredDirectionalLightEffect.ViewMatrix = camera.View;
|
||||
DeferredDirectionalLightEffect.EyePosition = Matrix.Invert(camera.View).Translation;
|
||||
|
||||
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||
GraphicsDevice.BlendState = BlendState.Additive;
|
||||
|
||||
foreach (EffectPass pass in DeferredDirectionalLightEffect.CurrentTechnique.Passes)
|
||||
{
|
||||
pass.Apply();
|
||||
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
|
||||
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderShadowMap(
|
||||
PerspectiveCamera camera,
|
||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||
DirectionalLight directionalLight,
|
||||
int shadowCascadeIndex
|
||||
) {
|
||||
GraphicsDevice.SetRenderTarget(ShadowRenderTargets[shadowCascadeIndex]);
|
||||
GraphicsDevice.Clear(Color.White);
|
||||
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||
GraphicsDevice.BlendState = BlendState.Opaque;
|
||||
|
||||
var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
|
||||
Vector3[] frustumCorners = cameraBoundingFrustum.GetCorners();
|
||||
|
||||
Vector3 frustumCenter = Vector3.Zero;
|
||||
for (var i = 0; i < frustumCorners.Length; i++)
|
||||
{
|
||||
frustumCenter += frustumCorners[i];
|
||||
}
|
||||
frustumCenter /= 8f;
|
||||
|
||||
var lightView = Matrix.CreateLookAt(frustumCenter + directionalLight.Direction, frustumCenter, Vector3.Backward);
|
||||
|
||||
for (var i = 0; i < frustumCorners.Length; i++)
|
||||
{
|
||||
frustumCorners[i] = Vector3.Transform(frustumCorners[i], lightView);
|
||||
}
|
||||
|
||||
BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners);
|
||||
|
||||
SimpleDepthEffect.View = lightView;
|
||||
SimpleDepthEffect.Projection = Matrix.CreateOrthographicOffCenter(
|
||||
lightBox.Min.X,
|
||||
lightBox.Max.X,
|
||||
lightBox.Min.Y,
|
||||
lightBox.Max.Y,
|
||||
-lightBox.Max.Z - 10f, // TODO: near clip plane needs scene AABB info to get rid of this magic value
|
||||
-lightBox.Min.Z
|
||||
);
|
||||
|
||||
var lightSpaceMatrix = SimpleDepthEffect.View * SimpleDepthEffect.Projection;
|
||||
|
||||
if (shadowCascadeIndex == 0)
|
||||
{
|
||||
DeferredDirectionalLightEffect.LightSpaceMatrixOne = lightSpaceMatrix;
|
||||
}
|
||||
else if (shadowCascadeIndex == 1)
|
||||
{
|
||||
DeferredDirectionalLightEffect.LightSpaceMatrixTwo = lightSpaceMatrix;
|
||||
}
|
||||
else if (shadowCascadeIndex == 2)
|
||||
{
|
||||
DeferredDirectionalLightEffect.LightSpaceMatrixThree = lightSpaceMatrix;
|
||||
}
|
||||
else if (shadowCascadeIndex == 3)
|
||||
{
|
||||
DeferredDirectionalLightEffect.LightSpaceMatrixFour = lightSpaceMatrix;
|
||||
}
|
||||
|
||||
DeferredDirectionalLightEffect.CascadeFarPlanes[shadowCascadeIndex] = camera.FarPlane;
|
||||
|
||||
foreach (var (model, transform) in modelTransforms)
|
||||
{
|
||||
|
@ -220,6 +403,15 @@ namespace Kav
|
|||
}
|
||||
}
|
||||
|
||||
public void Render(
|
||||
PerspectiveCamera camera,
|
||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||
IEnumerable<PointLight> pointLights,
|
||||
IEnumerable<DirectionalLight> directionalLights
|
||||
) {
|
||||
Render(camera.View, camera.Projection, modelTransforms, pointLights, directionalLights);
|
||||
}
|
||||
|
||||
private void Render(
|
||||
Matrix view,
|
||||
Matrix projection,
|
||||
|
@ -254,17 +446,6 @@ namespace Kav
|
|||
}
|
||||
}
|
||||
|
||||
if (meshPart.Effect is DirectionalLightEffect directionalLightEffect)
|
||||
{
|
||||
int i = 0;
|
||||
foreach (var directionalLight in directionalLights)
|
||||
{
|
||||
if (i > directionalLightEffect.MaxDirectionalLights) { break; }
|
||||
directionalLightEffect.DirectionalLights[i] = directionalLight;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var pass in meshPart.Effect.CurrentTechnique.Passes)
|
||||
{
|
||||
pass.Apply();
|
||||
|
|
51
Resources.cs
51
Resources.cs
|
@ -4,6 +4,41 @@ namespace Kav
|
|||
{
|
||||
internal class Resources
|
||||
{
|
||||
public static byte[] DeferredPBR_AmbientLightEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ambientLightEffect == null)
|
||||
{
|
||||
ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect");
|
||||
}
|
||||
return ambientLightEffect;
|
||||
}
|
||||
}
|
||||
public static byte[] DeferredPBR_PointLightEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pointLightEffect == null)
|
||||
{
|
||||
pointLightEffect = GetResource("DeferredPBR_PointLightEffect");
|
||||
}
|
||||
return pointLightEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DeferredPBR_DirectionalLightEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (directionalLightEffect == null)
|
||||
{
|
||||
directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect");
|
||||
}
|
||||
return directionalLightEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DeferredPBR_GBufferEffect
|
||||
{
|
||||
get
|
||||
|
@ -16,6 +51,18 @@ namespace Kav
|
|||
}
|
||||
}
|
||||
|
||||
public static byte[] ToneMapEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (toneMapEffect == null)
|
||||
{
|
||||
toneMapEffect = GetResource("ToneMapEffect");
|
||||
}
|
||||
return toneMapEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DeferredPBREffect
|
||||
{
|
||||
get
|
||||
|
@ -52,7 +99,11 @@ namespace Kav
|
|||
}
|
||||
}
|
||||
|
||||
private static byte[] ambientLightEffect;
|
||||
private static byte[] pointLightEffect;
|
||||
private static byte[] directionalLightEffect;
|
||||
private static byte[] gBufferEffect;
|
||||
private static byte[] toneMapEffect;
|
||||
private static byte[] deferredPBREffect;
|
||||
private static byte[] pbrEffect;
|
||||
private static byte[] simpleDepthEffect;
|
||||
|
|
Loading…
Reference in New Issue