Lighting optimization (caching shadow vertices & only checking hulls in range if the position or range of the light changes), ragdoll optimization, itemcomponent optimization, dragging stunned/dead characters

This commit is contained in:
Regalis11
2015-10-11 21:04:42 +03:00
parent 0a96254696
commit 8df9133e84
25 changed files with 377 additions and 201 deletions
+67 -12
View File
@@ -5,11 +5,30 @@ using System.Linq;
namespace Subsurface.Lights
{
class CachedShadow
{
public VertexPositionColor[] ShadowVertices;
public VertexPositionTexture[] PenumbraVertices;
public Vector2 LightPos;
public CachedShadow(VertexPositionColor[] shadowVertices, VertexPositionTexture[] penumbraVertices, Vector2 lightPos)
{
ShadowVertices = shadowVertices;
PenumbraVertices = penumbraVertices;
LightPos = lightPos;
}
}
class ConvexHull
{
public static List<ConvexHull> list = new List<ConvexHull>();
static BasicEffect shadowEffect;
static BasicEffect penumbraEffect;
private Dictionary<LightSource, CachedShadow> cachedShadows;
private Vector2[] vertices;
private int primitiveCount;
@@ -47,19 +66,14 @@ namespace Subsurface.Lights
penumbraEffect.LightingEnabled = false;
penumbraEffect.Texture = TextureLoader.FromFile("Content/Lights/penumbra.png");
}
cachedShadows = new Dictionary<LightSource, CachedShadow>();
vertices = points;
primitiveCount = vertices.Length;
CalculateDimensions();
//indices = new short[primitiveCount * 3];
//for (int i = 0; i < primitiveCount; i++)
//{
// indices[3 * i] = (short)i;
// indices[3 * i + 1] = (short)((i + 1) % vertexCount);
// indices[3 * i + 2] = (short)vertexCount;
//}
backFacing = new bool[primitiveCount];
Enabled = true;
@@ -90,6 +104,8 @@ namespace Subsurface.Lights
public void Move(Vector2 amount)
{
cachedShadows.Clear();
for (int i = 0; i < vertices.Count(); i++)
{
vertices[i] += amount;
@@ -100,6 +116,8 @@ namespace Subsurface.Lights
public void SetVertices(Vector2[] points)
{
cachedShadows.Clear();
vertices = points;
}
@@ -222,25 +240,62 @@ namespace Subsurface.Lights
}
}
public void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, LightSource light, Matrix transform, bool los = true)
{
if (!Enabled) return;
CachedShadow cachedShadow = null;
if (cachedShadows.TryGetValue(light, out cachedShadow))
{
if (light.Position == cachedShadow.LightPos ||
Vector2.DistanceSquared(light.Position, cachedShadow.LightPos) < 1.0f)
{
shadowVertices = cachedShadow.ShadowVertices;
penumbraVertices = cachedShadow.PenumbraVertices;
}
else
{
CalculateShadowVertices(light.Position, los);
cachedShadow.LightPos = light.Position;
cachedShadow.ShadowVertices = shadowVertices;
cachedShadow.PenumbraVertices = penumbraVertices;
}
}
else
{
CalculateShadowVertices(light.Position, los);
cachedShadow = new CachedShadow(shadowVertices, penumbraVertices, light.Position);
cachedShadows.Add(light, cachedShadow);
}
DrawShadows(graphicsDevice, cam, transform, los);
}
public void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, Vector2 lightSourcePos, Matrix transform, bool los = true)
{
if (!Enabled) return;
CalculateShadowVertices(lightSourcePos, los);
DrawShadows(graphicsDevice, cam, transform, los);
}
private void DrawShadows(GraphicsDevice graphicsDevice, Camera cam, Matrix transform, bool los = true)
{
shadowEffect.World = transform;
shadowEffect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, shadowVertices, 0, shadowVertices.Length - 2);
graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, shadowVertices, 0, shadowVertices.Length - 2);
if (los)
{
penumbraEffect.World = shadowEffect.World;
penumbraEffect.CurrentTechnique.Passes[0].Apply();
#if WINDOWS
graphicsDevice.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleList, penumbraVertices, 0, 2, VertexPositionTexture.VertexDeclaration);
graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, penumbraVertices, 0, 2, VertexPositionTexture.VertexDeclaration);
#endif
}
}
+33 -10
View File
@@ -57,12 +57,13 @@ namespace Subsurface.Lights
public void DrawLOS(GraphicsDevice graphics, Camera cam, Vector2 pos)
{
if (!LosEnabled) return;
Rectangle camView = new Rectangle(cam.WorldView.X, cam.WorldView.Y - cam.WorldView.Height, cam.WorldView.Width, cam.WorldView.Height);
Matrix shadowTransform = cam.ShaderTransform
* Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
if (!LosEnabled) return;
foreach (ConvexHull convexHull in ConvexHull.list)
{
if (!camView.Intersects(convexHull.BoundingBox)) continue;
@@ -72,6 +73,14 @@ namespace Subsurface.Lights
}
public void OnMapLoaded()
{
foreach (LightSource light in lights)
{
light.UpdateHullsInRange();
}
}
public void DrawLightmap(GraphicsDevice graphics, SpriteBatch spriteBatch, Camera cam)
{
Matrix shadowTransform = cam.ShaderTransform
@@ -81,28 +90,28 @@ namespace Subsurface.Lights
Rectangle viewRect = cam.WorldView;
viewRect.Y -= cam.WorldView.Height;
//clear to some small ambient light
graphics.Clear(AmbientLight);
foreach (LightSource light in lights)
{
if (light.Color.A < 0.01f || light.Range < 0.01f) continue;
//clear alpha to 1
ClearAlphaToOne(graphics, spriteBatch);
if (light.Color.A < 0.01f || light.Range < 0.01f || light.hullsInRange.Count == 0) continue;
if (!MathUtils.CircleIntersectsRectangle(light.Position, light.Range, viewRect)) continue;
//clear alpha to 1
ClearAlphaToOne(graphics, spriteBatch);
//draw all shadows
//write only to the alpha channel, which sets alpha to 0
graphics.RasterizerState = RasterizerState.CullNone;
graphics.BlendState = CustomBlendStates.WriteToAlpha;
foreach (ConvexHull ch in ConvexHull.list)
foreach (ConvexHull ch in light.hullsInRange)
{
if (!MathUtils.CircleIntersectsRectangle(light.Position, light.Range, ch.BoundingBox)) continue;
//if (!MathUtils.CircleIntersectsRectangle(light.Position, light.Range, ch.BoundingBox)) continue;
//draw shadow
ch.DrawShadows(graphics, cam, light.Position, shadowTransform, false);
ch.DrawShadows(graphics, cam, light, shadowTransform, false);
}
//draw the light shape
@@ -111,6 +120,20 @@ namespace Subsurface.Lights
light.Draw(spriteBatch);
spriteBatch.End();
}
//ClearAlphaToOne(graphics, spriteBatch);
//spriteBatch.Begin(SpriteSortMode.Immediate, CustomBlendStates.MultiplyWithAlpha, null, null, null, null, cam.Transform);
//foreach (LightSource light in lights)
//{
// if (light.Color.A < 0.01f || light.Range < 0.01f || light.hullsInRange.Count > 0) continue;
// if (!MathUtils.CircleIntersectsRectangle(light.Position, light.Range, viewRect)) continue;
// light.Draw(spriteBatch);
//}
//spriteBatch.End();
//clear alpha, to avoid messing stuff up later
ClearAlphaToOne(graphics, spriteBatch);
graphics.SetRenderTarget(null);
+34 -4
View File
@@ -11,13 +11,26 @@ namespace Subsurface.Lights
{
private static Texture2D lightTexture;
public List<ConvexHull> hullsInRange;
private Color color;
private float range;
private Texture2D texture;
public Vector2 Position;
private Vector2 position;
public Vector2 Position
{
get { return position; }
set
{
if (position == value) return;
position = value;
UpdateHullsInRange();
}
}
public Color Color
{
@@ -30,13 +43,19 @@ namespace Subsurface.Lights
get { return range; }
set
{
range = MathHelper.Clamp(value, 0.0f, 2048.0f);
float newRange = MathHelper.Clamp(value, 0.0f, 2048.0f);
if (range == newRange) return;
range = newRange;
UpdateHullsInRange();
}
}
public LightSource(Vector2 position, float range, Color color)
{
Position = position;
hullsInRange = new List<ConvexHull>();
this.position = position;
this.range = range;
this.color = color;
@@ -50,10 +69,21 @@ namespace Subsurface.Lights
GameMain.LightManager.AddLight(this);
}
public void UpdateHullsInRange()
{
hullsInRange.Clear();
if (range < 1.0f) return;
foreach (ConvexHull ch in ConvexHull.list)
{
if (MathUtils.CircleIntersectsRectangle(position, range, ch.BoundingBox)) hullsInRange.Add(ch);
}
}
public void Draw(SpriteBatch spriteBatch)
{
Vector2 center = new Vector2(lightTexture.Width / 2, lightTexture.Height / 2);
float scale = range / ((float)lightTexture.Width / 2.0f);
float scale = range / (lightTexture.Width / 2.0f);
spriteBatch.Draw(lightTexture, new Vector2(Position.X, -Position.Y), null, color, 0, center, scale, SpriteEffects.None, 1);
}