Enable depth buffer and 3D wall rendering

This commit is contained in:
Adam Coggeshall
2020-01-25 01:06:27 -07:00
committed by Acruid
parent 298efa3a91
commit 027e36f125
4 changed files with 150 additions and 60 deletions

View File

@@ -28,4 +28,7 @@ void main()
[SHADER_CODE]
FragColor = COLOR * modulate;
if (FragColor.a < 0.5)
discard;
}

View File

@@ -994,33 +994,25 @@ namespace Robust.Client.GameObjects
}
/// Render the sprite in 3D. This is almost entirely copy-pasted from the 2D version.
internal void Render3D(Graphics.Clyde.Clyde.Render3D render, in Matrix4 worldTransform, Angle worldRotation,
internal void Render3D(Graphics.Clyde.Clyde.Render3D render, Vector2 worldPosition, Angle worldRotation,
Sprite3DRenderMode renderMode, Direction? overrideDirection = null
) {
var angle = Rotation;
Angle angle;
if (Directional)
{
angle -= worldRotation;
angle = Rotation;
}
else
{
angle -= new Angle(MathHelper.PiOver2);
angle = Rotation + worldRotation;
}
var mOffset = Matrix4.CreateTranslation(new Vector3(Offset));
var mRotation = Matrix4.CreateRotationZ((float)angle.Theta); //Matrix4.CreateFromAxisAngle(new Vector3(0,0,1),(float)angle.Theta);
render.AdjustSpriteTransform(renderMode, ref mOffset);
//System.Console.WriteLine("???" + Offset);
//var transform = mRotation * mOffset;
var transform = mOffset * mRotation;
transform = transform * worldTransform;
var mRotation = Matrix4.CreateRotationZ((float)angle);
var mWorldOffset = Matrix4.CreateTranslation(worldPosition.X, worldPosition.Y, 0);
// Draw layers
int layer_n = 0;
foreach (var layer in Layers)
{
if (!layer.Visible)
@@ -1066,7 +1058,30 @@ namespace Robust.Client.GameObjects
texture ??= resourceCache.GetFallback<TextureResource>();
render.DrawRect3D(transform, texture, color * layer.Color);
float offsetZ = renderMode == Sprite3DRenderMode.SimpleSprite ? layer_n * 0.001f : 0.001f;
var mOffset = Matrix4.CreateTranslation(new Vector3(Offset.X, Offset.Y, offsetZ));
bool isWall = renderMode == Sprite3DRenderMode.Wall;
int rectCount = isWall ? 5 : 1;
for (int i = 0; i < rectCount; i++)
{
var m3D = render.GetSpriteTransform(renderMode, i);
var transform = mOffset * mRotation * m3D * mWorldOffset;
var rectColor = color * layer.Color;
var rectTexture = texture;
if (isWall && i == rectCount - 1)
{
rectColor = Color.Black;
}
render.DrawRect3D(transform, rectTexture, rectColor);
}
layer_n++;
}
}

View File

@@ -26,6 +26,7 @@ namespace Robust.Client.Graphics.Clyde
Floor, // Draw Flat on the ground, no extra transformations
Table, // Higher than floor
SimpleSprite, // Always rotate to face the camera
Wall // Render 4 sides + top cap
}
public Render3D(Clyde clyde)
@@ -145,20 +146,32 @@ namespace Robust.Client.Graphics.Clyde
return (projMatrixWorld, viewMatrixWorld);
}
public void AdjustSpriteTransform(Sprite3DRenderMode renderMode, ref Matrix4 matrix)
public Matrix4 GetSpriteTransform(Sprite3DRenderMode renderMode, int n = 0)
{
switch (renderMode)
{
case Sprite3DRenderMode.Floor:
matrix *= Matrix4.CreateTranslation(0, 0, -.5f);
break;
return Matrix4.CreateTranslation(0, 0, -.5f);
case Sprite3DRenderMode.Table:
matrix *= Matrix4.CreateTranslation(0, 0, -.25f);
break;
return Matrix4.CreateTranslation(0, 0, -.25f);
case Sprite3DRenderMode.Wall:
switch (n)
{
case 0:
return Matrix4.CreateRotationY(MathHelper.PiOver2) * Matrix4.CreateTranslation(.5f, 0, 0);
case 1:
return Matrix4.CreateRotationY(MathHelper.PiOver2) * Matrix4.CreateTranslation(-.5f, 0, 0);
case 2:
return Matrix4.CreateRotationX(MathHelper.PiOver2) * Matrix4.CreateTranslation(0, .5f, 0);
case 3:
return Matrix4.CreateRotationX(MathHelper.PiOver2) * Matrix4.CreateTranslation(0, -.5f, 0);
default:
return Matrix4.CreateTranslation(0, 0, .5f);
}
case Sprite3DRenderMode.SimpleSprite:
matrix *= FaceCameraRotation;
break;
return FaceCameraRotation;
}
return Matrix4.Identity;
}
public static Sprite3DRenderMode InferRenderMode(IEntity ent)
@@ -168,11 +181,15 @@ namespace Robust.Client.Graphics.Clyde
case "worktop":
return Sprite3DRenderMode.Table;
case "Solid wall":
return Sprite3DRenderMode.Table; // todo walls
return Sprite3DRenderMode.Wall;
case "Catwalk":
case "Wire":
return Sprite3DRenderMode.Floor;
}
if (ent.Name.Contains("Airlock"))
{
return Sprite3DRenderMode.Wall;
}
return Sprite3DRenderMode.SimpleSprite;
}

View File

@@ -66,8 +66,11 @@ namespace Robust.Client.Graphics.Clyde
private readonly RefList<RenderCommand> _queuedRenderCommands = new RefList<RenderCommand>();
private readonly RefList<(SpriteComponent sprite, Matrix3 worldMatrix, Angle worldRotation, Render3D.Sprite3DRenderMode renderMode)> _drawingSpriteList =
new RefList<(SpriteComponent, Matrix3, Angle, Render3D.Sprite3DRenderMode)>();
private readonly RefList<(SpriteComponent sprite, Matrix3 worldMatrix, Angle worldRotation)> _drawingSpriteList =
new RefList<(SpriteComponent, Matrix3, Angle)>();
private readonly RefList<(SpriteComponent sprite, Vector2 worldPosition, Angle worldRotation, Render3D.Sprite3DRenderMode renderMode)> _drawingSpriteList3D =
new RefList<(SpriteComponent, Vector2, Angle, Render3D.Sprite3DRenderMode)>();
public void Render()
{
@@ -131,6 +134,14 @@ namespace Robust.Client.Graphics.Clyde
_drawLights(worldBounds);
}
if (eye.Is3D)
{
// Start 3D rendering. Enable depth buffer.
GL.Enable(EnableCap.DepthTest);
GL.DepthMask(true);
GL.DepthFunc(DepthFunction.Less);
}
using (DebugGroup("Grids"))
{
_drawGrids(worldBounds);
@@ -141,6 +152,9 @@ namespace Robust.Client.Graphics.Clyde
DrawEntities(worldBounds);
}
// Any 3D rendering should be done.
GL.Disable(EnableCap.DepthTest);
RenderOverlays(OverlaySpace.WorldSpace);
_lightingReady = false;
@@ -166,8 +180,6 @@ namespace Robust.Client.Graphics.Clyde
return;
}
bool is3d = _eyeManager.CurrentEye.Is3D;
// So we could calculate the correct size of the entities based on the contents of their sprite...
// Or we can just assume that no entity is larger than 10x10 and get a stupid easy check.
// TODO: Make this check more accurate.
@@ -176,39 +188,36 @@ namespace Robust.Client.Graphics.Clyde
var mapEntity = _mapManager.GetMapEntity(_eyeManager.CurrentMap);
var identity = Matrix3.Identity;
ProcessSpriteEntities(mapEntity, ref identity, Angle.Zero, widerBounds, _drawingSpriteList, is3d);
// We use a separate list for indexing so that the sort is faster.
var indexList = ArrayPool<int>.Shared.Rent(_drawingSpriteList.Count);
for (var i = 0; i < _drawingSpriteList.Count; i++)
{
indexList[i] = i;
}
Array.Sort(indexList, 0, _drawingSpriteList.Count, new SpriteDrawingOrderComparer(_drawingSpriteList));
bool is3d = _eyeManager.CurrentEye.Is3D;
if (is3d)
{
ProcessSpriteEntities3D(mapEntity, ref identity, Angle.Zero, widerBounds, _drawingSpriteList3D);
var clyde3d = GetRender3D();
for (var i = 0; i < _drawingSpriteList3D.Count; i++)
{
ref var entry = ref _drawingSpriteList3D[i];
entry.sprite.Render3D(clyde3d, entry.worldPosition, entry.worldRotation, entry.renderMode);
}
_drawingSpriteList3D.Clear();
} else
{
ProcessSpriteEntities(mapEntity, ref identity, Angle.Zero, widerBounds, _drawingSpriteList);
// We use a separate list for indexing so that the sort is faster.
var indexList = ArrayPool<int>.Shared.Rent(_drawingSpriteList.Count);
for (var i = 0; i < _drawingSpriteList.Count; i++)
{
ref var entry = ref _drawingSpriteList[indexList[i]];
var mat3 = entry.worldMatrix;
var mat4 = new Matrix4(
mat3.R0C0, mat3.R1C0, 0, mat3.R2C0,
mat3.R0C1, mat3.R1C1, 0, mat3.R2C1,
0, 0, 1, 0,
mat3.R0C2, mat3.R1C2, 0, mat3.R2C2
);
entry.sprite.Render3D(clyde3d, mat4, entry.worldRotation, entry.renderMode);
indexList[i] = i;
}
} else
{
Array.Sort(indexList, 0, _drawingSpriteList.Count, new SpriteDrawingOrderComparer(_drawingSpriteList));
for (var i = 0; i < _drawingSpriteList.Count; i++)
{
ref var entry = ref _drawingSpriteList[indexList[i]];
@@ -250,15 +259,15 @@ namespace Robust.Client.Graphics.Clyde
_renderHandle.UseShader(null);
}
}
_drawingSpriteList.Clear();
}
_drawingSpriteList.Clear();
FlushRenderQueue();
}
private void ProcessSpriteEntities(IEntity entity, ref Matrix3 parentTransform, Angle parentRotation,
Box2 worldBounds, RefList<(SpriteComponent, Matrix3, Angle, Render3D.Sprite3DRenderMode)> list, bool include3DRenderMode)
Box2 worldBounds, RefList<(SpriteComponent, Matrix3, Angle)> list)
{
entity.TryGetComponent(out ContainerManagerComponent containerManager);
@@ -293,16 +302,61 @@ namespace Robust.Client.Graphics.Clyde
entry.Item1 = sprite;
entry.Item3 = childWorldRotation;
if (include3DRenderMode)
/*if (include3DRenderMode)
{
entry.Item4 = Render3D.InferRenderMode(childEntity);
}
}*/
}
}
if (childTransform.ChildCount > 0)
{
ProcessSpriteEntities(childEntity, ref matrix, rotation, worldBounds, list, include3DRenderMode);
ProcessSpriteEntities(childEntity, ref matrix, rotation, worldBounds, list);
}
}
}
private void ProcessSpriteEntities3D(IEntity entity, ref Matrix3 parentTransform, Angle parentRotation,
Box2 worldBounds, RefList<(SpriteComponent, Vector2, Angle, Render3D.Sprite3DRenderMode)> list)
{
entity.TryGetComponent(out ContainerManagerComponent containerManager);
var localMatrix = entity.Transform.GetLocalMatrix();
Matrix3.Multiply(ref parentTransform, ref localMatrix, out var matrix);
var rotation = parentRotation + entity.Transform.LocalRotation;
foreach (var child in entity.Transform.ChildEntityUids)
{
var childEntity = _entityManager.GetEntity(child);
if (containerManager != null && containerManager.TryGetContainer(childEntity, out var container) &&
!container.ShowContents)
{
continue;
}
var childTransform = childEntity.Transform;
var worldPosition = Matrix3.Transform(matrix, childTransform.LocalPosition);
if (worldBounds.Contains(worldPosition))
{
if (childEntity.TryGetComponent(out SpriteComponent sprite) && sprite.Visible)
{
ref var entry = ref list.AllocAdd();
var childWorldRotation = rotation + childTransform.LocalRotation;
entry.Item1 = sprite;
entry.Item2 = worldPosition;
entry.Item3 = childWorldRotation;
entry.Item4 = Render3D.InferRenderMode(childEntity);
}
}
if (childTransform.ChildCount > 0)
{
ProcessSpriteEntities3D(childEntity, ref matrix, rotation, worldBounds, list);
}
}
}
@@ -712,7 +766,8 @@ namespace Robust.Client.Graphics.Clyde
{
GL.ClearColor(color.ConvertOpenTK());
GL.ClearStencil(0);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit);
GL.ClearDepth(1);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.StencilBufferBit | ClearBufferMask.DepthBufferBit);
}
private (ShaderProgram, LoadedShader) ActivateShaderInstance(ClydeHandle handle)
@@ -1189,9 +1244,9 @@ namespace Robust.Client.Graphics.Clyde
private sealed class SpriteDrawingOrderComparer : IComparer<int>
{
private readonly RefList<(SpriteComponent, Matrix3, Angle, Render3D.Sprite3DRenderMode)> _drawList;
private readonly RefList<(SpriteComponent, Matrix3, Angle)> _drawList;
public SpriteDrawingOrderComparer(RefList<(SpriteComponent, Matrix3, Angle, Render3D.Sprite3DRenderMode)> drawList)
public SpriteDrawingOrderComparer(RefList<(SpriteComponent, Matrix3, Angle)> drawList)
{
_drawList = drawList;
}