-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGltfExport.cs
196 lines (185 loc) · 8.94 KB
/
GltfExport.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
using Rhino;
using Rhino.DocObjects;
using Rhino.FileIO;
using Rhino.Geometry;
using Rhino.Render;
using Rhino.Render.ChangeQueue;
using System.Collections.Concurrent;
namespace Web_Exporter
{
public class GltfExport : GH_Component
{
private string _lastResult = "";
private bool _executing = false;
public GltfExport()
: base("Gltf Exporter", "GltfExporter",
"Exports geometries or rhino scene as gltf file for web view",
"Web", "Gltf")
{
}
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddBooleanParameter("Export", "Exp", "Use button to export when needed.", GH_ParamAccess.item); //0
pManager.AddTextParameter("File Name", "Name", "Name your output file.", GH_ParamAccess.item, "model_01"); //1
pManager.AddTextParameter("Folder", "Path", "The folder you want to store the output in.", GH_ParamAccess.item); //2
pManager.AddGeometryParameter("Geometry Collection", "Geo", "Add the geometry you like to export.", GH_ParamAccess.tree); //3
pManager[3].Optional = true;
pManager.AddTextParameter("Material Name", "Material", "Add a name of a predefined material to export the model with.", GH_ParamAccess.tree);//4
pManager[4].Optional = true;
pManager.AddGenericParameter("FileGltfWriteOptions", "Options", "Write file options.", GH_ParamAccess.item); //5
pManager[5].Optional = true;
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager) =>
pManager.AddTextParameter("Errors and Feedback", "E", "Preliminary feedback.", GH_ParamAccess.item);
protected override void SolveInstance(IGH_DataAccess DA)
{
#region imputs
bool export = false; DA.GetData("Export", ref export);
string name = ""; DA.GetData("File Name", ref name);
string loc = ""; DA.GetData("Folder", ref loc);
DA.GetDataTree(3, out GH_Structure<IGH_GeometricGoo>? geo);
DA.GetDataTree(4, out GH_Structure<GH_String>? material);
object? options = null; DA.GetData("FileGltfWriteOptions", ref options);
#endregion
// Sanity
if (!Directory.Exists(loc))
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Path does not exist on machine.");
return;
}
var filePath = loc;
filePath += $@"\{name}.gltf";
// Label Input
var button = Params.Input.Find(p => p.NickName == "Exp")!.Sources[0].Attributes.DocObject;
if (button.GetType() == typeof(Grasshopper.Kernel.Special.GH_ButtonObject))
((Grasshopper.Kernel.Special.GH_ButtonObject)button).NickName = "Export";
// Mode
bool scene = false;
Message = "Geometry";
if (geo.DataCount < 1)// == null)
{
string msg = "Writing entire scene since \"geo\" failed to collect data";
AddRuntimeMessage(GH_RuntimeMessageLevel.Remark, msg);
scene = true;
Message = "Scene";
}
FileGltfWriteOptions? optionsGltf =
options != null
&& options is FileGltfWriteOptions ?
options as FileGltfWriteOptions : DefaultOptions();
if (!export || _executing)
{
if(_executing) _lastResult = "executing in background...";
goto Outputs;
}
_executing = true;
List<Guid> ids = [];
RhinoDoc doc = RhinoDoc.ActiveDoc;
Task.Run(() =>
{
string res= "";
try
{
switch (scene)
{
case false:
Rhino.Collections.ArchivableDictionary archiveCollection = optionsGltf!.ToDictionary();
// material assignment and baking
int path = 0;
foreach (var branch in geo!.Branches)
{
var matLst = material.Branches[RepeatLast(material.Branches.Count, path)]; // get mat branch list (repeating last if less)
int index = 0;
RenderMaterial? materialRH = null;
foreach (var g in branch)
{
// assigning custom materials if exists (repeating last item if less)
if (matLst != null)
{
var matName = matLst[RepeatLast(matLst.Count, index)].Value;
materialRH = doc.RenderMaterials
.FirstOrDefault(n => n.Name == matName); // get render mat
}
// baking
Guid id = doc.Objects.Add(GH_Convert.ToGeometryBase(g), new ObjectAttributes()
{
RenderMaterial = materialRH
});
ids.Add(id);
index++;
}
path++;
}
RhinoApp.Write("Object(s) baked\n", true);
// select object(s) into list
foreach (Guid id in ids)
doc.Objects.Select(id, true);
RhinoApp.Write("Object(s) selected\n", true);
// attempt export temp baked object(s)
if (doc.ExportSelected(filePath, archiveCollection))
res = $"File written successfully to path: {filePath}";
else
throw new Exception("Something went wrong when exporting");
break;
default:
// attempt export entire document scene
if (FileGltf.Write(filePath, doc, optionsGltf))
res = $"File written successfully to path: {filePath}";
else
throw new Exception("Something went wrong when exporting");
break;
}
}
catch (Exception e)
{
res += "\nError\n" + e;
}
finally
{
RhinoApp.Write($"Export attempted to directory: {loc}\n", true);
if (!scene)
{
// delete baked geometry quiet
foreach (Guid id in ids)
doc.Objects.Delete(id, true);
RhinoApp.Write("Object(s) deleted\n", true);
}
_lastResult = $"[{DateTime.Now.ToShortTimeString()}] {res}";
_executing = false;
RhinoApp.InvokeOnUiThread(()=>this.ExpireSolution(true));
}
});
#region Outputs
Outputs:
DA.SetData("Errors and Feedback", _lastResult);
#endregion Outputs
}
private static FileGltfWriteOptions DefaultOptions() =>
new()
{
CullBackfaces = true,
DracoCompressionLevel = 10,
DracoQuantizationBitsNormal = 8,
DracoQuantizationBitsPosition = 11,
DracoQuantizationBitsTextureCoordinate = 10,
ExportLayers = false,
ExportMaterials = true,
ExportOpenMeshes = true,
ExportTextureCoordinates = true,
ExportVertexColors = true,
ExportVertexNormals = true,
MapZToY = true,
SubDMeshType = FileGltfWriteOptions.SubDMeshing.Surface,
SubDSurfaceMeshingDensity = 4,
UseDisplayColorForUnsetMaterials = true,
UseDracoCompression = true
};
/// <summary>Repeat last if index exceeds collection count.</summary>
private static int RepeatLast(int last, int index) => index < last ? index : last - 1;
protected override System.Drawing.Bitmap Icon => Properties.Resources.gltfGH;
public override Guid ComponentGuid => new("d954350d-dcb0-486e-b78b-dd251424ec4a");
}
}