Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jrz371 non draco export #20

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 38 additions & 17 deletions glTF-BinExporter/GlTFExporterCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,23 +35,20 @@ protected override Result RunCommand(Rhino.RhinoDoc doc, RunMode mode)
{
GetObject go = Selection.GetValidExportObjects("Select objects to export.");

var opts = new ExportOptions() { UseDracoCompression = true, DracoCompressionLevel = 10, DracoQuantizationBits = 16, UseBinary = true };

// NOTE: The following options can be useful in dev/debug:
//bool useDracoCompression = true;
//Rhino.Input.RhinoGet.GetBool("Compression", true, "None", "Draco", ref useDracoCompression);
//bool useBinary = true;
//Rhino.Input.RhinoGet.GetBool("Mode", true, "Text", "Binary", ref useBinary);
//bool includeMaterials = true;
//Rhino.Input.RhinoGet.GetBool("Materials", true, "Exclude", "Include", ref opts.IncludeMaterial);
//int dracoCompressionLevel = 10;
Rhino.Input.RhinoGet.GetInteger("Draco Compression Level (max=10)", true, ref opts.DracoCompressionLevel, 1, 10);
//bool quantizaionBits = true;
Rhino.Input.RhinoGet.GetInteger("Quantization", true, ref opts.DracoQuantizationBits, 8, 32);
//Rhino.Input.RhinoGet.GetBool("Draco Quantization", true, "B", "Bits 16 Bits", ref quantizaionBits);
//opts.DracoQuantizationBits = quantizaionBits ? 24 : 12;

var dialog = new SaveFileDialog() { DefaultExt = ".glb", Title = "Select glTF Binary file to export to.", Filter = "glTF Binary (*.glb) | *.glb" };
var opts = new ExportOptions() { UseDracoCompression = false, DracoCompressionLevel = 10, DracoQuantizationBits = 16, UseBinary = true };

Rhino.Input.RhinoGet.GetBool("Binary or Text", true, "Text", "Binary", ref opts.UseBinary);

Rhino.Input.RhinoGet.GetBool("Compression", true, "None", "Draco", ref opts.UseDracoCompression);

if (opts.UseDracoCompression)
{
Rhino.Input.RhinoGet.GetInteger("Draco Compression Level (max=10)", true, ref opts.DracoCompressionLevel, 1, 10);
Rhino.Input.RhinoGet.GetInteger("Quantization", true, ref opts.DracoQuantizationBits, 8, 32);
}

var dialog = GetSaveFileDialog(opts.UseBinary);

var fileSelected = dialog.ShowSaveDialog();

if (!fileSelected) {
Expand Down Expand Up @@ -89,8 +86,32 @@ protected override Result RunCommand(Rhino.RhinoDoc doc, RunMode mode)
return Result.Success;
} catch (Exception e) {
RhinoApp.WriteLine("ERROR: Failed exporting selected geometry to file.");
System.Diagnostics.Debug.WriteLine(e.Message);
return Result.Failure;
}
}

private SaveFileDialog GetSaveFileDialog(bool binaryExport)
{
if(binaryExport)
{
return new SaveFileDialog()
{
DefaultExt = ".glb",
Title = "Select glTF Binary file to export to.",
Filter = "glTF Binary (*.glb) | *.glb"
};
}
else //Text glTF
{
return new SaveFileDialog()
{
DefaultExt = ".gltf",
Title = "Select glTF file to export to.",
Filter = "glTF Text (*.gltf) | *.gltf"
};
}
}

}
}
17 changes: 17 additions & 0 deletions glTF-BinExporter/glTF/GlBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class Buffer
public bool IsGLBinaryMode;

// dump to byte[] with ".flatten" + .ToArray();
[JsonIgnore]
public List<IEnumerable<byte>> RawBytes;

public bool ShouldSerializeRawBytes()
Expand Down Expand Up @@ -75,6 +76,22 @@ public void Add(Point3d point)
PrimitiveCount += 1;
}

public void Add(Vector3d point)
{
// Switch GL coords for Y<=>Z
float[] coords = new float[] { (float)point.X, (float)point.Z, -(float)point.Y };
Add(coords);
PrimitiveCount += 1;
}

public void Add(Point2f point)
{
// Switch GL coords for Y<=>Z
float[] coords = new float[] { (float)point.X, -(float)point.Y };
Add(coords);
PrimitiveCount += 1;
}

public void Add(MeshFace face)
{
if (face.IsTriangle)
Expand Down
250 changes: 169 additions & 81 deletions glTF-BinExporter/glTF/GlTFRootModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ namespace glTF_BinExporter.glTF
/// </summary>
public class RootModel
{
public int scene;
public int scene = 0;

public List<Scene> scenes;

public List<Node> nodes;
Expand Down Expand Up @@ -145,6 +146,9 @@ public void SerializeToGLB(in MemoryStream memoryStream)
bv.byteOffset = bv.bufferRef.binaryOffset;
}

//Have to get rid of the other buffers so only the new buffer
//all the data was dumped into remains
buffers.Clear();
buffers.Add(new Buffer(false) { byteLength = binaryChunkUnpaddedLength, uri = null });

// JSON Chunk
Expand Down Expand Up @@ -518,90 +522,174 @@ public void AddMaterial(Rhino.DocObjects.Material rhinoMaterial, Guid renderMatI

public void AddRhinoObject(Rhino.Geometry.Mesh[] rhinoMeshes, Rhino.DocObjects.Material material, Guid renderMatId)
{
// TODO: Disabled for now. Don't have bandwidth to fix none-DracoCompression for now. Beware of lot's of "old" code below.
//int currentMaterialIdx = materials.FindIndex(m => m.Id == material.Id);
//if (currentMaterialIdx == -1)
//{
// AddMaterial(material);
// currentMaterialIdx = materials.Count - 1;
//}
int currentMaterialIdx = materials.FindIndex(m => m.Id == material.Id);
if (currentMaterialIdx == -1)
{
AddMaterial(material, renderMatId);
currentMaterialIdx = materials.Count - 1;
}

//var primitives = new List<Primitive>();
//// For each rhino mesh, create gl-buffers, gl-meshes, etc.
//foreach (var rhinoMesh in rhinoMeshes)
//{
// // Create buffers for data (position, normals, indices etc.)
// var vtxBuffer = new Buffer(IsGLBinaryMode);
var primitives = new List<Primitive>();

// var min = new Point3d() { X = Double.PositiveInfinity, Y = Double.PositiveInfinity, Z = Double.PositiveInfinity };
// var max = new Point3d() { X = Double.NegativeInfinity, Y = Double.NegativeInfinity, Z = Double.NegativeInfinity };
// foreach (var p in rhinoMesh.Vertices)
// {
// vtxBuffer.Add(p);

// min.X = Math.Min(min.X, p.X);
// // Switch Y<=>Z for GL coords
// min.Y = Math.Min(min.Y, p.Z);
// min.Z = Math.Min(min.Z, -p.Y);

// max.X = Math.Max(max.X, p.X);
// // Switch Y<=>Z for GL coords
// max.Y = Math.Max(max.Y, p.Z);
// max.Z = Math.Max(max.Z, -p.Y);
// }
// buffers.Add(vtxBuffer);
// int vtxBufferIdx = buffers.Count - 1;

// var idsBuffer = new Buffer(IsGLBinaryMode);
// foreach (var f in rhinoMesh.Faces)
// {
// idsBuffer.Add(f);
// }
// buffers.Add(idsBuffer);
// int idsBufferIdx = buffers.Count - 1;

// // Create bufferviews
// var vtxBufferView = new BufferView() { bufferRef = vtxBuffer, buffer = vtxBufferIdx, byteOffset = 0, byteLength = vtxBuffer.byteLength, target = GlConstants.ARRAY_BUFFER };
// bufferViews.Add(vtxBufferView);
// int vtxBufferViewIdx = bufferViews.Count - 1;

// var idsBufferView = new BufferView() { bufferRef = idsBuffer, buffer = idsBufferIdx, byteOffset = 0, byteLength = idsBuffer.byteLength, target = GlConstants.ELEMENT_ARRAY_BUFFER };
// bufferViews.Add(idsBufferView);
// int idsBufferViewIdx = bufferViews.Count - 1;

// // Create accessors
// var vtxAccessor = new AccessorVec3
// {
// bufferView = vtxBufferViewIdx,
// count = vtxBuffer.PrimitiveCount,
// min = new float[] { (float)min.X, (float)min.Y, (float)min.Z },
// max = new float[] { (float)max.X, (float)max.Y, (float)max.Z }
// };
// accessors.Add(vtxAccessor);
// int vtxAccessorIdx = accessors.Count - 1;

// var idsAccessor = new AccessorScalar
// {
// bufferView = idsBufferViewIdx,
// count = idsBuffer.PrimitiveCount
// };
// accessors.Add(idsAccessor);
// int idsAccessorIdx = accessors.Count - 1;

// // Create primitives
// var attribute = new Attribute() { POSITION = vtxAccessorIdx };
// var primitive = new Primitive() { attributes = attribute, indices = idsAccessorIdx, material = currentMaterialIdx };

// // Create mesh
// primitives.Add(primitive);
//}
//var mesh = new Mesh() { primitives = primitives };
//meshes.Add(mesh);
foreach (var rhinoMesh in rhinoMeshes)
{
// Create buffers for data (position, normals, indices etc.)
var vtxBuffer = new Buffer(ExportOptions.UseBinary);
var vtxMin = new Point3d() { X = Double.PositiveInfinity, Y = Double.PositiveInfinity, Z = Double.PositiveInfinity };
var vtxMax = new Point3d() { X = Double.NegativeInfinity, Y = Double.NegativeInfinity, Z = Double.NegativeInfinity };
foreach (var p in rhinoMesh.Vertices)
{
vtxBuffer.Add(p);

//var node = new Node() { mesh = meshes.Count - 1 };
//nodes.Add(node);
vtxMin.X = Math.Min(vtxMin.X, p.X);
// Switch Y<=>Z for GL coords
vtxMin.Y = Math.Min(vtxMin.Y, p.Z);
vtxMin.Z = Math.Min(vtxMin.Z, -p.Y);

//scenes[scene].nodes.Add(nodes.Count - 1);
vtxMax.X = Math.Max(vtxMax.X, p.X);
// Switch Y<=>Z for GL coords
vtxMax.Y = Math.Max(vtxMax.Y, p.Z);
vtxMax.Z = Math.Max(vtxMax.Z, -p.Y);
}
buffers.Add(vtxBuffer);
int vtxBufferIdx = buffers.Count - 1;

var idsBuffer = new Buffer(ExportOptions.UseBinary);
foreach (var f in rhinoMesh.Faces)
{
idsBuffer.Add(f);
}
buffers.Add(idsBuffer);
int idsBufferIdx = buffers.Count - 1;

Buffer normalsBuffer = new Buffer(ExportOptions.UseBinary);
var normalsMin = new Point3d() { X = Double.PositiveInfinity, Y = Double.PositiveInfinity, Z = Double.PositiveInfinity };
var normalsMax = new Point3d() { X = Double.NegativeInfinity, Y = Double.NegativeInfinity, Z = Double.NegativeInfinity };
//normalsBuffer.Add(rhinoMesh.Normals.ToFloatArray());
foreach (var n in rhinoMesh.Normals)
{
normalsBuffer.Add(n);

normalsMin.X = Math.Min(normalsMin.X, n.X);
// Switch Y<=>Z for GL coords
normalsMin.Y = Math.Min(normalsMin.Y, n.Z);
normalsMin.Z = Math.Min(normalsMin.Z, -n.Y);

normalsMax.X = Math.Max(normalsMax.X, n.X);
// Switch Y<=>Z for GL coords
normalsMax.Y = Math.Max(normalsMax.Y, n.Z);
normalsMax.Z = Math.Max(normalsMax.Z, -n.Y);
}
int normalsIdx = buffers.AddAndReturnIndex(normalsBuffer);

Buffer texCoordsBuffer = new Buffer(ExportOptions.UseBinary);
var texCoordsMin = new Point2d() { X = Double.PositiveInfinity, Y = Double.PositiveInfinity };
var texCoordsMax = new Point2d() { X = Double.NegativeInfinity, Y = Double.NegativeInfinity };
foreach (var tx in rhinoMesh.TextureCoordinates)
{
texCoordsBuffer.Add(tx);

texCoordsMin.X = Math.Min(texCoordsMin.X, tx.X);
// Switch Y<=>Z for GL coords
texCoordsMin.Y = Math.Min(texCoordsMin.Y, -tx.Y);

texCoordsMax.X = Math.Max(texCoordsMax.X, tx.X);
// Switch Y<=>Z for GL coords
texCoordsMax.Y = Math.Max(texCoordsMax.Y, -tx.Y);
}

int texCoordsIdx = buffers.AddAndReturnIndex(texCoordsBuffer);

// Create bufferviews
var vtxBufferView = new BufferView() { bufferRef = vtxBuffer, buffer = vtxBufferIdx, byteOffset = 0, byteLength = vtxBuffer.byteLength, target = GLConstants.ARRAY_BUFFER };
bufferViews.Add(vtxBufferView);
int vtxBufferViewIdx = bufferViews.Count - 1;

var idsBufferView = new BufferView() { bufferRef = idsBuffer, buffer = idsBufferIdx, byteOffset = 0, byteLength = idsBuffer.byteLength, target = GLConstants.ELEMENT_ARRAY_BUFFER };
bufferViews.Add(idsBufferView);
int idsBufferViewIdx = bufferViews.Count - 1;

BufferView normalsBufferView = new BufferView()
{
bufferRef = normalsBuffer,
buffer = normalsIdx,
byteOffset = 0,
byteLength = normalsBuffer.byteLength,
target = GLConstants.ARRAY_BUFFER
};
int normalsBufferViewIdx = bufferViews.AddAndReturnIndex(normalsBufferView);

BufferView texCoordsBufferView = new BufferView()
{
bufferRef = texCoordsBuffer,
buffer = texCoordsIdx,
byteOffset = 0,
byteLength = texCoordsBuffer.byteLength,
target = GLConstants.ARRAY_BUFFER
};
int texCoordsBufferViewIdx = bufferViews.AddAndReturnIndex(texCoordsBufferView);

// Create accessors
var vtxAccessor = new AccessorVec3()
{
bufferView = vtxBufferViewIdx,
count = vtxBuffer.PrimitiveCount,
min = new float[] { (float)vtxMin.X, (float)vtxMin.Y, (float)vtxMin.Z },
max = new float[] { (float)vtxMax.X, (float)vtxMax.Y, (float)vtxMax.Z }
};

accessors.Add(vtxAccessor);
int vtxAccessorIdx = accessors.Count - 1;

var idsAccessor = new AccessorScalar()
{
min = new int[] { 0 },
max = new int[] { rhinoMesh.Vertices.Count - 1 },
bufferView = idsBufferViewIdx,
count = idsBuffer.PrimitiveCount
};
accessors.Add(idsAccessor);
int idsAccessorIdx = accessors.Count - 1;

AccessorVec3 normalsAccessor = new AccessorVec3()
{
bufferView = normalsBufferViewIdx,
count = rhinoMesh.Normals.Count,
min = new float[] { (float)normalsMin.X, (float)normalsMin.Y, (float)normalsMin.Z },
max = new float[] { (float)normalsMax.X, (float)normalsMax.Y, (float)normalsMax.Z }
};
int normalsAccessorIdx = accessors.AddAndReturnIndex(normalsAccessor);

AccessorVec2 texCoordsAccessor = new AccessorVec2()
{
bufferView = texCoordsBufferViewIdx,
count = rhinoMesh.TextureCoordinates.Count,
min = new float[] { 0.0f, 0.0f },
max = new float[] { 1.0f, 1.0f },
};
int texCoordsAccessorIdx = accessors.AddAndReturnIndex(texCoordsAccessor);

// Create primitives
var attribute = new Attribute()
{
POSITION = vtxAccessorIdx,
NORMAL = normalsAccessorIdx,
TEXCOORD_0 = texCoordsAccessorIdx
};

var primitive = new Primitive() { attributes = attribute, indices = idsAccessorIdx, material = currentMaterialIdx };

// Create mesh
primitives.Add(primitive);
}

var mesh = new Mesh() { primitives = primitives };
meshes.Add(mesh);

var node = new Node() { mesh = meshes.Count - 1 };
nodes.Add(node);

scenes[scene].nodes.Add(nodes.Count - 1);
}
}
}
7 changes: 7 additions & 0 deletions glTF-BinExporter/glTF/GlTFUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,12 @@ public static void ExportBinary(MemoryStream outStream, IEnumerable<RhinoObject>

outStream.Flush();
}

public static int AddAndReturnIndex<T>(this List<T> list, T item)
{
list.Add(item);
return list.Count - 1;
}

}
}