supporting directional lights
parent
86cc23b0ad
commit
393b8bcb03
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Kav
|
||||||
|
{
|
||||||
|
public interface DirectionalLightEffect
|
||||||
|
{
|
||||||
|
int MaxDirectionalLights { get; }
|
||||||
|
DirectionalLightCollection DirectionalLights { get; }
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
|
@ -23,12 +23,15 @@ BEGIN_CONSTANTS
|
||||||
|
|
||||||
// Light Info
|
// Light Info
|
||||||
float3 LightPositions[4] _ps(c4) _cb(c4);
|
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);
|
float3 EyePosition _ps(c20) _cb(c20);
|
||||||
float4x4 WorldInverseTranspose _vs(c4) _cb(c20);
|
|
||||||
|
float4x4 World _vs(c0) _cb(c21);
|
||||||
|
float4x4 WorldInverseTranspose _vs(c4) _cb(c25);
|
||||||
|
|
||||||
MATRIX_CONSTANTS
|
MATRIX_CONSTANTS
|
||||||
|
|
||||||
|
@ -121,6 +124,36 @@ float3 GetNormalFromMap(float3 worldPos, float2 texCoords, float3 normal)
|
||||||
return normalize(mul(tangentNormal, TBN));
|
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(
|
float4 ComputeColor(
|
||||||
float3 worldPosition,
|
float3 worldPosition,
|
||||||
float3 worldNormal,
|
float3 worldNormal,
|
||||||
|
@ -136,31 +169,24 @@ float4 ComputeColor(
|
||||||
|
|
||||||
float3 Lo = float3(0.0, 0.0, 0.0);
|
float3 Lo = float3(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
// point light
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
float3 lightDir = LightPositions[i] - worldPosition;
|
float3 lightDir = LightPositions[i] - worldPosition;
|
||||||
float3 L = normalize(lightDir);
|
|
||||||
float3 H = normalize(V + L);
|
|
||||||
|
|
||||||
float distance = length(lightDir);
|
float distance = length(lightDir);
|
||||||
float attenuation = 1.0 / (distance * distance);
|
float attenuation = 1.0 / (distance * distance);
|
||||||
float3 radiance = LightColors[i] * attenuation;
|
float3 radiance = PositionLightColors[i] * attenuation;
|
||||||
|
|
||||||
float NDF = DistributionGGX(N, H, roughness);
|
Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness);
|
||||||
float G = GeometrySmith(N, V, L, roughness);
|
}
|
||||||
float3 F = FresnelSchlick(max(dot(H, V), 0.0), F0);
|
|
||||||
|
|
||||||
float3 numerator = NDF * G * F;
|
// directional light
|
||||||
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0);
|
for (int i = 0; i < 4; i++)
|
||||||
float3 specular = numerator / max(denominator, 0.001);
|
{
|
||||||
|
float3 lightDir = LightDirections[i];
|
||||||
|
float3 radiance = DirectionLightColors[i];
|
||||||
|
|
||||||
float3 kS = F;
|
Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO;
|
float3 ambient = float3(0.03, 0.03, 0.03) * albedo * AO;
|
||||||
|
|
|
@ -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 worldParam;
|
||||||
EffectParameter worldViewProjectionParam;
|
EffectParameter worldViewProjectionParam;
|
||||||
|
@ -73,6 +115,7 @@ namespace Kav
|
||||||
Matrix view = Matrix.Identity;
|
Matrix view = Matrix.Identity;
|
||||||
Matrix projection = Matrix.Identity;
|
Matrix projection = Matrix.Identity;
|
||||||
PointLightCollection pointLightCollection;
|
PointLightCollection pointLightCollection;
|
||||||
|
DirectionalLightCollection directionalLightCollection;
|
||||||
|
|
||||||
Vector3 albedo;
|
Vector3 albedo;
|
||||||
float metallic;
|
float metallic;
|
||||||
|
@ -122,7 +165,15 @@ namespace Kav
|
||||||
public PointLightCollection PointLights
|
public PointLightCollection PointLights
|
||||||
{
|
{
|
||||||
get { return pointLightCollection; }
|
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
|
public Vector3 Albedo
|
||||||
|
@ -234,7 +285,12 @@ namespace Kav
|
||||||
|
|
||||||
pointLightCollection = new PointLightCollection(
|
pointLightCollection = new PointLightCollection(
|
||||||
Parameters["LightPositions"],
|
Parameters["LightPositions"],
|
||||||
Parameters["LightColors"]
|
Parameters["PositionLightColors"]
|
||||||
|
);
|
||||||
|
|
||||||
|
directionalLightCollection = new DirectionalLightCollection(
|
||||||
|
Parameters["LightDirections"],
|
||||||
|
Parameters["DirectionLightColors"]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,14 +304,24 @@ namespace Kav
|
||||||
|
|
||||||
PointLights = new PointLightCollection(
|
PointLights = new PointLightCollection(
|
||||||
Parameters["LightPositions"],
|
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];
|
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;
|
AlbedoTexture = cloneSource.AlbedoTexture;
|
||||||
NormalTexture = cloneSource.NormalTexture;
|
NormalTexture = cloneSource.NormalTexture;
|
||||||
EmissionTexture = cloneSource.EmissionTexture;
|
EmissionTexture = cloneSource.EmissionTexture;
|
||||||
|
|
|
@ -10,19 +10,5 @@ namespace Kav
|
||||||
{
|
{
|
||||||
Meshes = meshes;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
<EmbeddedResource Include="Effects\FXB\PBREffect.fxb">
|
<EmbeddedResource Include="Effects\FXB\PBREffect.fxb">
|
||||||
<LogicalName>Kav.Resources.PBREffect.fxb</LogicalName>
|
<LogicalName>Kav.Resources.PBREffect.fxb</LogicalName>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="Effects\FXB\SimpleDepthEffect.fxb">
|
||||||
|
<LogicalName>Kav.Resources.SimpleDepthEffect.fxb</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +2,11 @@ using Microsoft.Xna.Framework;
|
||||||
|
|
||||||
namespace Kav
|
namespace Kav
|
||||||
{
|
{
|
||||||
public class PointLight
|
public struct PointLight
|
||||||
{
|
{
|
||||||
public Vector3 Position { get; set; }
|
public Vector3 Position { get; }
|
||||||
public Color Color { get; set; }
|
public Color Color { get; }
|
||||||
public float Intensity { get; set; }
|
public float Intensity { get; }
|
||||||
|
|
||||||
public PointLight(Vector3 position, Color color, float intensity = 1f)
|
public PointLight(Vector3 position, Color color, float intensity = 1f)
|
||||||
{
|
{
|
||||||
|
|
39
Renderer.cs
39
Renderer.cs
|
@ -31,19 +31,23 @@ namespace Kav
|
||||||
SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice);
|
SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Render(Camera camera, IEnumerable<Model> models, IEnumerable<PointLight> pointLights)
|
public void Render(
|
||||||
{
|
Camera camera,
|
||||||
Render(camera.View, camera.Projection, models, pointLights);
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
|
IEnumerable<PointLight> pointLights,
|
||||||
|
IEnumerable<DirectionalLight> directionalLights
|
||||||
|
) {
|
||||||
|
Render(camera.View, camera.Projection, modelTransforms, pointLights, directionalLights);
|
||||||
}
|
}
|
||||||
|
|
||||||
// for shadow mapping
|
// for shadow mapping
|
||||||
public void DepthRender(Matrix view, Matrix projection, IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<PointLight> pointLights)
|
public void DepthRender(IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight)
|
||||||
{
|
{
|
||||||
GraphicsDevice.SetRenderTarget(DepthRenderTarget);
|
GraphicsDevice.SetRenderTarget(DepthRenderTarget);
|
||||||
GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1, 0);
|
GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1, 0);
|
||||||
|
|
||||||
SimpleDepthEffect.View = view;
|
SimpleDepthEffect.View = directionalLight.View;
|
||||||
SimpleDepthEffect.Projection = projection;
|
SimpleDepthEffect.Projection = directionalLight.Projection;
|
||||||
|
|
||||||
foreach (var (model, transform) in modelTransforms)
|
foreach (var (model, transform) in modelTransforms)
|
||||||
{
|
{
|
||||||
|
@ -74,9 +78,14 @@ namespace Kav
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Render(Matrix view, Matrix projection, IEnumerable<Model> models, IEnumerable<PointLight> pointLights)
|
private void Render(
|
||||||
{
|
Matrix view,
|
||||||
foreach (var model in models)
|
Matrix projection,
|
||||||
|
IEnumerable<(Model, Matrix)> modelTransforms,
|
||||||
|
IEnumerable<PointLight> pointLights,
|
||||||
|
IEnumerable<DirectionalLight> directionalLights
|
||||||
|
) {
|
||||||
|
foreach (var (model, transform) in modelTransforms)
|
||||||
{
|
{
|
||||||
foreach (var modelMesh in model.Meshes)
|
foreach (var modelMesh in model.Meshes)
|
||||||
{
|
{
|
||||||
|
@ -87,6 +96,7 @@ namespace Kav
|
||||||
|
|
||||||
if (meshPart.Effect is TransformEffect transformEffect)
|
if (meshPart.Effect is TransformEffect transformEffect)
|
||||||
{
|
{
|
||||||
|
transformEffect.World = transform;
|
||||||
transformEffect.View = view;
|
transformEffect.View = view;
|
||||||
transformEffect.Projection = projection;
|
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)
|
foreach (var pass in meshPart.Effect.CurrentTechnique.Passes)
|
||||||
{
|
{
|
||||||
pass.Apply();
|
pass.Apply();
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace Kav
|
||||||
{
|
{
|
||||||
if (simpleDepthEffect == null)
|
if (simpleDepthEffect == null)
|
||||||
{
|
{
|
||||||
simpleDepthEffect = GetResource("SimpleDepthEffecT");
|
simpleDepthEffect = GetResource("SimpleDepthEffect");
|
||||||
}
|
}
|
||||||
return simpleDepthEffect;
|
return simpleDepthEffect;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue