Skip to content
Permalink
Browse files

[Rendering] Remove various dependencies from lighting code to LightCo…

…mponent
  • Loading branch information
xen2 committed Feb 12, 2019
1 parent 15ffffd commit e7ca9d2c58f45077d13e9ecdd7ad6bd5a794988c
Showing with 335 additions and 304 deletions.
  1. +1 −83 sources/engine/Xenko.Engine/Engine/LightComponent.cs
  2. +9 −15 sources/engine/Xenko.Engine/Engine/Processors/LightShaftBoundingVolumeProcessor.cs
  3. +34 −11 sources/engine/Xenko.Engine/Engine/Processors/LightShaftProcessor.cs
  4. +22 −28 sources/engine/Xenko.Engine/Rendering/Images/LightShafts/LightShafts.cs
  5. +25 −0 sources/engine/Xenko.Engine/Rendering/Images/LightShafts/RenderLightShaft.cs
  6. +1 −1 sources/engine/Xenko.Engine/Rendering/Lights/ColorLightBase.cs
  7. +17 −17 sources/engine/Xenko.Engine/Rendering/Lights/ForwardLightingRenderFeature.cs
  8. +1 −1 sources/engine/Xenko.Engine/Rendering/Lights/ILight.cs
  9. +1 −1 sources/engine/Xenko.Engine/Rendering/Lights/LightAmbient.cs
  10. +5 −5 sources/engine/Xenko.Engine/Rendering/Lights/LightClusteredPointSpotGroupRenderer.cs
  11. +1 −1 sources/engine/Xenko.Engine/Rendering/Lights/LightDirectional.cs
  12. +2 −2 sources/engine/Xenko.Engine/Rendering/Lights/LightGroupRendererBase.cs
  13. +5 −6 sources/engine/Xenko.Engine/Rendering/Lights/LightGroupRendererShadow.cs
  14. +1 −1 sources/engine/Xenko.Engine/Rendering/Lights/LightPoint.cs
  15. +52 −17 sources/engine/Xenko.Engine/Rendering/Lights/LightProcessor.cs
  16. +2 −2 sources/engine/Xenko.Engine/Rendering/Lights/LightShaderGroup.cs
  17. +1 −1 sources/engine/Xenko.Engine/Rendering/Lights/LightShaderGroupDynamic.cs
  18. +2 −2 sources/engine/Xenko.Engine/Rendering/Lights/LightSkybox.cs
  19. +5 −11 sources/engine/Xenko.Engine/Rendering/Lights/LightSkyboxRenderer.cs
  20. +1 −1 sources/engine/Xenko.Engine/Rendering/Lights/LightSpot.cs
  21. +1 −1 sources/engine/Xenko.Engine/Rendering/Lights/LightSpotGroupRenderer.cs
  22. +13 −13 sources/engine/Xenko.Engine/Rendering/Lights/LightSpotTextureProjectionRenderer.cs
  23. +67 −0 sources/engine/Xenko.Engine/Rendering/Lights/RenderLight.cs
  24. +5 −5 ...ces/engine/Xenko.Engine/Rendering/Lights/{LightComponentCollection.cs → RenderLightCollection.cs}
  25. +28 −46 .../Xenko.Engine/Rendering/Lights/{LightComponentCollectionGroup.cs → RenderLightCollectionGroup.cs}
  26. +1 −1 sources/engine/Xenko.Engine/Rendering/Shadows/ILightShadowMapRenderer.cs
  27. +1 −1 sources/engine/Xenko.Engine/Rendering/Shadows/IShadowMapRenderer.cs
  28. +3 −3 sources/engine/Xenko.Engine/Rendering/Shadows/LightDirectionalShadowMapRenderer.cs
  29. +3 −3 sources/engine/Xenko.Engine/Rendering/Shadows/LightPointShadowMapRendererCubeMap.cs
  30. +4 −4 sources/engine/Xenko.Engine/Rendering/Shadows/LightPointShadowMapRendererParaboloid.cs
  31. +2 −2 sources/engine/Xenko.Engine/Rendering/Shadows/LightShadowMapRendererBase.cs
  32. +4 −4 sources/engine/Xenko.Engine/Rendering/Shadows/LightShadowMapTexture.cs
  33. +5 −5 sources/engine/Xenko.Engine/Rendering/Shadows/LightSpotShadowMapRenderer.cs
  34. +10 −10 sources/engine/Xenko.Engine/Rendering/Shadows/ShadowMapRenderer.cs
@@ -1,4 +1,4 @@
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using System.ComponentModel;
@@ -22,11 +22,6 @@ namespace Xenko.Engine
[ComponentOrder(12000)]
public sealed class LightComponent : ActivableEntityComponent
{
/// <summary>
/// The default direction of a light vector is (x,y,z) = (0,0,-1)
/// </summary>
public static readonly Vector3 DefaultDirection = new Vector3(0, 0, -1);

/// <summary>
/// Initializes a new instance of the <see cref="LightComponent"/> class.
/// </summary>
@@ -54,82 +49,5 @@ public LightComponent()
[DataMember(30)]
[DefaultValue(1.0f)]
public float Intensity { get; set; }

/// <summary>
/// Gets the light position in World-Space (computed by the <see cref="LightProcessor"/>) (readonly field). See remarks.
/// </summary>
/// <value>The position.</value>
/// <remarks>This property should only be used inside a renderer and not from a script as it is updated after scripts</remarks>
[DataMemberIgnore]
internal Vector3 Position;

/// <summary>
/// Gets the light direction in World-Space (computed by the <see cref="LightProcessor"/>) (readonly field).
/// </summary>
/// <value>The direction.</value>
/// <remarks>This property should only be used inside a renderer and not from a script as it is updated after scripts</remarks>
[DataMemberIgnore]
internal Vector3 Direction;

[DataMemberIgnore]
internal Color3 Color;

/// <summary>
/// The bounding box of this light in WS after the <see cref="LightProcessor"/> has been applied (readonly field).
/// </summary>
[DataMemberIgnore]
internal BoundingBox BoundingBox;

/// <summary>
/// The bounding box extents of this light in WS after the <see cref="LightProcessor"/> has been applied (readonly field).
/// </summary>
[DataMemberIgnore]
internal BoundingBoxExt BoundingBoxExt;

/// <summary>
/// The determines whether this instance has a valid bounding box (readonly field).
/// </summary>
[DataMemberIgnore]
internal bool HasBoundingBox;

/// <summary>
/// Updates this instance( <see cref="Position"/>, <see cref="Direction"/>, <see cref="HasBoundingBox"/>, <see cref="BoundingBox"/>, <see cref="BoundingBoxExt"/>
/// </summary>
/// <param name="colorSpace"></param>
public bool Update(ColorSpace colorSpace)
{
if (Type == null || !Enabled || !Type.Update(this))
{
return false;
}

// Compute light direction and position
Vector3 lightDirection;
var lightDir = DefaultDirection;
Vector3.TransformNormal(ref lightDir, ref Entity.Transform.WorldMatrix, out lightDirection);
lightDirection.Normalize();

Position = Entity.Transform.WorldMatrix.TranslationVector;
Direction = lightDirection;

// Color
var colorLight = Type as IColorLight;
Color = (colorLight != null) ? colorLight.ComputeColor(colorSpace, Intensity) : new Color3();

// Compute bounding boxes
HasBoundingBox = false;
BoundingBox = new BoundingBox();
BoundingBoxExt = new BoundingBoxExt();

var directLight = Type as IDirectLight;
if (directLight != null && directLight.HasBoundingBox)
{
// Computes the bounding boxes
BoundingBox = directLight.ComputeBounds(Position, Direction);
BoundingBoxExt = new BoundingBoxExt(BoundingBox);
}

return true;
}
}
}
@@ -6,12 +6,13 @@
using Xenko.Core.Mathematics;
using Xenko.Games;
using Xenko.Rendering;
using Xenko.Rendering.Images;

namespace Xenko.Engine.Processors
{
public class LightShaftBoundingVolumeProcessor : EntityProcessor<LightShaftBoundingVolumeComponent>
{
private Dictionary<LightShaftComponent, List<Data>> volumesPerLightShaft = new Dictionary<LightShaftComponent, List<Data>>();
private Dictionary<LightShaftComponent, List<RenderLightShaftBoundingVolume>> volumesPerLightShaft = new Dictionary<LightShaftComponent, List<RenderLightShaftBoundingVolume>>();
private bool isDirty;

public override void Update(GameTime time)
@@ -23,10 +24,9 @@ public override void Update(GameTime time)
}
}

public IReadOnlyList<Data> GetBoundingVolumesForComponent(LightShaftComponent component)
public IReadOnlyList<RenderLightShaftBoundingVolume> GetBoundingVolumesForComponent(LightShaftComponent component)
{
List<Data> data;
if (!volumesPerLightShaft.TryGetValue(component, out data))
if (!volumesPerLightShaft.TryGetValue(component, out var data))
return null;
return data;
}
@@ -75,22 +75,16 @@ private void UpdateVolumesPerLightShaft()
if (lightShaft == null)
continue;

List<Data> data;
List<RenderLightShaftBoundingVolume> data;
if (!volumesPerLightShaft.TryGetValue(lightShaft, out data))
volumesPerLightShaft.Add(lightShaft, data = new List<Data>());
volumesPerLightShaft.Add(lightShaft, data = new List<RenderLightShaftBoundingVolume>());

data.Add(new Data
data.Add(new RenderLightShaftBoundingVolume
{
Component = pair.Key,
World = pair.Key.Entity.Transform.WorldMatrix,
Model = pair.Key.Model,
});
}
}

public class Data
{
public LightShaftBoundingVolumeComponent Component;
public Matrix World => Component.Entity.Transform.WorldMatrix;
public Model Model => Component.Model;
}
}
}
@@ -2,17 +2,19 @@
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

using System.Collections.Generic;
using System.Linq;
using Xenko.Core.Mathematics;
using Xenko.Games;
using Xenko.Rendering.Images;
using Xenko.Rendering.Lights;

namespace Xenko.Engine.Processors
{
public class LightShaftProcessor : EntityProcessor<LightShaftComponent, LightShaftProcessor.AssociatedData>
{
private readonly List<AssociatedData> activeLightShafts = new List<AssociatedData>();
private readonly List<RenderLightShaft> activeLightShafts = new List<RenderLightShaft>();

public List<AssociatedData> LightShafts => activeLightShafts;
public List<RenderLightShaft> LightShafts => activeLightShafts;

/// <inheritdoc />
protected override AssociatedData GenerateComponentData(Entity entity, LightShaftComponent component)
@@ -35,32 +37,53 @@ protected override bool IsAssociatedDataValid(Entity entity, LightShaftComponent
public override void Update(GameTime time)
{
activeLightShafts.Clear();

// Get processors
var lightProcessor = EntityManager.GetProcessor<LightProcessor>();
if (lightProcessor == null)
return;

var lightShaftBoundingVolumeProcessor = EntityManager.GetProcessor<LightShaftBoundingVolumeProcessor>();
if (lightShaftBoundingVolumeProcessor == null)
return;

foreach (var pair in ComponentDatas)
{
if (!pair.Key.Enabled)
continue;

var lightShaft = pair.Value;
var light = lightShaft.LightComponent;
if (lightShaft.LightComponent == null)
continue;

var directLight = light?.Type as IDirectLight;
var light = lightProcessor.GetRenderLight(lightShaft.LightComponent);
if (light == null)
continue;

var directLight = light.Type as IDirectLight;
if (directLight == null)
continue;

lightShaft.Light = directLight;
activeLightShafts.Add(lightShaft);
var boundingVolumes = lightShaftBoundingVolumeProcessor.GetBoundingVolumesForComponent(lightShaft.Component);
if (boundingVolumes == null)
continue;

activeLightShafts.Add(new RenderLightShaft
{
Light = light,
Light2 = directLight,
SampleCount = lightShaft.Component.SampleCount,
DensityFactor = lightShaft.Component.DensityFactor,
BoundingVolumes = boundingVolumes,
SeparateBoundingVolumes = lightShaft.Component.SeparateBoundingVolumes,
});
}
}

public class AssociatedData
{
public LightShaftComponent Component;
public LightComponent LightComponent;
public IDirectLight Light;
public int SampleCount => Component.SampleCount;
public Matrix LightWorld => Component.Entity.Transform.WorldMatrix;
public float DensityFactor => Component.DensityFactor;
public bool SeparateBoundingVolumes => Component.SeparateBoundingVolumes;
}
}
}
@@ -51,12 +51,11 @@ public class LightShafts : ImageEffect

private IShadowMapRenderer shadowMapRenderer;
private LightShaftProcessor lightShaftProcessor;
private LightShaftBoundingVolumeProcessor lightShaftBoundingVolumeProcessor;

private MutablePipelineState[] minmaxPipelineStates = new MutablePipelineState[2];
private EffectBytecode previousMinmaxEffectBytecode;

private LightShaftBoundingVolumeProcessor.Data[] singleBoundingVolume = new LightShaftBoundingVolumeProcessor.Data[1];
private RenderLightShaftBoundingVolume[] singleBoundingVolume = new RenderLightShaftBoundingVolume[1];

// This could be used at some point when we have colored shadows
private bool needsColorLightBuffer = true;
@@ -122,12 +121,11 @@ protected override void Destroy()
public void Collect(RenderContext context)
{
lightShaftProcessor = context.SceneInstance.GetProcessor<LightShaftProcessor>();
lightShaftBoundingVolumeProcessor = context.SceneInstance.GetProcessor<LightShaftBoundingVolumeProcessor>();
}

protected override void DrawCore(RenderDrawContext context)
{
if (lightShaftProcessor == null || lightShaftBoundingVolumeProcessor == null)
if (lightShaftProcessor == null)
return; // Not collected

if (LightBufferDownsampleLevel < 1)
@@ -173,29 +171,25 @@ protected override void DrawCore(RenderDrawContext context)

foreach (var lightShaft in lightShaftDatas)
{
if (lightShaft.LightComponent == null)
if (lightShaft.Light == null)
continue; // Skip entities without a light component

// Set sample count for this light
lightShaftsParameters.Set(LightShaftsEffectKeys.SampleCount, lightShaft.SampleCount);

// Setup the shader group used for sampling shadows
var shadowMapTexture = shadowMapRenderer.FindShadowMap(renderView.LightingView ?? renderView, lightShaft.LightComponent);
var shadowMapTexture = shadowMapRenderer.FindShadowMap(renderView.LightingView ?? renderView, lightShaft.Light);
SetupLight(context, lightShaft, shadowMapTexture, lightShaftsParameters);

var boundingVolumes = lightShaftBoundingVolumeProcessor.GetBoundingVolumesForComponent(lightShaft.Component);
if (boundingVolumes == null)
continue;


// Check if we can pack bounding volumes together or need to draw them one by one
var boundingVolumeLoop = lightShaft.SeparateBoundingVolumes ? boundingVolumes.Count : 1;
var boundingVolumeLoop = lightShaft.SeparateBoundingVolumes ? lightShaft.BoundingVolumes.Count : 1;
var lightBufferUsed = false;
for (int i = 0; i < boundingVolumeLoop; ++i)
{
// Generate list of bounding volume (either all or one by one depending on SeparateBoundingVolumes)
var currentBoundingVolumes = (lightShaft.SeparateBoundingVolumes) ? singleBoundingVolume : boundingVolumes;
var currentBoundingVolumes = (lightShaft.SeparateBoundingVolumes) ? singleBoundingVolume : lightShaft.BoundingVolumes;
if (lightShaft.SeparateBoundingVolumes)
singleBoundingVolume[0] = boundingVolumes[i];
singleBoundingVolume[0] = lightShaft.BoundingVolumes[i];

using (context.PushRenderTargetsAndRestore())
{
@@ -253,7 +247,7 @@ protected override void DrawCore(RenderDrawContext context)
}

// Additive blend pass
Color3 lightColor = lightShaft.Light.ComputeColor(context.GraphicsDevice.ColorSpace, lightShaft.LightComponent.Intensity);
Color3 lightColor = lightShaft.Light2.ComputeColor(context.GraphicsDevice.ColorSpace, lightShaft.Light.Intensity);
applyLightEffectShader.Parameters.Set(AdditiveLightShaderKeys.LightColor, lightColor);
applyLightEffectShader.Parameters.Set(AdditiveLightEffectKeys.Color, needsColorLightBuffer);
applyLightEffectShader.SetInput(lightBuffer);
@@ -281,17 +275,17 @@ public void Draw(RenderDrawContext drawContext, Texture inputDepthStencil, Textu
Draw(drawContext);
}

private void UpdateRenderData(RenderDrawContext context, LightShaftRenderData data, LightShaftProcessor.AssociatedData lightShaft, LightShadowMapTexture shadowMapTexture)
private void UpdateRenderData(RenderDrawContext context, LightShaftRenderData data, RenderLightShaft lightShaft, LightShadowMapTexture shadowMapTexture)
{
if (lightShaft.Light is LightPoint)
if (lightShaft.Light2 is LightPoint)
{
data.GroupRenderer = new LightPointGroupRenderer();
}
else if (lightShaft.Light is LightSpot)
else if (lightShaft.Light2 is LightSpot)
{
data.GroupRenderer = new LightSpotGroupRenderer();
}
else if (lightShaft.Light is LightDirectional)
else if (lightShaft.Light2 is LightDirectional)
{
data.GroupRenderer = new LightDirectionalGroupRenderer();
}
@@ -315,15 +309,15 @@ private void UpdateRenderData(RenderDrawContext context, LightShaftRenderData da
data.ShaderGroup = data.GroupRenderer.CreateLightShaderGroup(context, shadowGroup); // TODO: Implement support for texture projection and attenuation?
}

private void SetupLight(RenderDrawContext context, LightShaftProcessor.AssociatedData lightShaft, LightShadowMapTexture shadowMapTexture, ParameterCollection lightParameterCollection)
private void SetupLight(RenderDrawContext context, RenderLightShaft lightShaft, LightShadowMapTexture shadowMapTexture, ParameterCollection lightParameterCollection)
{
BoundingBoxExt box = new BoundingBoxExt(new Vector3(-float.MaxValue), new Vector3(float.MaxValue)); // TODO

LightShaftRenderData data;
if (!renderData.TryGetValue(lightShaft.Light, out data))
if (!renderData.TryGetValue(lightShaft.Light2, out data))
{
data = new LightShaftRenderData();
renderData.Add(lightShaft.Light, data);
renderData.Add(lightShaft.Light2, data);
UpdateRenderData(context, data, lightShaft, shadowMapTexture);
}

@@ -343,7 +337,7 @@ private void SetupLight(RenderDrawContext context, LightShaftProcessor.Associate
data.ShaderGroup.SetViews(data.RenderViews);
data.ShaderGroup.AddView(0, context.RenderContext.RenderView, 1);

data.ShaderGroup.AddLight(lightShaft.LightComponent, shadowMapTexture);
data.ShaderGroup.AddLight(lightShaft.Light, shadowMapTexture);
data.ShaderGroup.UpdateLayout("lightGroup");

lightParameterCollection.Set(LightShaftsEffectKeys.LightGroup, data.ShaderGroup.ShaderSource);
@@ -357,27 +351,27 @@ private void SetupLight(RenderDrawContext context, LightShaftProcessor.Associate
data.UsageCounter = usageCounter;
}

private void DrawLightShaft(RenderDrawContext context, LightShaftProcessor.AssociatedData lightShaft)
private void DrawLightShaft(RenderDrawContext context, RenderLightShaft lightShaft)
{
lightShaftsEffectShader.Parameters.Set(LightShaftsShaderKeys.DensityFactor, lightShaft.DensityFactor);

lightShaftsEffectShader.Draw(context, $"Light shaft [{lightShaft.LightComponent.Entity.Name}]");
lightShaftsEffectShader.Draw(context, "Light shaft");
}

private bool DrawBoundingVolumeMinMax(RenderDrawContext context, IReadOnlyList<LightShaftBoundingVolumeProcessor.Data> boundingVolumes)
private bool DrawBoundingVolumeMinMax(RenderDrawContext context, IReadOnlyList<RenderLightShaftBoundingVolume> boundingVolumes)
{
return DrawBoundingVolumes(context, boundingVolumes, context.RenderContext.RenderView.ViewProjection);
}

private void DrawBoundingVolumeBackside(RenderDrawContext context, IReadOnlyList<LightShaftBoundingVolumeProcessor.Data> boundingVolumes)
private void DrawBoundingVolumeBackside(RenderDrawContext context, IReadOnlyList<RenderLightShaftBoundingVolume> boundingVolumes)
{
float backSideMaximumDistance = context.RenderContext.RenderView.FarClipPlane;
float backSideMinimumDistance = -context.RenderContext.RenderView.NearClipPlane;
Matrix backSideProjection = context.RenderContext.RenderView.View * Matrix.Scaling(1, 1, -1) * Matrix.OrthoRH(BackSideOrthographicSize, BackSideOrthographicSize, backSideMinimumDistance, backSideMaximumDistance);
DrawBoundingVolumes(context, boundingVolumes, backSideProjection);
}

private bool DrawBoundingVolumes(RenderDrawContext context, IReadOnlyList<LightShaftBoundingVolumeProcessor.Data> boundingVolumes, Matrix viewProjection)
private bool DrawBoundingVolumes(RenderDrawContext context, IReadOnlyList<RenderLightShaftBoundingVolume> boundingVolumes, Matrix viewProjection)
{
var commandList = context.CommandList;

0 comments on commit e7ca9d2

Please sign in to comment.
You can’t perform that action at this time.