Created
July 26, 2023 02:30
-
-
Save maluoi/d99aa64708099166f5c228a78adfa39f to your computer and use it in GitHub Desktop.
A quick format for writing a simple StereoKit mesh to a fairly slim file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using StereoKit; | |
class BinMesh { | |
const uint binMeshIdentifier = 0x06b8d800; // a nice blue color | |
const uint binMeshVersion = 0x00000001; // and then a version, should never make it to 255! | |
struct Header { | |
public uint identifier; | |
public ushort vertexCount; | |
public ushort indexCount; | |
public byte paletteCount; | |
public Vec3 meshOffset; | |
public Vec3 meshScale; | |
}; | |
public static byte[] Make(Mesh m) | |
{ | |
Vertex[] verts = m.GetVerts(); | |
uint [] inds = m.GetInds(); | |
Bounds b = m.Bounds; | |
Dictionary<Color32, int> palette = verts.Aggregate(new Dictionary<Color32, int>(), (dict, vert) => { | |
if (!dict.ContainsKey(vert.col)) dict.Add(vert.col, dict.Count); | |
return dict; | |
}); | |
byte[] buffer = new byte[ | |
sizeof(uint) + sizeof(ushort) + sizeof(ushort) + sizeof(byte) + sizeof(float)*3 + sizeof(float)*3 + // Header | |
(sizeof(short) * 3 + sizeof(byte)) * verts.Length + // Verts | |
sizeof(byte) * inds.Length + // Indices | |
sizeof(byte) * palette.Count * 4 // Palette | |
]; | |
BinaryWriter w = new BinaryWriter(new MemoryStream(buffer)); | |
Header h = new Header { | |
identifier = binMeshIdentifier | binMeshVersion, | |
vertexCount = (ushort)verts.Length, | |
indexCount = (ushort)inds.Length, | |
paletteCount = (byte)palette.Count, | |
meshOffset = b.center, | |
meshScale = b.dimensions, | |
}; | |
w.Write(h.identifier); | |
w.Write(h.vertexCount); | |
w.Write(h.indexCount); | |
w.Write(h.paletteCount); | |
w.Write(h.meshOffset.x); w.Write(h.meshOffset.y); w.Write(h.meshOffset.z); | |
w.Write(h.meshScale .x); w.Write(h.meshScale .y); w.Write(h.meshScale .z); | |
// Write the palette first | |
foreach (Color32 c in palette.OrderBy(x => x.Value).Select(x => x.Key)) | |
{ | |
w.Write(c.r); | |
w.Write(c.g); | |
w.Write(c.b); | |
w.Write(c.a); | |
} | |
// Quantized verts | |
for (int i = 0; i < verts.Length; i++) | |
{ | |
Vec3 v = verts[i].pos - b.center; | |
short x = (short)((verts[i].pos.x/b.dimensions.x) * short.MaxValue); | |
short y = (short)((verts[i].pos.y/b.dimensions.y) * short.MaxValue); | |
short z = (short)((verts[i].pos.z/b.dimensions.z) * short.MaxValue); | |
w.Write(x); | |
w.Write(y); | |
w.Write(z); | |
w.Write((byte)palette[verts[i].col]); | |
} | |
// And finally the indices | |
for (int i = 0; i < inds.Length; i++) | |
w.Write((byte)inds[i]); | |
w.Close(); | |
return buffer; | |
} | |
public static Mesh From(byte[] buffer) | |
{ | |
Header h = new Header(); | |
BinaryReader r = new BinaryReader(new MemoryStream(buffer)); | |
h.identifier = r.ReadUInt32(); | |
if (h.identifier != (binMeshIdentifier | binMeshVersion)) | |
return null; | |
h.vertexCount = r.ReadUInt16(); | |
h.indexCount = r.ReadUInt16(); | |
h.paletteCount = r.ReadByte(); | |
h.meshOffset = new Vec3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); | |
h.meshScale = new Vec3(r.ReadSingle(), r.ReadSingle(), r.ReadSingle()); | |
// Read the palette | |
Color32[] palette = new Color32[h.paletteCount]; | |
for (int i = 0; i < h.paletteCount; i++) | |
palette[i] = new Color32(r.ReadByte(), r.ReadByte(), r.ReadByte(), r.ReadByte()); | |
// Read the verts | |
Vertex[] verts = new Vertex[h.vertexCount]; | |
for (int i = 0; i < h.vertexCount; i++) | |
{ | |
verts[i].pos.x = (r.ReadInt16() / (float)short.MaxValue) * h.meshScale.x + h.meshOffset.x; | |
verts[i].pos.y = (r.ReadInt16() / (float)short.MaxValue) * h.meshScale.y + h.meshOffset.y; | |
verts[i].pos.z = (r.ReadInt16() / (float)short.MaxValue) * h.meshScale.z + h.meshOffset.z; | |
verts[i].col = palette[r.ReadByte()]; | |
} | |
// Read the indices | |
uint[] inds = new uint[h.indexCount]; | |
for (int i = 0; i < h.indexCount; i++) | |
inds[i] = r.ReadByte(); | |
r.Close(); | |
// calculate normals | |
for (int i = 0; i < inds.Length; i += 3) | |
{ | |
uint i1 = inds[i ]; | |
uint i2 = inds[i+1]; | |
uint i3 = inds[i+2]; | |
// Length of cross product is twice the area of the triangle it's | |
// from, so if we don't 'normalize' it, then we get trangle area | |
// weighting on our normals for free! | |
Vec3 normal = Vec3.Cross(verts[i3].pos - verts[i2].pos, verts[i1].pos - verts[i2].pos); | |
verts[i1].norm += normal; | |
verts[i2].norm += normal; | |
verts[i3].norm += normal; | |
} | |
for (int i = 0; i < verts.Length; i++) verts[i].norm = verts[i].norm.Normalized; | |
Mesh result = new Mesh(); | |
result.SetData(verts, inds); | |
return result; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment