10000 [glTF] Optimize serialization of buffer data. · Macad3D/Macad3D@159ae2f · GitHub
[go: up one dir, main page]

Skip to content

Commit

Permalink
[glTF] Optimize serialization of buffer data.
Browse files Browse the repository at this point in the history
  • Loading branch information
dipts committed Dec 13, 2024
1 parent 037733b commit 159ae2f
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 39 deletions.
84 changes: 57 additions & 27 deletions Source/Macad.Exchange/Gltf/GltfBodyExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Macad.Common;
using System.Runtime.InteropServices;
using Macad.Occt;
using Macad.Occt.Helper;

Expand All @@ -30,15 +30,30 @@ class LayerInfo(int nodeIndex, int materialIndex)

class MeshInfo
{
public MemoryStream VertexStream;
public float[] MinPosition;
public float[] MaxPosition;
public MemoryStream IndexStream;
public int VertexBufferOffset;
public int VertexBufferLength;
public int IndexBufferOffset;
public int IndexBufferLength;
public GltfDomAccessor.DataComponentType IndexDataType;
}

//--------------------------------------------------------------------------------------------------

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct Vertex(Pnt pos, Dir nrm)
{
float PosX = (float)pos.X;
float PosY = (float)pos.Z;
float PosZ = (float)-pos.Y;
float NrmX = (float)nrm.X;
float NrmY = (float)nrm.Z;
float NrmZ = (float)-nrm.Y;
}

//--------------------------------------------------------------------------------------------------

Body[] _Bodies;
GltfDomDocument _Document;
readonly Dictionary<Layer, LayerInfo> _LayerInfos = new();
Expand Down Expand Up @@ -84,12 +99,11 @@ MemoryStream[] _Export(IEnumerable<Body> bodies, GltfFileType fileType, string b
continue;
MeshInfo meshInfo = _SerializeBufferData(triangulation);

long vertexBufferOffset = _Document.AddBufferData(meshInfo.VertexStream);
GltfDomBufferView vertexBufferView = new()
{
BufferIndex = 0,
ByteOffset = vertexBufferOffset,
ByteLength = meshInfo.VertexStream.Length,
ByteOffset = meshInfo.VertexBufferOffset,
ByteLength = meshInfo.VertexBufferLength,
ByteStride = sizeof(float) * 6,
TargetHint = GltfDomBufferView.Target.ArrayBuffer
};
Expand Down Expand Up @@ -119,12 +133,11 @@ MemoryStream[] _Export(IEnumerable<Body> bodies, GltfFileType fileType, string b
int normalAccessorIndex = _Document.AddAccessor(normalAccessor);

// Add indices
long indexBufferOffset = _Document.AddBufferData(meshInfo.IndexStream);
GltfDomBufferView indexBufferView = new()
{
BufferIndex = 0,
ByteOffset = indexBufferOffset,
ByteLength = meshInfo.IndexStream.Length,
ByteOffset = meshInfo.IndexBufferOffset,
ByteLength = meshInfo.IndexBufferLength,
TargetHint = GltfDomBufferView.Target.ElementArrayBuffer
};
int indexBufferViewIndex = _Document.AddBufferView(indexBufferView);
Expand Down Expand Up @@ -180,53 +193,70 @@ MeshInfo _SerializeBufferData(TriangulationData triangulation)
{
MeshInfo info = new()
{
VertexStream = new MemoryStream(triangulation.Vertices.Length * sizeof(float) * 6),
MinPosition = [float.MaxValue, float.MaxValue, float.MaxValue],
MaxPosition = [float.MinValue, float.MinValue, float.MinValue],
IndexStream = new MemoryStream(triangulation.Indices.Length * sizeof(float) * 3)
MaxPosition = [float.MinValue, float.MinValue, float.MinValue]
};

BinaryWriter writer = new BinaryWriter(info.VertexStream);
// Vertices
info.VertexBufferLength = sizeof(float) * 6 * triangulation.Vertices.Length;
info.VertexBufferOffset = _Document.AddBufferData<Vertex>(triangulation.Vertices.Length, out var vspan);

for (var i = 0; i < triangulation.Vertices.Length; i++)
{
var pnt = triangulation.Vertices[i];
var nrm = triangulation.Normals[i];
vspan[i] = new (pnt, nrm);

float x = (float)pnt.X;
writer.Write(x);
info.MinPosition[0] = Math.Min(x, info.MinPosition[0]);
info.MaxPosition[0] = Math.Max(x, info.MaxPosition[0]);
float y = (float)pnt.Z;
writer.Write(y);
info.MinPosition[1] = Math.Min(y, info.MinPosition[1]);
info.MaxPosition[1] = Math.Max(y, info.MaxPosition[1]);
float z = -(float)pnt.Y;
writer.Write(z);
info.MinPosition[2] = Math.Min(z, info.MinPosition[2]);
info.MaxPosition[2] = Math.Max(z, info.MaxPosition[2]);

var nrm = triangulation.Normals[i];
writer.Write((float)nrm.X);
writer.Write((float)nrm.Z);
writer.Write(-(float)nrm.Y);
}
info.VertexStream.Position = 0;

writer = new BinaryWriter(info.IndexStream);
// Indices
switch (triangulation.Indices.Length)
{
case < 255:
{
info.IndexDataType = GltfDomAccessor.DataComponentType.UnsignedByte;
triangulation.Indices.ForEach(index => writer.Write((byte)index));
info.IndexBufferLength = sizeof(byte) * triangulation.Indices.Length;
info.IndexBufferOffset = _Document.AddBufferData<byte>(triangulation.Indices.Length, out var ispan);
for (var i = 0; i < triangulation.Indices.Length; i++)
{
ispan[i] = (byte)triangulation.Indices[i];
}
break;
}
case < 65535:
{
info.IndexDataType = GltfDomAccessor.DataComponentType.UnsignedShort;
triangulation.Indices.ForEach(index => writer.Write((ushort)index));
info.IndexBufferLength = sizeof(ushort) * triangulation.Indices.Length;
info.IndexBufferOffset = _Document.AddBufferData<ushort>(triangulation.Indices.Length, out var ispan);
for (var i = 0; i < triangulation.Indices.Length; i++)
{
ispan[i] = (ushort)triangulation.Indices[i];
}

break;
}
default:
{
info.IndexDataType = GltfDomAccessor.DataComponentType.UnsignedInt;
triangulation.Indices.ForEach(index => writer.Write((uint)index));
info.IndexBufferLength = sizeof(uint) * triangulation.Indices.Length;
info.IndexBufferOffset = _Document.AddBufferData<uint>(triangulation.Indices.Length, out var ispan);
for (var i = 0; i < triangulation.Indices.Length; i++)
{
ispan[i] = (uint)triangulation.Indices[i];
}

break;
}
}
info.IndexStream.Position = 0;

return info;
}
Expand Down
4 changes: 2 additions & 2 deletions Source/Macad.Exchange/Gltf/GltfDomBufferView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ internal sealed class GltfDomBufferView
public int BufferIndex { get; set; }

[JsonPropertyName("byteOffset")]
public long ByteOffset { get; set; }
public int ByteOffset { get; set; }

[JsonPropertyName("byteLength")]
public long ByteLength { get; set; }
public int ByteLength { get; set; }

[JsonPropertyName("byteStride")]
public int? ByteStride { get; set; }
Expand Down
25 changes: 15 additions & 10 deletions Source/Macad.Exchange/Gltf/GltfDomDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization;
using Macad.Common;
Expand Down Expand Up @@ -190,17 +191,21 @@ public int AddCamera(GltfDomCamera camera, int parent)

//--------------------------------------------------------------------------------------------------

public long AddBufferData(MemoryStream data)
public int AddBufferData<T>(int count, out Span<T> data) where T : struct
{
long offset = _CurrentBuffer.Data.Position;

data.Position = 0;
data.CopyTo(_CurrentBuffer.Data);
_CurrentBuffer.ByteLength += data.Length;

int binPadCount = (4 - (int)data.Length % 4) % 4;
_CurrentBuffer.Data.Write(_BinPadding, 0, binPadCount);
_CurrentBuffer.ByteLength += binPadCount;
int offset = (int)_CurrentBuffer.Data.Length;
int byteLength = count * Marshal.SizeOf<T>();
int binPadCount = (4 - byteLength % 4) % 4;

_CurrentBuffer.Data.SetLength(_CurrentBuffer.Data.Length + byteLength + binPadCount);
_CurrentBuffer.ByteLength = _CurrentBuffer.Data.Length;
data = MemoryMarshal.Cast<byte, T>(_CurrentBuffer.Data.GetBuffer().AsSpan(offset));

if (binPadCount > 0)
{
var padSpace = _CurrentBuffer.Data.GetBuffer().AsSpan(offset + byteLength, binPadCount);
padSpace.Clear();
}

return offset;
}
Expand Down

0 comments on commit 159ae2f

Please sign in to comment.
0