LOS effect optimization/changes:

- Rendering the shadows instead of light volumes to avoid the expensive raycasts needed to calculate the light volume.
- The LOS shadows are now rendered in two passes (fully obscured + penumbra) instead of each convex hull taking up 2 passes.

TODO: fix linux
This commit is contained in:
Joonas Rikkonen
2018-03-03 20:23:27 +02:00
parent e15fad6986
commit da7ea779b7
7 changed files with 224 additions and 187 deletions
@@ -6,41 +6,6 @@ using System.Diagnostics;
namespace Barotrauma.Lights
{
/*class CachedShadow : IDisposable
{
public VertexBuffer ShadowBuffer;
public Vector2 LightPos;
public int ShadowVertexCount, PenumbraVertexCount;
public CachedShadow(VertexPositionColor[] shadowVertices, Vector2 lightPos, int shadowVertexCount, int penumbraVertexCount)
{
//var ShadowVertices = new VertexPositionColor [shadowVertices.Count()];
//shadowVertices.CopyTo(ShadowVertices, 0);
ShadowBuffer = new VertexBuffer(GameMain.CurrGraphicsDevice, VertexPositionColor.VertexDeclaration, 6*2, BufferUsage.None);
ShadowBuffer.SetData(shadowVertices, 0, shadowVertices.Length);
ShadowVertexCount = shadowVertexCount;
PenumbraVertexCount = penumbraVertexCount;
LightPos = lightPos;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
ShadowBuffer.Dispose();
}
}*/
class ConvexHullList
{
private List<ConvexHull> list;
@@ -107,27 +72,30 @@ namespace Barotrauma.Lights
class ConvexHull
{
public static List<ConvexHullList> HullLists = new List<ConvexHullList>();
static BasicEffect shadowEffect;
static BasicEffect penumbraEffect;
//private Dictionary<LightSource, CachedShadow> cachedShadows;
public VertexBuffer ShadowBuffer;
public static BasicEffect shadowEffect;
public static BasicEffect penumbraEffect;
Segment[] segments = new Segment[4];
SegmentPoint[] vertices = new SegmentPoint[4];
SegmentPoint[] losVertices = new SegmentPoint[4];
//private Vector2[] vertices;
//private Vector2[] losVertices;
private bool[] backFacing;
private bool[] ignoreEdge;
private VertexPositionColor[] shadowVertices;
private VertexPositionTexture[] penumbraVertices;
int shadowVertexCount;
public VertexPositionColor[] ShadowVertices
{
get { return shadowVertices; }
}
public VertexPositionTexture[] PenumbraVertices
{
get { return penumbraVertices; }
}
public int shadowVertexCount;
private Entity parentEntity;
@@ -399,8 +367,14 @@ namespace Barotrauma.Lights
}
}
private void CalculateShadowVertices(Vector2 lightSourcePos, bool los = true)
public void CalculateShadowVertices(Vector2 lightSourcePos, bool los = true)
{
Vector3 offset = Vector3.Zero;
if (parentEntity != null && parentEntity.Submarine != null)
{
offset = new Vector3(parentEntity.Submarine.DrawPosition.X, parentEntity.Submarine.DrawPosition.Y, 0.0f);
}
shadowVertexCount = 0;
var vertices = los ? losVertices : this.vertices;
@@ -463,7 +437,7 @@ namespace Barotrauma.Lights
//one vertex on the hull
shadowVertices[i] = new VertexPositionColor();
shadowVertices[i].Color = los ? Color.Black : Color.Transparent;
shadowVertices[i].Position = vertexPos;
shadowVertices[i].Position = vertexPos+ offset;
//one extruded by the light direction
shadowVertices[j] = new VertexPositionColor();
@@ -472,7 +446,7 @@ namespace Barotrauma.Lights
Vector3 L2P = vertexPos - new Vector3(lightSourcePos, 0);
L2P.Normalize();
shadowVertices[j].Position = new Vector3(lightSourcePos, 0) + L2P * 9000;
shadowVertices[j].Position = new Vector3(lightSourcePos, 0) + L2P * 9000 + offset;
svCount += 2;
currentIndex = (currentIndex + 1) % 4;
@@ -486,12 +460,18 @@ namespace Barotrauma.Lights
private void CalculatePenumbraVertices(int startingIndex, int endingIndex, Vector2 lightSourcePos, bool los)
{
Vector3 offset = Vector3.Zero;
if (parentEntity != null && parentEntity.Submarine != null)
{
offset = new Vector3(parentEntity.Submarine.DrawPosition.X, parentEntity.Submarine.DrawPosition.Y, 0.0f);
}
for (int n = 0; n < 4; n += 3)
{
Vector3 penumbraStart = new Vector3((n == 0) ? vertices[startingIndex].Pos : vertices[endingIndex].Pos, 0.0f);
penumbraVertices[n] = new VertexPositionTexture();
penumbraVertices[n].Position = penumbraStart;
penumbraVertices[n].Position = penumbraStart + offset;
penumbraVertices[n].TextureCoordinate = new Vector2(0.0f, 1.0f);
//penumbraVertices[0].te = fow ? Color.Black : Color.Transparent;
@@ -506,7 +486,7 @@ namespace Barotrauma.Lights
vertexDir = penumbraStart - (new Vector3(lightSourcePos, 0) - normal * 20.0f);
vertexDir.Normalize();
penumbraVertices[n + i + 1].Position = new Vector3(lightSourcePos, 0) + vertexDir * 9000;
penumbraVertices[n + i + 1].Position = new Vector3(lightSourcePos, 0) + vertexDir * 9000 + offset;
if (los)
{
@@ -531,7 +511,7 @@ namespace Barotrauma.Lights
{
List<ConvexHull> list = new List<ConvexHull>();
foreach (ConvexHullList chList in ConvexHull.HullLists)
foreach (ConvexHullList chList in HullLists)
{
Vector2 lightPos = position;
if (ParentSub == null)
@@ -581,85 +561,7 @@ namespace Barotrauma.Lights
return list;
}
public void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, LightSource light, Matrix transform, bool los = true)
{
if (!Enabled) return;
Vector2 lightSourcePos = light.Position;
if (parentEntity != null && parentEntity.Submarine != null)
{
if (light.ParentSub == null)
{
lightSourcePos -= parentEntity.Submarine.Position;
}
else if (light.ParentSub != parentEntity.Submarine)
{
lightSourcePos += (light.ParentSub.Position-parentEntity.Submarine.Position);
}
}
CalculateShadowVertices(lightSourcePos, los);
ShadowBuffer = new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColor.VertexDeclaration, 6 * 2, BufferUsage.None);
ShadowBuffer.SetData(shadowVertices, 0, shadowVertices.Length);
graphicsDevice.SetVertexBuffer(ShadowBuffer);
shadowVertexCount = shadowVertices.Length;
DrawShadows(graphicsDevice, cam, transform, los);
}
public void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, Vector2 lightSourcePos, Matrix transform, bool los = true)
{
if (!Enabled) return;
if (parentEntity != null && parentEntity.Submarine != null) lightSourcePos -= parentEntity.Submarine.Position;
CalculateShadowVertices(lightSourcePos, los);
DrawShadows(graphicsDevice, cam, transform, los);
}
private void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, Matrix transform, bool los = true)
{
Vector3 offset = Vector3.Zero;
if (parentEntity != null && parentEntity.Submarine != null)
{
offset = new Vector3(parentEntity.Submarine.DrawPosition.X, parentEntity.Submarine.DrawPosition.Y, 0.0f);
}
if (shadowVertexCount>0)
{
shadowEffect.World = Matrix.CreateTranslation(offset) * transform;
if (los)
{
shadowEffect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, shadowVertices, 0, shadowVertexCount * 2 - 2, VertexPositionColor.VertexDeclaration);
}
else
{
shadowEffect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, shadowVertexCount * 2 - 2);
}
}
if (los)
{
penumbraEffect.World = shadowEffect.World;
penumbraEffect.CurrentTechnique.Passes[0].Apply();
#if WINDOWS
graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, penumbraVertices, 0, 2, VertexPositionTexture.VertexDeclaration);
#endif
}
}
public void Remove()
{
var chList = HullLists.Find(x => x.Submarine == parentEntity.Submarine);