Compare commits
64 Commits
Author | SHA1 | Date |
---|---|---|
cosmonaut | f5cdd0b566 | |
cosmonaut | 808d50ccc2 | |
cosmonaut | d537993530 | |
cosmonaut | 3338bf3b06 | |
cosmonaut | 16ecb5afa6 | |
cosmonaut | 51d7f3e772 | |
cosmonaut | 3a0aa8894d | |
cosmonaut | c468d6276d | |
cosmonaut | d476f254e4 | |
cosmonaut | 2ff5cb1ca5 | |
cosmonaut | 40ca0402d6 | |
cosmonaut | 0ebad486c5 | |
cosmonaut | 8ff6e26887 | |
cosmonaut | 7f0bf47f07 | |
cosmonaut | 2f589e584d | |
cosmonaut | 7964d8a171 | |
cosmonaut | d5d0a38ff1 | |
cosmonaut | ee909ba94e | |
cosmonaut | 0060c22d72 | |
cosmonaut | 2c113ed642 | |
cosmonaut | b1395babfe | |
cosmonaut | ef948cf7fb | |
cosmonaut | 9a7fb75ec5 | |
cosmonaut | 0c576668cb | |
cosmonaut | 367e2795ae | |
cosmonaut | 1723f1dff8 | |
cosmonaut | 14e07c7476 | |
cosmonaut | 4b7d31f2b2 | |
cosmonaut | 4d3c5fc316 | |
cosmonaut | 96f6d22896 | |
cosmonaut | 84601379b5 | |
cosmonaut | fe222e266f | |
cosmonaut | bb694d3dbe | |
cosmonaut | e2fdbff7d1 | |
cosmonaut | 283b078641 | |
cosmonaut | b784f9df4b | |
cosmonaut | 8b43e8f45e | |
cosmonaut | ee8b0c5ee8 | |
cosmonaut | c9a4e35816 | |
cosmonaut | 7f986c546a | |
cosmonaut | fc09082f1b | |
cosmonaut | 46f2cad81a | |
cosmonaut | ca6c91446e | |
cosmonaut | 60ebb19e24 | |
cosmonaut | 47242e4f52 | |
cosmonaut | ae445d94d3 | |
cosmonaut | 665ff6dd44 | |
cosmonaut | 56cdffdff6 | |
cosmonaut | acaafdcdcd | |
cosmonaut | d83aacd57f | |
cosmonaut | ed5a7df614 | |
cosmonaut | 8fa22260d2 | |
cosmonaut | cb0baf0bf0 | |
cosmonaut | 8407a34c37 | |
cosmonaut | 0a7698c315 | |
cosmonaut | 06e5523996 | |
cosmonaut | 19a61985ca | |
cosmonaut | 1f10698811 | |
cosmonaut | a914c586b2 | |
cosmonaut | d370d4e2e4 | |
cosmonaut | 632f0a5b06 | |
cosmonaut | 2fb20747e4 | |
cosmonaut | 565be374bb | |
cosmonaut | 66d4e5bf6e |
|
@ -0,0 +1 @@
|
|||
*.fxb filter=lfs diff=lfs merge=lfs -text
|
|
@ -2,22 +2,41 @@ using Microsoft.Xna.Framework;
|
|||
|
||||
namespace Kav
|
||||
{
|
||||
public struct Camera
|
||||
public struct PerspectiveCamera
|
||||
{
|
||||
public Matrix Transform { get; }
|
||||
public Matrix View
|
||||
{
|
||||
get
|
||||
{
|
||||
return Matrix.CreateLookAt(Transform.Translation, Transform.Translation + Transform.Forward, Transform.Up);
|
||||
}
|
||||
}
|
||||
public Matrix View { get; }
|
||||
public Matrix Projection { get; }
|
||||
|
||||
public Camera(Matrix transform, Matrix projection)
|
||||
{
|
||||
Transform = transform;
|
||||
Projection = projection;
|
||||
public Vector3 Position { get; }
|
||||
public Vector3 Forward { get; }
|
||||
public Vector3 Up { get; }
|
||||
public Vector3 Right { get; }
|
||||
|
||||
public float FieldOfView { get; }
|
||||
public float AspectRatio { get; }
|
||||
public float NearPlane { get; }
|
||||
public float FarPlane { get; }
|
||||
|
||||
public PerspectiveCamera(
|
||||
Vector3 position,
|
||||
Vector3 forward,
|
||||
Vector3 up,
|
||||
float fieldOfView,
|
||||
float aspectRatio,
|
||||
float nearPlane,
|
||||
float farPlane
|
||||
) {
|
||||
Position = position;
|
||||
Forward = forward;
|
||||
Up = up;
|
||||
Right = Vector3.Cross(forward, up);
|
||||
View = Matrix.CreateLookAt(Position, Position + Forward, Up);
|
||||
|
||||
FieldOfView = fieldOfView;
|
||||
AspectRatio = aspectRatio;
|
||||
NearPlane = nearPlane;
|
||||
FarPlane = farPlane;
|
||||
Projection = Matrix.CreatePerspectiveFieldOfView(FieldOfView, AspectRatio, NearPlane, FarPlane);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
namespace Kav
|
||||
{
|
||||
public struct AtlasAnimation
|
||||
{
|
||||
public UVData[] Frames { get; }
|
||||
public int Framerate { get; }
|
||||
|
||||
public AtlasAnimation(UVData[] frames, int framerate)
|
||||
{
|
||||
Frames = frames;
|
||||
Framerate = framerate;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class InstanceData<T> where T : struct, IVertexType
|
||||
{
|
||||
public T[] InstanceDataArray { get; }
|
||||
public DynamicVertexBuffer VertexBuffer { get; }
|
||||
public int InstanceCount { get; private set; }
|
||||
|
||||
public InstanceData(GraphicsDevice graphicsDevice, int size)
|
||||
{
|
||||
InstanceDataArray = new T[size];
|
||||
|
||||
VertexBuffer = new DynamicVertexBuffer(
|
||||
graphicsDevice,
|
||||
typeof(T),
|
||||
size,
|
||||
BufferUsage.WriteOnly
|
||||
);
|
||||
|
||||
InstanceCount = 0;
|
||||
}
|
||||
|
||||
public void AddAndSetData(IEnumerable<T> data)
|
||||
{
|
||||
InstanceCount = 0;
|
||||
foreach (var datum in data)
|
||||
{
|
||||
AddData(datum);
|
||||
}
|
||||
|
||||
if (InstanceCount == 0) { throw new System.Exception(); }
|
||||
|
||||
SetData();
|
||||
}
|
||||
|
||||
public void AddData(T datum)
|
||||
{
|
||||
InstanceDataArray[InstanceCount] = datum;
|
||||
InstanceCount += 1;
|
||||
}
|
||||
|
||||
public void SetData()
|
||||
{
|
||||
if (InstanceCount > 0)
|
||||
{
|
||||
VertexBuffer.SetData(
|
||||
InstanceDataArray,
|
||||
0,
|
||||
InstanceCount,
|
||||
SetDataOptions.NoOverwrite
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
InstanceCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav.Data
|
||||
{
|
||||
public struct MeshSpriteDrawData : IIndexDrawable, ICullable, ITransformable
|
||||
{
|
||||
public SpriteMesh MeshSprite { get; }
|
||||
public Texture2D Texture { get; }
|
||||
public Texture2D Normal { get; }
|
||||
public SpriteBillboardConstraint BillboardConstraint { get; }
|
||||
public Matrix TransformMatrix { get; }
|
||||
public UVData UVOffset { get; }
|
||||
|
||||
public IndexBuffer IndexBuffer => MeshSprite.IndexBuffer;
|
||||
public VertexBuffer VertexBuffer => MeshSprite.VertexBuffer;
|
||||
public BoundingBox BoundingBox => MeshSprite.BoundingBox;
|
||||
|
||||
public MeshSpriteDrawData(
|
||||
SpriteMesh meshSprite,
|
||||
Texture2D texture,
|
||||
Texture2D normal,
|
||||
SpriteBillboardConstraint billboardConstraint,
|
||||
Matrix transformMatrix,
|
||||
UVData offset
|
||||
) {
|
||||
MeshSprite = meshSprite;
|
||||
Texture = texture;
|
||||
Normal = normal;
|
||||
BillboardConstraint = billboardConstraint;
|
||||
TransformMatrix = transformMatrix;
|
||||
UVOffset = offset;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
using Kav.Data;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public struct TextureAtlasSlice
|
||||
{
|
||||
public int X { get; }
|
||||
public int Y { get; }
|
||||
public int W { get; }
|
||||
public int H { get; }
|
||||
|
||||
public UVData UVData { get; }
|
||||
|
||||
// for use with tiling
|
||||
public Vector2 TiledUVOffset { get; }
|
||||
|
||||
public TextureAtlasSlice(int x, int y, int w, int h, int totalW, int totalH)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
W = w;
|
||||
H = h;
|
||||
|
||||
UVData = new UVData(new Vector2(x, y), new Vector2(w, h), new Vector2(totalW, totalH));
|
||||
|
||||
TiledUVOffset = new Vector2(x / (float)totalW, y / (float)totalH);
|
||||
}
|
||||
}
|
||||
|
||||
public class TextureAtlas
|
||||
{
|
||||
public Texture2D Texture { get; }
|
||||
protected List<string> Names { get; } = new List<string>();
|
||||
protected Dictionary<string, TextureAtlasSlice> Slices { get; } = new Dictionary<string, TextureAtlasSlice>();
|
||||
|
||||
public TextureAtlas(GraphicsDevice graphicsDevice, FileInfo atlasMetadataFile)
|
||||
{
|
||||
var atlasData = CrunchAtlasReader.ReadTextureAtlas(atlasMetadataFile);
|
||||
|
||||
var textureData = atlasData.Textures[0];
|
||||
|
||||
using var stream = File.OpenRead(Path.Combine(atlasMetadataFile.DirectoryName, textureData.Name + ".png"));
|
||||
Texture = Texture2D.FromStream(graphicsDevice, stream);
|
||||
|
||||
foreach (var slice in textureData.Images)
|
||||
{
|
||||
Names.Add(slice.N);
|
||||
|
||||
Slices.Add(
|
||||
slice.N,
|
||||
new TextureAtlasSlice(
|
||||
slice.X,
|
||||
slice.Y,
|
||||
slice.W,
|
||||
slice.H,
|
||||
Texture.Width,
|
||||
Texture.Height
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public TextureAtlasSlice Lookup(string name)
|
||||
{
|
||||
return Slices[name];
|
||||
}
|
||||
|
||||
public string Name(int index)
|
||||
{
|
||||
return Names[index];
|
||||
}
|
||||
|
||||
public int Count()
|
||||
{
|
||||
return Names.Count;
|
||||
}
|
||||
}
|
||||
|
||||
// Assumes all subimages are the same size
|
||||
public class TiledTextureAtlas : TextureAtlas
|
||||
{
|
||||
public int NumRows { get; }
|
||||
public int NumColumns { get; }
|
||||
|
||||
public TiledTextureAtlas(GraphicsDevice graphicsDevice, FileInfo atlasMetadataFile) : base(graphicsDevice, atlasMetadataFile)
|
||||
{
|
||||
var subImageSlice = Slices[Names[0]];
|
||||
NumRows = Texture.Height / subImageSlice.H;
|
||||
NumColumns = Texture.Width / subImageSlice.W;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public struct UVData
|
||||
{
|
||||
public Vector2 Offset { get; }
|
||||
public Vector2 Percentage { get; }
|
||||
|
||||
public UVData(
|
||||
Vector2 positionInAtlas,
|
||||
Vector2 subTextureDimensions,
|
||||
Vector2 atlasDimensions
|
||||
) {
|
||||
Percentage = subTextureDimensions / atlasDimensions;
|
||||
Offset = positionInAtlas / atlasDimensions;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class DirectionalShadowMapData
|
||||
{
|
||||
public static readonly int MAX_SHADOW_CASCADES = 4;
|
||||
|
||||
public RenderTarget2D[] ShadowMaps { get; }
|
||||
|
||||
public Matrix[] LightSpaceViews { get; }
|
||||
public Matrix[] LightSpaceProjections { get; }
|
||||
|
||||
public float[] CascadeFarPlanes { get; }
|
||||
|
||||
public int ShadowMapSize { get; }
|
||||
public int NumShadowCascades { get; }
|
||||
|
||||
internal DirectionalShadowMapData(
|
||||
GraphicsDevice graphicsDevice,
|
||||
int shadowMapSize,
|
||||
int numCascades
|
||||
) {
|
||||
ShadowMapSize = shadowMapSize;
|
||||
NumShadowCascades = (int)MathHelper.Clamp(numCascades, 1, MAX_SHADOW_CASCADES);
|
||||
|
||||
LightSpaceViews = new Matrix[4];
|
||||
LightSpaceProjections = new Matrix[4];
|
||||
|
||||
ShadowMaps = new RenderTarget2D[NumShadowCascades];
|
||||
|
||||
for (var i = 0; i < NumShadowCascades; i++)
|
||||
{
|
||||
ShadowMaps[i] = new RenderTarget2D(
|
||||
graphicsDevice,
|
||||
shadowMapSize,
|
||||
shadowMapSize,
|
||||
false,
|
||||
SurfaceFormat.Single,
|
||||
DepthFormat.Depth24,
|
||||
0,
|
||||
RenderTargetUsage.PreserveContents
|
||||
);
|
||||
}
|
||||
|
||||
CascadeFarPlanes = new float[MAX_SHADOW_CASCADES];
|
||||
}
|
||||
|
||||
public void Clear(GraphicsDevice graphicsDevice)
|
||||
{
|
||||
foreach (var shadowMap in ShadowMaps)
|
||||
{
|
||||
graphicsDevice.SetRenderTarget(shadowMap);
|
||||
graphicsDevice.Clear(Color.White);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Kav
|
||||
{
|
||||
public interface DirectionalLightEffect
|
||||
{
|
||||
int MaxDirectionalLights { get; }
|
||||
DirectionalLightCollection DirectionalLights { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public interface IHasTranslation
|
||||
{
|
||||
Vector3 Translation { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public interface IHasWorldMatrix
|
||||
{
|
||||
Matrix World { get; set; }
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -10,15 +10,47 @@ namespace Kav
|
|||
EffectParameter gNormalParam;
|
||||
EffectParameter gMetallicRoughnessParam;
|
||||
|
||||
EffectParameter shadowMapOneParam;
|
||||
EffectParameter shadowMapTwoParam;
|
||||
EffectParameter shadowMapThreeParam;
|
||||
EffectParameter shadowMapFourParam;
|
||||
|
||||
EffectParameter lightSpaceMatrixOneParam;
|
||||
EffectParameter lightSpaceMatrixTwoParam;
|
||||
EffectParameter lightSpaceMatrixThreeParam;
|
||||
EffectParameter lightSpaceMatrixFourParam;
|
||||
|
||||
EffectParameter viewMatrixParam;
|
||||
EffectParameter cascadeFarPlanesParam;
|
||||
|
||||
EffectParameter directionalLightColorParam;
|
||||
EffectParameter directionalLightDirectionParam;
|
||||
|
||||
EffectParameter eyePositionParam;
|
||||
|
||||
PointLightCollection pointLightCollection;
|
||||
DirectionalLightCollection directionalLightCollection;
|
||||
|
||||
public Texture2D GPosition { get; set; }
|
||||
public Texture2D GAlbedo { get; set; }
|
||||
public Texture2D GNormal { get; set; }
|
||||
public Texture2D GMetallicRoughness { get; set; }
|
||||
|
||||
public Texture2D ShadowMapOne { get; set; }
|
||||
public Texture2D ShadowMapTwo { get; set; }
|
||||
public Texture2D ShadowMapThree { get; set; }
|
||||
public Texture2D ShadowMapFour { get; set; }
|
||||
|
||||
public Matrix LightSpaceMatrixOne { get; set; }
|
||||
public Matrix LightSpaceMatrixTwo { get; set; }
|
||||
public Matrix LightSpaceMatrixThree { get; set; }
|
||||
public Matrix LightSpaceMatrixFour { get; set; }
|
||||
|
||||
public Matrix ViewMatrix { get; set; }
|
||||
public readonly float[] CascadeFarPlanes;
|
||||
|
||||
public Vector3 DirectionalLightColor { get; set; }
|
||||
public Vector3 DirectionalLightDirection { get; set; }
|
||||
|
||||
public Vector3 EyePosition { get; set; }
|
||||
|
||||
public int MaxPointLights { get; } = 64;
|
||||
|
@ -29,16 +61,10 @@ namespace Kav
|
|||
private set { pointLightCollection = value; }
|
||||
}
|
||||
|
||||
public int MaxDirectionalLights { get; } = 4;
|
||||
|
||||
public DirectionalLightCollection DirectionalLights
|
||||
{
|
||||
get { return directionalLightCollection; }
|
||||
private set { directionalLightCollection = value; }
|
||||
}
|
||||
|
||||
public DeferredPBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBREffect)
|
||||
{
|
||||
CascadeFarPlanes = new float[4];
|
||||
|
||||
CacheEffectParameters();
|
||||
|
||||
pointLightCollection = new PointLightCollection(
|
||||
|
@ -46,47 +72,6 @@ namespace Kav
|
|||
Parameters["PointLightColors"],
|
||||
MaxPointLights
|
||||
);
|
||||
|
||||
DirectionalLights = new DirectionalLightCollection(
|
||||
Parameters["DirectionalLightDirections"],
|
||||
Parameters["DirectionalLightColors"]
|
||||
);
|
||||
}
|
||||
|
||||
protected DeferredPBREffect(DeferredPBREffect cloneSource) : base(cloneSource)
|
||||
{
|
||||
GPosition = cloneSource.GPosition;
|
||||
GAlbedo = cloneSource.GAlbedo;
|
||||
GNormal = cloneSource.GNormal;
|
||||
GMetallicRoughness = cloneSource.GMetallicRoughness;
|
||||
|
||||
EyePosition = cloneSource.EyePosition;
|
||||
|
||||
PointLights = new PointLightCollection(
|
||||
Parameters["LightPositions"],
|
||||
Parameters["PositionLightColors"],
|
||||
MaxPointLights
|
||||
);
|
||||
|
||||
for (int i = 0; i < MaxPointLights; i++)
|
||||
{
|
||||
PointLights[i] = cloneSource.PointLights[i];
|
||||
}
|
||||
|
||||
DirectionalLights = new DirectionalLightCollection(
|
||||
Parameters["DirectionalLightDirections"],
|
||||
Parameters["DirectionalLightColors"]
|
||||
);
|
||||
|
||||
for (int i = 0; i < MaxDirectionalLights; i++)
|
||||
{
|
||||
DirectionalLights[i] = cloneSource.DirectionalLights[i];
|
||||
}
|
||||
}
|
||||
|
||||
public override Effect Clone()
|
||||
{
|
||||
return new DeferredPBREffect(this);
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
|
@ -96,6 +81,22 @@ namespace Kav
|
|||
gNormalParam.SetValue(GNormal);
|
||||
gMetallicRoughnessParam.SetValue(GMetallicRoughness);
|
||||
|
||||
shadowMapOneParam.SetValue(ShadowMapOne);
|
||||
shadowMapTwoParam.SetValue(ShadowMapTwo);
|
||||
shadowMapThreeParam.SetValue(ShadowMapThree);
|
||||
shadowMapFourParam.SetValue(ShadowMapFour);
|
||||
|
||||
lightSpaceMatrixOneParam.SetValue(LightSpaceMatrixOne);
|
||||
lightSpaceMatrixTwoParam.SetValue(LightSpaceMatrixTwo);
|
||||
lightSpaceMatrixThreeParam.SetValue(LightSpaceMatrixThree);
|
||||
lightSpaceMatrixFourParam.SetValue(LightSpaceMatrixFour);
|
||||
|
||||
viewMatrixParam.SetValue(ViewMatrix);
|
||||
cascadeFarPlanesParam.SetValue(CascadeFarPlanes);
|
||||
|
||||
directionalLightColorParam.SetValue(DirectionalLightColor);
|
||||
directionalLightDirectionParam.SetValue(DirectionalLightDirection);
|
||||
|
||||
eyePositionParam.SetValue(EyePosition);
|
||||
}
|
||||
|
||||
|
@ -106,6 +107,22 @@ namespace Kav
|
|||
gNormalParam = Parameters["gNormal"];
|
||||
gMetallicRoughnessParam = Parameters["gMetallicRoughness"];
|
||||
|
||||
shadowMapOneParam = Parameters["shadowMapOne"];
|
||||
shadowMapTwoParam = Parameters["shadowMapTwo"];
|
||||
shadowMapThreeParam = Parameters["shadowMapThree"];
|
||||
shadowMapFourParam = Parameters["shadowMapFour"];
|
||||
|
||||
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];
|
||||
lightSpaceMatrixTwoParam = Parameters["LightSpaceMatrixTwo"];
|
||||
lightSpaceMatrixThreeParam = Parameters["LightSpaceMatrixThree"];
|
||||
lightSpaceMatrixFourParam = Parameters["LightSpaceMatrixFour"];
|
||||
|
||||
viewMatrixParam = Parameters["ViewMatrix"];
|
||||
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
|
||||
|
||||
directionalLightDirectionParam = Parameters["DirectionalLightDirection"];
|
||||
directionalLightColorParam = Parameters["DirectionalLightColor"];
|
||||
|
||||
eyePositionParam = Parameters["EyePosition"];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
|
||||
public class DeferredPBR_AmbientLightEffect : Effect
|
||||
{
|
||||
EffectParameter gPositionParam;
|
||||
EffectParameter gAlbedoParam;
|
||||
|
||||
EffectParameter ambientColorParam;
|
||||
|
||||
public Texture2D GPosition { get; set; }
|
||||
public Texture2D GAlbedo { get; set; }
|
||||
|
||||
public Vector3 AmbientColor { get; set; }
|
||||
|
||||
public DeferredPBR_AmbientLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_AmbientLightEffect)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
{
|
||||
gPositionParam.SetValue(GPosition);
|
||||
gAlbedoParam.SetValue(GAlbedo);
|
||||
ambientColorParam.SetValue(AmbientColor);
|
||||
}
|
||||
|
||||
void CacheEffectParameters()
|
||||
{
|
||||
gPositionParam = Parameters["gPosition"];
|
||||
gAlbedoParam = Parameters["gAlbedo"];
|
||||
ambientColorParam = Parameters["AmbientLightColor"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class DeferredPBR_DirectionalLightEffect : Effect, ShadowCascadeEffect
|
||||
{
|
||||
EffectParameter gPositionParam;
|
||||
EffectParameter gAlbedoParam;
|
||||
EffectParameter gNormalParam;
|
||||
EffectParameter gMetallicRoughnessParam;
|
||||
|
||||
EffectParameter shadowMapOneParam;
|
||||
EffectParameter shadowMapTwoParam;
|
||||
EffectParameter shadowMapThreeParam;
|
||||
EffectParameter shadowMapFourParam;
|
||||
|
||||
EffectParameter eyePositionParam;
|
||||
|
||||
EffectParameter directionalLightColorParam;
|
||||
EffectParameter directionalLightDirectionParam;
|
||||
|
||||
EffectParameter cascadeFarPlanesParam;
|
||||
|
||||
EffectParameter shadowMapSizeParam;
|
||||
|
||||
EffectParameter lightSpaceMatrixOneParam;
|
||||
EffectParameter lightSpaceMatrixTwoParam;
|
||||
EffectParameter lightSpaceMatrixThreeParam;
|
||||
EffectParameter lightSpaceMatrixFourParam;
|
||||
|
||||
EffectParameter viewMatrixParam;
|
||||
|
||||
public Texture2D GPosition { get; set; }
|
||||
public Texture2D GAlbedo { get; set; }
|
||||
public Texture2D GNormal { get; set; }
|
||||
public Texture2D GMetallicRoughness { get; set; }
|
||||
|
||||
public Texture2D ShadowMapOne { get; set; }
|
||||
public Texture2D ShadowMapTwo { get; set; }
|
||||
public Texture2D ShadowMapThree { get; set; }
|
||||
public Texture2D ShadowMapFour { get; set; }
|
||||
|
||||
public Vector3 EyePosition { get; set; }
|
||||
|
||||
public Vector3 DirectionalLightDirection { get; set; }
|
||||
public Vector3 DirectionalLightColor { get; set; }
|
||||
|
||||
public float[] CascadeFarPlanes { get; }
|
||||
|
||||
public int ShadowMapSize { get; set; }
|
||||
|
||||
public Matrix LightSpaceMatrixOne { get; set; }
|
||||
public Matrix LightSpaceMatrixTwo { get; set; }
|
||||
public Matrix LightSpaceMatrixThree { get; set; }
|
||||
public Matrix LightSpaceMatrixFour { get; set; }
|
||||
|
||||
public Matrix ViewMatrix { get; set; }
|
||||
|
||||
public DeferredPBR_DirectionalLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_DirectionalLightEffect)
|
||||
{
|
||||
CascadeFarPlanes = new float[4];
|
||||
CacheEffectParameters();
|
||||
}
|
||||
|
||||
public DeferredPBR_DirectionalLightEffect(DeferredPBR_DirectionalLightEffect cloneSource) : base(cloneSource)
|
||||
{
|
||||
GPosition = cloneSource.GPosition;
|
||||
GAlbedo = cloneSource.GAlbedo;
|
||||
GNormal = cloneSource.GNormal;
|
||||
GMetallicRoughness = cloneSource.GMetallicRoughness;
|
||||
|
||||
ShadowMapOne = cloneSource.ShadowMapOne;
|
||||
ShadowMapTwo = cloneSource.ShadowMapTwo;
|
||||
ShadowMapThree = cloneSource.ShadowMapThree;
|
||||
ShadowMapFour = cloneSource.ShadowMapFour;
|
||||
|
||||
EyePosition = cloneSource.EyePosition;
|
||||
|
||||
DirectionalLightDirection = cloneSource.DirectionalLightDirection;
|
||||
DirectionalLightColor = cloneSource.DirectionalLightColor;
|
||||
|
||||
CascadeFarPlanes = new float[4];
|
||||
for (int i = 0 ; i < 4; i++)
|
||||
{
|
||||
CascadeFarPlanes[i] = cloneSource.CascadeFarPlanes[i];
|
||||
}
|
||||
|
||||
ShadowMapSize = cloneSource.ShadowMapSize;
|
||||
|
||||
LightSpaceMatrixOne = cloneSource.LightSpaceMatrixOne;
|
||||
LightSpaceMatrixTwo = cloneSource.LightSpaceMatrixTwo;
|
||||
LightSpaceMatrixThree = cloneSource.LightSpaceMatrixThree;
|
||||
LightSpaceMatrixFour = cloneSource.LightSpaceMatrixFour;
|
||||
|
||||
ViewMatrix = cloneSource.ViewMatrix;
|
||||
}
|
||||
|
||||
public override Effect Clone()
|
||||
{
|
||||
return new DeferredPBR_DirectionalLightEffect(this);
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
{
|
||||
gPositionParam.SetValue(GPosition);
|
||||
gAlbedoParam.SetValue(GAlbedo);
|
||||
gNormalParam.SetValue(GNormal);
|
||||
gMetallicRoughnessParam.SetValue(GMetallicRoughness);
|
||||
|
||||
shadowMapOneParam.SetValue(ShadowMapOne);
|
||||
shadowMapTwoParam.SetValue(ShadowMapTwo);
|
||||
shadowMapThreeParam.SetValue(ShadowMapThree);
|
||||
shadowMapFourParam.SetValue(ShadowMapFour);
|
||||
|
||||
eyePositionParam.SetValue(EyePosition);
|
||||
|
||||
directionalLightDirectionParam.SetValue(DirectionalLightDirection);
|
||||
directionalLightColorParam.SetValue(DirectionalLightColor);
|
||||
|
||||
cascadeFarPlanesParam.SetValue(CascadeFarPlanes);
|
||||
shadowMapSizeParam.SetValue(ShadowMapSize);
|
||||
|
||||
lightSpaceMatrixOneParam.SetValue(LightSpaceMatrixOne);
|
||||
lightSpaceMatrixTwoParam.SetValue(LightSpaceMatrixTwo);
|
||||
lightSpaceMatrixThreeParam.SetValue(LightSpaceMatrixThree);
|
||||
lightSpaceMatrixFourParam.SetValue(LightSpaceMatrixFour);
|
||||
|
||||
viewMatrixParam.SetValue(ViewMatrix);
|
||||
}
|
||||
|
||||
void CacheEffectParameters()
|
||||
{
|
||||
gPositionParam = Parameters["gPosition"];
|
||||
gAlbedoParam = Parameters["gAlbedo"];
|
||||
gNormalParam = Parameters["gNormal"];
|
||||
gMetallicRoughnessParam = Parameters["gMetallicRoughness"];
|
||||
|
||||
shadowMapOneParam = Parameters["shadowMapOne"];
|
||||
shadowMapTwoParam = Parameters["shadowMapTwo"];
|
||||
shadowMapThreeParam = Parameters["shadowMapThree"];
|
||||
shadowMapFourParam = Parameters["shadowMapFour"];
|
||||
|
||||
eyePositionParam = Parameters["EyePosition"];
|
||||
|
||||
directionalLightDirectionParam = Parameters["DirectionalLightDirection"];
|
||||
directionalLightColorParam = Parameters["DirectionalLightColor"];
|
||||
|
||||
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
|
||||
shadowMapSizeParam = Parameters["ShadowMapSize"];
|
||||
|
||||
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];
|
||||
lightSpaceMatrixTwoParam = Parameters["LightSpaceMatrixTwo"];
|
||||
lightSpaceMatrixThreeParam = Parameters["LightSpaceMatrixThree"];
|
||||
lightSpaceMatrixFourParam = Parameters["LightSpaceMatrixFour"];
|
||||
|
||||
viewMatrixParam = Parameters["ViewMatrix"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,8 +6,7 @@ namespace Kav
|
|||
public class DeferredPBR_GBufferEffect : Effect, TransformEffect
|
||||
{
|
||||
EffectParameter worldParam;
|
||||
EffectParameter worldViewProjectionParam;
|
||||
EffectParameter worldInverseTransposeParam;
|
||||
EffectParameter viewProjectionParam;
|
||||
|
||||
EffectParameter albedoTextureParam;
|
||||
EffectParameter normalTextureParam;
|
||||
|
@ -17,6 +16,13 @@ namespace Kav
|
|||
EffectParameter metallicParam;
|
||||
EffectParameter roughnessParam;
|
||||
|
||||
EffectParameter uvOffsetAndDimensionsParam;
|
||||
EffectParameter isSpriteParam;
|
||||
|
||||
EffectParameter numTextureRowsParam;
|
||||
EffectParameter numTextureColumnsParam;
|
||||
|
||||
EffectParameter vertexShaderIndexParam;
|
||||
EffectParameter shaderIndexParam;
|
||||
|
||||
Matrix world = Matrix.Identity;
|
||||
|
@ -27,9 +33,18 @@ namespace Kav
|
|||
float metallic;
|
||||
float roughness;
|
||||
|
||||
Vector2 uvOffset;
|
||||
Vector2 subTextureDimensions;
|
||||
|
||||
bool isSprite = false;
|
||||
|
||||
int numTextureRows = 1;
|
||||
int numTextureColumns = 1;
|
||||
|
||||
bool albedoTextureEnabled = false;
|
||||
bool metallicRoughnessMapEnabled = false;
|
||||
bool normalMapEnabled = false;
|
||||
bool hardwareInstancingEnabled = false;
|
||||
|
||||
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
|
||||
|
||||
|
@ -39,7 +54,7 @@ namespace Kav
|
|||
set
|
||||
{
|
||||
world = value;
|
||||
dirtyFlags |= EffectDirtyFlags.World | EffectDirtyFlags.WorldViewProj;
|
||||
dirtyFlags |= EffectDirtyFlags.World;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +64,7 @@ namespace Kav
|
|||
set
|
||||
{
|
||||
view = value;
|
||||
dirtyFlags |= EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.EyePosition;
|
||||
dirtyFlags |= EffectDirtyFlags.ViewProj | EffectDirtyFlags.EyePosition;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +74,7 @@ namespace Kav
|
|||
set
|
||||
{
|
||||
projection = value;
|
||||
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||
dirtyFlags |= EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +115,7 @@ namespace Kav
|
|||
{
|
||||
albedoTextureParam.SetValue(value);
|
||||
albedoTextureEnabled = value != null;
|
||||
dirtyFlags |= EffectDirtyFlags.ShaderIndex;
|
||||
dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,7 +126,7 @@ namespace Kav
|
|||
{
|
||||
normalTextureParam.SetValue(value);
|
||||
normalMapEnabled = value != null;
|
||||
dirtyFlags |= EffectDirtyFlags.ShaderIndex;
|
||||
dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,7 +137,70 @@ namespace Kav
|
|||
{
|
||||
metallicRoughnessTextureParam.SetValue(value);
|
||||
metallicRoughnessMapEnabled = value != null;
|
||||
dirtyFlags |= EffectDirtyFlags.ShaderIndex;
|
||||
dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public int NumTextureRows
|
||||
{
|
||||
get { return numTextureRows; }
|
||||
set
|
||||
{
|
||||
numTextureRows = value;
|
||||
numTextureRowsParam.SetValue(numTextureRows);
|
||||
}
|
||||
}
|
||||
|
||||
public int NumTextureColumns
|
||||
{
|
||||
get { return numTextureColumns; }
|
||||
set
|
||||
{
|
||||
numTextureColumns = value;
|
||||
numTextureColumnsParam.SetValue(numTextureColumns);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 UVOffset
|
||||
{
|
||||
get { return uvOffset; }
|
||||
set
|
||||
{
|
||||
uvOffset = value;
|
||||
dirtyFlags |= EffectDirtyFlags.UVOrDimensions;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 SubTextureDimensions
|
||||
{
|
||||
get { return subTextureDimensions; }
|
||||
set
|
||||
{
|
||||
subTextureDimensions = value;
|
||||
dirtyFlags |= EffectDirtyFlags.UVOrDimensions;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSprite
|
||||
{
|
||||
get { return isSprite; }
|
||||
set
|
||||
{
|
||||
isSprite = value;
|
||||
isSpriteParam.SetValue(isSprite ? 1f : 0f);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HardwareInstancingEnabled
|
||||
{
|
||||
get { return hardwareInstancingEnabled; }
|
||||
set
|
||||
{
|
||||
if (value != hardwareInstancingEnabled)
|
||||
{
|
||||
hardwareInstancingEnabled = value;
|
||||
dirtyFlags |= EffectDirtyFlags.VertexShaderIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,30 +237,40 @@ namespace Kav
|
|||
{
|
||||
worldParam.SetValue(world);
|
||||
|
||||
Matrix.Invert(ref world, out Matrix worldInverse);
|
||||
Matrix.Transpose(ref worldInverse, out Matrix worldInverseTranspose);
|
||||
worldInverseTransposeParam.SetValue(worldInverseTranspose);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.World;
|
||||
}
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
|
||||
if ((dirtyFlags & EffectDirtyFlags.ViewProj) != 0)
|
||||
{
|
||||
Matrix.Multiply(ref world, ref view, out Matrix worldView);
|
||||
Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj);
|
||||
worldViewProjectionParam.SetValue(worldViewProj);
|
||||
Matrix.Multiply(ref view, ref projection, out Matrix viewProj);
|
||||
viewProjectionParam.SetValue(viewProj);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
|
||||
dirtyFlags &= ~EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.EyePosition) != 0)
|
||||
if ((dirtyFlags & EffectDirtyFlags.UVOrDimensions) != 0)
|
||||
{
|
||||
Matrix.Invert(ref view, out Matrix inverseView);
|
||||
uvOffsetAndDimensionsParam.SetValue(new Vector4(
|
||||
UVOffset.X, UVOffset.Y,
|
||||
SubTextureDimensions.X, SubTextureDimensions.Y
|
||||
));
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.EyePosition;
|
||||
dirtyFlags &= ~EffectDirtyFlags.UVOrDimensions;
|
||||
}
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0)
|
||||
if ((dirtyFlags & EffectDirtyFlags.VertexShaderIndex) != 0)
|
||||
{
|
||||
int vertexShaderIndex = 0;
|
||||
|
||||
if (hardwareInstancingEnabled)
|
||||
{
|
||||
vertexShaderIndex = 1;
|
||||
}
|
||||
|
||||
vertexShaderIndexParam.SetValue(vertexShaderIndex);
|
||||
}
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.PixelShaderIndex) != 0)
|
||||
{
|
||||
int shaderIndex = 0;
|
||||
|
||||
|
@ -217,15 +305,14 @@ namespace Kav
|
|||
|
||||
shaderIndexParam.SetValue(shaderIndex);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.ShaderIndex;
|
||||
dirtyFlags &= ~EffectDirtyFlags.PixelShaderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
void CacheEffectParameters()
|
||||
{
|
||||
worldParam = Parameters["World"];
|
||||
worldViewProjectionParam = Parameters["WorldViewProjection"];
|
||||
worldInverseTransposeParam = Parameters["WorldInverseTranspose"];
|
||||
viewProjectionParam = Parameters["ViewProjection"];
|
||||
|
||||
albedoTextureParam = Parameters["AlbedoTexture"];
|
||||
normalTextureParam = Parameters["NormalTexture"];
|
||||
|
@ -235,7 +322,14 @@ namespace Kav
|
|||
metallicParam = Parameters["MetallicValue"];
|
||||
roughnessParam = Parameters["RoughnessValue"];
|
||||
|
||||
shaderIndexParam = Parameters["ShaderIndex"];
|
||||
numTextureRowsParam = Parameters["NumTextureRows"];
|
||||
numTextureColumnsParam = Parameters["NumTextureColumns"];
|
||||
|
||||
uvOffsetAndDimensionsParam = Parameters["UVOffsetAndDimensions"];
|
||||
isSpriteParam = Parameters["IsSprite"];
|
||||
|
||||
shaderIndexParam = Parameters["PixelShaderIndex"];
|
||||
vertexShaderIndexParam = Parameters["VertexShaderIndex"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class DeferredPBR_PointLightEffect : Effect
|
||||
{
|
||||
EffectParameter gPositionParam;
|
||||
EffectParameter gAlbedoParam;
|
||||
EffectParameter gNormalParam;
|
||||
EffectParameter gMetallicRoughnessParam;
|
||||
EffectParameter shadowMapParam;
|
||||
|
||||
EffectParameter eyePositionParam;
|
||||
|
||||
EffectParameter pointLightColorParam;
|
||||
EffectParameter pointLightPositionParam;
|
||||
|
||||
EffectParameter farPlaneParam;
|
||||
|
||||
EffectParameter worldViewProjectionParam;
|
||||
|
||||
public Texture2D GPosition { get; set; }
|
||||
public Texture2D GAlbedo { get; set; }
|
||||
public Texture2D GNormal { get; set; }
|
||||
public Texture2D GMetallicRoughness { get; set; }
|
||||
public TextureCube ShadowMap { get; set; }
|
||||
|
||||
public Vector3 EyePosition { get; set; }
|
||||
|
||||
public Vector3 PointLightPosition { get; set; }
|
||||
public Vector3 PointLightColor { get; set; }
|
||||
|
||||
public float FarPlane { get; set; }
|
||||
|
||||
Matrix world = Matrix.Identity;
|
||||
Matrix view = Matrix.Identity;
|
||||
Matrix projection = Matrix.Identity;
|
||||
|
||||
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
|
||||
|
||||
public Matrix World
|
||||
{
|
||||
get { return world; }
|
||||
set
|
||||
{
|
||||
world = value;
|
||||
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 DeferredPBR_PointLightEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBR_PointLightEffect)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
}
|
||||
|
||||
public DeferredPBR_PointLightEffect(DeferredPBR_PointLightEffect cloneSource) : base(cloneSource)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
|
||||
GPosition = cloneSource.GPosition;
|
||||
GAlbedo = cloneSource.GAlbedo;
|
||||
GNormal = cloneSource.GNormal;
|
||||
GMetallicRoughness = cloneSource.GMetallicRoughness;
|
||||
ShadowMap = cloneSource.ShadowMap;
|
||||
|
||||
EyePosition = cloneSource.EyePosition;
|
||||
|
||||
PointLightPosition = cloneSource.PointLightPosition;
|
||||
PointLightColor = cloneSource.PointLightColor;
|
||||
|
||||
FarPlane = cloneSource.FarPlane;
|
||||
}
|
||||
|
||||
public override Effect Clone()
|
||||
{
|
||||
return new DeferredPBR_PointLightEffect(this);
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
{
|
||||
gPositionParam.SetValue(GPosition);
|
||||
gAlbedoParam.SetValue(GAlbedo);
|
||||
gNormalParam.SetValue(GNormal);
|
||||
gMetallicRoughnessParam.SetValue(GMetallicRoughness);
|
||||
shadowMapParam.SetValue(ShadowMap);
|
||||
|
||||
eyePositionParam.SetValue(EyePosition);
|
||||
|
||||
pointLightPositionParam.SetValue(PointLightPosition);
|
||||
pointLightColorParam.SetValue(PointLightColor);
|
||||
|
||||
farPlaneParam.SetValue(FarPlane);
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
|
||||
{
|
||||
worldViewProjectionParam.SetValue(world * view * projection);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
void CacheEffectParameters()
|
||||
{
|
||||
gPositionParam = Parameters["gPosition"];
|
||||
gAlbedoParam = Parameters["gAlbedo"];
|
||||
gNormalParam = Parameters["gNormal"];
|
||||
gMetallicRoughnessParam = Parameters["gMetallicRoughness"];
|
||||
shadowMapParam = Parameters["shadowMap"];
|
||||
|
||||
eyePositionParam = Parameters["EyePosition"];
|
||||
|
||||
pointLightPositionParam = Parameters["PointLightPosition"];
|
||||
pointLightColorParam = Parameters["PointLightColor"];
|
||||
|
||||
farPlaneParam = Parameters["FarPlane"];
|
||||
|
||||
worldViewProjectionParam = Parameters["WorldViewProjection"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
using Kav.Data;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class DiffuseLitSpriteEffect : Effect
|
||||
{
|
||||
EffectParameter ambientColorParam;
|
||||
|
||||
EffectParameter directionalLightDirectionParam;
|
||||
EffectParameter directionalLightColorParam;
|
||||
|
||||
EffectParameter uvOffsetAndDimensionsParam;
|
||||
|
||||
EffectParameter worldParam;
|
||||
EffectParameter worldViewProjectionParam;
|
||||
EffectParameter worldInverseTransposeParam;
|
||||
|
||||
EffectParameter shaderIndexParam;
|
||||
|
||||
Texture2D texture;
|
||||
Texture2D normal;
|
||||
|
||||
bool normalMapEnabled = false;
|
||||
|
||||
Vector3 ambientColor;
|
||||
|
||||
Vector3 directionalLightDirection;
|
||||
Vector3 directionalLightColor;
|
||||
|
||||
Matrix world = Matrix.Identity;
|
||||
Matrix view = Matrix.Identity;
|
||||
Matrix projection = Matrix.Identity;
|
||||
|
||||
Vector2 uvOffset;
|
||||
Vector2 subTextureDimensions;
|
||||
|
||||
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
|
||||
|
||||
public bool NormalMapEnabled
|
||||
{
|
||||
get { return normalMapEnabled; }
|
||||
set
|
||||
{
|
||||
if (normalMapEnabled != value)
|
||||
{
|
||||
normalMapEnabled = value;
|
||||
dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix World
|
||||
{
|
||||
get { return world; }
|
||||
set
|
||||
{
|
||||
world = value;
|
||||
dirtyFlags |= EffectDirtyFlags.World | EffectDirtyFlags.WorldViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix View
|
||||
{
|
||||
get { return view; }
|
||||
set
|
||||
{
|
||||
view = value;
|
||||
dirtyFlags |= EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.EyePosition;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix Projection
|
||||
{
|
||||
get { return projection; }
|
||||
set
|
||||
{
|
||||
projection = value;
|
||||
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
public int MaxPointLights { get; } = 8;
|
||||
|
||||
public Vector3 AmbientColor
|
||||
{
|
||||
get { return ambientColor; }
|
||||
set
|
||||
{
|
||||
ambientColor = value;
|
||||
ambientColorParam.SetValue(ambientColor);
|
||||
}
|
||||
}
|
||||
|
||||
public PointLightCollection PointLights { get; private set; }
|
||||
|
||||
public Vector3 DirectionalLightDirection
|
||||
{
|
||||
get { return directionalLightDirection; }
|
||||
set
|
||||
{
|
||||
directionalLightDirection = value;
|
||||
directionalLightDirectionParam.SetValue(directionalLightDirection);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 DirectionalLightColor
|
||||
{
|
||||
get { return directionalLightColor; }
|
||||
set
|
||||
{
|
||||
directionalLightColor = value;
|
||||
directionalLightColorParam.SetValue(directionalLightColor);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 UVOffset
|
||||
{
|
||||
get { return uvOffset; }
|
||||
set
|
||||
{
|
||||
uvOffset = value;
|
||||
dirtyFlags |= EffectDirtyFlags.UVOrDimensions;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 SubTextureDimensions
|
||||
{
|
||||
get { return subTextureDimensions; }
|
||||
set
|
||||
{
|
||||
subTextureDimensions = value;
|
||||
dirtyFlags |= EffectDirtyFlags.UVOrDimensions;
|
||||
}
|
||||
}
|
||||
|
||||
public DiffuseLitSpriteEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DiffuseLitSpriteEffect)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
|
||||
PointLights = new PointLightCollection(
|
||||
Parameters["PointLightPositions"],
|
||||
Parameters["PointLightColors"],
|
||||
MaxPointLights
|
||||
);
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
{
|
||||
if ((dirtyFlags & EffectDirtyFlags.World) != 0)
|
||||
{
|
||||
worldParam.SetValue(world);
|
||||
|
||||
Matrix.Invert(ref world, out Matrix worldInverse);
|
||||
Matrix.Transpose(ref worldInverse, out Matrix worldInverseTranspose);
|
||||
worldInverseTransposeParam.SetValue(worldInverseTranspose);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.World;
|
||||
}
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
|
||||
{
|
||||
Matrix.Multiply(ref world, ref view, out Matrix worldView);
|
||||
Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj);
|
||||
worldViewProjectionParam.SetValue(worldViewProj);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
|
||||
}
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.UVOrDimensions) != 0)
|
||||
{
|
||||
uvOffsetAndDimensionsParam.SetValue(new Vector4(
|
||||
UVOffset.X, UVOffset.Y,
|
||||
SubTextureDimensions.X, SubTextureDimensions.Y
|
||||
));
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.UVOrDimensions;
|
||||
}
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.PixelShaderIndex) != 0)
|
||||
{
|
||||
int shaderIndex = 0;
|
||||
|
||||
if (normalMapEnabled)
|
||||
{
|
||||
shaderIndex = 1;
|
||||
}
|
||||
|
||||
shaderIndexParam.SetValue(shaderIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void CacheEffectParameters()
|
||||
{
|
||||
worldParam = Parameters["World"];
|
||||
worldViewProjectionParam = Parameters["WorldViewProjection"];
|
||||
worldInverseTransposeParam = Parameters["WorldInverseTranspose"];
|
||||
|
||||
ambientColorParam = Parameters["AmbientColor"];
|
||||
|
||||
directionalLightDirectionParam = Parameters["DirectionalLightDirection"];
|
||||
directionalLightColorParam = Parameters["DirectionalLightColor"];
|
||||
|
||||
uvOffsetAndDimensionsParam = Parameters["UVOffsetAndDimensions"];
|
||||
|
||||
shaderIndexParam = Parameters["ShaderIndex"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class DirectionalLightCollection
|
||||
{
|
||||
private readonly Vector3[] directions = new Vector3[4];
|
||||
private readonly Vector3[] colors = new Vector3[4];
|
||||
private readonly float[] intensities = new float[4];
|
||||
|
||||
readonly EffectParameter lightDirectionsParam;
|
||||
readonly EffectParameter lightColorsParam;
|
||||
|
||||
public DirectionalLightCollection(EffectParameter lightDirectionsParam, EffectParameter lightColorsParam)
|
||||
{
|
||||
this.lightDirectionsParam = lightDirectionsParam;
|
||||
this.lightColorsParam = lightColorsParam;
|
||||
}
|
||||
|
||||
public DirectionalLight this[int i]
|
||||
{
|
||||
get
|
||||
{
|
||||
var color = colors[i] / intensities[i];
|
||||
return new DirectionalLight(
|
||||
directions[i],
|
||||
new Color(
|
||||
color.X,
|
||||
color.Y,
|
||||
color.Z,
|
||||
1f
|
||||
),
|
||||
intensities[i]
|
||||
);
|
||||
}
|
||||
set
|
||||
{
|
||||
directions[i] = value.Direction;
|
||||
colors[i] = value.Color.ToVector3() * value.Intensity;
|
||||
intensities[i] = value.Intensity;
|
||||
lightDirectionsParam.SetValue(directions);
|
||||
lightColorsParam.SetValue(colors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,10 @@ namespace Kav
|
|||
WorldViewProj = 1,
|
||||
World = 2,
|
||||
EyePosition = 4,
|
||||
ShaderIndex = 8,
|
||||
VertexShaderIndex = 8,
|
||||
PixelShaderIndex = 16,
|
||||
ViewProj = 32,
|
||||
UVOrDimensions = 64,
|
||||
All = -1
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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;
|
||||
}
|
|
@ -2,12 +2,16 @@
|
|||
|
||||
static const float PI = 3.141592653589793;
|
||||
static const int MAX_POINT_LIGHTS = 64;
|
||||
static const int MAX_DIRECTIONAL_LIGHTS = 4;
|
||||
static const int NUM_SHADOW_CASCADES = 4;
|
||||
|
||||
DECLARE_TEXTURE(gPosition, 0);
|
||||
DECLARE_TEXTURE(gAlbedo, 1);
|
||||
DECLARE_TEXTURE(gNormal, 2);
|
||||
DECLARE_TEXTURE(gMetallicRoughness, 3);
|
||||
DECLARE_TEXTURE(shadowMapOne, 4);
|
||||
DECLARE_TEXTURE(shadowMapTwo, 5);
|
||||
DECLARE_TEXTURE(shadowMapThree, 6);
|
||||
DECLARE_TEXTURE(shadowMapFour, 7);
|
||||
|
||||
BEGIN_CONSTANTS
|
||||
|
||||
|
@ -16,19 +20,45 @@ BEGIN_CONSTANTS
|
|||
float3 PointLightPositions[MAX_POINT_LIGHTS] _ps(c1) _cb(c1);
|
||||
float3 PointLightColors[MAX_POINT_LIGHTS] _ps(c65) _cb(c65);
|
||||
|
||||
float3 DirectionalLightDirections[MAX_DIRECTIONAL_LIGHTS] _ps(c129) _cb(c129);
|
||||
float3 DirectionalLightColors[MAX_DIRECTIONAL_LIGHTS] _ps(c133) _cb(c133);
|
||||
float3 DirectionalLightDirection _ps(c129) _cb(c129);
|
||||
float3 DirectionalLightColor _ps(c130) _cb(c130);
|
||||
|
||||
float CascadeFarPlanes[NUM_SHADOW_CASCADES] _ps(c131) _cb(c131);
|
||||
|
||||
MATRIX_CONSTANTS
|
||||
|
||||
float4x4 LightSpaceMatrixOne _ps(c135) _cb(c135);
|
||||
float4x4 LightSpaceMatrixTwo _ps(c139) _cb(c139);
|
||||
float4x4 LightSpaceMatrixThree _ps(c143) _cb(c143);
|
||||
float4x4 LightSpaceMatrixFour _ps(c147) _cb(c147);
|
||||
|
||||
// used to select shadow cascade
|
||||
float4x4 ViewMatrix _ps(c151) _cb(c151);
|
||||
|
||||
END_CONSTANTS
|
||||
|
||||
struct VertexInput
|
||||
{
|
||||
float4 Position : POSITION;
|
||||
float2 TexCoord : TEXCOORD;
|
||||
};
|
||||
|
||||
struct PixelInput
|
||||
{
|
||||
float4 Position : SV_POSITION;
|
||||
float2 TexCoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
PixelInput main_vs(VertexInput input)
|
||||
{
|
||||
PixelInput output;
|
||||
|
||||
output.Position = input.Position;
|
||||
output.TexCoord = input.TexCoord;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// Pixel Shader
|
||||
|
||||
float3 FresnelSchlick(float cosTheta, float3 F0)
|
||||
|
@ -71,17 +101,119 @@ float GeometrySmith(float3 N, float3 V, float3 L, float roughness)
|
|||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
float ComputeShadow(float3 positionWorldSpace, float3 N, float L)
|
||||
{
|
||||
float bias = 0.005 * tan(acos(dot(N, L)));
|
||||
bias = clamp(bias, 0, 0.01);
|
||||
|
||||
float4 positionCameraSpace = mul(float4(positionWorldSpace, 1.0), ViewMatrix);
|
||||
|
||||
int shadowCascadeIndex = 0; // 0 is closest
|
||||
for (int i = 0; i < NUM_SHADOW_CASCADES; i++)
|
||||
{
|
||||
if (abs(positionCameraSpace.z) < CascadeFarPlanes[i])
|
||||
{
|
||||
shadowCascadeIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float4x4 lightSpaceMatrix;
|
||||
|
||||
if (shadowCascadeIndex == 0)
|
||||
{
|
||||
lightSpaceMatrix = LightSpaceMatrixOne;
|
||||
}
|
||||
else if (shadowCascadeIndex == 1)
|
||||
{
|
||||
lightSpaceMatrix = LightSpaceMatrixTwo;
|
||||
}
|
||||
else if (shadowCascadeIndex == 2)
|
||||
{
|
||||
lightSpaceMatrix = LightSpaceMatrixThree;
|
||||
}
|
||||
else
|
||||
{
|
||||
lightSpaceMatrix = LightSpaceMatrixFour;
|
||||
}
|
||||
|
||||
float4 positionLightSpace = mul(float4(positionWorldSpace, 1.0), lightSpaceMatrix);
|
||||
|
||||
// maps to [-1, 1]
|
||||
float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w;
|
||||
|
||||
// maps to [0, 1]
|
||||
projectionCoords.x = (projectionCoords.x * 0.5) + 0.5;
|
||||
projectionCoords.y = (projectionCoords.y * 0.5) + 0.5;
|
||||
projectionCoords.y *= -1;
|
||||
// in XNA clip z is 0 to 1 already
|
||||
|
||||
float inc = 1.0 / 1024.0;
|
||||
|
||||
float shadowFactor = 0;
|
||||
for (int row = -1; row <= 1; row++)
|
||||
{
|
||||
for (int col = -1; col <= 1; col++)
|
||||
{
|
||||
float closestDepth;
|
||||
if (shadowCascadeIndex == 0)
|
||||
{
|
||||
closestDepth = SAMPLE_TEXTURE(shadowMapOne, projectionCoords.xy + float2(row, col) * inc).r;
|
||||
}
|
||||
else if (shadowCascadeIndex == 1)
|
||||
{
|
||||
closestDepth = SAMPLE_TEXTURE(shadowMapTwo, projectionCoords.xy + float2(row, col) * inc).r;
|
||||
}
|
||||
else if (shadowCascadeIndex == 2)
|
||||
{
|
||||
closestDepth = SAMPLE_TEXTURE(shadowMapThree, projectionCoords.xy + float2(row, col) * inc).r;
|
||||
}
|
||||
else
|
||||
{
|
||||
closestDepth = SAMPLE_TEXTURE(shadowMapFour, projectionCoords.xy + float2(row, col) * inc).r;
|
||||
}
|
||||
shadowFactor += projectionCoords.z - bias > closestDepth ? 1.0 : 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
shadowFactor /= 9.0;
|
||||
|
||||
if (projectionCoords.z > 1.0)
|
||||
{
|
||||
shadowFactor = 1.0;
|
||||
}
|
||||
|
||||
return shadowFactor;
|
||||
|
||||
|
||||
// float currentDepth = projectionCoords.z;
|
||||
|
||||
// if (currentDepth > 1.0)
|
||||
// {
|
||||
// return 0.0;
|
||||
// }
|
||||
|
||||
// if (currentDepth - bias > closestDepth)
|
||||
// {
|
||||
// return 1.0;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return 0.0;
|
||||
// }
|
||||
}
|
||||
|
||||
float3 ComputeLight(
|
||||
float3 lightDir,
|
||||
float3 L,
|
||||
float3 radiance,
|
||||
float3 F0,
|
||||
float3 V,
|
||||
float3 N,
|
||||
float3 albedo,
|
||||
float metallic,
|
||||
float roughness
|
||||
float roughness,
|
||||
float shadow
|
||||
) {
|
||||
float3 L = normalize(lightDir);
|
||||
float3 H = normalize(V + L);
|
||||
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
|
@ -98,7 +230,7 @@ float3 ComputeLight(
|
|||
kD *= 1.0 - metallic;
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
return (kD * albedo / PI + specular) * radiance * NdotL;
|
||||
return (kD * albedo / PI + specular) * radiance * NdotL * shadow;
|
||||
}
|
||||
|
||||
float4 ComputeColor(
|
||||
|
@ -120,21 +252,20 @@ float4 ComputeColor(
|
|||
for (int i = 0; i < MAX_POINT_LIGHTS; i++)
|
||||
{
|
||||
float3 lightDir = PointLightPositions[i] - worldPosition;
|
||||
float3 L = normalize(lightDir);
|
||||
float distance = length(lightDir);
|
||||
float attenuation = 1.0 / (distance * distance);
|
||||
float3 radiance = PointLightColors[i] * attenuation;
|
||||
|
||||
Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness);
|
||||
Lo += ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, 1.0);
|
||||
}
|
||||
|
||||
// directional light
|
||||
for (int i = 0; i < MAX_DIRECTIONAL_LIGHTS; i++)
|
||||
{
|
||||
float3 lightDir = DirectionalLightDirections[i];
|
||||
float3 radiance = DirectionalLightColors[i];
|
||||
float3 L = normalize(DirectionalLightDirection);
|
||||
float3 radiance = DirectionalLightColor;
|
||||
|
||||
Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness);
|
||||
}
|
||||
float shadow = ComputeShadow(worldPosition, N, L);
|
||||
Lo += ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, (1.0 - shadow));
|
||||
|
||||
float3 ambient = float3(0.03, 0.03, 0.03) * albedo; // * AO;
|
||||
float3 color = ambient + Lo;
|
||||
|
@ -148,13 +279,13 @@ float4 ComputeColor(
|
|||
|
||||
float4 main_ps(PixelInput input) : SV_TARGET0
|
||||
{
|
||||
float3 fragPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb;
|
||||
float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb;
|
||||
float3 normal = SAMPLE_TEXTURE(gNormal, input.TexCoord).xyz;
|
||||
float3 albedo = SAMPLE_TEXTURE(gAlbedo, input.TexCoord).rgb;
|
||||
float2 metallicRoughness = SAMPLE_TEXTURE(gMetallicRoughness, input.TexCoord).rg;
|
||||
|
||||
return ComputeColor(
|
||||
fragPosition,
|
||||
worldPosition,
|
||||
normal,
|
||||
albedo,
|
||||
metallicRoughness.r,
|
||||
|
@ -166,6 +297,7 @@ Technique DeferredPBR
|
|||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
#include "Macros.fxh" // from FNA
|
||||
|
||||
DECLARE_TEXTURE(gPosition, 0);
|
||||
DECLARE_TEXTURE(gAlbedo, 1);
|
||||
|
||||
BEGIN_CONSTANTS
|
||||
|
||||
float3 AmbientLightColor _ps(c0) _cb(c0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
float4 ComputeColor(
|
||||
float3 worldPosition,
|
||||
float3 albedo
|
||||
) {
|
||||
float3 color = AmbientLightColor * albedo;
|
||||
return float4(color, 1.0);
|
||||
}
|
||||
|
||||
float4 main_ps(PixelInput input) : SV_TARGET0
|
||||
{
|
||||
float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb;
|
||||
float3 albedo = SAMPLE_TEXTURE(gAlbedo, input.TexCoord).rgb;
|
||||
|
||||
return ComputeColor(
|
||||
worldPosition,
|
||||
albedo
|
||||
);
|
||||
}
|
||||
|
||||
Technique DeferredPBR_Ambient
|
||||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
#include "Macros.fxh" //from FNA
|
||||
#include "Lighting.fxh"
|
||||
#include "Shadow.fxh"
|
||||
|
||||
static const int NUM_SHADOW_CASCADES = 4;
|
||||
|
||||
DECLARE_TEXTURE(gPosition, 0);
|
||||
DECLARE_TEXTURE(gAlbedo, 1);
|
||||
DECLARE_TEXTURE(gNormal, 2);
|
||||
DECLARE_TEXTURE(gMetallicRoughness, 3);
|
||||
DECLARE_TEXTURE(shadowMapOne, 4);
|
||||
DECLARE_TEXTURE(shadowMapTwo, 5);
|
||||
DECLARE_TEXTURE(shadowMapThree, 6);
|
||||
DECLARE_TEXTURE(shadowMapFour, 7);
|
||||
|
||||
BEGIN_CONSTANTS
|
||||
|
||||
float3 EyePosition _ps(c0) _cb(c0);
|
||||
|
||||
float3 DirectionalLightDirection _ps(c1) _cb(c1);
|
||||
float3 DirectionalLightColor _ps(c2) _cb(c2);
|
||||
|
||||
float CascadeFarPlanes[NUM_SHADOW_CASCADES] _ps(c3) _cb(c3);
|
||||
|
||||
float ShadowMapSize _ps(c7) _cb(c7);
|
||||
|
||||
MATRIX_CONSTANTS
|
||||
|
||||
float4x4 LightSpaceMatrixOne _ps(c8) _cb(c8);
|
||||
float4x4 LightSpaceMatrixTwo _ps(c12) _cb(c12);
|
||||
float4x4 LightSpaceMatrixThree _ps(c16) _cb(c16);
|
||||
float4x4 LightSpaceMatrixFour _ps(c20) _cb(c20);
|
||||
|
||||
// used to select shadow cascade
|
||||
float4x4 ViewMatrix _ps(c24) _cb(c24);
|
||||
|
||||
END_CONSTANTS
|
||||
|
||||
struct VertexInput
|
||||
{
|
||||
float4 Position : POSITION;
|
||||
float2 TexCoord : TEXCOORD;
|
||||
};
|
||||
|
||||
struct PixelInput
|
||||
{
|
||||
float4 Position : SV_POSITION;
|
||||
float2 TexCoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
PixelInput main_vs(VertexInput input)
|
||||
{
|
||||
PixelInput output;
|
||||
|
||||
output.Position = input.Position;
|
||||
output.TexCoord = input.TexCoord;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// Pixel Shader
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// PCF + Poisson soft shadows
|
||||
|
||||
if (shadowCascadeIndex == 0)
|
||||
{
|
||||
return PoissonShadow(
|
||||
positionWorldSpace,
|
||||
N,
|
||||
L,
|
||||
lightSpaceMatrix,
|
||||
SAMPLER(shadowMapOne),
|
||||
ShadowMapSize
|
||||
);
|
||||
}
|
||||
else if (shadowCascadeIndex == 1)
|
||||
{
|
||||
return PoissonShadow(
|
||||
positionWorldSpace,
|
||||
N,
|
||||
L,
|
||||
lightSpaceMatrix,
|
||||
SAMPLER(shadowMapTwo),
|
||||
ShadowMapSize
|
||||
);
|
||||
}
|
||||
else if (shadowCascadeIndex == 2)
|
||||
{
|
||||
return PoissonShadow(
|
||||
positionWorldSpace,
|
||||
N,
|
||||
L,
|
||||
lightSpaceMatrix,
|
||||
SAMPLER(shadowMapThree),
|
||||
ShadowMapSize
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return PoissonShadow(
|
||||
positionWorldSpace,
|
||||
N,
|
||||
L,
|
||||
lightSpaceMatrix,
|
||||
SAMPLER(shadowMapFour),
|
||||
ShadowMapSize
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
float4 ComputeColor(
|
||||
float3 worldPosition,
|
||||
float3 worldNormal,
|
||||
float3 albedo,
|
||||
float metallic,
|
||||
float roughness
|
||||
) {
|
||||
float3 V = normalize(EyePosition - worldPosition);
|
||||
float3 N = normalize(worldNormal);
|
||||
|
||||
float3 F0 = float3(0.04, 0.04, 0.04);
|
||||
F0 = lerp(F0, albedo, metallic);
|
||||
|
||||
float3 L = normalize(DirectionalLightDirection);
|
||||
float3 radiance = DirectionalLightColor;
|
||||
|
||||
float shadow = ComputeShadow(worldPosition, N, L);
|
||||
float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, shadow);
|
||||
|
||||
return float4(color, 1.0);
|
||||
}
|
||||
|
||||
float4 main_ps(PixelInput input) : SV_TARGET0
|
||||
{
|
||||
float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb;
|
||||
float3 normal = SAMPLE_TEXTURE(gNormal, input.TexCoord).xyz;
|
||||
float3 albedo = SAMPLE_TEXTURE(gAlbedo, input.TexCoord).rgb;
|
||||
float2 metallicRoughness = SAMPLE_TEXTURE(gMetallicRoughness, input.TexCoord).rg;
|
||||
|
||||
return ComputeColor(
|
||||
worldPosition,
|
||||
normal,
|
||||
albedo,
|
||||
metallicRoughness.r,
|
||||
metallicRoughness.g
|
||||
);
|
||||
}
|
||||
|
||||
Technique DeferredPBR_Directional
|
||||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -4,17 +4,22 @@ DECLARE_TEXTURE(AlbedoTexture, 0);
|
|||
DECLARE_TEXTURE(NormalTexture, 1);
|
||||
DECLARE_TEXTURE(MetallicRoughnessTexture, 2);
|
||||
|
||||
float4 UVOffsetAndDimensions;
|
||||
float IsSprite;
|
||||
|
||||
BEGIN_CONSTANTS
|
||||
|
||||
float3 AlbedoValue _ps(c0) _cb(c0);
|
||||
float MetallicValue _ps(c1) _cb(c1);
|
||||
float RoughnessValue _ps(c2) _cb(c2);
|
||||
|
||||
int NumTextureRows _vs(c9) _cb(c3);
|
||||
int NumTextureColumns _vs(c10) _cb(c4);
|
||||
|
||||
MATRIX_CONSTANTS
|
||||
|
||||
float4x4 World _vs(c0) _cb(c7);
|
||||
float4x4 WorldInverseTranspose _vs(c4) _cb(c11);
|
||||
float4x4 WorldViewProjection _vs(c8) _cb(c15);
|
||||
float4x4 ViewProjection _vs(c4) _cb(c11);
|
||||
|
||||
END_CONSTANTS
|
||||
|
||||
|
@ -22,7 +27,7 @@ struct VertexInput
|
|||
{
|
||||
float4 Position : POSITION;
|
||||
float3 Normal : NORMAL;
|
||||
float2 TexCoord : TEXCOORD0;
|
||||
float2 TexCoord : TEXCOORD;
|
||||
};
|
||||
|
||||
struct PixelInput
|
||||
|
@ -48,9 +53,44 @@ PixelInput main_vs(VertexInput input)
|
|||
PixelInput output;
|
||||
|
||||
output.PositionWorld = mul(input.Position, World).xyz;
|
||||
output.NormalWorld = mul(input.Normal, (float3x3)WorldInverseTranspose).xyz;
|
||||
output.TexCoord = input.TexCoord;
|
||||
output.Position = mul(input.Position, WorldViewProjection);
|
||||
output.NormalWorld = normalize(mul(input.Normal, World));
|
||||
|
||||
float2 texCoord;
|
||||
texCoord.x = (input.TexCoord.x * UVOffsetAndDimensions.z) + UVOffsetAndDimensions.x;
|
||||
texCoord.y = (input.TexCoord.y * UVOffsetAndDimensions.w) + UVOffsetAndDimensions.y;
|
||||
output.TexCoord = texCoord;
|
||||
|
||||
float4x4 worldViewProjection = mul(World, ViewProjection);
|
||||
output.Position = mul(input.Position, worldViewProjection);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PixelInput instanced_vs(
|
||||
VertexInput input,
|
||||
float3 Translation : TEXCOORD2,
|
||||
float2 UVOffset : TEXCOORD5
|
||||
) {
|
||||
PixelInput output;
|
||||
|
||||
float4x4 world = float4x4(
|
||||
float4(1, 0, 0, 0),
|
||||
float4(0, 1, 0, 0),
|
||||
float4(0, 0, 1, 0),
|
||||
float4(Translation.x, Translation.y, Translation.z, 1)
|
||||
);
|
||||
|
||||
float4x4 worldViewProjection = mul(world, ViewProjection);
|
||||
|
||||
output.PositionWorld = mul(input.Position, world);
|
||||
output.NormalWorld = mul(input.Normal, world);
|
||||
|
||||
float2 texCoord;
|
||||
texCoord.x = (input.TexCoord.x / NumTextureColumns + UVOffset.x);
|
||||
texCoord.y = (input.TexCoord.y / NumTextureRows + UVOffset.y);
|
||||
output.TexCoord = texCoord;
|
||||
|
||||
output.Position = mul(input.Position, worldViewProjection);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -79,10 +119,10 @@ PixelOutput NonePS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), IsSprite);
|
||||
output.gAlbedo = float4(AlbedoValue, 1.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 0.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 1.0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -91,10 +131,12 @@ PixelOutput AlbedoPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), IsSprite);
|
||||
output.gAlbedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 0.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 1.0);
|
||||
|
||||
if (output.gAlbedo.a == 0.0) { discard; }
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -103,8 +145,8 @@ PixelOutput MetallicRoughnessPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), IsSprite);
|
||||
output.gAlbedo = float4(AlbedoValue, 1.0);
|
||||
output.gMetallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord);
|
||||
|
||||
|
@ -115,10 +157,10 @@ PixelOutput NormalPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), IsSprite);
|
||||
output.gAlbedo = float4(AlbedoValue, 1.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 0.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 1.0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -127,11 +169,13 @@ PixelOutput AlbedoMetallicRoughnessPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(normalize(input.NormalWorld), IsSprite);
|
||||
output.gAlbedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord);
|
||||
output.gMetallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord);
|
||||
|
||||
if (output.gAlbedo.a == 0.0) { discard; }
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
@ -139,10 +183,12 @@ PixelOutput AlbedoNormalPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), IsSprite);
|
||||
output.gAlbedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 0.0);
|
||||
output.gMetallicRoughness = float4(MetallicValue, RoughnessValue, 0.0, 1.0);
|
||||
|
||||
if (output.gAlbedo.a == 0.0) { discard; }
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@ -151,8 +197,8 @@ PixelOutput MetallicRoughnessNormalPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), IsSprite);
|
||||
output.gAlbedo = float4(AlbedoValue, 1.0);
|
||||
output.gMetallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord);
|
||||
|
||||
|
@ -163,14 +209,29 @@ PixelOutput AlbedoMetallicRoughnessNormalMapPS(PixelInput input)
|
|||
{
|
||||
PixelOutput output;
|
||||
|
||||
output.gPosition = float4(input.PositionWorld, 0.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), 0.0);
|
||||
output.gPosition = float4(input.PositionWorld, 1.0);
|
||||
output.gNormal = float4(GetNormalFromMap(input.PositionWorld, input.TexCoord, input.NormalWorld), IsSprite);
|
||||
output.gAlbedo = SAMPLE_TEXTURE(AlbedoTexture, input.TexCoord);
|
||||
output.gMetallicRoughness = SAMPLE_TEXTURE(MetallicRoughnessTexture, input.TexCoord);
|
||||
|
||||
if (output.gAlbedo.a == 0.0) { discard; }
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
VertexShader VSArray[2] =
|
||||
{
|
||||
compile vs_3_0 main_vs(),
|
||||
compile vs_3_0 instanced_vs()
|
||||
};
|
||||
|
||||
int VSIndices[2] =
|
||||
{
|
||||
0, 1
|
||||
};
|
||||
|
||||
int VertexShaderIndex = 0;
|
||||
|
||||
PixelShader PSArray[8] =
|
||||
{
|
||||
compile ps_3_0 NonePS(),
|
||||
|
@ -191,13 +252,13 @@ int PSIndices[8] =
|
|||
0, 1, 2, 3, 4, 5, 6, 7
|
||||
};
|
||||
|
||||
int ShaderIndex = 0;
|
||||
int PixelShaderIndex = 0;
|
||||
|
||||
Technique GBuffer
|
||||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = (PSArray[PSIndices[ShaderIndex]]);
|
||||
VertexShader = (VSArray[VSIndices[VertexShaderIndex]]);
|
||||
PixelShader = (PSArray[PSIndices[PixelShaderIndex]]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
// Assumes you are drawing a sphere!!
|
||||
|
||||
#include "Macros.fxh" //from FNA
|
||||
#include "Lighting.fxh"
|
||||
#include "Shadow.fxh"
|
||||
|
||||
DECLARE_TEXTURE(gPosition, 0);
|
||||
DECLARE_TEXTURE(gAlbedo, 1);
|
||||
DECLARE_TEXTURE(gNormal, 2);
|
||||
DECLARE_TEXTURE(gMetallicRoughness, 3);
|
||||
DECLARE_CUBEMAP(shadowMap, 4);
|
||||
|
||||
BEGIN_CONSTANTS
|
||||
|
||||
float3 EyePosition _ps(c0) _cb(c0);
|
||||
|
||||
float3 PointLightPosition _ps(c1) _cb(c1);
|
||||
float3 PointLightColor _ps(c2) _cb(c2);
|
||||
|
||||
float FarPlane _ps(c3) _cb(c3);
|
||||
|
||||
MATRIX_CONSTANTS
|
||||
|
||||
float4x4 WorldViewProjection _vs(c0) _cb(c4);
|
||||
|
||||
END_CONSTANTS
|
||||
|
||||
struct VertexInput
|
||||
{
|
||||
float4 Position : POSITION;
|
||||
};
|
||||
|
||||
struct PixelInput
|
||||
{
|
||||
float4 Position : SV_POSITION;
|
||||
float4 ScreenPosition : TEXCOORD0;
|
||||
};
|
||||
|
||||
PixelInput main_vs(VertexInput input)
|
||||
{
|
||||
PixelInput output;
|
||||
|
||||
output.Position = mul(input.Position, WorldViewProjection);
|
||||
output.ScreenPosition = output.Position;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// Pixel Shader
|
||||
|
||||
float4 ComputeColor(
|
||||
float3 worldPosition,
|
||||
float3 worldNormal,
|
||||
float3 albedo,
|
||||
float metallic,
|
||||
float roughness
|
||||
) {
|
||||
float3 V = normalize(EyePosition - worldPosition);
|
||||
float3 N = normalize(worldNormal);
|
||||
|
||||
float3 F0 = float3(0.04, 0.04, 0.04);
|
||||
F0 = lerp(F0, albedo, metallic);
|
||||
|
||||
float3 lightDir = PointLightPosition - worldPosition;
|
||||
float3 L = normalize(lightDir);
|
||||
float distance = length(lightDir);
|
||||
float attenuation = 1.0 / (distance * distance);
|
||||
float3 radiance = PointLightColor * attenuation;
|
||||
|
||||
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(shadow, shadow, shadow, 1.0);
|
||||
}
|
||||
|
||||
float4 main_ps(PixelInput input) : SV_TARGET0
|
||||
{
|
||||
input.ScreenPosition.xy /= input.ScreenPosition.w;
|
||||
float2 texCoord = 0.5f * float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 0.5f;
|
||||
|
||||
float3 worldPosition = SAMPLE_TEXTURE(gPosition, texCoord).rgb;
|
||||
float4 normalSample = SAMPLE_TEXTURE(gNormal, texCoord);
|
||||
float3 normal = normalSample.xyz;
|
||||
float isSprite = normalSample.a;
|
||||
float3 albedo = SAMPLE_TEXTURE(gAlbedo, texCoord).rgb;
|
||||
float2 metallicRoughness = SAMPLE_TEXTURE(gMetallicRoughness, texCoord).rg;
|
||||
|
||||
if (isSprite == 1.0)
|
||||
{
|
||||
float3 lightDir = PointLightPosition - worldPosition;
|
||||
float3 L = normalize(lightDir);
|
||||
float distance = length(lightDir);
|
||||
float attenuation = 1.0 / (distance * distance);
|
||||
float3 radiance = PointLightColor * attenuation;
|
||||
|
||||
return float4(albedo * radiance * 0.1, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ComputeColor(
|
||||
worldPosition,
|
||||
normal,
|
||||
albedo,
|
||||
metallicRoughness.r,
|
||||
metallicRoughness.g
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Technique DeferredPBR_Point
|
||||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,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,140 @@
|
|||
#include "Macros.fxh" //from FNA
|
||||
|
||||
// Effect applies normalmapped lighting to a 2D sprite.
|
||||
|
||||
DECLARE_TEXTURE(Texture, 0);
|
||||
DECLARE_TEXTURE(Normal, 1);
|
||||
|
||||
float3 AmbientColor;
|
||||
|
||||
float3 PointLightPositions[8];
|
||||
float3 PointLightColors[8];
|
||||
|
||||
float3 DirectionalLightDirection;
|
||||
float3 DirectionalLightColor;
|
||||
|
||||
float4 UVOffsetAndDimensions;
|
||||
|
||||
float4x4 WorldInverseTranspose;
|
||||
float4x4 World;
|
||||
float4x4 WorldViewProjection;
|
||||
|
||||
struct VertexShaderInput
|
||||
{
|
||||
float4 Position : POSITION;
|
||||
float3 Normal : NORMAL;
|
||||
float2 TexCoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct PixelShaderInput
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float2 TexCoord : TEXCOORD0;
|
||||
float3 NormalWS : TEXCOORD1;
|
||||
float3 PositionWS : TEXCOORD2;
|
||||
};
|
||||
|
||||
PixelShaderInput main_vs(VertexShaderInput input)
|
||||
{
|
||||
PixelShaderInput output;
|
||||
|
||||
output.Position = mul(input.Position, WorldViewProjection);
|
||||
output.NormalWS = normalize(mul(input.Normal, (float3x3)WorldInverseTranspose));
|
||||
output.PositionWS = mul(input.Position, World).xyz;
|
||||
|
||||
float2 texCoord;
|
||||
texCoord.x = (input.TexCoord.x * UVOffsetAndDimensions.z) + UVOffsetAndDimensions.x;
|
||||
texCoord.y = (input.TexCoord.y * UVOffsetAndDimensions.w) + UVOffsetAndDimensions.y;
|
||||
output.TexCoord = texCoord;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
// Easy trick to get tangent-normals to world-space to keep PBR code simplified.
|
||||
float3 GetNormalFromMap(float3 worldPos, float2 texCoords, float3 normal)
|
||||
{
|
||||
float3 tangentNormal = SAMPLE_TEXTURE(Normal, texCoords).xyz * 2.0 - 1.0;
|
||||
|
||||
float3 Q1 = ddx(worldPos);
|
||||
float3 Q2 = ddy(worldPos);
|
||||
float2 st1 = ddx(texCoords);
|
||||
float2 st2 = ddy(texCoords);
|
||||
|
||||
float3 N = normalize(normal);
|
||||
float3 T = normalize(Q1*st2.y - Q2*st1.y);
|
||||
float3 B = -normalize(cross(N, T));
|
||||
float3x3 TBN = float3x3(T, B, N);
|
||||
|
||||
return normalize(mul(tangentNormal, TBN));
|
||||
}
|
||||
|
||||
float4 LightColor(float3 worldPosition, float3 worldNormal)
|
||||
{
|
||||
float3 lightColor = float3(0.0, 0.0, 0.0);
|
||||
|
||||
// point lights
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
float3 lightVec = PointLightPositions[i] - worldPosition;
|
||||
float distance = length(lightVec);
|
||||
|
||||
float3 lightDir = normalize(lightVec);
|
||||
float diffuse = max(dot(worldNormal, lightDir), 0.0);
|
||||
float3 attenuation = 1.0 / (distance * distance);
|
||||
|
||||
lightColor += diffuse * attenuation * PointLightColors[i];
|
||||
}
|
||||
|
||||
// directional light
|
||||
float directionalDiffuse = max(dot(worldNormal, DirectionalLightDirection), 0.0);
|
||||
lightColor += directionalDiffuse * DirectionalLightColor;
|
||||
|
||||
// ambient light
|
||||
lightColor += AmbientColor;
|
||||
|
||||
return float4(lightColor, 1.0);
|
||||
}
|
||||
|
||||
float4 WithoutNormalMap(PixelShaderInput input) : COLOR0
|
||||
{
|
||||
float4 tex = SAMPLE_TEXTURE(Texture, input.TexCoord);
|
||||
|
||||
if (tex.a == 0.0) { discard; }
|
||||
|
||||
float3 normalWS = normalize(input.NormalWS);
|
||||
|
||||
return tex * LightColor(input.PositionWS, normalWS);
|
||||
}
|
||||
|
||||
float4 WithNormalMap(PixelShaderInput input) : COLOR0
|
||||
{
|
||||
float4 tex = SAMPLE_TEXTURE(Texture, input.TexCoord);
|
||||
|
||||
if (tex.a == 0.0) { discard; }
|
||||
|
||||
float3 normalWS = GetNormalFromMap(input.PositionWS, input.TexCoord, input.NormalWS);
|
||||
|
||||
return tex * LightColor(input.PositionWS, normalWS);
|
||||
}
|
||||
|
||||
PixelShader PSArray[2] =
|
||||
{
|
||||
compile ps_3_0 WithoutNormalMap(),
|
||||
compile ps_3_0 WithNormalMap()
|
||||
};
|
||||
|
||||
int PSIndices[2] =
|
||||
{
|
||||
0, 1
|
||||
};
|
||||
|
||||
int ShaderIndex = 0;
|
||||
|
||||
Technique DiffuseLitSprite
|
||||
{
|
||||
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,71 @@
|
|||
static const float PI = 3.141592653589793;
|
||||
|
||||
float3 FresnelSchlick(float cosTheta, float3 F0)
|
||||
{
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float DistributionGGX(float3 N, float3 H, float roughness)
|
||||
{
|
||||
float a = roughness * roughness;
|
||||
float a2 = a * a;
|
||||
float NdotH = max(dot(N, H), 0.0);
|
||||
float NdotH2 = NdotH * NdotH;
|
||||
|
||||
float num = a2;
|
||||
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
|
||||
denom = PI * denom * denom;
|
||||
|
||||
return num / denom;
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
|
||||
float num = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
|
||||
return num / denom;
|
||||
}
|
||||
|
||||
float GeometrySmith(float3 N, float3 V, float3 L, float roughness)
|
||||
{
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float ggx2 = GeometrySchlickGGX(NdotV, roughness);
|
||||
float ggx1 = GeometrySchlickGGX(NdotL, roughness);
|
||||
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
float3 ComputeLight(
|
||||
float3 L,
|
||||
float3 radiance,
|
||||
float3 F0,
|
||||
float3 V,
|
||||
float3 N,
|
||||
float3 albedo,
|
||||
float metallic,
|
||||
float roughness,
|
||||
float visibility
|
||||
) {
|
||||
float3 H = normalize(V + L);
|
||||
|
||||
float NDF = DistributionGGX(N, H, roughness);
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0);
|
||||
|
||||
float3 numerator = NDF * G * F;
|
||||
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
|
||||
float3 specular = numerator / max(denominator, 0.001);
|
||||
|
||||
float3 kS = F;
|
||||
float3 kD = float3(1.0, 1.0, 1.0) - kS;
|
||||
|
||||
kD *= 1.0 - metallic;
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
return (kD * albedo / PI + specular) * radiance * NdotL * visibility;
|
||||
}
|
|
@ -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,55 @@
|
|||
#include "Macros.fxh"
|
||||
|
||||
BEGIN_CONSTANTS
|
||||
|
||||
float4x4 ViewProjection _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 instanced_vs(VertexShaderInput input, float3 Translation : TEXCOORD2)
|
||||
{
|
||||
VertexShaderOutput output;
|
||||
|
||||
float4x4 world = float4x4(
|
||||
float4(1, 0, 0, 0),
|
||||
float4(0, 1, 0, 0),
|
||||
float4(0, 0, 1, 0),
|
||||
float4(Translation.x, Translation.y, Translation.z, 1)
|
||||
);
|
||||
|
||||
float4x4 worldViewProjection = mul(world, ViewProjection);
|
||||
output.Position = mul(input.Position, worldViewProjection);
|
||||
output.Position.x *= -1; // otherwise cube map render will be horizontally flipped
|
||||
output.PositionWorld = mul(input.Position, world);
|
||||
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 instanced_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -54,4 +54,5 @@
|
|||
#define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord)
|
||||
#define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name##Sampler, texCoord)
|
||||
#define SAMPLE_CUBEMAP_LOD(Name, texCoord) texCUBElod(Name##Sampler, texCoord)
|
||||
#define SAMPLER(Name) Name##Sampler
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
#include "Macros.fxh"
|
||||
|
||||
DECLARE_TEXTURE(Texture, 0);
|
||||
DECLARE_TEXTURE(Palette, 1);
|
||||
|
||||
BEGIN_CONSTANTS
|
||||
|
||||
int PaletteWidth _ps(c0) _cb(c0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
float4 main_ps(PixelInput input) : SV_TARGET0
|
||||
{
|
||||
float4 sampled = SAMPLE_TEXTURE(Texture, input.TexCoord);
|
||||
|
||||
float3 sampled_color = sampled.rgb;
|
||||
|
||||
float3 closest_color = float3(0, 0, 0);
|
||||
float closest_dist = 100000;
|
||||
|
||||
for (int i = 0; i < PaletteWidth; i++)
|
||||
{
|
||||
float texX = (i / (float)PaletteWidth);
|
||||
float3 palette_color = SAMPLE_TEXTURE(Palette, float2(texX, 0));
|
||||
float dist = distance(palette_color, sampled_color);
|
||||
if (dist < closest_dist)
|
||||
{
|
||||
closest_dist = dist;
|
||||
closest_color = palette_color;
|
||||
}
|
||||
}
|
||||
|
||||
return float4(closest_color, sampled.a);
|
||||
}
|
||||
|
||||
Technique PaletteCrush
|
||||
{
|
||||
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);
|
||||
}
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
BEGIN_CONSTANTS
|
||||
|
||||
float4x4 ModelViewProjection _vs(c0) _cb(c0);
|
||||
|
||||
MATRIX_CONSTANTS
|
||||
|
||||
float4x4 World _vs(c0) _cb(c0);
|
||||
float4x4 ViewProjection _vs(c4) _cb(c4);
|
||||
|
||||
END_CONSTANTS
|
||||
|
||||
struct VertexShaderInput
|
||||
|
@ -15,22 +16,31 @@ struct VertexShaderInput
|
|||
|
||||
struct VertexShaderOutput
|
||||
{
|
||||
float4 Position : SV_Position;
|
||||
float4 Position : SV_POSITION;
|
||||
float Depth : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertexShaderOutput main_vs(VertexShaderInput input)
|
||||
{
|
||||
VertexShaderOutput output;
|
||||
|
||||
output.Position = mul(float4(input.Position.xyz, 1.0), ModelViewProjection);
|
||||
float4x4 worldViewProjection = mul(World, ViewProjection);
|
||||
output.Position = mul(input.Position, worldViewProjection);
|
||||
output.Depth = output.Position.z / output.Position.w;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 main_ps(VertexShaderOutput input) : SV_TARGET0
|
||||
{
|
||||
return float4(input.Depth, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
Technique SimpleDepth
|
||||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 main_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
float4x4 ViewProjection;
|
||||
|
||||
struct VertexShaderInput
|
||||
{
|
||||
float4 Position : POSITION;
|
||||
};
|
||||
|
||||
struct VertexShaderOutput
|
||||
{
|
||||
float4 Position : POSITION0;
|
||||
float4 ProjectedPosition : TEXCOORD0;
|
||||
};
|
||||
|
||||
VertexShaderOutput instanced_vs(VertexShaderInput input, float3 Translation : TEXCOORD2)
|
||||
{
|
||||
VertexShaderOutput output;
|
||||
|
||||
float4x4 world = float4x4(
|
||||
float4(1, 0, 0, 0),
|
||||
float4(0, 1, 0, 0),
|
||||
float4(0, 0, 1, 0),
|
||||
float4(Translation.x, Translation.y, Translation.z, 1)
|
||||
);
|
||||
|
||||
float4x4 worldViewProjection = mul(world, ViewProjection);
|
||||
|
||||
output.Position = mul(input.Position, worldViewProjection);
|
||||
output.ProjectedPosition = output.Position;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 main_ps(VertexShaderOutput input) : COLOR0
|
||||
{
|
||||
return float4(input.ProjectedPosition.z / input.ProjectedPosition.w, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
Technique SimpleDepth
|
||||
{
|
||||
Pass
|
||||
{
|
||||
VertexShader = compile vs_3_0 instanced_vs();
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -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,20 @@
|
|||
sampler TextureSampler : register(s0);
|
||||
|
||||
float4 main_ps(float2 texCoord : TEXCOORD0) : COLOR0
|
||||
{
|
||||
float3 color = tex2D(TextureSampler, texCoord).xyz;
|
||||
|
||||
color = color / (color + float3(1.0, 1.0, 1.0));
|
||||
float exposureConstant = 1.0 / 2.2;
|
||||
color = pow(color, float3(exposureConstant, exposureConstant, exposureConstant));
|
||||
|
||||
return float4(color, 1.0);
|
||||
}
|
||||
|
||||
Technique DeferredPBR
|
||||
{
|
||||
Pass
|
||||
{
|
||||
PixelShader = compile ps_3_0 main_ps();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class LinearDepthEffect : Effect, IHasWorldMatrix
|
||||
{
|
||||
EffectParameter worldParam;
|
||||
EffectParameter worldViewProjectionParam;
|
||||
EffectParameter lightPositionParam;
|
||||
EffectParameter farPlaneParam;
|
||||
|
||||
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
|
||||
|
||||
Matrix world;
|
||||
Matrix view;
|
||||
Matrix projection;
|
||||
|
||||
public Vector3 LightPosition { get; set; }
|
||||
public float FarPlane { get; set; }
|
||||
|
||||
public Matrix World
|
||||
{
|
||||
get { return world; }
|
||||
set
|
||||
{
|
||||
world = 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 world, ref viewProjection, out Matrix worldViewProj);
|
||||
|
||||
worldViewProjectionParam.SetValue(worldViewProj);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
|
||||
}
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.World) != 0)
|
||||
{
|
||||
worldParam.SetValue(world);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.World;
|
||||
}
|
||||
|
||||
lightPositionParam.SetValue(LightPosition);
|
||||
farPlaneParam.SetValue(FarPlane);
|
||||
}
|
||||
|
||||
private void CacheEffectParameters()
|
||||
{
|
||||
worldParam = Parameters["Model"];
|
||||
worldViewProjectionParam = Parameters["ModelViewProjection"];
|
||||
|
||||
lightPositionParam = Parameters["LightPosition"];
|
||||
farPlaneParam = Parameters["FarPlane"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class LinearDepthEffectInstanced : Effect
|
||||
{
|
||||
EffectParameter viewProjectionParam;
|
||||
EffectParameter lightPositionParam;
|
||||
EffectParameter farPlaneParam;
|
||||
|
||||
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
|
||||
|
||||
Matrix view;
|
||||
Matrix projection;
|
||||
|
||||
public Vector3 LightPosition { get; set; }
|
||||
public float FarPlane { get; set; }
|
||||
|
||||
public Matrix View
|
||||
{
|
||||
get { return view; }
|
||||
set
|
||||
{
|
||||
view = value;
|
||||
dirtyFlags |= EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix Projection
|
||||
{
|
||||
get { return projection; }
|
||||
set
|
||||
{
|
||||
projection = value;
|
||||
dirtyFlags |= EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
public LinearDepthEffectInstanced(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.LinearDepthEffectInstanced)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
{
|
||||
if ((dirtyFlags & EffectDirtyFlags.ViewProj) != 0)
|
||||
{
|
||||
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection);
|
||||
viewProjectionParam.SetValue(viewProjection);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
|
||||
lightPositionParam.SetValue(LightPosition);
|
||||
farPlaneParam.SetValue(FarPlane);
|
||||
}
|
||||
|
||||
private void CacheEffectParameters()
|
||||
{
|
||||
viewProjectionParam = Parameters["ViewProjection"];
|
||||
|
||||
lightPositionParam = Parameters["LightPosition"];
|
||||
farPlaneParam = Parameters["FarPlane"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
|
|||
|
||||
namespace Kav
|
||||
{
|
||||
public class PBREffect : Effect, TransformEffect, PointLightEffect, DirectionalLightEffect
|
||||
public class PBREffect : Effect, TransformEffect, PointLightEffect
|
||||
{
|
||||
EffectParameter worldParam;
|
||||
EffectParameter worldViewProjectionParam;
|
||||
|
@ -31,7 +31,6 @@ namespace Kav
|
|||
Matrix view = Matrix.Identity;
|
||||
Matrix projection = Matrix.Identity;
|
||||
PointLightCollection pointLightCollection;
|
||||
DirectionalLightCollection directionalLightCollection;
|
||||
|
||||
Vector3 albedo;
|
||||
float metallic;
|
||||
|
@ -84,14 +83,6 @@ namespace Kav
|
|||
private set { pointLightCollection = value; }
|
||||
}
|
||||
|
||||
public int MaxDirectionalLights { get; } = 4;
|
||||
|
||||
public DirectionalLightCollection DirectionalLights
|
||||
{
|
||||
get { return directionalLightCollection; }
|
||||
private set { directionalLightCollection = value; }
|
||||
}
|
||||
|
||||
public Vector3 Albedo
|
||||
{
|
||||
get { return albedo; }
|
||||
|
@ -139,7 +130,7 @@ namespace Kav
|
|||
{
|
||||
albedoTextureParam.SetValue(value);
|
||||
albedoTextureEnabled = value != null;
|
||||
dirtyFlags |= EffectDirtyFlags.ShaderIndex;
|
||||
dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +141,7 @@ namespace Kav
|
|||
{
|
||||
normalTextureParam.SetValue(value);
|
||||
normalMapEnabled = value != null;
|
||||
dirtyFlags |= EffectDirtyFlags.ShaderIndex;
|
||||
dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,7 +164,7 @@ namespace Kav
|
|||
{
|
||||
metallicRoughnessTextureParam.SetValue(value);
|
||||
metallicRoughnessMapEnabled = value != null;
|
||||
dirtyFlags |= EffectDirtyFlags.ShaderIndex;
|
||||
dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,60 +195,6 @@ namespace Kav
|
|||
Parameters["PositionLightColors"],
|
||||
MaxPointLights
|
||||
);
|
||||
|
||||
directionalLightCollection = new DirectionalLightCollection(
|
||||
Parameters["LightDirections"],
|
||||
Parameters["DirectionLightColors"]
|
||||
);
|
||||
}
|
||||
|
||||
protected PBREffect(PBREffect cloneSource) : base(cloneSource)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
|
||||
World = cloneSource.World;
|
||||
View = cloneSource.View;
|
||||
Projection = cloneSource.Projection;
|
||||
|
||||
PointLights = new PointLightCollection(
|
||||
Parameters["LightPositions"],
|
||||
Parameters["PositionLightColors"],
|
||||
MaxPointLights
|
||||
);
|
||||
|
||||
for (int i = 0; i < MaxPointLights; i++)
|
||||
{
|
||||
PointLights[i] = cloneSource.PointLights[i];
|
||||
}
|
||||
|
||||
DirectionalLights = new DirectionalLightCollection(
|
||||
Parameters["LightDirections"],
|
||||
Parameters["DirectionLightColors"]
|
||||
);
|
||||
|
||||
for (int i = 0; i < MaxDirectionalLights; i++)
|
||||
{
|
||||
DirectionalLights[i] = cloneSource.DirectionalLights[i];
|
||||
}
|
||||
|
||||
AlbedoTexture = cloneSource.AlbedoTexture;
|
||||
NormalTexture = cloneSource.NormalTexture;
|
||||
EmissionTexture = cloneSource.EmissionTexture;
|
||||
OcclusionTexture = cloneSource.OcclusionTexture;
|
||||
MetallicRoughnessTexture = cloneSource.MetallicRoughnessTexture;
|
||||
EnvDiffuseTexture = cloneSource.EnvDiffuseTexture;
|
||||
BRDFLutTexture = cloneSource.BRDFLutTexture;
|
||||
EnvSpecularTexture = cloneSource.EnvSpecularTexture;
|
||||
|
||||
Albedo = cloneSource.Albedo;
|
||||
Metallic = cloneSource.Metallic;
|
||||
Roughness = cloneSource.Roughness;
|
||||
AO = cloneSource.AO;
|
||||
}
|
||||
|
||||
public override Effect Clone()
|
||||
{
|
||||
return new PBREffect(this);
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
|
@ -290,7 +227,7 @@ namespace Kav
|
|||
dirtyFlags &= ~EffectDirtyFlags.EyePosition;
|
||||
}
|
||||
|
||||
if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0)
|
||||
if ((dirtyFlags & EffectDirtyFlags.PixelShaderIndex) != 0)
|
||||
{
|
||||
int shaderIndex = 0;
|
||||
|
||||
|
@ -325,7 +262,7 @@ namespace Kav
|
|||
|
||||
shaderIndexParam.SetValue(shaderIndex);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.ShaderIndex;
|
||||
dirtyFlags &= ~EffectDirtyFlags.PixelShaderIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class PaletteCrushEffect : Effect
|
||||
{
|
||||
EffectParameter textureParam;
|
||||
EffectParameter paletteParam;
|
||||
EffectParameter paletteWidthParam;
|
||||
|
||||
Texture2D texture;
|
||||
Texture2D palette;
|
||||
|
||||
int paletteWidth;
|
||||
|
||||
public Texture2D Texture
|
||||
{
|
||||
get { return texture; }
|
||||
set
|
||||
{
|
||||
texture = value;
|
||||
textureParam.SetValue(texture);
|
||||
}
|
||||
}
|
||||
|
||||
public Texture2D Palette
|
||||
{
|
||||
get { return palette; }
|
||||
set
|
||||
{
|
||||
palette = value;
|
||||
paletteWidth = palette.Width;
|
||||
paletteParam.SetValue(palette);
|
||||
paletteWidthParam.SetValue(paletteWidth);
|
||||
}
|
||||
}
|
||||
|
||||
public PaletteCrushEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.PaletteCrushEffect)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
}
|
||||
|
||||
void CacheEffectParameters()
|
||||
{
|
||||
textureParam = Parameters["Texture"];
|
||||
paletteParam = Parameters["Palette"];
|
||||
|
||||
paletteWidthParam = Parameters["PaletteWidth"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,41 +7,24 @@ namespace Kav
|
|||
{
|
||||
private readonly Vector3[] positions;
|
||||
private readonly Vector3[] colors;
|
||||
private readonly float[] intensities;
|
||||
|
||||
readonly EffectParameter lightPositionsParam;
|
||||
readonly EffectParameter lightColorsParam;
|
||||
|
||||
public PointLightCollection(EffectParameter lightPositionsParam, EffectParameter lightColorsParam, int maxLights)
|
||||
{
|
||||
this.positions = new Vector3[maxLights];
|
||||
this.colors = new Vector3[maxLights];
|
||||
this.intensities = new float[maxLights];
|
||||
positions = new Vector3[maxLights];
|
||||
colors = new Vector3[maxLights];
|
||||
this.lightPositionsParam = lightPositionsParam;
|
||||
this.lightColorsParam = lightColorsParam;
|
||||
}
|
||||
|
||||
public PointLight this[int i]
|
||||
{
|
||||
get
|
||||
{
|
||||
var color = colors[i] / intensities[i];
|
||||
return new PointLight(
|
||||
positions[i],
|
||||
new Color(
|
||||
color.X,
|
||||
color.Y,
|
||||
color.Z,
|
||||
1f
|
||||
),
|
||||
intensities[i]
|
||||
);
|
||||
}
|
||||
set
|
||||
{
|
||||
positions[i] = value.Position;
|
||||
colors[i] = value.Color.ToVector3() * value.Intensity;
|
||||
intensities[i] = value.Intensity;
|
||||
colors[i] = value.Color.ToVector3() * value.Radius;
|
||||
lightPositionsParam.SetValue(positions);
|
||||
lightColorsParam.SetValue(colors);
|
||||
}
|
||||
|
|
|
@ -3,23 +3,24 @@ using Microsoft.Xna.Framework.Graphics;
|
|||
|
||||
namespace Kav
|
||||
{
|
||||
public class SimpleDepthEffect : Effect
|
||||
public class SimpleDepthEffect : Effect, IHasWorldMatrix
|
||||
{
|
||||
EffectParameter modelViewProjectionParam;
|
||||
EffectParameter worldParam;
|
||||
EffectParameter viewProjectionParam;
|
||||
|
||||
Matrix model;
|
||||
Matrix world;
|
||||
Matrix view;
|
||||
Matrix projection;
|
||||
|
||||
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
|
||||
|
||||
public Matrix Model
|
||||
public Matrix World
|
||||
{
|
||||
get { return model; }
|
||||
get { return world; }
|
||||
set
|
||||
{
|
||||
model = value;
|
||||
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||
world = value;
|
||||
dirtyFlags |= EffectDirtyFlags.World;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +30,7 @@ namespace Kav
|
|||
set
|
||||
{
|
||||
view = value;
|
||||
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||
dirtyFlags |= EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,9 +40,10 @@ namespace Kav
|
|||
set
|
||||
{
|
||||
projection = value;
|
||||
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
|
||||
dirtyFlags |= EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleDepthEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SimpleDepthEffect)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
|
@ -49,20 +51,26 @@ namespace Kav
|
|||
|
||||
protected override void OnApply()
|
||||
{
|
||||
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
|
||||
if ((dirtyFlags & EffectDirtyFlags.World) != 0)
|
||||
{
|
||||
Matrix.Multiply(ref model, ref view, out Matrix modelView);
|
||||
Matrix.Multiply(ref modelView, ref projection, out Matrix worldViewProj);
|
||||
worldParam.SetValue(world);
|
||||
|
||||
modelViewProjectionParam.SetValue(worldViewProj);
|
||||
dirtyFlags &= ~EffectDirtyFlags.World;
|
||||
}
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
|
||||
if ((dirtyFlags & EffectDirtyFlags.ViewProj) != 0)
|
||||
{
|
||||
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection);
|
||||
viewProjectionParam.SetValue(viewProjection);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
private void CacheEffectParameters()
|
||||
{
|
||||
modelViewProjectionParam = Parameters["ModelViewProjection"];
|
||||
worldParam = Parameters["World"];
|
||||
viewProjectionParam = Parameters["ViewProjection"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class SimpleDepthEffectInstanced : Effect
|
||||
{
|
||||
EffectParameter viewProjectionParam;
|
||||
|
||||
Matrix view;
|
||||
Matrix projection;
|
||||
|
||||
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
|
||||
|
||||
public Matrix View
|
||||
{
|
||||
get { return view; }
|
||||
set
|
||||
{
|
||||
view = value;
|
||||
dirtyFlags |= EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
public Matrix Projection
|
||||
{
|
||||
get { return projection; }
|
||||
set
|
||||
{
|
||||
projection = value;
|
||||
dirtyFlags |= EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
public SimpleDepthEffectInstanced(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SimpleDepthEffectInstanced)
|
||||
{
|
||||
CacheEffectParameters();
|
||||
}
|
||||
|
||||
protected override void OnApply()
|
||||
{
|
||||
if ((dirtyFlags & EffectDirtyFlags.ViewProj) != 0)
|
||||
{
|
||||
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection);
|
||||
viewProjectionParam.SetValue(viewProjection);
|
||||
|
||||
dirtyFlags &= ~EffectDirtyFlags.ViewProj;
|
||||
}
|
||||
}
|
||||
|
||||
private void CacheEffectParameters()
|
||||
{
|
||||
viewProjectionParam = Parameters["ViewProjection"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
namespace Kav
|
||||
{
|
||||
public enum SpriteBillboardConstraint
|
||||
{
|
||||
None,
|
||||
Horizontal,
|
||||
Full
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public interface ICullable
|
||||
{
|
||||
BoundingBox BoundingBox { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public interface IGBufferDrawable
|
||||
{
|
||||
Vector3 Albedo { get; }
|
||||
float Metallic { get; }
|
||||
float Roughness { get; }
|
||||
|
||||
Texture2D AlbedoTexture { get; }
|
||||
Texture2D NormalTexture { get; }
|
||||
Texture2D MetallicRoughnessTexture { get; }
|
||||
|
||||
int NumTextureRows { get; }
|
||||
int NumTextureColumns { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public interface IHasVertexPositions
|
||||
{
|
||||
Vector3[] Positions { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public interface IIndexDrawable
|
||||
{
|
||||
VertexBuffer VertexBuffer { get; }
|
||||
IndexBuffer IndexBuffer { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public interface ITransformable
|
||||
{
|
||||
Matrix TransformMatrix { get; }
|
||||
}
|
||||
}
|
|
@ -1,12 +1,23 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class Mesh
|
||||
{
|
||||
public MeshPart[] MeshParts { get; }
|
||||
public BoundingBox BoundingBox { get; }
|
||||
|
||||
public Mesh(MeshPart[] meshParts)
|
||||
{
|
||||
MeshParts = meshParts;
|
||||
|
||||
BoundingBox boundingBox = new BoundingBox();
|
||||
foreach (var meshPart in MeshParts)
|
||||
{
|
||||
boundingBox = BoundingBox.CreateMerged(boundingBox, meshPart.BoundingBox);
|
||||
}
|
||||
|
||||
BoundingBox = boundingBox;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,21 +3,60 @@ using Microsoft.Xna.Framework.Graphics;
|
|||
|
||||
namespace Kav
|
||||
{
|
||||
public class MeshPart
|
||||
public class MeshPart : IIndexDrawable, IGBufferDrawable, ICullable, IHasVertexPositions
|
||||
{
|
||||
public IndexBuffer IndexBuffer { get; }
|
||||
public VertexBuffer VertexBuffer { get; }
|
||||
public Triangle[] Triangles { get; }
|
||||
public Vector3[] Positions { get; }
|
||||
public Effect Effect { get; }
|
||||
|
||||
public MeshPart(VertexBuffer vertexBuffer, IndexBuffer indexBuffer, Vector3[] positions, Triangle[] triangles, Effect effect)
|
||||
public BoundingBox BoundingBox { get; }
|
||||
|
||||
private Texture2D albedoTexture = null;
|
||||
private Texture2D normalTexture = null;
|
||||
private Texture2D metallicRoughnessTexture = null;
|
||||
|
||||
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 int NumTextureRows { get; set; } = 1;
|
||||
public int NumTextureColumns { get; set; } = 1;
|
||||
|
||||
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;
|
||||
IndexBuffer = indexBuffer;
|
||||
Positions = positions;
|
||||
Triangles = triangles;
|
||||
Effect = effect;
|
||||
|
||||
BoundingBox = BoundingBox.CreateFromPoints(Positions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,97 @@ using Microsoft.Xna.Framework;
|
|||
|
||||
namespace Kav
|
||||
{
|
||||
public class Model
|
||||
public class Model : ICullable
|
||||
{
|
||||
public Mesh[] Meshes { get; }
|
||||
public BoundingBox BoundingBox { 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)
|
||||
{
|
||||
Meshes = meshes;
|
||||
|
||||
BoundingBox boundingBox = new BoundingBox();
|
||||
foreach (var mesh in Meshes)
|
||||
{
|
||||
boundingBox = BoundingBox.CreateMerged(boundingBox, mesh.BoundingBox);
|
||||
}
|
||||
|
||||
BoundingBox = boundingBox;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public struct Sprite
|
||||
{
|
||||
public Texture2D Texture { get; }
|
||||
public Vector3 Position { get; }
|
||||
public Vector2 Origin { get; }
|
||||
public float Rotation { get; }
|
||||
public Vector2 Scale { get; }
|
||||
public SpriteBillboardConstraint BillboardConstraint { get; }
|
||||
|
||||
public Matrix TransformMatrix { get; }
|
||||
|
||||
public Sprite(
|
||||
Texture2D texture,
|
||||
Vector3 position,
|
||||
Vector2 origin,
|
||||
float rotation,
|
||||
Vector2 scale,
|
||||
SpriteBillboardConstraint billboardConstraint = SpriteBillboardConstraint.None
|
||||
) {
|
||||
Texture = texture;
|
||||
Position = position;
|
||||
Origin = origin;
|
||||
Rotation = rotation;
|
||||
Scale = scale;
|
||||
BillboardConstraint = billboardConstraint;
|
||||
TransformMatrix = ConstructTransformMatrix(Position, Scale);
|
||||
}
|
||||
|
||||
public Sprite(
|
||||
Texture2D texture,
|
||||
Vector3 position,
|
||||
SpriteBillboardConstraint billboardConstraint = SpriteBillboardConstraint.None
|
||||
) {
|
||||
Texture = texture;
|
||||
Position = position;
|
||||
Origin = Vector2.Zero;
|
||||
Rotation = 0;
|
||||
Scale = Vector2.One;
|
||||
BillboardConstraint = billboardConstraint;
|
||||
TransformMatrix = ConstructTransformMatrix(Position, Scale);
|
||||
}
|
||||
|
||||
private static Matrix ConstructTransformMatrix(
|
||||
Vector3 position,
|
||||
Vector2 scale
|
||||
) {
|
||||
return
|
||||
Matrix.CreateTranslation(position) *
|
||||
Matrix.CreateScale(scale.X, scale.Y, 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
using System.Collections.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public class SpriteMesh : ICullable, IIndexDrawable
|
||||
{
|
||||
public enum FlipOptions
|
||||
{
|
||||
None,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
Both
|
||||
}
|
||||
|
||||
private static readonly short[] Indices = new short[]
|
||||
{
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
1,
|
||||
3,
|
||||
2
|
||||
};
|
||||
|
||||
public IndexBuffer IndexBuffer { get; }
|
||||
public VertexBuffer VertexBuffer { get; }
|
||||
public BoundingBox BoundingBox { get; }
|
||||
|
||||
public SpriteMesh(
|
||||
GraphicsDevice graphicsDevice,
|
||||
int width,
|
||||
int height,
|
||||
FlipOptions flipOptions
|
||||
) {
|
||||
IndexBuffer = new IndexBuffer(
|
||||
graphicsDevice,
|
||||
IndexElementSize.SixteenBits,
|
||||
6,
|
||||
BufferUsage.WriteOnly
|
||||
);
|
||||
IndexBuffer.SetData(Indices);
|
||||
|
||||
var vertexArray = GenerateVertexArray(width, height, flipOptions);
|
||||
|
||||
VertexBuffer = new VertexBuffer(
|
||||
graphicsDevice,
|
||||
typeof(VertexPositionNormalTexture),
|
||||
4,
|
||||
BufferUsage.WriteOnly
|
||||
);
|
||||
VertexBuffer.SetData(vertexArray);
|
||||
|
||||
BoundingBox = BoundingBox.CreateFromPoints(Positions(vertexArray));
|
||||
}
|
||||
|
||||
private static VertexPositionNormalTexture[] GenerateVertexArray(int pixelWidth, int pixelHeight, FlipOptions flipOptions)
|
||||
{
|
||||
var width = pixelWidth / (float)40;
|
||||
var height = pixelHeight / (float)40;
|
||||
|
||||
VertexPositionNormalTexture[] result = new VertexPositionNormalTexture[4];
|
||||
|
||||
var xLeft = 0;
|
||||
var xRight = 1;
|
||||
|
||||
var yTop = 0;
|
||||
var yBottom = 1;
|
||||
|
||||
if (flipOptions == FlipOptions.Horizontal || flipOptions == FlipOptions.Both)
|
||||
{
|
||||
xLeft = 1;
|
||||
xRight = 0;
|
||||
}
|
||||
if (flipOptions == FlipOptions.Vertical || flipOptions == FlipOptions.Both)
|
||||
{
|
||||
yTop = 1;
|
||||
yBottom = 0;
|
||||
}
|
||||
|
||||
result[0].Position = new Vector3(-width / 2, height / 2, 0);
|
||||
result[0].Normal = new Vector3(0, 0, -1);
|
||||
result[0].TextureCoordinate = new Vector2(xLeft, yTop);
|
||||
|
||||
result[1].Position = new Vector3(width / 2, height / 2, 0);
|
||||
result[1].Normal = new Vector3(0, 0, -1);
|
||||
result[1].TextureCoordinate = new Vector2(xRight, yTop);
|
||||
|
||||
result[2].Position = new Vector3(-width / 2, -height / 2, 0);
|
||||
result[2].Normal = new Vector3(0, 0, -1);
|
||||
result[2].TextureCoordinate = new Vector2(xLeft, yBottom);
|
||||
|
||||
result[3].Position = new Vector3(width / 2, -height / 2, 0);
|
||||
result[3].Normal = new Vector3(0, 0, -1);
|
||||
result[3].TextureCoordinate = new Vector2(xRight, yBottom);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<Vector3> Positions(IEnumerable<VertexPositionNormalTexture> vertices)
|
||||
{
|
||||
foreach (var vertex in vertices)
|
||||
{
|
||||
yield return vertex.Position;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<RootNamespace>Kav</RootNamespace>
|
||||
<Authors>Evan Hemsley</Authors>
|
||||
<Copyright>Evan Hemsley 2020</Copyright>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<AssemblyName>Kav</AssemblyName>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -15,9 +17,24 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_AmbientLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_AmbientLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_PointLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_PointLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_DirectionalLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_DirectionalLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_GBufferEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_GBufferEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb">
|
||||
<LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\Deferred_ToonEffect.fxb">
|
||||
<LogicalName>Kav.Resources.Deferred_ToonEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
|
@ -27,6 +44,30 @@
|
|||
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb">
|
||||
<LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffectInstanced.fxb">
|
||||
<LogicalName>Kav.Resources.SimpleDepthEffectInstanced.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\LinearDepthEffect.fxb">
|
||||
<LogicalName>Kav.Resources.LinearDepthEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\LinearDepthEffectInstanced.fxb">
|
||||
<LogicalName>Kav.Resources.LinearDepthEffectInstanced.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\SkyboxEffect.fxb">
|
||||
<LogicalName>Kav.Resources.SkyboxEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DiffuseLitSpriteEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DiffuseLitSpriteEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\PaletteCrushEffect.fxb">
|
||||
<LogicalName>Kav.Resources.PaletteCrushEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Models\UnitCube.glb">
|
||||
<LogicalName>Kav.Resources.UnitCube.glb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Models\UnitSphere.glb">
|
||||
<LogicalName>Kav.Resources.UnitSphere.glb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26124.0
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kav", "Kav.Core.csproj", "{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Debug|x64.Build.0 = Debug|x64
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Release|x64.ActiveCfg = Release|x64
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,12 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<RootNamespace>Kav</RootNamespace>
|
||||
<Authors>Evan Hemsley</Authors>
|
||||
<Copyright>Evan Hemsley 2020</Copyright>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<AssemblyName>Kav</AssemblyName>
|
||||
<Platforms>x64;x86</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -15,9 +17,24 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_AmbientLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_AmbientLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_PointLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_PointLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_DirectionalLightEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_DirectionalLightEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBR_GBufferEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBR_GBufferEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\ToneMapEffect.fxb">
|
||||
<LogicalName>Kav.Resources.ToneMapEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\Deferred_ToonEffect.fxb">
|
||||
<LogicalName>Kav.Resources.Deferred_ToonEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DeferredPBREffect.fxb">
|
||||
<LogicalName>Kav.Resources.DeferredPBREffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
|
@ -27,6 +44,30 @@
|
|||
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb">
|
||||
<LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffectInstanced.fxb">
|
||||
<LogicalName>Kav.Resources.SimpleDepthEffectInstanced.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\LinearDepthEffect.fxb">
|
||||
<LogicalName>Kav.Resources.LinearDepthEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\LinearDepthEffectInstanced.fxb">
|
||||
<LogicalName>Kav.Resources.LinearDepthEffectInstanced.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\SkyboxEffect.fxb">
|
||||
<LogicalName>Kav.Resources.SkyboxEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\DiffuseLitSpriteEffect.fxb">
|
||||
<LogicalName>Kav.Resources.DiffuseLitSpriteEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Effects\FXB\PaletteCrushEffect.fxb">
|
||||
<LogicalName>Kav.Resources.PaletteCrushEffect.fxb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Models\UnitCube.glb">
|
||||
<LogicalName>Kav.Resources.UnitCube.glb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Models\UnitSphere.glb">
|
||||
<LogicalName>Kav.Resources.UnitSphere.glb</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26124.0
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kav.Framework", "Kav.Framework.csproj", "{B46F5438-2EE3-4EB1-9ECD-251D3B3CBD9A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B46F5438-2EE3-4EB1-9ECD-251D3B3CBD9A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{B46F5438-2EE3-4EB1-9ECD-251D3B3CBD9A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{B46F5438-2EE3-4EB1-9ECD-251D3B3CBD9A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{B46F5438-2EE3-4EB1-9ECD-251D3B3CBD9A}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
34
Kav.sln
34
Kav.sln
|
@ -1,34 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26124.0
|
||||
MinimumVisualStudioVersion = 15.0.26124.0
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kav", "Kav.csproj", "{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{34C1B784-AE9C-4EBC-A03A-AC401CB1219A}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -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,15 +4,15 @@ namespace Kav
|
|||
{
|
||||
public struct DirectionalLight
|
||||
{
|
||||
public Vector3 Direction { get; set; }
|
||||
public Color Color { get; set; }
|
||||
public float Intensity { get; set; }
|
||||
public Vector3 Direction { get; }
|
||||
public Color Color { get; }
|
||||
public float Intensity { get; }
|
||||
|
||||
public Matrix View
|
||||
{
|
||||
get
|
||||
{
|
||||
return Matrix.CreateLookAt(-Direction * 100f, Vector3.Zero, Vector3.Up);
|
||||
return Matrix.CreateLookAt(Direction * 100f, Vector3.Zero, Vector3.Up);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,55 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public struct PointLight
|
||||
public sealed class PointLight : IDisposable
|
||||
{
|
||||
public Vector3 Position { get; }
|
||||
public Color Color { get; }
|
||||
public float Intensity { get; }
|
||||
public float Radius { get; }
|
||||
|
||||
public PointLight(Vector3 position, Color color, float intensity = 1f)
|
||||
{
|
||||
public BoundingSphere BoundingSphere { get; }
|
||||
|
||||
public RenderTargetCube ShadowMap { get; }
|
||||
|
||||
public PointLight(
|
||||
GraphicsDevice graphicsDevice,
|
||||
Vector3 position,
|
||||
Color color,
|
||||
float radius,
|
||||
int shadowMapSize
|
||||
) {
|
||||
Position = position;
|
||||
Color = color;
|
||||
Intensity = intensity;
|
||||
Radius = radius;
|
||||
|
||||
BoundingSphere = new BoundingSphere(position, Radius);
|
||||
|
||||
ShadowMap = new RenderTargetCube(
|
||||
graphicsDevice,
|
||||
shadowMapSize,
|
||||
false,
|
||||
SurfaceFormat.Single,
|
||||
DepthFormat.Depth24,
|
||||
0,
|
||||
RenderTargetUsage.PreserveContents
|
||||
);
|
||||
|
||||
var currentRTs = graphicsDevice.GetRenderTargets();
|
||||
foreach (CubeMapFace face in Enum.GetValues(typeof(CubeMapFace)))
|
||||
{
|
||||
graphicsDevice.SetRenderTarget(ShadowMap, face);
|
||||
graphicsDevice.Clear(Color.White);
|
||||
}
|
||||
|
||||
graphicsDevice.SetRenderTargets(currentRTs);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ShadowMap.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public static class CrunchAtlasReader
|
||||
{
|
||||
static JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
|
||||
public static CrunchTextureAtlasData ReadTextureAtlas(FileInfo file)
|
||||
{
|
||||
return JsonSerializer.Deserialize<CrunchTextureAtlasData>(File.ReadAllText(file.FullName), options);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
namespace Kav
|
||||
{
|
||||
public struct CrunchTextureAtlasData
|
||||
{
|
||||
public CrunchTextureAtlasTextureData[] Textures { get; set; }
|
||||
}
|
||||
|
||||
public struct CrunchTextureAtlasTextureData
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public CrunchTextureAtlasImageData[] Images { get; set; }
|
||||
}
|
||||
|
||||
public struct CrunchTextureAtlasImageData
|
||||
{
|
||||
public string N { get; set; }
|
||||
public int X { get; set; }
|
||||
public int Y { get; set; }
|
||||
public int W { get; set; }
|
||||
public int H { get; set; }
|
||||
}
|
||||
}
|
|
@ -15,19 +15,6 @@ namespace Kav
|
|||
|
||||
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];
|
||||
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.IndexBuffer,
|
||||
meshPartData.Positions,
|
||||
triangles,
|
||||
effect
|
||||
));
|
||||
triangles
|
||||
);
|
||||
|
||||
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()));
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,29 @@
|
|||
# Kav
|
||||
|
||||
A 3D renderer built on top of FNA.
|
||||
|
||||
## Roadmap
|
||||
|
||||
Essential
|
||||
|
||||
- [x] PBR shading
|
||||
- [x] Deferred rendering
|
||||
- [x] Point lighting
|
||||
- [x] Directional lighting
|
||||
- [x] Directional shadow maps
|
||||
- [x] Cascading shadow maps
|
||||
- [x] Tone map shader
|
||||
- [x] Poisson soft shadowing
|
||||
- [x] Frustum culling
|
||||
- [x] Shadow-casting point lights
|
||||
- [ ] Parabolic lights
|
||||
- [x] Skyboxes
|
||||
- [ ] Screen-space reflection
|
||||
|
||||
Nice-To-Haves
|
||||
|
||||
- [ ] Anti-aliasing
|
||||
- [ ] Image-based lighting
|
||||
- [ ] Volumetric lighting
|
||||
- [ ] Volumetric smoke
|
||||
- [ ]
|
1213
Renderer.cs
1213
Renderer.cs
File diff suppressed because it is too large
Load Diff
179
Resources.cs
179
Resources.cs
|
@ -4,25 +4,84 @@ namespace Kav
|
|||
{
|
||||
internal class Resources
|
||||
{
|
||||
public static byte[] DeferredPBR_AmbientLightEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ambientLightEffect == null)
|
||||
{
|
||||
ambientLightEffect = GetResource("DeferredPBR_AmbientLightEffect.fxb");
|
||||
}
|
||||
return ambientLightEffect;
|
||||
}
|
||||
}
|
||||
public static byte[] DeferredPBR_PointLightEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pointLightEffect == null)
|
||||
{
|
||||
pointLightEffect = GetResource("DeferredPBR_PointLightEffect.fxb");
|
||||
}
|
||||
return pointLightEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DeferredPBR_DirectionalLightEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (directionalLightEffect == null)
|
||||
{
|
||||
directionalLightEffect = GetResource("DeferredPBR_DirectionalLightEffect.fxb");
|
||||
}
|
||||
return directionalLightEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DeferredPBR_GBufferEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (gBufferEffect == null)
|
||||
{
|
||||
gBufferEffect = GetResource("DeferredPBR_GBufferEffect");
|
||||
gBufferEffect = GetResource("DeferredPBR_GBufferEffect.fxb");
|
||||
}
|
||||
return gBufferEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] ToneMapEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (toneMapEffect == null)
|
||||
{
|
||||
toneMapEffect = GetResource("ToneMapEffect.fxb");
|
||||
}
|
||||
return toneMapEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Deferred_ToonEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (deferredToonEffect == null)
|
||||
{
|
||||
deferredToonEffect = GetResource("Deferred_ToonEffect.fxb");
|
||||
}
|
||||
return deferredToonEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DeferredPBREffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (deferredPBREffect == null)
|
||||
{
|
||||
deferredPBREffect = GetResource("DeferredPBREffect");
|
||||
deferredPBREffect = GetResource("DeferredPBREffect.fxb");
|
||||
}
|
||||
return deferredPBREffect;
|
||||
}
|
||||
|
@ -34,7 +93,7 @@ namespace Kav
|
|||
{
|
||||
if (pbrEffect == null)
|
||||
{
|
||||
pbrEffect = GetResource("PBREffect");
|
||||
pbrEffect = GetResource("PBREffect.fxb");
|
||||
}
|
||||
return pbrEffect;
|
||||
}
|
||||
|
@ -46,21 +105,131 @@ namespace Kav
|
|||
{
|
||||
if (simpleDepthEffect == null)
|
||||
{
|
||||
simpleDepthEffect = GetResource("SimpleDepthEffect");
|
||||
simpleDepthEffect = GetResource("SimpleDepthEffect.fxb");
|
||||
}
|
||||
return simpleDepthEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] SimpleDepthEffectInstanced
|
||||
{
|
||||
get
|
||||
{
|
||||
if (simpleDepthEffectInstanced == null)
|
||||
{
|
||||
simpleDepthEffectInstanced = GetResource("SimpleDepthEffectInstanced.fxb");
|
||||
}
|
||||
return simpleDepthEffectInstanced;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] LinearDepthEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (linearDepthEffect == null)
|
||||
{
|
||||
linearDepthEffect = GetResource("LinearDepthEffect.fxb");
|
||||
}
|
||||
return linearDepthEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] LinearDepthEffectInstanced
|
||||
{
|
||||
get
|
||||
{
|
||||
if (linearDepthEffectInstanced == null)
|
||||
{
|
||||
linearDepthEffectInstanced = GetResource("LinearDepthEffectInstanced.fxb");
|
||||
}
|
||||
return linearDepthEffectInstanced;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] SkyboxEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (skyboxEffect == null)
|
||||
{
|
||||
skyboxEffect = GetResource("SkyboxEffect.fxb");
|
||||
}
|
||||
return skyboxEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] DiffuseLitSpriteEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (diffuseLitSpriteEffect == null)
|
||||
{
|
||||
diffuseLitSpriteEffect = GetResource("DiffuseLitSpriteEffect.fxb");
|
||||
}
|
||||
return diffuseLitSpriteEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] PaletteCrushEffect
|
||||
{
|
||||
get
|
||||
{
|
||||
if (paletteCrushEffect == null)
|
||||
{
|
||||
paletteCrushEffect = GetResource("PaletteCrushEffect.fxb");
|
||||
}
|
||||
return paletteCrushEffect;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] UnitCubeModel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (unitCubeModel == null)
|
||||
{
|
||||
unitCubeModel = GetResource("UnitCube.glb");
|
||||
}
|
||||
return unitCubeModel;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] UnitSphereModel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (unitSphereModel == null)
|
||||
{
|
||||
unitSphereModel = GetResource("UnitSphere.glb");
|
||||
}
|
||||
return unitSphereModel;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] ambientLightEffect;
|
||||
private static byte[] pointLightEffect;
|
||||
private static byte[] directionalLightEffect;
|
||||
private static byte[] gBufferEffect;
|
||||
private static byte[] toneMapEffect;
|
||||
private static byte[] deferredToonEffect;
|
||||
private static byte[] deferredPBREffect;
|
||||
private static byte[] pbrEffect;
|
||||
private static byte[] simpleDepthEffect;
|
||||
private static byte[] simpleDepthEffectInstanced;
|
||||
private static byte[] linearDepthEffect;
|
||||
private static byte[] linearDepthEffectInstanced;
|
||||
private static byte[] skyboxEffect;
|
||||
private static byte[] diffuseLitSpriteEffect;
|
||||
private static byte[] paletteCrushEffect;
|
||||
|
||||
private static byte[] unitCubeModel;
|
||||
private static byte[] unitSphereModel;
|
||||
|
||||
private static byte[] GetResource(string name)
|
||||
{
|
||||
Stream stream = typeof(Resources).Assembly.GetManifestResourceStream(
|
||||
"Kav.Resources." + name + ".fxb"
|
||||
"Kav.Resources." + name
|
||||
);
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Kav.Utils
|
||||
{
|
||||
public static class QuaternionUtils
|
||||
{
|
||||
// assumes that the input vectors are normalized and orthogonal
|
||||
public static Quaternion LookAt(in Vector3 forward, in Vector3 up)
|
||||
{
|
||||
Matrix orientation = Matrix.Identity;
|
||||
orientation.Forward = forward;
|
||||
orientation.Right = Vector3.Normalize(Vector3.Cross(forward, up));
|
||||
orientation.Up = Vector3.Cross(orientation.Right, forward);
|
||||
|
||||
return Quaternion.CreateFromRotationMatrix(orientation);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
public static class VertexDeclarations
|
||||
{
|
||||
public static VertexDeclaration PositionInstanceDeclaration = new VertexDeclaration
|
||||
(
|
||||
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.TextureCoordinate, 2)
|
||||
);
|
||||
|
||||
public static VertexDeclaration PositionTextureOffsetInstanceDeclaration = new VertexDeclaration
|
||||
(
|
||||
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.TextureCoordinate, 2),
|
||||
new VertexElement(12, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 5)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Kav
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct PositionTextureOffsetInstanceVertex : IVertexType
|
||||
{
|
||||
VertexDeclaration IVertexType.VertexDeclaration
|
||||
{
|
||||
get
|
||||
{
|
||||
return VertexDeclarations.PositionTextureOffsetInstanceDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 Translation { get; set; }
|
||||
public Vector2 UVOffset { get; set; }
|
||||
|
||||
public static readonly VertexDeclaration VertexDeclaration;
|
||||
|
||||
public PositionTextureOffsetInstanceVertex(
|
||||
Vector3 translation,
|
||||
Vector2 uvOffset
|
||||
) {
|
||||
Translation = translation;
|
||||
UVOffset = uvOffset;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue