diff --git a/EffectInterfaces/DirectionalLightEffect.cs b/EffectInterfaces/DirectionalLightEffect.cs
new file mode 100644
index 0000000..53ba894
--- /dev/null
+++ b/EffectInterfaces/DirectionalLightEffect.cs
@@ -0,0 +1,8 @@
+namespace Kav
+{
+ public interface DirectionalLightEffect
+ {
+ int MaxDirectionalLights { get; }
+ DirectionalLightCollection DirectionalLights { get; }
+ }
+}
diff --git a/Effects/FXB/PBREffect.fxb b/Effects/FXB/PBREffect.fxb
index 9763762..1cac37b 100644
Binary files a/Effects/FXB/PBREffect.fxb and b/Effects/FXB/PBREffect.fxb differ
diff --git a/Effects/HLSL/PBREffect.fx b/Effects/HLSL/PBREffect.fx
index ee5ecb7..34ce0ec 100644
--- a/Effects/HLSL/PBREffect.fx
+++ b/Effects/HLSL/PBREffect.fx
@@ -23,12 +23,15 @@ BEGIN_CONSTANTS
// Light Info
float3 LightPositions[4] _ps(c4) _cb(c4);
- float3 LightColors[4] _ps(c8) _cb(c8);
+ float3 PositionLightColors[4] _ps(c8) _cb(c8);
- float3 EyePosition _ps(c12) _cb(c12);
+ float3 LightDirections[4] _ps(c12) _cb(c12);
+ float3 DirectionLightColors[4] _ps(c16) _cb(c16);
- float4x4 World _vs(c0) _cb(c16);
- float4x4 WorldInverseTranspose _vs(c4) _cb(c20);
+ float3 EyePosition _ps(c20) _cb(c20);
+
+ float4x4 World _vs(c0) _cb(c21);
+ float4x4 WorldInverseTranspose _vs(c4) _cb(c25);
MATRIX_CONSTANTS
@@ -121,6 +124,36 @@ float3 GetNormalFromMap(float3 worldPos, float2 texCoords, float3 normal)
return normalize(mul(tangentNormal, TBN));
}
+float3 ComputeLight(
+ float3 lightDir,
+ float3 radiance,
+ float3 F0,
+ float3 V,
+ float3 N,
+ float3 albedo,
+ float metallic,
+ float roughness
+) {
+ float3 L = normalize(lightDir);
+ 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;
+}
+
float4 ComputeColor(
float3 worldPosition,
float3 worldNormal,
@@ -136,31 +169,24 @@ float4 ComputeColor(
float3 Lo = float3(0.0, 0.0, 0.0);
+ // point light
for (int i = 0; i < 4; i++)
{
float3 lightDir = LightPositions[i] - worldPosition;
- float3 L = normalize(lightDir);
- float3 H = normalize(V + L);
-
float distance = length(lightDir);
float attenuation = 1.0 / (distance * distance);
- float3 radiance = LightColors[i] * attenuation;
+ float3 radiance = PositionLightColors[i] * attenuation;
- float NDF = DistributionGGX(N, H, roughness);
- float G = GeometrySmith(N, V, L, roughness);
- float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0);
+ Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness);
+ }
- 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);
+ // directional light
+ for (int i = 0; i < 4; i++)
+ {
+ float3 lightDir = LightDirections[i];
+ float3 radiance = DirectionLightColors[i];
- 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);
- Lo += (kD * albedo / PI + specular) * radiance * NdotL;
+ Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness);
}
float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO;
diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs
index f7927b4..09e313e 100644
--- a/Effects/PBREffect.cs
+++ b/Effects/PBREffect.cs
@@ -45,7 +45,49 @@ namespace Kav
}
}
- public class PBREffect : Effect, TransformEffect, PointLightEffect
+ 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 lightPositionsParam;
+ readonly EffectParameter lightColorsParam;
+
+ public DirectionalLightCollection(EffectParameter lightPositionsParam, EffectParameter lightColorsParam)
+ {
+ this.lightPositionsParam = lightPositionsParam;
+ 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;
+ lightPositionsParam.SetValue(directions);
+ lightColorsParam.SetValue(colors);
+ }
+ }
+ }
+
+ public class PBREffect : Effect, TransformEffect, PointLightEffect, DirectionalLightEffect
{
EffectParameter worldParam;
EffectParameter worldViewProjectionParam;
@@ -73,6 +115,7 @@ namespace Kav
Matrix view = Matrix.Identity;
Matrix projection = Matrix.Identity;
PointLightCollection pointLightCollection;
+ DirectionalLightCollection directionalLightCollection;
Vector3 albedo;
float metallic;
@@ -122,7 +165,15 @@ namespace Kav
public PointLightCollection PointLights
{
get { return pointLightCollection; }
- internal set { pointLightCollection = value; }
+ private set { pointLightCollection = value; }
+ }
+
+ public int MaxDirectionalLights { get; } = 4;
+
+ public DirectionalLightCollection DirectionalLights
+ {
+ get { return directionalLightCollection; }
+ private set { directionalLightCollection = value; }
}
public Vector3 Albedo
@@ -234,7 +285,12 @@ namespace Kav
pointLightCollection = new PointLightCollection(
Parameters["LightPositions"],
- Parameters["LightColors"]
+ Parameters["PositionLightColors"]
+ );
+
+ directionalLightCollection = new DirectionalLightCollection(
+ Parameters["LightDirections"],
+ Parameters["DirectionLightColors"]
);
}
@@ -248,14 +304,24 @@ namespace Kav
PointLights = new PointLightCollection(
Parameters["LightPositions"],
- Parameters["LightColors"]
+ Parameters["PositionLightColors"]
);
- for (int i = 0; i < 4; i++)
+ 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;
diff --git a/Geometry/Model.cs b/Geometry/Model.cs
index 049532f..1d83410 100644
--- a/Geometry/Model.cs
+++ b/Geometry/Model.cs
@@ -10,19 +10,5 @@ namespace Kav
{
Meshes = meshes;
}
-
- public void ApplyTransform(Matrix transform)
- {
- foreach (var mesh in Meshes)
- {
- foreach (var meshPart in mesh.MeshParts)
- {
- if (meshPart.Effect is TransformEffect transformEffect)
- {
- transformEffect.World = transform;
- }
- }
- }
- }
}
}
diff --git a/Kav.csproj b/Kav.csproj
index 41937d0..4497042 100644
--- a/Kav.csproj
+++ b/Kav.csproj
@@ -18,6 +18,9 @@
Kav.Resources.PBREffect.fxb
+
+ Kav.Resources.SimpleDepthEffect.fxb
+
diff --git a/Lights/DirectionalLight.cs b/Lights/DirectionalLight.cs
new file mode 100644
index 0000000..31ca4fd
--- /dev/null
+++ b/Lights/DirectionalLight.cs
@@ -0,0 +1,34 @@
+using Microsoft.Xna.Framework;
+
+namespace Kav
+{
+ public struct DirectionalLight
+ {
+ public Vector3 Direction { get; set; }
+ public Color Color { get; set; }
+ public float Intensity { get; set; }
+
+ public Matrix View
+ {
+ get
+ {
+ return Matrix.CreateLookAt(-Direction * 100f, Vector3.Zero, Vector3.Up);
+ }
+ }
+
+ public Matrix Projection
+ {
+ get
+ {
+ return Matrix.CreateOrthographic(20f, 20f, 1f, 101f);
+ }
+ }
+
+ public DirectionalLight(Vector3 direction, Color color, float intensity = 1f)
+ {
+ Direction = direction;
+ Color = color;
+ Intensity = intensity;
+ }
+ }
+}
diff --git a/Lights/PointLight.cs b/Lights/PointLight.cs
index 657f7ea..6d3fb90 100644
--- a/Lights/PointLight.cs
+++ b/Lights/PointLight.cs
@@ -2,11 +2,11 @@ using Microsoft.Xna.Framework;
namespace Kav
{
- public class PointLight
+ public struct PointLight
{
- public Vector3 Position { get; set; }
- public Color Color { get; set; }
- public float Intensity { get; set; }
+ public Vector3 Position { get; }
+ public Color Color { get; }
+ public float Intensity { get; }
public PointLight(Vector3 position, Color color, float intensity = 1f)
{
diff --git a/Renderer.cs b/Renderer.cs
index 79b078d..77037b3 100644
--- a/Renderer.cs
+++ b/Renderer.cs
@@ -31,19 +31,23 @@ namespace Kav
SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice);
}
- public void Render(Camera camera, IEnumerable models, IEnumerable pointLights)
- {
- Render(camera.View, camera.Projection, models, pointLights);
+ public void Render(
+ Camera camera,
+ IEnumerable<(Model, Matrix)> modelTransforms,
+ IEnumerable pointLights,
+ IEnumerable directionalLights
+ ) {
+ Render(camera.View, camera.Projection, modelTransforms, pointLights, directionalLights);
}
// for shadow mapping
- public void DepthRender(Matrix view, Matrix projection, IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable pointLights)
+ public void DepthRender(IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight)
{
GraphicsDevice.SetRenderTarget(DepthRenderTarget);
GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1, 0);
- SimpleDepthEffect.View = view;
- SimpleDepthEffect.Projection = projection;
+ SimpleDepthEffect.View = directionalLight.View;
+ SimpleDepthEffect.Projection = directionalLight.Projection;
foreach (var (model, transform) in modelTransforms)
{
@@ -74,9 +78,14 @@ namespace Kav
}
}
- private void Render(Matrix view, Matrix projection, IEnumerable models, IEnumerable pointLights)
- {
- foreach (var model in models)
+ private void Render(
+ Matrix view,
+ Matrix projection,
+ IEnumerable<(Model, Matrix)> modelTransforms,
+ IEnumerable pointLights,
+ IEnumerable directionalLights
+ ) {
+ foreach (var (model, transform) in modelTransforms)
{
foreach (var modelMesh in model.Meshes)
{
@@ -87,6 +96,7 @@ namespace Kav
if (meshPart.Effect is TransformEffect transformEffect)
{
+ transformEffect.World = transform;
transformEffect.View = view;
transformEffect.Projection = projection;
}
@@ -102,6 +112,17 @@ namespace Kav
}
}
+ if (meshPart.Effect is DirectionalLightEffect directionalLightEffect)
+ {
+ int i = 0;
+ foreach (var directionalLight in directionalLights)
+ {
+ if (i > directionalLightEffect.MaxDirectionalLights) { break; }
+ directionalLightEffect.DirectionalLights[i] = directionalLight;
+ i++;
+ }
+ }
+
foreach (var pass in meshPart.Effect.CurrentTechnique.Passes)
{
pass.Apply();
diff --git a/Resources.cs b/Resources.cs
index 4964b4a..6ff3806 100644
--- a/Resources.cs
+++ b/Resources.cs
@@ -22,7 +22,7 @@ namespace Kav
{
if (simpleDepthEffect == null)
{
- simpleDepthEffect = GetResource("SimpleDepthEffecT");
+ simpleDepthEffect = GetResource("SimpleDepthEffect");
}
return simpleDepthEffect;
}