Skip to content

Commit

Permalink
Migrate DebugSkeletonRenderer to Mlang
Browse files Browse the repository at this point in the history
  • Loading branch information
Helco committed Jan 18, 2024
1 parent aec3293 commit 4f4613f
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 102 deletions.
7 changes: 1 addition & 6 deletions zzre.core/rendering/DynamicMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,7 @@ private void UpdateIndexBuffer(CommandList cl)

if (uploadedPrimitiveCount < PrimitiveCount)
{
var indices = new ushort[IndexPattern.Count * (PrimitiveCount - uploadedPrimitiveCount)];
for (int i = uploadedPrimitiveCount; i < PrimitiveCount; i++)
{
for (int j = 0; j < IndexPattern.Count; j++)
indices[i * PrimitiveCount + j] = (ushort)(i * verticesPerPrimitive + IndexPattern[j]);
}
var indices = StaticMesh.GeneratePatternIndices(indexPattern, uploadedPrimitiveCount, PrimitiveCount, verticesPerPrimitive);
cl.UpdateBuffer(indexBuffer, (uint)(uploadedPrimitiveCount * PrimitiveCount * sizeof(ushort)), indices);
}
}
Expand Down
35 changes: 33 additions & 2 deletions zzre.core/rendering/Mesh.cs → zzre.core/rendering/StaticMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace zzre.rendering;

public class Mesh : BaseDisposable, IVertexAttributeContainer
public class StaticMesh : BaseDisposable, IVertexAttributeContainer
{
public readonly record struct SubMesh(int IndexOffset, int IndexCount, int Material, int Section = 0) : IComparable<SubMesh>
{
Expand Down Expand Up @@ -43,7 +43,7 @@ public class VertexAttribute
throw new InvalidOperationException("Index buffer was not yet set on mesh");
public string Name { get; }

public Mesh(ITagContainer diContainer, string name)
public StaticMesh(ITagContainer diContainer, string name)
{
graphicsDevice = diContainer.GetTag<GraphicsDevice>();
resourceFactory = graphicsDevice.ResourceFactory;
Expand Down Expand Up @@ -166,6 +166,37 @@ public void SetIndices(ReadOnlySpan<uint> indices)
graphicsDevice.UpdateBuffer(buffer, 0u, indices);
}

public void SetIndicesFromPattern(IReadOnlyList<ushort> pattern)
{
if (VertexCount <= 0)
throw new InvalidOperationException("Cannot generate indices from pattern without vertices");
var verticesPerPrimitive = pattern.Max() + 1;
var primitiveCount = VertexCount / verticesPerPrimitive;
var buffer = SetIndexCount(primitiveCount * pattern.Count, IndexFormat.UInt16);
var indices = GeneratePatternIndices(pattern, 0, primitiveCount, verticesPerPrimitive);
graphicsDevice.UpdateBuffer(buffer, 0u, indices);
}

internal static ushort[] GeneratePatternIndices(IReadOnlyList<ushort> pattern,
int primitiveStart,
int primitiveCount,
int verticesPerPrimitive)
{
if (pattern.Count == 0)
throw new ArgumentOutOfRangeException(nameof(pattern));
if (primitiveStart < 0 || primitiveStart > primitiveCount)
throw new ArgumentOutOfRangeException(nameof(primitiveStart));
if (primitiveStart == primitiveCount)
return Array.Empty<ushort>();
var indices = new ushort[pattern.Count * (primitiveCount - primitiveStart)];
for (int i = primitiveStart; i < primitiveCount; i++)
{
for (int j = 0; j < pattern.Count; j++)
indices[i * pattern.Count + j] = (ushort)(i * verticesPerPrimitive + pattern[j]);
}
return indices;
}

public void AddSubMesh(SubMesh subMesh)
{
if (IndexCount <= 0)
Expand Down
100 changes: 35 additions & 65 deletions zzre/debug/DebugSkeletonRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,24 @@ public class DebugSkeletonRenderer : BaseDisposable

private readonly LocationBuffer locationBuffer;
private readonly GraphicsDevice device;
private readonly DeviceBuffer vertexBuffer;
private readonly DeviceBuffer indexBuffer;
private readonly DeviceBuffer skinBuffer;
private readonly DeviceBuffer lineBuffer;
private readonly StaticMesh boneMesh;
private readonly StaticMesh.VertexAttribute boneColorAttribute;
private readonly DebugLineRenderer lineRenderer;
private readonly IReadOnlyList<int> boneDepths;
private readonly DeviceBufferRange worldBufferRange;

private DebugSkeletonRenderMode renderMode = DebugSkeletonRenderMode.Invisible;
private int highlightedBoneI = -1;

public DebugSkinnedMaterial BoneMaterial { get; }
public DebugMaterial BoneMaterial { get; }
public DebugMaterial SkinMaterial { get; }
public DebugMaterial SkinHighlightedMaterial { get; }
public DebugLinesMaterial LinesMaterial { get; }
public Mesh Mesh { get; }
public DebugMaterial LinesMaterial => lineRenderer.Material;
public StaticMesh Mesh { get; }
public Skeleton Skeleton { get; }
public ref DebugSkeletonRenderMode RenderMode => ref renderMode; // reference for using the field with ImGui

public DebugSkeletonRenderer(ITagContainer diContainer, Mesh mesh, Skeleton skeleton)
public DebugSkeletonRenderer(ITagContainer diContainer, StaticMesh mesh, Skeleton skeleton)
{
Mesh = mesh;
Skeleton = skeleton;
Expand All @@ -78,20 +77,20 @@ void LinkTransformsFor(IStandardTransformMaterial m)
m.LinkTransformsTo(camera);
m.World.BufferRange = worldBufferRange;
}
BoneMaterial = new DebugSkinnedMaterial(diContainer);
BoneMaterial = new DebugMaterial(diContainer) { IsSkinned = true };
LinkTransformsFor(BoneMaterial);
BoneMaterial.Pose.Skeleton = skeleton;
SkinMaterial = new(diContainer) { Color = DebugMaterial.ColorMode.SkinWeights };
LinkTransformsFor(SkinMaterial);
SkinHighlightedMaterial = new(diContainer) { Color = DebugMaterial.ColorMode.SingleBoneWeight };
LinkTransformsFor(SkinHighlightedMaterial);
LinesMaterial = new DebugLinesMaterial(diContainer);
lineRenderer = new(diContainer);
LinkTransformsFor(LinesMaterial);
device = diContainer.GetTag<GraphicsDevice>();

var vertices = Enumerable.Empty<ColoredVertex>();
var skinVertices = Enumerable.Empty<SkinVertex>();
var indices = Enumerable.Empty<ushort>();
var vertices = Enumerable.Empty<Vector3>();
var colors = Enumerable.Empty<IColor>();
var skinIndices = Enumerable.Empty<IColor>(); // color as this is also 4 bytes
foreach (var (bone, index) in skeleton.Bones.Indexed())
{
if (bone.Parent == null)
Expand All @@ -116,44 +115,22 @@ void LinkTransformsFor(IStandardTransformMaterial m)
baseCenter + tangent + bitangent,
baseCenter - tangent + bitangent,
to
}.Select(p => new ColoredVertex(p, Colors[index % Colors.Length])));
skinVertices = skinVertices.Concat(Enumerable.Repeat(new SkinVertex()
{
bone0 = unchecked((byte)Skeleton.Parents[index]),
weights = Vector4.UnitX
}, RhombusVertexCount));
indices = indices.Concat(RhombusIndices.Select(i => (ushort)(i + index * RhombusVertexCount)));
});
colors = colors.Concat(Enumerable.Repeat(Colors[index % Colors.Length], RhombusVertexCount));
var indices = new IColor(unchecked((byte)Skeleton.Parents[index]), 0, 0, 0);
skinIndices = skinIndices.Concat(Enumerable.Repeat(indices, RhombusVertexCount));
}

var vertexArray = vertices.ToArray();
var skinVertexArray = skinVertices.ToArray();
var indexArray = indices.ToArray();
vertexBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription(
(uint)vertexArray.Length * ColoredVertex.Stride, BufferUsage.VertexBuffer));
skinBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription(
(uint)skinVertexArray.Length * SkinVertex.Stride, BufferUsage.VertexBuffer));
indexBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription(
(uint)indexArray.Length * sizeof(ushort), BufferUsage.IndexBuffer));
vertexBuffer.Name = $"DebugSkeleton Vertices {GetHashCode()}";
skinBuffer.Name = $"DebugSkeleton Skin {GetHashCode()}";
indexBuffer.Name = $"DebugSkeleton Indices {GetHashCode()}";
device.UpdateBuffer(vertexBuffer, 0, vertexArray);
device.UpdateBuffer(skinBuffer, 0, skinVertexArray);
device.UpdateBuffer(indexBuffer, 0, indexArray);

var lineVertices = new ColoredVertex[]
{
new ColoredVertex(Vector3.Zero, Colors[0]),
new ColoredVertex(Vector3.UnitX * LineLength, Colors[0]),
new ColoredVertex(Vector3.Zero, Colors[1]),
new ColoredVertex(Vector3.UnitY * LineLength, Colors[1]),
new ColoredVertex(Vector3.Zero, Colors[2]),
new ColoredVertex(Vector3.UnitZ * LineLength, Colors[2])
};
lineBuffer = device.ResourceFactory.CreateBuffer(new BufferDescription(
(uint)lineVertices.Length * ColoredVertex.Stride, BufferUsage.VertexBuffer));
lineBuffer.Name = $"DebugSkeleton LineVertices {GetHashCode()}";
device.UpdateBuffer(lineBuffer, 0, lineVertices);
boneMesh = new(diContainer, "Debug Skeleton Bones");
boneMesh.Add("Pos", "inPos", vertices.ToArray());
boneColorAttribute = boneMesh.Add("Color", "inColor", colors.ToArray());
boneMesh.Add("Bone Weights", "inWeights", Enumerable.Repeat(Vector4.UnitX, boneMesh.VertexCount).ToArray());
boneMesh.Add("Bone Indices", "inIndices", skinIndices.ToArray());
boneMesh.SetIndicesFromPattern(RhombusIndices);

lineRenderer.Reserve(3);
lineRenderer.Add(Colors[0], Vector3.Zero, Vector3.UnitX * LineLength);
lineRenderer.Add(Colors[1], Vector3.Zero, Vector3.UnitY * LineLength);
lineRenderer.Add(Colors[2], Vector3.Zero, Vector3.UnitZ * LineLength);

var boneDepthsArr = new int[Skeleton.Bones.Count];
for (int i = 0; i < Skeleton.Bones.Count; i++)
Expand All @@ -164,10 +141,8 @@ void LinkTransformsFor(IStandardTransformMaterial m)
protected override void DisposeManaged()
{
base.DisposeManaged();
vertexBuffer.Dispose();
skinBuffer.Dispose();
indexBuffer.Dispose();
lineBuffer.Dispose();
boneMesh.Dispose();
lineRenderer.Dispose();
BoneMaterial.Dispose();
SkinMaterial.Dispose();
SkinHighlightedMaterial.Dispose();
Expand All @@ -187,17 +162,14 @@ public void Render(CommandList cl)

// always draw bones when visible
(BoneMaterial as IMaterial).Apply(cl);
cl.SetVertexBuffer(0, vertexBuffer);
cl.SetVertexBuffer(1, skinBuffer);
cl.SetIndexBuffer(indexBuffer, IndexFormat.UInt16);
cl.DrawIndexed(indexBuffer.SizeInBytes / sizeof(ushort));
BoneMaterial.ApplyAttributes(cl, boneMesh);
cl.SetIndexBuffer(boneMesh.IndexBuffer, boneMesh.IndexFormat);
cl.DrawIndexed((uint)boneMesh.IndexCount);

if (highlightedBoneI >= 0)
{
LinesMaterial.World.Ref = Skeleton.Bones[highlightedBoneI].LocalToWorld;
(LinesMaterial as IMaterial).Apply(cl);
cl.SetVertexBuffer(0, lineBuffer);
cl.Draw(lineBuffer.SizeInBytes / ColoredVertex.Stride);
lineRenderer.Render(cl);
}
}

Expand All @@ -224,10 +196,8 @@ private void SetBoneAlpha(int boneI, byte alpha)
// this is probably a terrible but also very lazy way of doing this
for (int vertexI = 0; vertexI < RhombusVertexCount; vertexI++)
{
var offset =
(boneI * RhombusVertexCount + vertexI) * ColoredVertex.Stride +
3 * sizeof(float) + 3 * sizeof(byte);
device.UpdateBuffer(vertexBuffer, (uint)offset, alpha);
var offset = (boneI * RhombusVertexCount + vertexI) * 4 + 3;
device.UpdateBuffer(boneColorAttribute.DeviceBuffer, (uint)offset, alpha);
}
}

Expand Down
27 changes: 0 additions & 27 deletions zzre/materials/CommonStructs.cs

This file was deleted.

22 changes: 22 additions & 0 deletions zzre/materials/DebugMaterial.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
using System.Numerics;
using System.Runtime.InteropServices;
using Veldrid;
using zzio;
using zzre.rendering;

namespace zzre.materials;

public struct ColoredVertex
{
public Vector3 pos;
public IColor color;

public ColoredVertex(Vector3 pos, IColor color)
{
this.pos = pos;
this.color = color;
}

public static uint Stride = sizeof(float) * 3 + sizeof(uint);
}

public struct SkinVertex
{
public Vector4 weights;
public byte bone0, bone1, bone2, bone3;
}


public class DebugMaterial : MlangMaterial, IStandardTransformMaterial
{
public enum ColorMode : uint
Expand Down
2 changes: 1 addition & 1 deletion zzre/rendering/ClumpMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace zzre.rendering;

public class ClumpMesh : Mesh
public class ClumpMesh : StaticMesh
{
public RWGeometry Geometry { get; }
public RWSkinPLG? Skin { get; }
Expand Down
2 changes: 1 addition & 1 deletion zzre/rendering/WorldMesh.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace zzre.rendering;

public class WorldMesh : Mesh
public class WorldMesh : StaticMesh
{
public abstract class BaseSection
{
Expand Down

0 comments on commit 4f4613f

Please sign in to comment.