Toon Shading + Point Shadows #3
|
@ -0,0 +1,14 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace Kav
|
||||||
|
{
|
||||||
|
public interface ShadowCascadeEffect
|
||||||
|
{
|
||||||
|
Matrix LightSpaceMatrixOne { get; set; }
|
||||||
|
Matrix LightSpaceMatrixTwo { get; set; }
|
||||||
|
Matrix LightSpaceMatrixThree { get; set; }
|
||||||
|
Matrix LightSpaceMatrixFour { get; set; }
|
||||||
|
|
||||||
|
float[] CascadeFarPlanes { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
namespace Kav
|
namespace Kav
|
||||||
|
@ -8,9 +9,13 @@ namespace Kav
|
||||||
EffectParameter gPositionParam;
|
EffectParameter gPositionParam;
|
||||||
EffectParameter gAlbedoParam;
|
EffectParameter gAlbedoParam;
|
||||||
|
|
||||||
|
EffectParameter ambientColorParam;
|
||||||
|
|
||||||
public Texture2D GPosition { get; set; }
|
public Texture2D GPosition { get; set; }
|
||||||
public Texture2D GAlbedo { get; set; }
|
public Texture2D GAlbedo { get; set; }
|
||||||
|
|
||||||
|
public Vector3 AmbientColor { get; set; }
|
||||||
|
|
||||||
public DeferredPBR_AmbientLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_AmbientLightEffect)
|
public DeferredPBR_AmbientLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_AmbientLightEffect)
|
||||||
{
|
{
|
||||||
CacheEffectParameters();
|
CacheEffectParameters();
|
||||||
|
@ -20,12 +25,14 @@ namespace Kav
|
||||||
{
|
{
|
||||||
gPositionParam.SetValue(GPosition);
|
gPositionParam.SetValue(GPosition);
|
||||||
gAlbedoParam.SetValue(GAlbedo);
|
gAlbedoParam.SetValue(GAlbedo);
|
||||||
|
ambientColorParam.SetValue(AmbientColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CacheEffectParameters()
|
void CacheEffectParameters()
|
||||||
{
|
{
|
||||||
gPositionParam = Parameters["gPosition"];
|
gPositionParam = Parameters["gPosition"];
|
||||||
gAlbedoParam = Parameters["gAlbedo"];
|
gAlbedoParam = Parameters["gAlbedo"];
|
||||||
|
ambientColorParam = Parameters["AmbientLightColor"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
namespace Kav
|
namespace Kav
|
||||||
{
|
{
|
||||||
public class DeferredPBR_DirectionalLightEffect : Effect
|
public class DeferredPBR_DirectionalLightEffect : Effect, ShadowCascadeEffect
|
||||||
{
|
{
|
||||||
EffectParameter gPositionParam;
|
EffectParameter gPositionParam;
|
||||||
EffectParameter gAlbedoParam;
|
EffectParameter gAlbedoParam;
|
||||||
|
@ -46,7 +46,7 @@ namespace Kav
|
||||||
public Vector3 DirectionalLightDirection { get; set; }
|
public Vector3 DirectionalLightDirection { get; set; }
|
||||||
public Vector3 DirectionalLightColor { get; set; }
|
public Vector3 DirectionalLightColor { get; set; }
|
||||||
|
|
||||||
public readonly float[] CascadeFarPlanes;
|
public float[] CascadeFarPlanes { get; }
|
||||||
|
|
||||||
public int ShadowMapSize { get; set; }
|
public int ShadowMapSize { get; set; }
|
||||||
|
|
||||||
|
@ -147,7 +147,6 @@ namespace Kav
|
||||||
directionalLightColorParam = Parameters["DirectionalLightColor"];
|
directionalLightColorParam = Parameters["DirectionalLightColor"];
|
||||||
|
|
||||||
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
|
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
|
||||||
|
|
||||||
shadowMapSizeParam = Parameters["ShadowMapSize"];
|
shadowMapSizeParam = Parameters["ShadowMapSize"];
|
||||||
|
|
||||||
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];
|
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];
|
||||||
|
|
|
@ -9,22 +9,28 @@ namespace Kav
|
||||||
EffectParameter gAlbedoParam;
|
EffectParameter gAlbedoParam;
|
||||||
EffectParameter gNormalParam;
|
EffectParameter gNormalParam;
|
||||||
EffectParameter gMetallicRoughnessParam;
|
EffectParameter gMetallicRoughnessParam;
|
||||||
|
EffectParameter shadowMapParam;
|
||||||
|
|
||||||
EffectParameter eyePositionParam;
|
EffectParameter eyePositionParam;
|
||||||
|
|
||||||
EffectParameter pointLightColorParam;
|
EffectParameter pointLightColorParam;
|
||||||
EffectParameter pointLightPositionParam;
|
EffectParameter pointLightPositionParam;
|
||||||
|
|
||||||
|
EffectParameter farPlaneParam;
|
||||||
|
|
||||||
public Texture2D GPosition { get; set; }
|
public Texture2D GPosition { get; set; }
|
||||||
public Texture2D GAlbedo { get; set; }
|
public Texture2D GAlbedo { get; set; }
|
||||||
public Texture2D GNormal { get; set; }
|
public Texture2D GNormal { get; set; }
|
||||||
public Texture2D GMetallicRoughness { get; set; }
|
public Texture2D GMetallicRoughness { get; set; }
|
||||||
|
public TextureCube ShadowMap { get; set; }
|
||||||
|
|
||||||
public Vector3 EyePosition { get; set; }
|
public Vector3 EyePosition { get; set; }
|
||||||
|
|
||||||
public Vector3 PointLightPosition { get; set; }
|
public Vector3 PointLightPosition { get; set; }
|
||||||
public Vector3 PointLightColor { get; set; }
|
public Vector3 PointLightColor { get; set; }
|
||||||
|
|
||||||
|
public float FarPlane { get; set; }
|
||||||
|
|
||||||
public DeferredPBR_PointLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_PointLightEffect)
|
public DeferredPBR_PointLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_PointLightEffect)
|
||||||
{
|
{
|
||||||
CacheEffectParameters();
|
CacheEffectParameters();
|
||||||
|
@ -32,15 +38,20 @@ namespace Kav
|
||||||
|
|
||||||
public DeferredPBR_PointLightEffect(DeferredPBR_PointLightEffect cloneSource) : base(cloneSource)
|
public DeferredPBR_PointLightEffect(DeferredPBR_PointLightEffect cloneSource) : base(cloneSource)
|
||||||
{
|
{
|
||||||
|
CacheEffectParameters();
|
||||||
|
|
||||||
GPosition = cloneSource.GPosition;
|
GPosition = cloneSource.GPosition;
|
||||||
GAlbedo = cloneSource.GAlbedo;
|
GAlbedo = cloneSource.GAlbedo;
|
||||||
GNormal = cloneSource.GNormal;
|
GNormal = cloneSource.GNormal;
|
||||||
GMetallicRoughness = cloneSource.GMetallicRoughness;
|
GMetallicRoughness = cloneSource.GMetallicRoughness;
|
||||||
|
ShadowMap = cloneSource.ShadowMap;
|
||||||
|
|
||||||
EyePosition = cloneSource.EyePosition;
|
EyePosition = cloneSource.EyePosition;
|
||||||
|
|
||||||
PointLightPosition = cloneSource.PointLightPosition;
|
PointLightPosition = cloneSource.PointLightPosition;
|
||||||
PointLightColor = cloneSource.PointLightColor;
|
PointLightColor = cloneSource.PointLightColor;
|
||||||
|
|
||||||
|
FarPlane = cloneSource.FarPlane;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Effect Clone()
|
public override Effect Clone()
|
||||||
|
@ -54,11 +65,14 @@ namespace Kav
|
||||||
gAlbedoParam.SetValue(GAlbedo);
|
gAlbedoParam.SetValue(GAlbedo);
|
||||||
gNormalParam.SetValue(GNormal);
|
gNormalParam.SetValue(GNormal);
|
||||||
gMetallicRoughnessParam.SetValue(GMetallicRoughness);
|
gMetallicRoughnessParam.SetValue(GMetallicRoughness);
|
||||||
|
shadowMapParam.SetValue(ShadowMap);
|
||||||
|
|
||||||
eyePositionParam.SetValue(EyePosition);
|
eyePositionParam.SetValue(EyePosition);
|
||||||
|
|
||||||
pointLightPositionParam.SetValue(PointLightPosition);
|
pointLightPositionParam.SetValue(PointLightPosition);
|
||||||
pointLightColorParam.SetValue(PointLightColor);
|
pointLightColorParam.SetValue(PointLightColor);
|
||||||
|
|
||||||
|
farPlaneParam.SetValue(FarPlane);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CacheEffectParameters()
|
void CacheEffectParameters()
|
||||||
|
@ -67,11 +81,14 @@ namespace Kav
|
||||||
gAlbedoParam = Parameters["gAlbedo"];
|
gAlbedoParam = Parameters["gAlbedo"];
|
||||||
gNormalParam = Parameters["gNormal"];
|
gNormalParam = Parameters["gNormal"];
|
||||||
gMetallicRoughnessParam = Parameters["gMetallicRoughness"];
|
gMetallicRoughnessParam = Parameters["gMetallicRoughness"];
|
||||||
|
shadowMapParam = Parameters["shadowMap"];
|
||||||
|
|
||||||
eyePositionParam = Parameters["EyePosition"];
|
eyePositionParam = Parameters["EyePosition"];
|
||||||
|
|
||||||
pointLightPositionParam = Parameters["PointLightPosition"];
|
pointLightPositionParam = Parameters["PointLightPosition"];
|
||||||
pointLightColorParam = Parameters["PointLightColor"];
|
pointLightColorParam = Parameters["PointLightColor"];
|
||||||
|
|
||||||
|
farPlaneParam = Parameters["FarPlane"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace Kav
|
||||||
|
{
|
||||||
|
public class Deferred_ToonEffect : Effect, ShadowCascadeEffect
|
||||||
|
{
|
||||||
|
EffectParameter gPositionParam;
|
||||||
|
EffectParameter gAlbedoParam;
|
||||||
|
EffectParameter gNormalParam;
|
||||||
|
EffectParameter gMetallicRoughnessParam;
|
||||||
|
|
||||||
|
EffectParameter shadowMapOneParam;
|
||||||
|
EffectParameter shadowMapTwoParam;
|
||||||
|
EffectParameter shadowMapThreeParam;
|
||||||
|
EffectParameter shadowMapFourParam;
|
||||||
|
|
||||||
|
EffectParameter eyePositionParam;
|
||||||
|
EffectParameter directionalLightDirectionParam;
|
||||||
|
EffectParameter directionalLightColorParam;
|
||||||
|
|
||||||
|
EffectParameter cascadeFarPlanesParam;
|
||||||
|
EffectParameter shadowMapSizeParam;
|
||||||
|
|
||||||
|
EffectParameter lightSpaceMatrixOneParam;
|
||||||
|
EffectParameter lightSpaceMatrixTwoParam;
|
||||||
|
EffectParameter lightSpaceMatrixThreeParam;
|
||||||
|
EffectParameter lightSpaceMatrixFourParam;
|
||||||
|
|
||||||
|
EffectParameter viewMatrixParam;
|
||||||
|
|
||||||
|
EffectParameter shaderIndexParam;
|
||||||
|
|
||||||
|
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 float[] CascadeFarPlanes { get; }
|
||||||
|
public float 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; }
|
||||||
|
|
||||||
|
private bool ditheredShadowValue = false;
|
||||||
|
public bool DitheredShadows
|
||||||
|
{
|
||||||
|
get { return ditheredShadowValue; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ditheredShadowValue = value;
|
||||||
|
CalculateShaderIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int shaderIndex = 0;
|
||||||
|
|
||||||
|
public Deferred_ToonEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.Deferred_ToonEffect)
|
||||||
|
{
|
||||||
|
CascadeFarPlanes = new float[4];
|
||||||
|
CacheEffectParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
shaderIndexParam.SetValue(shaderIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
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"];
|
||||||
|
|
||||||
|
shaderIndexParam = Parameters["ShaderIndex"];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateShaderIndex()
|
||||||
|
{
|
||||||
|
if (ditheredShadowValue)
|
||||||
|
{
|
||||||
|
shaderIndex = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shaderIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
Effects/FXB/DeferredPBR_AmbientLightEffect.fxb (Stored with Git LFS)
BIN
Effects/FXB/DeferredPBR_AmbientLightEffect.fxb (Stored with Git LFS)
Binary file not shown.
BIN
Effects/FXB/DeferredPBR_DirectionalLightEffect.fxb (Stored with Git LFS)
BIN
Effects/FXB/DeferredPBR_DirectionalLightEffect.fxb (Stored with Git LFS)
Binary file not shown.
BIN
Effects/FXB/DeferredPBR_PointLightEffect.fxb (Stored with Git LFS)
BIN
Effects/FXB/DeferredPBR_PointLightEffect.fxb (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Effects/FXB/SimpleDepthEffect.fxb (Stored with Git LFS)
BIN
Effects/FXB/SimpleDepthEffect.fxb (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,34 @@
|
||||||
|
float3 HUEtoRGB(in float H)
|
||||||
|
{
|
||||||
|
float R = abs(H * 6 - 3) - 1;
|
||||||
|
float G = 2 - abs(H * 6 - 2);
|
||||||
|
float B = 2 - abs(H * 6 - 4);
|
||||||
|
return saturate(float3(R,G,B));
|
||||||
|
}
|
||||||
|
|
||||||
|
float Epsilon = 1e-10;
|
||||||
|
|
||||||
|
float3 RGBtoHCV(in float3 RGB)
|
||||||
|
{
|
||||||
|
// Based on work by Sam Hocevar and Emil Persson
|
||||||
|
float4 P = (RGB.g < RGB.b) ? float4(RGB.bg, -1.0, 2.0/3.0) : float4(RGB.gb, 0.0, -1.0/3.0);
|
||||||
|
float4 Q = (RGB.r < P.x) ? float4(P.xyw, RGB.r) : float4(RGB.r, P.yzx);
|
||||||
|
float C = Q.x - min(Q.w, Q.y);
|
||||||
|
float H = abs((Q.w - Q.y) / (6 * C + Epsilon) + Q.z);
|
||||||
|
return float3(H, C, Q.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 RGBtoHSL(float3 RGB)
|
||||||
|
{
|
||||||
|
float3 HCV = RGBtoHCV(RGB);
|
||||||
|
float L = HCV.z - HCV.y * 0.5;
|
||||||
|
float S = HCV.y / (1 - abs(L * 2 - 1) + Epsilon);
|
||||||
|
return float3(HCV.x, S, L);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 HSLtoRGB(float3 HSL)
|
||||||
|
{
|
||||||
|
float3 RGB = HUEtoRGB(HSL.x);
|
||||||
|
float C = (1 - abs(2 * HSL.z - 1)) * HSL.y;
|
||||||
|
return (RGB - 0.5) * C + HSL.z;
|
||||||
|
}
|
|
@ -3,6 +3,12 @@
|
||||||
DECLARE_TEXTURE(gPosition, 0);
|
DECLARE_TEXTURE(gPosition, 0);
|
||||||
DECLARE_TEXTURE(gAlbedo, 1);
|
DECLARE_TEXTURE(gAlbedo, 1);
|
||||||
|
|
||||||
|
BEGIN_CONSTANTS
|
||||||
|
|
||||||
|
float3 AmbientLightColor _ps(c0) _cb(c0);
|
||||||
|
|
||||||
|
END_CONSTANTS
|
||||||
|
|
||||||
struct VertexInput
|
struct VertexInput
|
||||||
{
|
{
|
||||||
float4 Position : POSITION;
|
float4 Position : POSITION;
|
||||||
|
@ -29,7 +35,7 @@ float4 ComputeColor(
|
||||||
float3 worldPosition,
|
float3 worldPosition,
|
||||||
float3 albedo
|
float3 albedo
|
||||||
) {
|
) {
|
||||||
float3 color = float3(0.03, 0.03, 0.03) * albedo;
|
float3 color = AmbientLightColor * albedo;
|
||||||
return float4(color, 1.0);
|
return float4(color, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "Macros.fxh" //from FNA
|
#include "Macros.fxh" //from FNA
|
||||||
#include "Lighting.fxh"
|
#include "Lighting.fxh"
|
||||||
|
#include "Shadow.fxh"
|
||||||
|
|
||||||
static const int NUM_SHADOW_CASCADES = 4;
|
static const int NUM_SHADOW_CASCADES = 4;
|
||||||
|
|
||||||
|
@ -35,26 +36,6 @@ MATRIX_CONSTANTS
|
||||||
|
|
||||||
END_CONSTANTS
|
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
|
struct VertexInput
|
||||||
{
|
{
|
||||||
float4 Position : POSITION;
|
float4 Position : POSITION;
|
||||||
|
@ -79,35 +60,8 @@ PixelInput main_vs(VertexInput input)
|
||||||
|
|
||||||
// Pixel Shader
|
// 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 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);
|
float4 positionCameraSpace = mul(float4(positionWorldSpace, 1.0), ViewMatrix);
|
||||||
|
|
||||||
int shadowCascadeIndex = 0; // 0 is closest
|
int shadowCascadeIndex = 0; // 0 is closest
|
||||||
|
@ -139,69 +93,52 @@ float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L)
|
||||||
lightSpaceMatrix = LightSpaceMatrixFour;
|
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
|
// 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)
|
if (shadowCascadeIndex == 0)
|
||||||
{
|
{
|
||||||
visibility = PoissonCoord(SAMPLER(shadowMapOne), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
return PoissonShadow(
|
||||||
|
positionWorldSpace,
|
||||||
|
N,
|
||||||
|
L,
|
||||||
|
lightSpaceMatrix,
|
||||||
|
SAMPLER(shadowMapOne),
|
||||||
|
ShadowMapSize
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (shadowCascadeIndex == 1)
|
else if (shadowCascadeIndex == 1)
|
||||||
{
|
{
|
||||||
visibility = PoissonCoord(SAMPLER(shadowMapTwo), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
return PoissonShadow(
|
||||||
|
positionWorldSpace,
|
||||||
|
N,
|
||||||
|
L,
|
||||||
|
lightSpaceMatrix,
|
||||||
|
SAMPLER(shadowMapTwo),
|
||||||
|
ShadowMapSize
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (shadowCascadeIndex == 2)
|
else if (shadowCascadeIndex == 2)
|
||||||
{
|
{
|
||||||
visibility = PoissonCoord(SAMPLER(shadowMapThree), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
return PoissonShadow(
|
||||||
|
positionWorldSpace,
|
||||||
|
N,
|
||||||
|
L,
|
||||||
|
lightSpaceMatrix,
|
||||||
|
SAMPLER(shadowMapThree),
|
||||||
|
ShadowMapSize
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
visibility = PoissonCoord(SAMPLER(shadowMapFour), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
return PoissonShadow(
|
||||||
|
positionWorldSpace,
|
||||||
|
N,
|
||||||
|
L,
|
||||||
|
lightSpaceMatrix,
|
||||||
|
SAMPLER(shadowMapFour),
|
||||||
|
ShadowMapSize
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return visibility;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float4 ComputeColor(
|
float4 ComputeColor(
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
#include "Macros.fxh" //from FNA
|
#include "Macros.fxh" //from FNA
|
||||||
#include "Lighting.fxh"
|
#include "Lighting.fxh"
|
||||||
|
#include "Shadow.fxh"
|
||||||
|
|
||||||
DECLARE_TEXTURE(gPosition, 0);
|
DECLARE_TEXTURE(gPosition, 0);
|
||||||
DECLARE_TEXTURE(gAlbedo, 1);
|
DECLARE_TEXTURE(gAlbedo, 1);
|
||||||
DECLARE_TEXTURE(gNormal, 2);
|
DECLARE_TEXTURE(gNormal, 2);
|
||||||
DECLARE_TEXTURE(gMetallicRoughness, 3);
|
DECLARE_TEXTURE(gMetallicRoughness, 3);
|
||||||
|
DECLARE_CUBEMAP(shadowMap, 4);
|
||||||
|
|
||||||
BEGIN_CONSTANTS
|
BEGIN_CONSTANTS
|
||||||
|
|
||||||
|
@ -13,6 +15,8 @@ BEGIN_CONSTANTS
|
||||||
float3 PointLightPosition _ps(c1) _cb(c1);
|
float3 PointLightPosition _ps(c1) _cb(c1);
|
||||||
float3 PointLightColor _ps(c2) _cb(c2);
|
float3 PointLightColor _ps(c2) _cb(c2);
|
||||||
|
|
||||||
|
float FarPlane _ps(c3) _cb(c3);
|
||||||
|
|
||||||
MATRIX_CONSTANTS
|
MATRIX_CONSTANTS
|
||||||
|
|
||||||
END_CONSTANTS
|
END_CONSTANTS
|
||||||
|
@ -60,9 +64,11 @@ float4 ComputeColor(
|
||||||
float attenuation = 1.0 / (distance * distance);
|
float attenuation = 1.0 / (distance * distance);
|
||||||
float3 radiance = PointLightColor * attenuation;
|
float3 radiance = PointLightColor * attenuation;
|
||||||
|
|
||||||
float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, 1.0);
|
float shadow = HardPointShadow(worldPosition, N, L, PointLightPosition, SAMPLER(shadowMap), FarPlane);
|
||||||
|
float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, shadow);
|
||||||
|
|
||||||
return float4(color, 1.0);
|
return float4(color, 1.0);
|
||||||
|
//return float4(shadow, shadow, shadow, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
float4 main_ps(PixelInput input) : SV_TARGET0
|
float4 main_ps(PixelInput input) : SV_TARGET0
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
#include "Macros.fxh"
|
||||||
|
#include "Shadow.fxh"
|
||||||
|
#include "Dither.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(c4) _cb(c4);
|
||||||
|
|
||||||
|
float ShadowMapSize _ps(c8) _cb(c8);
|
||||||
|
|
||||||
|
MATRIX_CONSTANTS
|
||||||
|
|
||||||
|
float4x4 LightSpaceMatrixOne _ps(c9) _cb(c9);
|
||||||
|
float4x4 LightSpaceMatrixTwo _ps(c13) _cb(c13);
|
||||||
|
float4x4 LightSpaceMatrixThree _ps(c17) _cb(c17);
|
||||||
|
float4x4 LightSpaceMatrixFour _ps(c21) _cb(c21);
|
||||||
|
|
||||||
|
float4x4 ViewMatrix _ps(c25) _cb(c25);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shadowCascadeIndex == 0)
|
||||||
|
{
|
||||||
|
return HardShadow(
|
||||||
|
positionWorldSpace,
|
||||||
|
N,
|
||||||
|
L,
|
||||||
|
lightSpaceMatrix,
|
||||||
|
SAMPLER(shadowMapOne),
|
||||||
|
ShadowMapSize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (shadowCascadeIndex == 1)
|
||||||
|
{
|
||||||
|
return HardShadow(
|
||||||
|
positionWorldSpace,
|
||||||
|
N,
|
||||||
|
L,
|
||||||
|
lightSpaceMatrix,
|
||||||
|
SAMPLER(shadowMapTwo),
|
||||||
|
ShadowMapSize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (shadowCascadeIndex == 2)
|
||||||
|
{
|
||||||
|
return HardShadow(
|
||||||
|
positionWorldSpace,
|
||||||
|
N,
|
||||||
|
L,
|
||||||
|
lightSpaceMatrix,
|
||||||
|
SAMPLER(shadowMapThree),
|
||||||
|
ShadowMapSize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HardShadow(
|
||||||
|
positionWorldSpace,
|
||||||
|
N,
|
||||||
|
L,
|
||||||
|
lightSpaceMatrix,
|
||||||
|
SAMPLER(shadowMapFour),
|
||||||
|
ShadowMapSize
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float IntensityBanding(float NdotL)
|
||||||
|
{
|
||||||
|
// if (NdotL > 0.5)
|
||||||
|
// {
|
||||||
|
// return 1.0;
|
||||||
|
// }
|
||||||
|
// else if (NdotL > 0.25)
|
||||||
|
// {
|
||||||
|
// return 0.5;
|
||||||
|
// }
|
||||||
|
// else if (NdotL > 0.0)
|
||||||
|
// {
|
||||||
|
// return 0.25;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// return 0.0;
|
||||||
|
// }
|
||||||
|
if (NdotL > 0)
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0.25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 FlatShadow(PixelInput input) : SV_TARGET0
|
||||||
|
{
|
||||||
|
float2 screenPosition = input.Position.xy;
|
||||||
|
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;
|
||||||
|
|
||||||
|
// the lower the glossiness, the sharper the specular highlight
|
||||||
|
float glossiness = lerp(64, 16, 1.0 - metallicRoughness.r);
|
||||||
|
|
||||||
|
float3 V = normalize(EyePosition - worldPosition);
|
||||||
|
float3 L = normalize(DirectionalLightDirection);
|
||||||
|
float3 N = normalize(normal);
|
||||||
|
float3 H = normalize(V + L);
|
||||||
|
|
||||||
|
float NdotL = dot(N, L);
|
||||||
|
float NdotH = max(dot(N, H), 0.0);
|
||||||
|
|
||||||
|
float lightIntensity = IntensityBanding(NdotL);
|
||||||
|
float3 light = lightIntensity * DirectionalLightColor;
|
||||||
|
|
||||||
|
float specularIntensity = pow(NdotH * lightIntensity, glossiness * glossiness);
|
||||||
|
float specularSmooth = smoothstep(0.005, 0.01, specularIntensity);
|
||||||
|
|
||||||
|
float3 specular = specularSmooth * float3(1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
if (metallicRoughness.r == 0.0) { specular = float3(0.0, 0.0, 0.0); }
|
||||||
|
|
||||||
|
float3 rimColor = float3(1.0, 1.0, 1.0);
|
||||||
|
float rimThreshold = 0.1;
|
||||||
|
float rimAmount = 1 - metallicRoughness.g;
|
||||||
|
float rimDot = 1 - dot(V, N);
|
||||||
|
float rimIntensity = rimDot * pow(max(NdotL, 0.0), rimThreshold);
|
||||||
|
rimIntensity = smoothstep(rimAmount - 0.01, rimAmount + 0.01, rimIntensity);
|
||||||
|
float3 rim = rimIntensity * rimColor;
|
||||||
|
|
||||||
|
float shadow = ComputeShadow(worldPosition, N, L);
|
||||||
|
float3 color = albedo * (light + specular + rim) * shadow;
|
||||||
|
|
||||||
|
return float4(color, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: organize this
|
||||||
|
float4 DitheredShadow(PixelInput input) : SV_TARGET0
|
||||||
|
{
|
||||||
|
float2 screenPosition = input.Position.xy;
|
||||||
|
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;
|
||||||
|
|
||||||
|
// the lower the glossiness, the sharper the specular highlight
|
||||||
|
float glossiness = lerp(64, 16, 1.0 - metallicRoughness.r);
|
||||||
|
|
||||||
|
float3 V = normalize(EyePosition - worldPosition);
|
||||||
|
float3 L = normalize(DirectionalLightDirection);
|
||||||
|
float3 N = normalize(normal);
|
||||||
|
float3 H = normalize(V + L);
|
||||||
|
|
||||||
|
float NdotL = dot(N, L);
|
||||||
|
float NdotH = max(dot(N, H), 0.0);
|
||||||
|
|
||||||
|
float lightIntensity = IntensityBanding(NdotL);
|
||||||
|
//float3 light = lightIntensity * DirectionalLightColor;
|
||||||
|
float3 light = DirectionalLightColor;
|
||||||
|
|
||||||
|
if (lightIntensity < 1)
|
||||||
|
{
|
||||||
|
light *= dither(lightIntensity, screenPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
float specularIntensity = pow(NdotH * lightIntensity, glossiness * glossiness);
|
||||||
|
float specularSmooth = smoothstep(0.005, 0.01, specularIntensity);
|
||||||
|
|
||||||
|
float3 specular = specularSmooth * float3(1.0, 1.0, 1.0);
|
||||||
|
|
||||||
|
if (metallicRoughness.r == 0.0) { specular = float3(0.0, 0.0, 0.0); }
|
||||||
|
|
||||||
|
float3 rimColor = float3(1.0, 1.0, 1.0);
|
||||||
|
float rimThreshold = 0.1;
|
||||||
|
float rimAmount = 1 - metallicRoughness.g;
|
||||||
|
float rimDot = 1 - dot(V, N);
|
||||||
|
float rimIntensity = rimDot * pow(max(NdotL, 0.0), rimThreshold);
|
||||||
|
rimIntensity = smoothstep(rimAmount - 0.01, rimAmount + 0.01, rimIntensity);
|
||||||
|
float3 rim = rimIntensity * rimColor;
|
||||||
|
|
||||||
|
float shadow = ComputeShadow(worldPosition, N, L);
|
||||||
|
float3 color = albedo * (light + specular + rim); // * shadow;
|
||||||
|
|
||||||
|
if (shadow < 1)
|
||||||
|
{
|
||||||
|
color *= dither(shadow, screenPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return float4(color, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelShader PSArray[2] =
|
||||||
|
{
|
||||||
|
compile ps_3_0 FlatShadow(),
|
||||||
|
compile ps_3_0 DitheredShadow()
|
||||||
|
};
|
||||||
|
|
||||||
|
int PSIndices[2] =
|
||||||
|
{
|
||||||
|
0, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
int ShaderIndex = 0;
|
||||||
|
|
||||||
|
Technique Deferred_Toon
|
||||||
|
{
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
VertexShader = compile vs_3_0 main_vs();
|
||||||
|
PixelShader = (PSArray[PSIndices[ShaderIndex]]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include "Conversion.fxh"
|
||||||
|
|
||||||
|
// technique from http://alex-charlton.com/posts/Dithering_on_the_GPU/
|
||||||
|
|
||||||
|
uniform float3 palette[8];
|
||||||
|
static const int paletteSize = 8;
|
||||||
|
|
||||||
|
static const int indexMatrix4x4[16] =
|
||||||
|
{
|
||||||
|
0, 8, 2, 10,
|
||||||
|
12, 4, 14, 6,
|
||||||
|
3, 11, 1, 9,
|
||||||
|
15, 7, 13, 5
|
||||||
|
};
|
||||||
|
|
||||||
|
float indexValue(float2 screenCoords)
|
||||||
|
{
|
||||||
|
int x = int(screenCoords.x % 4);
|
||||||
|
int y = int(screenCoords.y % 4);
|
||||||
|
|
||||||
|
return indexMatrix4x4[(x + y * 4)] / 16.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float hueDistance(float h1, float h2)
|
||||||
|
{
|
||||||
|
float diff = abs(h1 - h2);
|
||||||
|
return min(abs(1.0 - diff), diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void closestColors(float hue, out float3 ret[2])
|
||||||
|
{
|
||||||
|
float3 closest = float3(-2, 0, 0);
|
||||||
|
float3 secondClosest = float3(-2, 0, 0);
|
||||||
|
float3 temp;
|
||||||
|
|
||||||
|
for (int i = 0; i < paletteSize; i++)
|
||||||
|
{
|
||||||
|
temp = palette[i];
|
||||||
|
float tempDistance = hueDistance(temp.x, hue);
|
||||||
|
if (tempDistance < hueDistance(closest.x, hue))
|
||||||
|
{
|
||||||
|
secondClosest = closest;
|
||||||
|
closest = temp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (tempDistance < hueDistance(secondClosest.x, hue))
|
||||||
|
{
|
||||||
|
secondClosest = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret[0] = closest;
|
||||||
|
ret[1] = secondClosest;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 dither(float3 color, float2 screenCoords)
|
||||||
|
{
|
||||||
|
float3 colors[2];
|
||||||
|
float3 hsl = RGBtoHSL(color);
|
||||||
|
closestColors(hsl.x, colors);
|
||||||
|
float3 closestColor = colors[0];
|
||||||
|
float3 secondClosestColor = colors[1];
|
||||||
|
float d = indexValue(screenCoords);
|
||||||
|
float hueDiff = hueDistance(hsl.x, closestColor.x) / hueDistance(secondClosestColor.x, secondClosestColor.x);
|
||||||
|
return HSLtoRGB(hueDiff < d ? closestColor : secondClosestColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// brightColor refers to undithered max color
|
||||||
|
// float3 dither(float3 color, float3 brightColor, float2 screenCoords)
|
||||||
|
// {
|
||||||
|
// float brightHue = RGBtoHSL(brightColor.x);
|
||||||
|
// float colorHue = RGBtoHSL(color.x);
|
||||||
|
// float halfDistance = hueDistance(0.0, brightHue) / 2.0;
|
||||||
|
// float3 closestColor = (colorHue < halfDistance) ? float3(0.0, 0.0, 0.0) : brightColor;
|
||||||
|
// float3 secondClosestColor = brightColor - closestColor;
|
||||||
|
// float d = indexValue(screenCoords);
|
||||||
|
// float distance = abs(closestColor - color);
|
||||||
|
// return (distance < d) ? closestColor : secondClosestColor;
|
||||||
|
// }
|
||||||
|
|
||||||
|
float3 dither(float color, float2 screenCoords) {
|
||||||
|
float closestColor = (color < 0.5) ? 0 : 1;
|
||||||
|
float secondClosestColor = 1 - closestColor;
|
||||||
|
float d = indexValue(screenCoords);
|
||||||
|
float distance = abs(closestColor - color);
|
||||||
|
return (distance < d) ? closestColor : secondClosestColor;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "Macros.fxh"
|
||||||
|
|
||||||
|
BEGIN_CONSTANTS
|
||||||
|
|
||||||
|
float4x4 Model _vs(c0) _cb(c0);
|
||||||
|
float4x4 ModelViewProjection _vs(c4) _cb(c4);
|
||||||
|
|
||||||
|
float3 LightPosition _ps(c0) _cb(c8);
|
||||||
|
float FarPlane _ps(c1) _cb(c9);
|
||||||
|
|
||||||
|
END_CONSTANTS
|
||||||
|
|
||||||
|
struct VertexShaderInput
|
||||||
|
{
|
||||||
|
float4 Position : POSITION;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexShaderOutput
|
||||||
|
{
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
float3 PositionWorld : TEXCOORD0;
|
||||||
|
};
|
||||||
|
|
||||||
|
VertexShaderOutput main_vs(VertexShaderInput input)
|
||||||
|
{
|
||||||
|
VertexShaderOutput output;
|
||||||
|
output.Position = mul(input.Position, ModelViewProjection);
|
||||||
|
output.Position.x *= -1; // otherwise cube map render will be horizontally flipped
|
||||||
|
output.PositionWorld = mul(input.Position, Model);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 main_ps(VertexShaderOutput input) : SV_TARGET0
|
||||||
|
{
|
||||||
|
float lightDistance = length(input.PositionWorld - LightPosition);
|
||||||
|
lightDistance /= FarPlane;
|
||||||
|
return float4(lightDistance, 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,141 @@
|
||||||
|
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 )
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: this should probably sample a noise texture instead
|
||||||
|
// 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 PoissonShadow(
|
||||||
|
float3 positionWorldSpace,
|
||||||
|
float3 N,
|
||||||
|
float3 L,
|
||||||
|
float4x4 lightSpaceMatrix,
|
||||||
|
sampler shadowMap,
|
||||||
|
int shadowMapSize
|
||||||
|
) {
|
||||||
|
float bias = 0.005 * tan(acos(dot(N, L)));
|
||||||
|
bias = clamp(bias, 0, 0.01);
|
||||||
|
|
||||||
|
float4 positionLightSpace = mul(float4(positionWorldSpace, 1.0), lightSpaceMatrix);
|
||||||
|
|
||||||
|
// maps to [-1, 1]
|
||||||
|
float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w;
|
||||||
|
|
||||||
|
// maps to [0, 1]
|
||||||
|
// NOTE: In XNA, clip space z is [0, 1] range
|
||||||
|
projectionCoords.x = (projectionCoords.x * 0.5) + 0.5;
|
||||||
|
projectionCoords.y = (projectionCoords.y * 0.5) + 0.5;
|
||||||
|
projectionCoords.y *= -1;
|
||||||
|
|
||||||
|
if (projectionCoords.z > 1.0)
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float inc = 1.0 / shadowMapSize;
|
||||||
|
|
||||||
|
// Poisson soft shadows
|
||||||
|
float visibility = 0.0;
|
||||||
|
|
||||||
|
visibility = PoissonCoord(
|
||||||
|
shadowMap,
|
||||||
|
positionWorldSpace,
|
||||||
|
projectionCoords.xy,
|
||||||
|
projectionCoords.z,
|
||||||
|
bias
|
||||||
|
);
|
||||||
|
|
||||||
|
return visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
float HardShadow(
|
||||||
|
float3 positionWorldSpace,
|
||||||
|
float3 N,
|
||||||
|
float3 L,
|
||||||
|
float4x4 lightSpaceMatrix,
|
||||||
|
sampler shadowMap,
|
||||||
|
int shadowMapSize
|
||||||
|
) {
|
||||||
|
// float bias = 0.005 * tan(acos(dot(N, L)));
|
||||||
|
// bias = clamp(bias, 0, 0.01);
|
||||||
|
|
||||||
|
float bias = max(0.05 * (1.0 - dot(N, L)), 0.005);
|
||||||
|
|
||||||
|
float4 positionLightSpace = mul(float4(positionWorldSpace, 1.0), lightSpaceMatrix);
|
||||||
|
|
||||||
|
// maps to [-1, 1]
|
||||||
|
float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w;
|
||||||
|
|
||||||
|
// maps to [0, 1]
|
||||||
|
// NOTE: In XNA, clip space z is [0, 1] range
|
||||||
|
projectionCoords.x = (projectionCoords.x * 0.5) + 0.5;
|
||||||
|
projectionCoords.y = (projectionCoords.y * 0.5) + 0.5;
|
||||||
|
projectionCoords.y *= -1;
|
||||||
|
|
||||||
|
if (projectionCoords.z > 1.0)
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float closestDepth = tex2D(shadowMap, projectionCoords.xy);
|
||||||
|
float currentDepth = projectionCoords.z;
|
||||||
|
|
||||||
|
return (currentDepth - bias > closestDepth ? 0.25 : 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float HardPointShadow(
|
||||||
|
float3 positionWorldSpace,
|
||||||
|
float3 N,
|
||||||
|
float3 L,
|
||||||
|
float3 lightPosition,
|
||||||
|
sampler shadowMap,
|
||||||
|
float farPlane
|
||||||
|
) {
|
||||||
|
float3 lightToFrag = positionWorldSpace - lightPosition;
|
||||||
|
float closestDepth = texCUBE(shadowMap, lightToFrag).r;
|
||||||
|
closestDepth *= farPlane;
|
||||||
|
|
||||||
|
float currentDepth = length(lightToFrag);
|
||||||
|
|
||||||
|
float bias = max(0.05 * (1.0 - dot(N, L)), 0.005);
|
||||||
|
|
||||||
|
return (currentDepth - bias > closestDepth ? 0 : 1.0);
|
||||||
|
}
|
|
@ -24,7 +24,7 @@ VertexShaderOutput main_vs(VertexShaderInput input)
|
||||||
VertexShaderOutput output;
|
VertexShaderOutput output;
|
||||||
|
|
||||||
output.Position = mul(input.Position, ModelViewProjection);
|
output.Position = mul(input.Position, ModelViewProjection);
|
||||||
output.Depth = output.Position.z;
|
output.Depth = output.Position.z / output.Position.w;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include "Macros.fxh"
|
||||||
|
|
||||||
|
DECLARE_CUBEMAP(skybox, 0);
|
||||||
|
|
||||||
|
BEGIN_CONSTANTS
|
||||||
|
|
||||||
|
float4x4 ViewProjection _vs(c0) _cb(c0);
|
||||||
|
|
||||||
|
END_CONSTANTS
|
||||||
|
|
||||||
|
struct VertexShaderInput
|
||||||
|
{
|
||||||
|
float3 Position : POSITION;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexShaderOutput
|
||||||
|
{
|
||||||
|
float4 Position : SV_POSITION;
|
||||||
|
float3 TexCoord : TEXCOORD;
|
||||||
|
};
|
||||||
|
|
||||||
|
VertexShaderOutput main_vs(VertexShaderInput input)
|
||||||
|
{
|
||||||
|
VertexShaderOutput output;
|
||||||
|
|
||||||
|
output.Position = mul(float4(input.Position, 1.0), ViewProjection);
|
||||||
|
output.Position = output.Position.xyww;
|
||||||
|
output.TexCoord = input.Position;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4 main_ps(VertexShaderOutput input) : SV_TARGET0
|
||||||
|
{
|
||||||
|
return SAMPLE_CUBEMAP(skybox, input.TexCoord);
|
||||||
|
}
|
||||||
|
|
||||||
|
Technique Skybox
|
||||||
|
{
|
||||||
|
Pass
|
||||||
|
{
|
||||||
|
VertexShader = compile vs_3_0 main_vs();
|
||||||
|
PixelShader = compile ps_3_0 main_ps();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace Kav
|
||||||
|
{
|
||||||
|
public class LinearDepthEffect : Effect
|
||||||
|
{
|
||||||
|
EffectParameter modelParam;
|
||||||
|
EffectParameter modelViewProjectionParam;
|
||||||
|
EffectParameter lightPositionParam;
|
||||||
|
EffectParameter farPlaneParam;
|
||||||
|
|
||||||
|
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
|
||||||
|
|
||||||
|
Matrix model;
|
||||||
|
Matrix view;
|
||||||
|
Matrix projection;
|
||||||
|
|
||||||
|
public Vector3 LightPosition { get; set; }
|
||||||
|
public float FarPlane { get; set; }
|
||||||
|
|
||||||
|
public Matrix Model
|
||||||
|
{
|
||||||
|
get { return model; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
model = value;
|
||||||
|
dirtyFlags |= EffectDirtyFlags.World;
|
||||||
|
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix View
|
||||||
|
{
|
||||||
|
get { return view; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
view = value;
|
||||||
|
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix Projection
|
||||||
|
{
|
||||||
|
get { return projection; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
projection = value;
|
||||||
|
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LinearDepthEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.LinearDepthEffect)
|
||||||
|
{
|
||||||
|
CacheEffectParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnApply()
|
||||||
|
{
|
||||||
|
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
|
||||||
|
{
|
||||||
|
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection);
|
||||||
|
Matrix.Multiply(ref model, ref viewProjection, out Matrix worldViewProj);
|
||||||
|
|
||||||
|
modelViewProjectionParam.SetValue(worldViewProj);
|
||||||
|
|
||||||
|
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dirtyFlags & EffectDirtyFlags.World) != 0)
|
||||||
|
{
|
||||||
|
modelParam.SetValue(model);
|
||||||
|
|
||||||
|
dirtyFlags &= ~EffectDirtyFlags.World;
|
||||||
|
}
|
||||||
|
|
||||||
|
lightPositionParam.SetValue(LightPosition);
|
||||||
|
farPlaneParam.SetValue(FarPlane);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheEffectParameters()
|
||||||
|
{
|
||||||
|
modelParam = Parameters["Model"];
|
||||||
|
modelViewProjectionParam = Parameters["ModelViewProjection"];
|
||||||
|
|
||||||
|
lightPositionParam = Parameters["LightPosition"];
|
||||||
|
farPlaneParam = Parameters["FarPlane"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
namespace Kav
|
||||||
|
{
|
||||||
|
public class SkyboxEffect : Effect
|
||||||
|
{
|
||||||
|
EffectParameter viewProjectionParam;
|
||||||
|
EffectParameter skyboxParam;
|
||||||
|
|
||||||
|
Matrix view;
|
||||||
|
Matrix projection;
|
||||||
|
TextureCube skybox;
|
||||||
|
|
||||||
|
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
|
||||||
|
|
||||||
|
public Matrix View
|
||||||
|
{
|
||||||
|
get { return view; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
view = value;
|
||||||
|
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix Projection
|
||||||
|
{
|
||||||
|
get { return projection; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
projection = value;
|
||||||
|
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureCube Skybox
|
||||||
|
{
|
||||||
|
get { return skybox; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
skybox = value;
|
||||||
|
dirtyFlags |= EffectDirtyFlags.World; // hack flag but whatever
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkyboxEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SkyboxEffect)
|
||||||
|
{
|
||||||
|
CacheEffectParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnApply()
|
||||||
|
{
|
||||||
|
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
|
||||||
|
{
|
||||||
|
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection);
|
||||||
|
|
||||||
|
viewProjectionParam.SetValue(viewProjection);
|
||||||
|
|
||||||
|
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((dirtyFlags & EffectDirtyFlags.World) != 0)
|
||||||
|
{
|
||||||
|
skyboxParam.SetValue(skybox);
|
||||||
|
|
||||||
|
dirtyFlags &= ~EffectDirtyFlags.World;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheEffectParameters()
|
||||||
|
{
|
||||||
|
viewProjectionParam = Parameters["ViewProjection"];
|
||||||
|
skyboxParam = Parameters["skybox"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,15 +9,47 @@ namespace Kav
|
||||||
public VertexBuffer VertexBuffer { get; }
|
public VertexBuffer VertexBuffer { get; }
|
||||||
public Triangle[] Triangles { get; }
|
public Triangle[] Triangles { get; }
|
||||||
public Vector3[] Positions { get; }
|
public Vector3[] Positions { get; }
|
||||||
public Effect Effect { get; }
|
|
||||||
|
private Texture2D albedoTexture = null;
|
||||||
|
private Texture2D normalTexture = null;
|
||||||
|
private Texture2D metallicRoughnessTexture = null;
|
||||||
|
|
||||||
public MeshPart(VertexBuffer vertexBuffer, IndexBuffer indexBuffer, Vector3[] positions, Triangle[] triangles, Effect effect)
|
public Texture2D AlbedoTexture
|
||||||
{
|
{
|
||||||
|
get { return DisableAlbedoMap ? null : albedoTexture; }
|
||||||
|
set { albedoTexture = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Texture2D NormalTexture
|
||||||
|
{
|
||||||
|
get { return DisableNormalMap ? null : normalTexture; }
|
||||||
|
set { normalTexture = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Texture2D MetallicRoughnessTexture
|
||||||
|
{
|
||||||
|
get { return DisableMetallicRoughnessMap ? null : metallicRoughnessTexture; }
|
||||||
|
set { metallicRoughnessTexture = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 Albedo { get; set; } = Vector3.One;
|
||||||
|
public float Metallic { get; set; } = 0.5f;
|
||||||
|
public float Roughness { get; set; } = 0.5f;
|
||||||
|
|
||||||
|
public bool DisableAlbedoMap { get; set; } = false;
|
||||||
|
public bool DisableNormalMap { get; set; } = false;
|
||||||
|
public bool DisableMetallicRoughnessMap { get; set; } = false;
|
||||||
|
|
||||||
|
public MeshPart(
|
||||||
|
VertexBuffer vertexBuffer,
|
||||||
|
IndexBuffer indexBuffer,
|
||||||
|
Vector3[] positions,
|
||||||
|
Triangle[] triangles
|
||||||
|
) {
|
||||||
VertexBuffer = vertexBuffer;
|
VertexBuffer = vertexBuffer;
|
||||||
IndexBuffer = indexBuffer;
|
IndexBuffer = indexBuffer;
|
||||||
Positions = positions;
|
Positions = positions;
|
||||||
Triangles = triangles;
|
Triangles = triangles;
|
||||||
Effect = effect;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,84 @@ namespace Kav
|
||||||
{
|
{
|
||||||
public Mesh[] Meshes { get; }
|
public Mesh[] Meshes { get; }
|
||||||
|
|
||||||
|
public Color Albedo
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
foreach (var mesh in Meshes)
|
||||||
|
{
|
||||||
|
foreach (var meshPart in mesh.MeshParts)
|
||||||
|
{
|
||||||
|
meshPart.Albedo = value.ToVector3();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Metallic
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
foreach (var mesh in Meshes)
|
||||||
|
{
|
||||||
|
foreach (var meshPart in mesh.MeshParts)
|
||||||
|
{
|
||||||
|
meshPart.Metallic = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Roughness
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
foreach (var mesh in Meshes)
|
||||||
|
{
|
||||||
|
foreach (var meshPart in mesh.MeshParts)
|
||||||
|
{
|
||||||
|
meshPart.Roughness = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Model(Mesh[] meshes)
|
public Model(Mesh[] meshes)
|
||||||
{
|
{
|
||||||
Meshes = meshes;
|
Meshes = meshes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DisableAlbedoMaps()
|
||||||
|
{
|
||||||
|
foreach (var mesh in Meshes)
|
||||||
|
{
|
||||||
|
foreach (var meshPart in mesh.MeshParts)
|
||||||
|
{
|
||||||
|
meshPart.DisableAlbedoMap = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisableNormalMaps()
|
||||||
|
{
|
||||||
|
foreach (var mesh in Meshes)
|
||||||
|
{
|
||||||
|
foreach (var meshPart in mesh.MeshParts)
|
||||||
|
{
|
||||||
|
meshPart.DisableNormalMap = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DisableMetallicRoughnessMaps()
|
||||||
|
{
|
||||||
|
foreach (var mesh in Meshes)
|
||||||
|
{
|
||||||
|
foreach (var meshPart in mesh.MeshParts)
|
||||||
|
{
|
||||||
|
meshPart.DisableMetallicRoughnessMap = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
<EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb">
|
<EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb">
|
||||||
<LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName>
|
<LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Effects\FXB\Deferred_ToonEffect.fxb">
|
||||||
|
<LogicalName>Kav.Resources.Deferred_ToonEffect.fxb</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb">
|
<EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb">
|
||||||
<LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName>
|
<LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
@ -39,6 +42,15 @@
|
||||||
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb">
|
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb">
|
||||||
<LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName>
|
<LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Effects\FXB\LinearDepthEffect.fxb">
|
||||||
|
<LogicalName>Kav.Resources.LinearDepthEffect.fxb</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Effects\FXB\SkyboxEffect.fxb">
|
||||||
|
<LogicalName>Kav.Resources.SkyboxEffect.fxb</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Models\UnitCube.glb">
|
||||||
|
<LogicalName>Kav.Resources.UnitCube.glb</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
<EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb">
|
<EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb">
|
||||||
<LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName>
|
<LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Effects\FXB\Deferred_ToonEffect.fxb">
|
||||||
|
<LogicalName>Kav.Resources.Deferred_ToonEffect.fxb</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb">
|
<EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb">
|
||||||
<LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName>
|
<LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
@ -39,6 +42,15 @@
|
||||||
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb">
|
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb">
|
||||||
<LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName>
|
<LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Effects\FXB\LinearDepthEffect.fxb">
|
||||||
|
<LogicalName>Kav.Resources.LinearDepthEffect.fxb</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Effects\FXB\SkyboxEffect.fxb">
|
||||||
|
<LogicalName>Kav.Resources.SkyboxEffect.fxb</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Models\UnitCube.glb">
|
||||||
|
<LogicalName>Kav.Resources.UnitCube.glb</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
|
namespace Kav
|
||||||
|
{
|
||||||
|
public struct AmbientLight
|
||||||
|
{
|
||||||
|
public Color Color { get; set; }
|
||||||
|
|
||||||
|
public AmbientLight(Color color)
|
||||||
|
{
|
||||||
|
Color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,9 +4,9 @@ namespace Kav
|
||||||
{
|
{
|
||||||
public struct DirectionalLight
|
public struct DirectionalLight
|
||||||
{
|
{
|
||||||
public Vector3 Direction { get; set; }
|
public Vector3 Direction { get; }
|
||||||
public Color Color { get; set; }
|
public Color Color { get; }
|
||||||
public float Intensity { get; set; }
|
public float Intensity { get; }
|
||||||
|
|
||||||
public Matrix View
|
public Matrix View
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,19 +15,6 @@ namespace Kav
|
||||||
|
|
||||||
foreach (var meshPartData in meshData.MeshParts)
|
foreach (var meshPartData in meshData.MeshParts)
|
||||||
{
|
{
|
||||||
var effect = new Kav.DeferredPBR_GBufferEffect(
|
|
||||||
graphicsDevice
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Albedo = meshPartData.Albedo,
|
|
||||||
Metallic = meshPartData.Metallic,
|
|
||||||
Roughness = meshPartData.Roughness,
|
|
||||||
|
|
||||||
AlbedoTexture = meshPartData.AlbedoTexture,
|
|
||||||
NormalTexture = meshPartData.NormalTexture,
|
|
||||||
MetallicRoughnessTexture = meshPartData.MetallicRoughnessTexture
|
|
||||||
};
|
|
||||||
|
|
||||||
var triangles = new Kav.Triangle[meshPartData.Triangles.Length];
|
var triangles = new Kav.Triangle[meshPartData.Triangles.Length];
|
||||||
for (int i = 0; i < meshPartData.Triangles.Length; i++)
|
for (int i = 0; i < meshPartData.Triangles.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -40,13 +27,22 @@ namespace Kav
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
meshParts.Add(new Kav.MeshPart(
|
var meshPart = new Kav.MeshPart(
|
||||||
meshPartData.VertexBuffer,
|
meshPartData.VertexBuffer,
|
||||||
meshPartData.IndexBuffer,
|
meshPartData.IndexBuffer,
|
||||||
meshPartData.Positions,
|
meshPartData.Positions,
|
||||||
triangles,
|
triangles
|
||||||
effect
|
);
|
||||||
));
|
|
||||||
|
meshPart.Albedo = meshPartData.Albedo;
|
||||||
|
meshPart.Metallic = meshPartData.Metallic;
|
||||||
|
meshPart.Roughness = meshPartData.Roughness;
|
||||||
|
|
||||||
|
meshPart.AlbedoTexture = meshPartData.AlbedoTexture;
|
||||||
|
meshPart.NormalTexture = meshPartData.NormalTexture;
|
||||||
|
meshPart.MetallicRoughnessTexture = meshPartData.MetallicRoughnessTexture;
|
||||||
|
|
||||||
|
meshParts.Add(meshPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
meshes.Add(new Kav.Mesh(meshParts.ToArray()));
|
meshes.Add(new Kav.Mesh(meshParts.ToArray()));
|
||||||
|
|
Binary file not shown.
|
@ -15,9 +15,9 @@ Essential
|
||||||
- [x] Tone map shader
|
- [x] Tone map shader
|
||||||
- [x] Poisson soft shadowing
|
- [x] Poisson soft shadowing
|
||||||
- [ ] Frustum culling
|
- [ ] Frustum culling
|
||||||
- [ ] Shadow-casting point lights
|
- [x] Shadow-casting point lights
|
||||||
- [ ] Parabolic lights
|
- [ ] Parabolic lights
|
||||||
- [ ] Skyboxes
|
- [x] Skyboxes
|
||||||
- [ ] Screen-space reflection
|
- [ ] Screen-space reflection
|
||||||
|
|
||||||
Nice-To-Haves
|
Nice-To-Haves
|
||||||
|
|
471
Renderer.cs
471
Renderer.cs
|
@ -1,4 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
@ -21,19 +23,27 @@ namespace Kav
|
||||||
private RenderTarget2D[] ShadowRenderTargets { get; }
|
private RenderTarget2D[] ShadowRenderTargets { get; }
|
||||||
|
|
||||||
private DeferredPBREffect DeferredPBREffect { get; }
|
private DeferredPBREffect DeferredPBREffect { get; }
|
||||||
|
/* FIXME: these next two dont actually have anything to do with PBR */
|
||||||
|
private DeferredPBR_GBufferEffect Deferred_GBufferEffect { get; }
|
||||||
private DeferredPBR_AmbientLightEffect DeferredAmbientLightEffect { get; }
|
private DeferredPBR_AmbientLightEffect DeferredAmbientLightEffect { get; }
|
||||||
private DeferredPBR_PointLightEffect DeferredPointLightEffect { get; }
|
private DeferredPBR_PointLightEffect DeferredPointLightEffect { get; }
|
||||||
private DeferredPBR_DirectionalLightEffect DeferredDirectionalLightEffect { get; }
|
private DeferredPBR_DirectionalLightEffect DeferredDirectionalLightEffect { get; }
|
||||||
|
private Deferred_ToonEffect Deferred_ToonEffect { get; }
|
||||||
private SimpleDepthEffect SimpleDepthEffect { get; }
|
private SimpleDepthEffect SimpleDepthEffect { get; }
|
||||||
|
private LinearDepthEffect LinearDepthEffect { get; }
|
||||||
private Effect ToneMapEffect { get; }
|
private Effect ToneMapEffect { get; }
|
||||||
|
private SkyboxEffect SkyboxEffect { get; }
|
||||||
|
|
||||||
private RenderTarget2D gPosition { get; }
|
private RenderTarget2D gPosition { get; }
|
||||||
private RenderTarget2D gNormal { get; }
|
private RenderTarget2D gNormal { get; }
|
||||||
private RenderTarget2D gAlbedo { get; }
|
private RenderTarget2D gAlbedo { get; }
|
||||||
private RenderTarget2D gMetallicRoughness { get; }
|
private RenderTarget2D gMetallicRoughness { get; }
|
||||||
|
private RenderTargetCube PointShadowCubeMap { get; }
|
||||||
|
|
||||||
private RenderTargetBinding[] GBuffer { get; }
|
private RenderTargetBinding[] GBuffer { get; }
|
||||||
|
|
||||||
|
private Kav.Model UnitCube { get; }
|
||||||
|
|
||||||
private SpriteBatch SpriteBatch { get; }
|
private SpriteBatch SpriteBatch { get; }
|
||||||
|
|
||||||
public Renderer(
|
public Renderer(
|
||||||
|
@ -70,7 +80,7 @@ namespace Kav
|
||||||
renderDimensionsY,
|
renderDimensionsY,
|
||||||
false,
|
false,
|
||||||
SurfaceFormat.Color,
|
SurfaceFormat.Color,
|
||||||
DepthFormat.None,
|
DepthFormat.Depth24,
|
||||||
0,
|
0,
|
||||||
RenderTargetUsage.PreserveContents
|
RenderTargetUsage.PreserveContents
|
||||||
);
|
);
|
||||||
|
@ -129,13 +139,26 @@ namespace Kav
|
||||||
new RenderTargetBinding(gMetallicRoughness)
|
new RenderTargetBinding(gMetallicRoughness)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PointShadowCubeMap = new RenderTargetCube(
|
||||||
|
GraphicsDevice,
|
||||||
|
shadowMapSize,
|
||||||
|
false,
|
||||||
|
SurfaceFormat.Single,
|
||||||
|
DepthFormat.Depth24
|
||||||
|
);
|
||||||
|
|
||||||
SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice);
|
SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice);
|
||||||
|
LinearDepthEffect = new LinearDepthEffect(GraphicsDevice);
|
||||||
DeferredPBREffect = new DeferredPBREffect(GraphicsDevice);
|
DeferredPBREffect = new DeferredPBREffect(GraphicsDevice);
|
||||||
|
|
||||||
|
Deferred_GBufferEffect = new DeferredPBR_GBufferEffect(GraphicsDevice);
|
||||||
DeferredAmbientLightEffect = new DeferredPBR_AmbientLightEffect(GraphicsDevice);
|
DeferredAmbientLightEffect = new DeferredPBR_AmbientLightEffect(GraphicsDevice);
|
||||||
DeferredPointLightEffect = new DeferredPBR_PointLightEffect(GraphicsDevice);
|
DeferredPointLightEffect = new DeferredPBR_PointLightEffect(GraphicsDevice);
|
||||||
DeferredDirectionalLightEffect = new DeferredPBR_DirectionalLightEffect(GraphicsDevice);
|
DeferredDirectionalLightEffect = new DeferredPBR_DirectionalLightEffect(GraphicsDevice);
|
||||||
DeferredDirectionalLightEffect.ShadowMapSize = ShadowMapSize;
|
DeferredDirectionalLightEffect.ShadowMapSize = ShadowMapSize;
|
||||||
ToneMapEffect = new Effect(graphicsDevice, Resources.ToneMapEffect);
|
ToneMapEffect = new Effect(graphicsDevice, Resources.ToneMapEffect);
|
||||||
|
Deferred_ToonEffect = new Deferred_ToonEffect(GraphicsDevice);
|
||||||
|
SkyboxEffect = new SkyboxEffect(GraphicsDevice);
|
||||||
|
|
||||||
FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly);
|
FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly);
|
||||||
FullscreenTriangle.SetData(new VertexPositionTexture[3] {
|
FullscreenTriangle.SetData(new VertexPositionTexture[3] {
|
||||||
|
@ -144,39 +167,93 @@ namespace Kav
|
||||||
new VertexPositionTexture(new Vector3(3, 1, 0), new Vector2(2, 0))
|
new VertexPositionTexture(new Vector3(3, 1, 0), new Vector2(2, 0))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
UnitCube = Kav.ModelLoader.Load(
|
||||||
|
GraphicsDevice,
|
||||||
|
Smuggler.Importer.ImportGLB(GraphicsDevice, new MemoryStream(Resources.UnitCubeModel))
|
||||||
|
);
|
||||||
|
|
||||||
SpriteBatch = new SpriteBatch(graphicsDevice);
|
SpriteBatch = new SpriteBatch(graphicsDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeferredRender(
|
public void DeferredRender(
|
||||||
PerspectiveCamera camera,
|
PerspectiveCamera camera,
|
||||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
|
AmbientLight ambientLight,
|
||||||
IEnumerable<PointLight> pointLights,
|
IEnumerable<PointLight> pointLights,
|
||||||
DirectionalLight directionalLight
|
DirectionalLight directionalLight
|
||||||
) {
|
) {
|
||||||
// g-buffer pass
|
GBufferRender(camera, modelTransforms);
|
||||||
|
|
||||||
GraphicsDevice.SetRenderTargets(GBuffer);
|
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||||
|
GraphicsDevice.Clear(Color.Black);
|
||||||
|
|
||||||
|
AmbientLightRender(ambientLight);
|
||||||
|
|
||||||
|
DeferredPointLightEffect.EyePosition = camera.Position;
|
||||||
|
|
||||||
|
foreach (var pointLight in pointLights)
|
||||||
|
{
|
||||||
|
PointLightRender(camera, modelTransforms, pointLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectionalLightRender(camera, modelTransforms, directionalLight);
|
||||||
|
|
||||||
|
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 DeferredToonRender(
|
||||||
|
PerspectiveCamera camera,
|
||||||
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
|
AmbientLight ambientLight,
|
||||||
|
IEnumerable<PointLight> pointLights,
|
||||||
|
DirectionalLight directionalLight,
|
||||||
|
TextureCube skybox
|
||||||
|
) {
|
||||||
|
GBufferRender(camera, modelTransforms);
|
||||||
|
|
||||||
|
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||||
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
|
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
|
||||||
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||||
GraphicsDevice.BlendState = BlendState.Opaque;
|
|
||||||
|
|
||||||
|
DepthRender(camera, modelTransforms);
|
||||||
|
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
|
||||||
|
|
||||||
|
AmbientLightRender(ambientLight);
|
||||||
|
foreach (var pointLight in pointLights)
|
||||||
|
{
|
||||||
|
PointLightRender(camera, modelTransforms, pointLight);
|
||||||
|
}
|
||||||
|
DirectionalLightToonRender(camera, modelTransforms, directionalLight);
|
||||||
|
SkyboxRender(camera, skybox);
|
||||||
|
|
||||||
|
GraphicsDevice.SetRenderTarget(null);
|
||||||
|
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, null);
|
||||||
|
SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White);
|
||||||
|
SpriteBatch.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DepthRender(
|
||||||
|
PerspectiveCamera camera,
|
||||||
|
IEnumerable<(Model, Matrix)> modelTransforms
|
||||||
|
) {
|
||||||
foreach (var (model, transform) in modelTransforms)
|
foreach (var (model, transform) in modelTransforms)
|
||||||
{
|
{
|
||||||
foreach (var modelMesh in model.Meshes)
|
foreach (var modelMesh in model.Meshes)
|
||||||
{
|
{
|
||||||
foreach (var meshPart in modelMesh.MeshParts)
|
foreach (var meshPart in modelMesh.MeshParts)
|
||||||
{
|
{
|
||||||
|
SimpleDepthEffect.Model = transform;
|
||||||
|
SimpleDepthEffect.View = camera.View;
|
||||||
|
SimpleDepthEffect.Projection = camera.Projection;
|
||||||
|
|
||||||
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
|
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
|
||||||
GraphicsDevice.Indices = meshPart.IndexBuffer;
|
GraphicsDevice.Indices = meshPart.IndexBuffer;
|
||||||
|
|
||||||
if (meshPart.Effect is TransformEffect transformEffect)
|
foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes)
|
||||||
{
|
|
||||||
transformEffect.World = transform;
|
|
||||||
transformEffect.View = camera.View;
|
|
||||||
transformEffect.Projection = camera.Projection;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var pass in meshPart.Effect.CurrentTechnique.Passes)
|
|
||||||
{
|
{
|
||||||
pass.Apply();
|
pass.Apply();
|
||||||
|
|
||||||
|
@ -192,14 +269,96 @@ namespace Kav
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SkyboxRender(
|
||||||
|
PerspectiveCamera camera,
|
||||||
|
TextureCube skybox
|
||||||
|
) {
|
||||||
|
GraphicsDevice.RasterizerState.CullMode = CullMode.CullClockwiseFace;
|
||||||
|
SkyboxEffect.Skybox = skybox;
|
||||||
|
|
||||||
|
var view = camera.View;
|
||||||
|
view.Translation = Vector3.Zero;
|
||||||
|
SkyboxEffect.View = view;
|
||||||
|
|
||||||
|
SkyboxEffect.Projection = camera.Projection;
|
||||||
|
|
||||||
|
GraphicsDevice.SetVertexBuffer(UnitCube.Meshes[0].MeshParts[0].VertexBuffer);
|
||||||
|
GraphicsDevice.Indices = UnitCube.Meshes[0].MeshParts[0].IndexBuffer;
|
||||||
|
|
||||||
|
foreach (var pass in SkyboxEffect.CurrentTechnique.Passes)
|
||||||
|
{
|
||||||
|
pass.Apply();
|
||||||
|
|
||||||
|
GraphicsDevice.DrawIndexedPrimitives(
|
||||||
|
PrimitiveType.TriangleList,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
UnitCube.Meshes[0].MeshParts[0].VertexBuffer.VertexCount,
|
||||||
|
0,
|
||||||
|
UnitCube.Meshes[0].MeshParts[0].Triangles.Length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
GraphicsDevice.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GBufferRender(
|
||||||
|
PerspectiveCamera camera,
|
||||||
|
IEnumerable<(Model, Matrix)> modelTransforms
|
||||||
|
) {
|
||||||
|
GraphicsDevice.SetRenderTargets(GBuffer);
|
||||||
|
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
|
||||||
|
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||||
|
GraphicsDevice.BlendState = BlendState.Opaque;
|
||||||
|
|
||||||
|
foreach (var (model, transform) in modelTransforms)
|
||||||
|
{
|
||||||
|
foreach (var modelMesh in model.Meshes)
|
||||||
|
{
|
||||||
|
foreach (var meshPart in modelMesh.MeshParts)
|
||||||
|
{
|
||||||
|
Deferred_GBufferEffect.World = transform;
|
||||||
|
Deferred_GBufferEffect.View = camera.View;
|
||||||
|
Deferred_GBufferEffect.Projection = camera.Projection;
|
||||||
|
|
||||||
|
Deferred_GBufferEffect.Albedo = meshPart.Albedo;
|
||||||
|
Deferred_GBufferEffect.Metallic = meshPart.Metallic;
|
||||||
|
Deferred_GBufferEffect.Roughness = meshPart.Roughness;
|
||||||
|
|
||||||
|
Deferred_GBufferEffect.AlbedoTexture = meshPart.AlbedoTexture;
|
||||||
|
Deferred_GBufferEffect.NormalTexture = meshPart.NormalTexture;
|
||||||
|
Deferred_GBufferEffect.MetallicRoughnessTexture = meshPart.MetallicRoughnessTexture;
|
||||||
|
|
||||||
|
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
|
||||||
|
GraphicsDevice.Indices = meshPart.IndexBuffer;
|
||||||
|
|
||||||
|
foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes)
|
||||||
|
{
|
||||||
|
pass.Apply();
|
||||||
|
|
||||||
|
GraphicsDevice.DrawIndexedPrimitives(
|
||||||
|
PrimitiveType.TriangleList,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
meshPart.VertexBuffer.VertexCount,
|
||||||
|
0,
|
||||||
|
meshPart.Triangles.Length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AmbientLightRender(AmbientLight ambientLight)
|
||||||
|
{
|
||||||
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||||
GraphicsDevice.Clear(Color.Black);
|
GraphicsDevice.BlendState = BlendState.Opaque;
|
||||||
GraphicsDevice.BlendState = BlendState.Additive;
|
|
||||||
GraphicsDevice.DepthStencilState = DepthStencilState.None;
|
|
||||||
|
|
||||||
DeferredAmbientLightEffect.GPosition = gPosition;
|
DeferredAmbientLightEffect.GPosition = gPosition;
|
||||||
DeferredAmbientLightEffect.GAlbedo = gAlbedo;
|
DeferredAmbientLightEffect.GAlbedo = gAlbedo;
|
||||||
|
DeferredAmbientLightEffect.AmbientColor = ambientLight.Color.ToVector3();
|
||||||
|
|
||||||
foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes)
|
foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes)
|
||||||
{
|
{
|
||||||
|
@ -207,39 +366,31 @@ namespace Kav
|
||||||
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
|
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
|
||||||
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
|
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeferredPointLightEffect.EyePosition = camera.Position;
|
|
||||||
|
|
||||||
foreach (var pointLight in pointLights)
|
|
||||||
{
|
|
||||||
PointLightRender(pointLight);
|
|
||||||
}
|
|
||||||
|
|
||||||
DirectionalLightRender(camera, modelTransforms, directionalLight);
|
|
||||||
// return;
|
|
||||||
// GraphicsDevice.SetRenderTarget(null);
|
|
||||||
// SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
|
|
||||||
// SpriteBatch.Draw(DirectionalRenderTarget, Vector2.Zero, Color.White);
|
|
||||||
// SpriteBatch.End();
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PointLightRender(PointLight pointLight)
|
private void PointLightRender(
|
||||||
{
|
PerspectiveCamera camera,
|
||||||
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
|
PointLight pointLight
|
||||||
|
) {
|
||||||
|
RenderPointShadows(camera, modelTransforms, pointLight);
|
||||||
|
|
||||||
|
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||||
|
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
|
||||||
|
GraphicsDevice.BlendState = BlendState.Additive;
|
||||||
|
|
||||||
DeferredPointLightEffect.GPosition = gPosition;
|
DeferredPointLightEffect.GPosition = gPosition;
|
||||||
DeferredPointLightEffect.GAlbedo = gAlbedo;
|
DeferredPointLightEffect.GAlbedo = gAlbedo;
|
||||||
DeferredPointLightEffect.GNormal = gNormal;
|
DeferredPointLightEffect.GNormal = gNormal;
|
||||||
DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness;
|
DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness;
|
||||||
|
DeferredPointLightEffect.ShadowMap = PointShadowCubeMap;
|
||||||
|
|
||||||
DeferredPointLightEffect.PointLightPosition = pointLight.Position;
|
DeferredPointLightEffect.PointLightPosition = pointLight.Position;
|
||||||
DeferredPointLightEffect.PointLightColor =
|
DeferredPointLightEffect.PointLightColor =
|
||||||
pointLight.Color.ToVector3() * pointLight.Intensity;
|
pointLight.Color.ToVector3() * pointLight.Intensity;
|
||||||
|
|
||||||
|
DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value
|
||||||
|
|
||||||
foreach (var pass in DeferredPointLightEffect.CurrentTechnique.Passes)
|
foreach (var pass in DeferredPointLightEffect.CurrentTechnique.Passes)
|
||||||
{
|
{
|
||||||
pass.Apply();
|
pass.Apply();
|
||||||
|
@ -253,28 +404,7 @@ namespace Kav
|
||||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
DirectionalLight directionalLight
|
DirectionalLight directionalLight
|
||||||
) {
|
) {
|
||||||
// render the individual shadow cascades
|
RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect);
|
||||||
var previousFarPlane = camera.NearPlane;
|
|
||||||
for (var i = 0; i < NumShadowCascades; i++)
|
|
||||||
{
|
|
||||||
var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f));
|
|
||||||
|
|
||||||
// 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.GPosition = gPosition;
|
||||||
DeferredDirectionalLightEffect.GAlbedo = gAlbedo;
|
DeferredDirectionalLightEffect.GAlbedo = gAlbedo;
|
||||||
|
@ -300,7 +430,7 @@ namespace Kav
|
||||||
directionalLight.Color.ToVector3() * directionalLight.Intensity;
|
directionalLight.Color.ToVector3() * directionalLight.Intensity;
|
||||||
|
|
||||||
DeferredDirectionalLightEffect.ViewMatrix = camera.View;
|
DeferredDirectionalLightEffect.ViewMatrix = camera.View;
|
||||||
DeferredDirectionalLightEffect.EyePosition = Matrix.Invert(camera.View).Translation;
|
DeferredDirectionalLightEffect.EyePosition = camera.Position;
|
||||||
|
|
||||||
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||||
GraphicsDevice.BlendState = BlendState.Additive;
|
GraphicsDevice.BlendState = BlendState.Additive;
|
||||||
|
@ -313,10 +443,89 @@ namespace Kav
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderShadowMap(
|
private void DirectionalLightToonRender(
|
||||||
|
PerspectiveCamera camera,
|
||||||
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
|
DirectionalLight directionalLight
|
||||||
|
) {
|
||||||
|
RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect);
|
||||||
|
|
||||||
|
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
|
||||||
|
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
|
||||||
|
GraphicsDevice.BlendState = BlendState.Additive;
|
||||||
|
|
||||||
|
Deferred_ToonEffect.GPosition = gPosition;
|
||||||
|
Deferred_ToonEffect.GAlbedo = gAlbedo;
|
||||||
|
Deferred_ToonEffect.GNormal = gNormal;
|
||||||
|
Deferred_ToonEffect.GMetallicRoughness = gMetallicRoughness;
|
||||||
|
|
||||||
|
Deferred_ToonEffect.DitheredShadows = false;
|
||||||
|
|
||||||
|
Deferred_ToonEffect.EyePosition = camera.Position;
|
||||||
|
Deferred_ToonEffect.DirectionalLightDirection = directionalLight.Direction;
|
||||||
|
Deferred_ToonEffect.DirectionalLightColor =
|
||||||
|
directionalLight.Color.ToVector3() * directionalLight.Intensity;
|
||||||
|
|
||||||
|
Deferred_ToonEffect.ShadowMapOne = ShadowRenderTargets[0];
|
||||||
|
if (NumShadowCascades > 1)
|
||||||
|
{
|
||||||
|
Deferred_ToonEffect.ShadowMapTwo = ShadowRenderTargets[1];
|
||||||
|
}
|
||||||
|
if (NumShadowCascades > 2)
|
||||||
|
{
|
||||||
|
Deferred_ToonEffect.ShadowMapThree = ShadowRenderTargets[2];
|
||||||
|
}
|
||||||
|
if (NumShadowCascades > 3)
|
||||||
|
{
|
||||||
|
Deferred_ToonEffect.ShadowMapFour = ShadowRenderTargets[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
Deferred_ToonEffect.ViewMatrix = camera.View;
|
||||||
|
|
||||||
|
foreach (EffectPass pass in Deferred_ToonEffect.CurrentTechnique.Passes)
|
||||||
|
{
|
||||||
|
pass.Apply();
|
||||||
|
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
|
||||||
|
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderDirectionalShadows(
|
||||||
|
PerspectiveCamera camera,
|
||||||
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
|
DirectionalLight directionalLight,
|
||||||
|
ShadowCascadeEffect effect
|
||||||
|
) {
|
||||||
|
// render the individual shadow cascades
|
||||||
|
var previousFarPlane = camera.NearPlane;
|
||||||
|
for (var i = 0; i < NumShadowCascades; i++)
|
||||||
|
{
|
||||||
|
var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f));
|
||||||
|
|
||||||
|
// 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
|
||||||
|
RenderDirectionalShadowMap(shadowCamera, modelTransforms, directionalLight, effect, i);
|
||||||
|
|
||||||
|
effect.CascadeFarPlanes[i] = farPlane;
|
||||||
|
previousFarPlane = farPlane;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RenderDirectionalShadowMap(
|
||||||
PerspectiveCamera camera,
|
PerspectiveCamera camera,
|
||||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
DirectionalLight directionalLight,
|
DirectionalLight directionalLight,
|
||||||
|
ShadowCascadeEffect effect,
|
||||||
int shadowCascadeIndex
|
int shadowCascadeIndex
|
||||||
) {
|
) {
|
||||||
GraphicsDevice.SetRenderTarget(ShadowRenderTargets[shadowCascadeIndex]);
|
GraphicsDevice.SetRenderTarget(ShadowRenderTargets[shadowCascadeIndex]);
|
||||||
|
@ -357,23 +566,21 @@ namespace Kav
|
||||||
|
|
||||||
if (shadowCascadeIndex == 0)
|
if (shadowCascadeIndex == 0)
|
||||||
{
|
{
|
||||||
DeferredDirectionalLightEffect.LightSpaceMatrixOne = lightSpaceMatrix;
|
effect.LightSpaceMatrixOne = lightSpaceMatrix;
|
||||||
}
|
}
|
||||||
else if (shadowCascadeIndex == 1)
|
else if (shadowCascadeIndex == 1)
|
||||||
{
|
{
|
||||||
DeferredDirectionalLightEffect.LightSpaceMatrixTwo = lightSpaceMatrix;
|
effect.LightSpaceMatrixTwo = lightSpaceMatrix;
|
||||||
}
|
}
|
||||||
else if (shadowCascadeIndex == 2)
|
else if (shadowCascadeIndex == 2)
|
||||||
{
|
{
|
||||||
DeferredDirectionalLightEffect.LightSpaceMatrixThree = lightSpaceMatrix;
|
effect.LightSpaceMatrixThree = lightSpaceMatrix;
|
||||||
}
|
}
|
||||||
else if (shadowCascadeIndex == 3)
|
else if (shadowCascadeIndex == 3)
|
||||||
{
|
{
|
||||||
DeferredDirectionalLightEffect.LightSpaceMatrixFour = lightSpaceMatrix;
|
effect.LightSpaceMatrixFour = lightSpaceMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeferredDirectionalLightEffect.CascadeFarPlanes[shadowCascadeIndex] = camera.FarPlane;
|
|
||||||
|
|
||||||
foreach (var (model, transform) in modelTransforms)
|
foreach (var (model, transform) in modelTransforms)
|
||||||
{
|
{
|
||||||
foreach (var modelMesh in model.Meshes)
|
foreach (var modelMesh in model.Meshes)
|
||||||
|
@ -403,62 +610,98 @@ namespace Kav
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Render(
|
private void RenderPointShadows(
|
||||||
PerspectiveCamera camera,
|
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,
|
|
||||||
IEnumerable<(Model, Matrix)> modelTransforms,
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
IEnumerable<PointLight> pointLights,
|
PointLight pointLight
|
||||||
IEnumerable<DirectionalLight> directionalLights
|
|
||||||
) {
|
) {
|
||||||
foreach (var (model, transform) in modelTransforms)
|
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
|
||||||
|
GraphicsDevice.BlendState = BlendState.Opaque;
|
||||||
|
|
||||||
|
LinearDepthEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
|
||||||
|
MathHelper.PiOver2,
|
||||||
|
1,
|
||||||
|
0.1f,
|
||||||
|
25f // FIXME: magic value
|
||||||
|
);
|
||||||
|
LinearDepthEffect.FarPlane = 25f;
|
||||||
|
LinearDepthEffect.LightPosition = pointLight.Position;
|
||||||
|
|
||||||
|
foreach (CubeMapFace face in Enum.GetValues(typeof(CubeMapFace)))
|
||||||
{
|
{
|
||||||
foreach (var modelMesh in model.Meshes)
|
GraphicsDevice.SetRenderTarget(PointShadowCubeMap, face);
|
||||||
|
|
||||||
|
Vector3 targetDirection;
|
||||||
|
Vector3 targetUpDirection;
|
||||||
|
switch(face)
|
||||||
{
|
{
|
||||||
foreach (var meshPart in modelMesh.MeshParts)
|
case CubeMapFace.PositiveX:
|
||||||
|
targetDirection = Vector3.Right;
|
||||||
|
targetUpDirection = Vector3.Up;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CubeMapFace.NegativeX:
|
||||||
|
targetDirection = Vector3.Left;
|
||||||
|
targetUpDirection = Vector3.Up;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CubeMapFace.PositiveY:
|
||||||
|
targetDirection = Vector3.Up;
|
||||||
|
targetUpDirection = Vector3.Forward;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CubeMapFace.NegativeY:
|
||||||
|
targetDirection = Vector3.Down;
|
||||||
|
targetUpDirection = Vector3.Backward;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CubeMapFace.PositiveZ:
|
||||||
|
targetDirection = Vector3.Backward;
|
||||||
|
targetUpDirection = Vector3.Up;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CubeMapFace.NegativeZ:
|
||||||
|
targetDirection = Vector3.Forward;
|
||||||
|
targetUpDirection = Vector3.Up;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
targetDirection = Vector3.Right;
|
||||||
|
targetUpDirection = Vector3.Up;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearDepthEffect.View = Matrix.CreateLookAt(
|
||||||
|
pointLight.Position,
|
||||||
|
pointLight.Position + targetDirection,
|
||||||
|
targetUpDirection
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach (var (model, transform) in modelTransforms)
|
||||||
|
{
|
||||||
|
foreach (var modelMesh in model.Meshes)
|
||||||
{
|
{
|
||||||
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
|
foreach (var meshPart in modelMesh.MeshParts)
|
||||||
GraphicsDevice.Indices = meshPart.IndexBuffer;
|
|
||||||
|
|
||||||
if (meshPart.Effect is TransformEffect transformEffect)
|
|
||||||
{
|
{
|
||||||
transformEffect.World = transform;
|
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
|
||||||
transformEffect.View = view;
|
GraphicsDevice.Indices = meshPart.IndexBuffer;
|
||||||
transformEffect.Projection = projection;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (meshPart.Effect is PointLightEffect pointLightEffect)
|
LinearDepthEffect.Model = transform;
|
||||||
{
|
|
||||||
int i = 0;
|
foreach (var pass in LinearDepthEffect.CurrentTechnique.Passes)
|
||||||
foreach (var pointLight in pointLights)
|
|
||||||
{
|
{
|
||||||
if (i > pointLightEffect.MaxPointLights) { break; }
|
pass.Apply();
|
||||||
pointLightEffect.PointLights[i] = pointLight;
|
|
||||||
i++;
|
GraphicsDevice.DrawIndexedPrimitives(
|
||||||
|
PrimitiveType.TriangleList,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
meshPart.VertexBuffer.VertexCount,
|
||||||
|
0,
|
||||||
|
meshPart.Triangles.Length
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var pass in meshPart.Effect.CurrentTechnique.Passes)
|
|
||||||
{
|
|
||||||
pass.Apply();
|
|
||||||
|
|
||||||
GraphicsDevice.DrawIndexedPrimitives(
|
|
||||||
PrimitiveType.TriangleList,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
meshPart.VertexBuffer.VertexCount,
|
|
||||||
0,
|
|
||||||
meshPart.Triangles.Length
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
71
Resources.cs
71
Resources.cs
|
@ -10,7 +10,7 @@ namespace Kav
|
||||||
{
|
{
|
||||||
if (ambientLightEffect == null)
|
if (ambientLightEffect == null)
|
||||||
{
|
{
|
||||||
ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect");
|
ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect.fxb");
|
||||||
}
|
}
|
||||||
return ambientLightEffect;
|
return ambientLightEffect;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ namespace Kav
|
||||||
{
|
{
|
||||||
if (pointLightEffect == null)
|
if (pointLightEffect == null)
|
||||||
{
|
{
|
||||||
pointLightEffect = GetResource("DeferredPBR_PointLightEffect");
|
pointLightEffect = GetResource("DeferredPBR_PointLightEffect.fxb");
|
||||||
}
|
}
|
||||||
return pointLightEffect;
|
return pointLightEffect;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ namespace Kav
|
||||||
{
|
{
|
||||||
if (directionalLightEffect == null)
|
if (directionalLightEffect == null)
|
||||||
{
|
{
|
||||||
directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect");
|
directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect.fxb");
|
||||||
}
|
}
|
||||||
return directionalLightEffect;
|
return directionalLightEffect;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ namespace Kav
|
||||||
{
|
{
|
||||||
if (gBufferEffect == null)
|
if (gBufferEffect == null)
|
||||||
{
|
{
|
||||||
gBufferEffect = GetResource("DeferredPBR_GBufferEffect");
|
gBufferEffect = GetResource("DeferredPBR_GBufferEffect.fxb");
|
||||||
}
|
}
|
||||||
return gBufferEffect;
|
return gBufferEffect;
|
||||||
}
|
}
|
||||||
|
@ -57,19 +57,31 @@ namespace Kav
|
||||||
{
|
{
|
||||||
if (toneMapEffect == null)
|
if (toneMapEffect == null)
|
||||||
{
|
{
|
||||||
toneMapEffect = GetResource("ToneMapEffect");
|
toneMapEffect = GetResource("ToneMapEffect.fxb");
|
||||||
}
|
}
|
||||||
return toneMapEffect;
|
return toneMapEffect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] Deferred_ToonEffect
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (deferredToonEffect == null)
|
||||||
|
{
|
||||||
|
deferredToonEffect = GetResource("Deferred_ToonEffect.fxb");
|
||||||
|
}
|
||||||
|
return deferredToonEffect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] DeferredPBREffect
|
public static byte[] DeferredPBREffect
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (deferredPBREffect == null)
|
if (deferredPBREffect == null)
|
||||||
{
|
{
|
||||||
deferredPBREffect = GetResource("DeferredPBREffect");
|
deferredPBREffect = GetResource("DeferredPBREffect.fxb");
|
||||||
}
|
}
|
||||||
return deferredPBREffect;
|
return deferredPBREffect;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +93,7 @@ namespace Kav
|
||||||
{
|
{
|
||||||
if (pbrEffect == null)
|
if (pbrEffect == null)
|
||||||
{
|
{
|
||||||
pbrEffect = GetResource("PBREffect");
|
pbrEffect = GetResource("PBREffect.fxb");
|
||||||
}
|
}
|
||||||
return pbrEffect;
|
return pbrEffect;
|
||||||
}
|
}
|
||||||
|
@ -93,25 +105,66 @@ namespace Kav
|
||||||
{
|
{
|
||||||
if (simpleDepthEffect == null)
|
if (simpleDepthEffect == null)
|
||||||
{
|
{
|
||||||
simpleDepthEffect = GetResource("SimpleDepthEffect");
|
simpleDepthEffect = GetResource("SimpleDepthEffect.fxb");
|
||||||
}
|
}
|
||||||
return simpleDepthEffect;
|
return simpleDepthEffect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] LinearDepthEffect
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (linearDepthEffect == null)
|
||||||
|
{
|
||||||
|
linearDepthEffect = GetResource("LinearDepthEffect.fxb");
|
||||||
|
}
|
||||||
|
return linearDepthEffect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] SkyboxEffect
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (skyboxEffect == null)
|
||||||
|
{
|
||||||
|
skyboxEffect = GetResource("SkyboxEffect.fxb");
|
||||||
|
}
|
||||||
|
return skyboxEffect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] UnitCubeModel
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (unitCubeModel == null)
|
||||||
|
{
|
||||||
|
unitCubeModel = GetResource("UnitCube.glb");
|
||||||
|
}
|
||||||
|
return unitCubeModel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] ambientLightEffect;
|
private static byte[] ambientLightEffect;
|
||||||
private static byte[] pointLightEffect;
|
private static byte[] pointLightEffect;
|
||||||
private static byte[] directionalLightEffect;
|
private static byte[] directionalLightEffect;
|
||||||
private static byte[] gBufferEffect;
|
private static byte[] gBufferEffect;
|
||||||
private static byte[] toneMapEffect;
|
private static byte[] toneMapEffect;
|
||||||
|
private static byte[] deferredToonEffect;
|
||||||
private static byte[] deferredPBREffect;
|
private static byte[] deferredPBREffect;
|
||||||
private static byte[] pbrEffect;
|
private static byte[] pbrEffect;
|
||||||
private static byte[] simpleDepthEffect;
|
private static byte[] simpleDepthEffect;
|
||||||
|
private static byte[] linearDepthEffect;
|
||||||
|
private static byte[] skyboxEffect;
|
||||||
|
|
||||||
|
private static byte[] unitCubeModel;
|
||||||
|
|
||||||
private static byte[] GetResource(string name)
|
private static byte[] GetResource(string name)
|
||||||
{
|
{
|
||||||
Stream stream = typeof(Resources).Assembly.GetManifestResourceStream(
|
Stream stream = typeof(Resources).Assembly.GetManifestResourceStream(
|
||||||
"Kav.Resources." + name + ".fxb"
|
"Kav.Resources." + name
|
||||||
);
|
);
|
||||||
using (MemoryStream ms = new MemoryStream())
|
using (MemoryStream ms = new MemoryStream())
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue