supporting directional lights

shadows
cosmonaut 2020-08-07 01:12:46 -07:00
parent 86cc23b0ad
commit 393b8bcb03
10 changed files with 198 additions and 54 deletions

View File

@ -0,0 +1,8 @@
namespace Kav
{
public interface DirectionalLightEffect
{
int MaxDirectionalLights { get; }
DirectionalLightCollection DirectionalLights { get; }
}
}

Binary file not shown.

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}
}
}
} }
} }

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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)
{ {

View File

@ -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();

View File

@ -22,7 +22,7 @@ namespace Kav
{ {
if (simpleDepthEffect == null) if (simpleDepthEffect == null)
{ {
simpleDepthEffect = GetResource("SimpleDepthEffecT"); simpleDepthEffect = GetResource("SimpleDepthEffect");
} }
return simpleDepthEffect; return simpleDepthEffect;
} }