├── .gitattributes
├── .vs
└── RevitExportGltf
│ ├── v15
│ ├── .suo
│ └── Server
│ │ └── sqlite3
│ │ ├── db.lock
│ │ ├── storage.ide
│ │ ├── storage.ide-shm
│ │ └── storage.ide-wal
│ └── v16
│ └── .suo
├── App.config
├── App.xaml
├── App.xaml.cs
├── Command.cs
├── Containers.cs
├── Docume
├── binFilePrint.txt
├── 丢失有纹理贴图.png
└── 效果图.png
├── LICENSE
├── ObjectData.cs
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
├── README.md
├── RevitExportGltf.csproj
├── RevitExportGltf.md
├── RevitExportGltf.sln
├── RevitExportGltf
├── App.config
├── App.xaml
├── App.xaml.cs
├── Command.cs
├── Containers.cs
├── Docume
│ ├── Revit导出gltf工具说明文档.md
│ ├── binFilePrint.txt
│ ├── 丢失有纹理贴图.png
│ └── 效果图.png
├── ObjectData.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── RevitExportGltf.csproj
├── RevitExportGltfContext.cs
├── Util.cs
├── WPF
│ ├── MainWindow.xaml
│ └── MainWindow.xaml.cs
├── bin
│ └── Dotfuscator1.xml
├── glTF.cs
├── libs
│ ├── Revit2018
│ │ ├── RevitAPI.dll
│ │ ├── RevitAPIUI.dll
│ │ └── UIFrameworkServices.dll
│ └── SharpGLTF
│ │ ├── SharpGLTF.Core.dll
│ │ └── SharpGLTF.Toolkit.dll
└── packages.config
├── RevitExportGltfContext.cs
├── Util.cs
├── WPF
├── MainWindow.xaml
└── MainWindow.xaml.cs
├── glTF.cs
├── libs
├── Revit2018
│ ├── RevitAPI.dll
│ ├── RevitAPIUI.dll
│ └── UIFrameworkServices.dll
├── Revit2020
│ ├── RevitAPI.dll
│ ├── RevitAPIUI.dll
│ └── UIFrameworkServices.dll
└── SharpGLTF
│ ├── SharpGLTF.Core.dll
│ └── SharpGLTF.Toolkit.dll
├── packages.config
└── packages
└── Newtonsoft.Json.13.0.1
├── .signature.p7s
├── LICENSE.md
├── Newtonsoft.Json.13.0.1.nupkg
├── lib
├── net20
│ ├── Newtonsoft.Json.dll
│ └── Newtonsoft.Json.xml
├── net35
│ ├── Newtonsoft.Json.dll
│ └── Newtonsoft.Json.xml
├── net40
│ ├── Newtonsoft.Json.dll
│ └── Newtonsoft.Json.xml
├── net45
│ ├── Newtonsoft.Json.dll
│ └── Newtonsoft.Json.xml
├── netstandard1.0
│ ├── Newtonsoft.Json.dll
│ └── Newtonsoft.Json.xml
├── netstandard1.3
│ ├── Newtonsoft.Json.dll
│ └── Newtonsoft.Json.xml
└── netstandard2.0
│ ├── Newtonsoft.Json.dll
│ └── Newtonsoft.Json.xml
└── packageIcon.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.vs/RevitExportGltf/v15/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/.vs/RevitExportGltf/v15/.suo
--------------------------------------------------------------------------------
/.vs/RevitExportGltf/v15/Server/sqlite3/db.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/.vs/RevitExportGltf/v15/Server/sqlite3/db.lock
--------------------------------------------------------------------------------
/.vs/RevitExportGltf/v15/Server/sqlite3/storage.ide:
--------------------------------------------------------------------------------
1 | SQLite format 3 @ .A
--------------------------------------------------------------------------------
/.vs/RevitExportGltf/v15/Server/sqlite3/storage.ide-shm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/.vs/RevitExportGltf/v15/Server/sqlite3/storage.ide-shm
--------------------------------------------------------------------------------
/.vs/RevitExportGltf/v15/Server/sqlite3/storage.ide-wal:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/.vs/RevitExportGltf/v15/Server/sqlite3/storage.ide-wal
--------------------------------------------------------------------------------
/.vs/RevitExportGltf/v16/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/.vs/RevitExportGltf/v16/.suo
--------------------------------------------------------------------------------
/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace RevitExportGltf
10 | {
11 | ///
12 | /// App.xaml 的交互逻辑
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Command.cs:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright:MyCompany
3 |
4 | Author: chenwy
5 |
6 | Date:2020-7-31
7 |
8 | Description:Provide Revit export 3D file in gltf format
9 |
10 | HistoryRecord:
11 | **************************************************************************/
12 |
13 | using Autodesk.Revit.Attributes;
14 | using Autodesk.Revit.DB;
15 | using Autodesk.Revit.UI;
16 | using Microsoft.Win32;
17 | using Newtonsoft.Json;
18 | using System;
19 | using System.Collections.Generic;
20 | using System.Diagnostics;
21 | using System.IO;
22 | using System.Linq;
23 | using System.Reflection;
24 | using System.Text;
25 | using System.Threading.Tasks;
26 | using System.Windows;
27 | using System.Windows.Forms;
28 |
29 | namespace RevitExportGltf
30 | {
31 | [Transaction(TransactionMode.Manual)]
32 | class Command : IExternalCommand
33 | {
34 |
35 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
36 | {
37 | //以导出当前视图
38 | UIApplication uiapp = commandData.Application;
39 | UIDocument uidoc = uiapp.ActiveUIDocument;
40 | Autodesk.Revit.ApplicationServices.Application app = uiapp.Application;
41 | Document doc = uidoc.Document;
42 |
43 | //没打开文档
44 | if (null == doc)
45 | {
46 | message = "Please open the project.";
47 | return Result.Failed;
48 | }
49 |
50 | //没有打开文档
51 | if (null == uidoc)
52 | {
53 | message = "Please run this command in an active project document.";
54 | return Result.Failed;
55 | }
56 |
57 | //3D视图下
58 | View3D view = doc.ActiveView as View3D;
59 | if (null == view)
60 | {
61 | message = "Please run this command in a 3D view.";
62 | return Result.Failed;
63 | }
64 |
65 | //保存导出的文件 包括过滤器gltf与glb格式
66 | System.Windows.Forms.SaveFileDialog sdial = new System.Windows.Forms.SaveFileDialog();
67 | sdial.Filter = "gltf|*.gltf|glb|*.glb";
68 | if (sdial.ShowDialog() == DialogResult.OK)
69 | {
70 | string filename = sdial.FileName;
71 | string directory = Path.GetDirectoryName(filename) + "\\"; ;
72 | //拿到revit的doc CustomExporter 用户自定义导出
73 | RevitExportGltfContext context = new RevitExportGltfContext(doc, sdial.FileName);
74 | using (CustomExporter exporter = new CustomExporter(doc, context))
75 | {
76 | //是否包括Geom对象
77 | exporter.IncludeGeometricObjects = false;
78 | exporter.ShouldStopOnError = true;
79 | //导出3D模型
80 | exporter.Export(view);
81 | }
82 |
83 | System.Diagnostics.Process p = new System.Diagnostics.Process();
84 | p.StartInfo.FileName = "cmd.exe";
85 | p.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
86 | p.StartInfo.RedirectStandardInput = true; //接受来自调用程序的输入信息
87 | p.StartInfo.RedirectStandardOutput = true; //由调用程序获取输出信息
88 | p.StartInfo.RedirectStandardError = true; //重定向标准错误输出
89 | p.StartInfo.CreateNoWindow = true;//不显示程序窗口
90 | p.Start();//启动程序
91 | //使用gltf pipeline命令行工具
92 | //向cmd窗口发送输入信息 (node.js已经是配置好了系统环境变量)
93 | //string str = @"cd D:\cmder";
94 | //p.StandardInput.WriteLine(str);
95 |
96 | //将GLTF转换为glb二进制 压缩纹理与bin顶点
97 | string glbName = Path.GetFileNameWithoutExtension(sdial.FileName) + "(Draco)" + ".glb";
98 | string glbstr = string.Format("gltf-pipeline.cmd gltf-pipeline -i {0} -o {1}", sdial.FileName, Path.GetDirectoryName(sdial.FileName) + "\\" + glbName);
99 | p.StandardInput.WriteLine(glbstr);
100 |
101 |
102 | //gltf-pipeline.c md gltf-pipeline -i model.gltf -o modelDraco.gltf -d
103 | //运用Draco算法将GLTF压缩 压缩纹理与bin顶点是json文件
104 | string gltfDracoName = Path.GetFileNameWithoutExtension(sdial.FileName) + "(Draco)" + ".gltf";
105 | string gltfDraco = string.Format("gltf-pipeline.cmd gltf-pipeline -i {0} -o {1} -d", sdial.FileName, Path.GetDirectoryName(sdial.FileName) + "\\" + gltfDracoName);
106 | p.StandardInput.WriteLine(gltfDraco);
107 |
108 | //gltf - pipeline - i model.gltf - t
109 | //压缩bin二进制为base64编码,但是保留纹理
110 | string gltfTextureName = Path.GetFileNameWithoutExtension(sdial.FileName) + "(Texture)" + ".gltf";
111 | string gltfTexture = string.Format("gltf-pipeline.cmd gltf-pipeline -i {0} -o {1} -t", sdial.FileName, Path.GetDirectoryName(sdial.FileName) + "\\" + gltfTextureName);
112 | p.StandardInput.WriteLine(gltfTexture);
113 |
114 | p.StandardInput.AutoFlush = true;
115 | p.StandardInput.WriteLine("exit");
116 |
117 | //获取cmd窗口的输出信息
118 | string output = p.StandardOutput.ReadToEnd();
119 | System.Windows.MessageBox.Show(output);
120 | }
121 | return Result.Succeeded;
122 | }
123 |
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/Containers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Autodesk.Revit.DB;
4 |
5 | namespace RevitExportGltf
6 | {
7 |
8 |
9 | ///
10 | /// Container for holding a strict set of items
11 | /// that is also addressable by a unique ID.
12 | ///
13 | /// The type of item contained.
14 | class IndexedDictionary
15 | {
16 | private Dictionary _dict = new Dictionary();
17 | public List List { get; } = new List();
18 | public string CurrentKey { get; private set; }
19 | public Dictionary Dict
20 | {
21 | get
22 | {
23 | var output = new Dictionary();
24 | foreach (var kvp in _dict)
25 | {
26 | output.Add(kvp.Key, List[kvp.Value]);
27 | }
28 | return output;
29 | }
30 | }
31 |
32 | ///
33 | /// The most recently accessed item (not effected by GetElement()).
34 | ///
35 | public T CurrentItem
36 | {
37 | get { return List[_dict[CurrentKey]]; }
38 | }
39 |
40 | ///
41 | /// The index of the most recently accessed item (not effected by GetElement()).
42 | ///
43 | public int CurrentIndex
44 | {
45 | get { return _dict[CurrentKey]; }
46 | }
47 |
48 | ///
49 | /// Add a new item to the list, if it already exists then the
50 | /// current item will be set to this item.
51 | ///
52 | /// Unique identifier for the item.
53 | /// The item to add.
54 | /// true if item did not already exist.
55 | public bool AddOrUpdateCurrent(string uuid, T elem)
56 | {
57 | if (!_dict.ContainsKey(uuid))
58 | {
59 | List.Add(elem);
60 | _dict.Add(uuid, (List.Count - 1));
61 | CurrentKey = uuid;
62 | return true;
63 | }
64 |
65 | CurrentKey = uuid;
66 | return false;
67 | }
68 |
69 | ///
70 | /// Check if the container already has an item with this key.
71 | ///
72 | /// Unique identifier for the item.
73 | ///
74 | public bool Contains(string uuid)
75 | {
76 | return _dict.ContainsKey(uuid);
77 | }
78 |
79 | ///
80 | /// Returns the index for an item given it's unique identifier.
81 | ///
82 | /// Unique identifier for the item.
83 | /// index of item or -1
84 | public int GetIndexFromUUID(string uuid)
85 | {
86 | if (!Contains(uuid)) throw new Exception("Specified item could not be found.");
87 | return _dict[uuid];
88 | }
89 |
90 | ///
91 | /// Returns an item given it's unique identifier.
92 | ///
93 | /// Unique identifier for the item
94 | /// the item
95 | public T GetElement(string uuid)
96 | {
97 | int index = GetIndexFromUUID(uuid);
98 | return List[index];
99 | }
100 |
101 | ///
102 | /// Returns as item given it's index location.
103 | ///
104 | /// The item's index location.
105 | /// the item
106 | public T GetElement(int index)
107 | {
108 | if (index < 0 || index > List.Count - 1) throw new Exception("Specified item could not be found.");
109 | return List[index];
110 | }
111 | }
112 |
113 | ///
114 | /// From Jeremy Tammik's RvtVa3c exporter:
115 | /// https://github.com/va3c/RvtVa3c
116 | /// A vertex lookup class to eliminate
117 | /// duplicate vertex definitions.
118 | ///
119 | class VertexLookupXyz : Dictionary
120 | {
121 | ///
122 | /// Define equality for Revit XYZ points.
123 | /// Very rough tolerance, as used by Revit itself.
124 | ///
125 | class XyzEqualityComparer : IEqualityComparer
126 | {
127 | const double _sixteenthInchInFeet = 1.0 / (16.0 * 12.0);
128 |
129 | public bool Equals(XYZ p, XYZ q)
130 | {
131 | return p.IsAlmostEqualTo(q, _sixteenthInchInFeet);
132 | }
133 |
134 | public int GetHashCode(XYZ p)
135 | {
136 | return Util.PointString(p).GetHashCode();
137 | }
138 | }
139 |
140 | public VertexLookupXyz() : base(new XyzEqualityComparer())
141 | {
142 | }
143 |
144 | ///
145 | /// Return the index of the given vertex,
146 | /// adding a new entry if required.
147 | ///
148 | public int AddVertex(XYZ p)
149 | {
150 | return ContainsKey(p)
151 | ? this[p]
152 | : this[p] = Count;
153 | }
154 | }
155 |
156 | ///
157 | /// From Jeremy Tammik's RvtVa3c exporter:
158 | /// https://github.com/va3c/RvtVa3c
159 | /// An integer-based 3D point class.
160 | ///
161 | class PointInt : IComparable
162 | {
163 | public long X { get; set; }
164 | public long Y { get; set; }
165 | public long Z { get; set; }
166 |
167 | ///
168 | /// Consider a Revit length zero
169 | /// if is smaller than this.
170 | ///
171 | const double _eps = 1.0e-9;
172 |
173 | ///
174 | /// Conversion factor from feet to millimetres.
175 | ///
176 | const double _feet_to_mm = 25.4 * 12;
177 |
178 | ///
179 | /// Conversion a given length value
180 | /// from feet to millimetre.
181 | ///
182 | static long ConvertFeetToMillimetres(double d)
183 | {
184 | if (0 < d)
185 | {
186 | return _eps > d
187 | ? 0
188 | : (long)(_feet_to_mm * d + 0.5);
189 | }
190 | else
191 | {
192 | return _eps > -d
193 | ? 0
194 | : (long)(_feet_to_mm * d - 0.5);
195 | }
196 | }
197 |
198 | public PointInt(XYZ p, bool switch_coordinates)
199 | {
200 | X = ConvertFeetToMillimetres(p.X);
201 | Y = ConvertFeetToMillimetres(p.Y);
202 | Z = ConvertFeetToMillimetres(p.Z);
203 |
204 | if (switch_coordinates)
205 | {
206 | X = -X;
207 | long tmp = Y;
208 | Y = Z;
209 | Z = tmp;
210 | }
211 | }
212 |
213 | public int CompareTo(PointInt a)
214 | {
215 | long d = X - a.X;
216 | if (0 == d)
217 | {
218 | d = Y - a.Y;
219 | if (0 == d)
220 | {
221 | d = Z - a.Z;
222 | }
223 | }
224 | return (0 == d) ? 0 : ((0 < d) ? 1 : -1);
225 | }
226 | }
227 |
228 | ///
229 | /// From Jeremy Tammik's RvtVa3c exporter:
230 | /// https://github.com/va3c/RvtVa3c
231 | /// A vertex lookup class to eliminate
232 | /// duplicate vertex definitions.
233 | ///
234 | class VertexLookupInt : Dictionary
235 | {
236 | ///
237 | /// Define equality for integer-based PointInt.
238 | ///
239 | class PointIntEqualityComparer : IEqualityComparer
240 | {
241 | public bool Equals(PointInt p, PointInt q)
242 | {
243 | return 0 == p.CompareTo(q);
244 | }
245 |
246 | public int GetHashCode(PointInt p)
247 | {
248 | return (p.X.ToString()
249 | + "," + p.Y.ToString()
250 | + "," + p.Z.ToString())
251 | .GetHashCode();
252 | }
253 | }
254 |
255 | public VertexLookupInt() : base(new PointIntEqualityComparer())
256 | {
257 | }
258 |
259 | ///
260 | /// Return the index of the given vertex,
261 | /// adding a new entry if required.
262 | ///
263 | public int AddVertex(PointInt p)
264 | {
265 | return ContainsKey(p)
266 | ? this[p]
267 | : this[p] = Count;
268 | }
269 | }
270 | }
271 |
--------------------------------------------------------------------------------
/Docume/binFilePrint.txt:
--------------------------------------------------------------------------------
1 | 16.66 0 37.02 16.66 0 2.72 16.66 9.19 2.72 16.66 9.19 37.02 16 0 37.02 16 9.19 37.02 16 9.19 2.72 16 0 2.72 16.66 0 2.72 16.66 0 37.02 16 0 37.02 16 0 2.72 16.66 9.19 2.72 16.66 0 2.72 16 0 2.72 16 9.19 2.72 16.66 9.19 37.02 16.66 9.19 2.72 16 9.19 2.72 16 9.19 37.02 16.66 0 37.02 16.66 9.19 37.02 16 9.19 37.02 16 0 37.02
2 | ***********vertexBuffer*******第1次*********
3 | 3 0 2 1 2 0 6 7 5 4 5 7 8 9 10 10 11 8 12 13 14 14 15 12 16 17 18 18 19 16 20 21 22 22 23 20
4 | *************indexBuffer********第1次*********
5 | 0 0 34.3 0 34.3 9.19 0 9.19 0 0 0 9.19 -34.3 9.19 -34.3 0 34.3 0.33 0 0.33 0 -0.33 34.3 -0.33 -0.33 9.19 -0.33 0 0.33 0 0.33 9.19 0 -0.33 34.3 -0.33 34.3 0.33 0 0.33 0.33 0 0.33 9.19 -0.33 9.19 -0.33 0
6 | **************uvBuffer*********第1次*********
7 |
--------------------------------------------------------------------------------
/Docume/丢失有纹理贴图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/Docume/丢失有纹理贴图.png
--------------------------------------------------------------------------------
/Docume/效果图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/Docume/效果图.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 喂鱼
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ObjectData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.ComponentModel;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace RevitExportGltf
10 | {
11 | class ObjectData : INotifyPropertyChanged
12 | {
13 |
14 | ///
15 | /// 子项
16 | ///
17 | private ObservableCollection _children = new ObservableCollection();
18 | public ObservableCollection Children
19 | {
20 | get { return _children; }
21 | set
22 | {
23 | _children = value;
24 | }
25 | }
26 |
27 | public ObjectData()
28 | {
29 | _children = new ObservableCollection();
30 | _isExpanded = false;
31 | _isChecked = true;
32 | _isEnabled = true;
33 | }
34 |
35 | public string ElementName { set; get; }
36 | public string ElementId { set; get; }
37 | public string SimilarObjectID { set; get; }
38 | public List ElementLocation { set; get; }
39 | public string ElementVertices { set; get; }
40 | public string ElementNormal { set; get; }
41 | public string ElementArea { set; get; }
42 | public string ElementVolum { set; get; }
43 | public string VertexIndices { set; get; }
44 |
45 |
46 |
47 |
48 |
49 | public string SimilarToJson()
50 | {
51 | string s = string.Format
52 | ("\n \"ElementLocation\":{0},"
53 | + "\n \"ElementNormal\":{1}",
54 | "\"" + ElementLocation + "\"",
55 | "\"" + ElementNormal + "\"");
56 | return "\n{" + s + "\n}" + ",";
57 | }
58 | public string CurrentToJson()
59 | {
60 | string s = string.Format
61 | ("\n \"ElementName\":{0},"
62 | + "\n \"ElementId\":{1},"
63 | + "\n \"ElementLocation\":{2},"
64 | + "\n \"ElementVertices\":{3},"
65 | + "\n \"VertexIndices\":{4},"
66 | + "\n \"ElementNormal\":{5},"
67 | + "\n \"ElementArea\":{6},"
68 | + "\n \"ElementVolum\":{7},"
69 | + "\n \"SimilarObject\":{8}",
70 | "\"" + ElementName + "\"",
71 | "\"" + ElementId + "\"",
72 | "\"" + ElementLocation + "\"",
73 | "\"" + ElementVertices + "\"",
74 | "\"" + VertexIndices + "\"",
75 | "\"" + ElementNormal + "\"",
76 | "\"" + ElementArea + "\"",
77 | "\"" + ElementVolum + "\"",
78 | SimilarEleJson());
79 | return "\n{" + s + "\n}" + ",";
80 | }
81 | public string SimilarEleJson()
82 | {
83 | string s = null;
84 | foreach (ObjectData child in Children)
85 | {
86 | s += child.SimilarToJson();
87 | }
88 | return "[" + s + "\n]";
89 | }
90 |
91 | public string ToJson()
92 | {
93 | //string s = string.Format
94 | // ("\n \"Name\":{0},"
95 | // + "\n \"Children\":{1}",
96 | // "\"" + ElementName + "\"",
97 | // ChildrenToJson2());
98 | //return "\n{" + s + "\n}"+",";
99 |
100 | string s = null;
101 | s += CurrentToJson();
102 | return s;
103 | }
104 |
105 |
106 |
107 |
108 |
109 | ///
110 | /// 选中状态
111 | ///
112 | public bool _isChecked;
113 | public bool IsChecked
114 | {
115 | get
116 | {
117 | return _isChecked;
118 | }
119 | set
120 | {
121 | if (value != _isChecked)
122 | {
123 | _isChecked = value;
124 | NotifyPropertyChanged("IsChecked");
125 | if (_isChecked)
126 | {
127 | foreach (ObjectData child in Children)
128 | {
129 | child.IsEnabled = true;
130 | }
131 | }
132 | else
133 | {
134 | foreach (ObjectData child in Children)
135 | {
136 | child.IsEnabled = false;
137 | }
138 | }
139 | }
140 | }
141 | }
142 |
143 | ///
144 | /// 可见行
145 | ///
146 | private bool _isEnabled;
147 | public bool IsEnabled
148 | {
149 | get { return _isEnabled; }
150 | set
151 | {
152 | if (value != _isEnabled)
153 | {
154 | _isEnabled = value;
155 | NotifyPropertyChanged("IsEnabled");
156 | if (_isEnabled)
157 | {
158 | foreach (ObjectData child in Children)
159 | {
160 | child.IsEnabled = true;
161 | }
162 | }
163 | else
164 | {
165 | foreach (ObjectData child in Children)
166 | {
167 | child.IsEnabled = false;
168 | }
169 | }
170 |
171 |
172 | }
173 | }
174 | }
175 | ///
176 | /// 折叠状态
177 | ///
178 | private bool _isExpanded;
179 | public bool IsExpanded
180 | {
181 | get { return _isExpanded; }
182 | set
183 | {
184 | if (value != _isExpanded)
185 | {
186 | //折叠状态改变
187 | _isExpanded = value;
188 | NotifyPropertyChanged("IsExpanded");
189 | }
190 | }
191 | }
192 |
193 | ///
194 | /// 设置所有子项的选中状态
195 | ///
196 | ///
197 | public void SetChildrenChecked(bool isChecked)
198 | {
199 | foreach (ObjectData child in Children)
200 | {
201 | child.IsChecked = IsChecked;
202 | child.SetChildrenChecked(IsChecked);
203 | }
204 | }
205 |
206 | ///
207 | /// 设置所有子项展开状态
208 | ///
209 | ///
210 | public void SetChildrenExpanded(bool isExpanded)
211 | {
212 | foreach (ObjectData child in Children)
213 | {
214 | child.IsExpanded = isExpanded;
215 | child.SetChildrenExpanded(isExpanded);
216 | }
217 | }
218 |
219 | ///
220 | /// 属性改变事件
221 | ///
222 | public event PropertyChangedEventHandler PropertyChanged;
223 | private void NotifyPropertyChanged(String info)
224 | {
225 | if (PropertyChanged != null)
226 | {
227 | PropertyChanged(this, new PropertyChangedEventArgs(info));
228 | }
229 | }
230 | }
231 | }
232 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // 有关程序集的一般信息由以下
8 | // 控制。更改这些特性值可修改
9 | // 与程序集关联的信息。
10 | [assembly: AssemblyTitle("RevitExportGltf")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("RevitExportGltf")]
15 | [assembly: AssemblyCopyright("Copyright © 2020")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // 将 ComVisible 设置为 false 会使此程序集中的类型
20 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
21 | //请将此类型的 ComVisible 特性设置为 true。
22 | [assembly: ComVisible(false)]
23 |
24 | //若要开始生成可本地化的应用程序,请设置
25 | //.csproj 文件中的 CultureYouAreCodingWith
26 | //例如,如果您在源文件中使用的是美国英语,
27 | //使用的是美国英语,请将 设置为 en-US。 然后取消
28 | //对以下 NeutralResourceLanguage 特性的注释。 更新
29 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置
36 | //(未在页面中找到资源时使用,
37 | //或应用程序资源字典中找到时使用)
38 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
39 | //(未在页面中找到资源时使用,
40 | //、应用程序或任何主题专用资源字典中找到时使用)
41 | )]
42 |
43 |
44 | // 程序集的版本信息由下列四个值组成:
45 | //
46 | // 主版本
47 | // 次版本
48 | // 生成号
49 | // 修订号
50 | //
51 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
52 | //通过使用 "*",如下所示:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本: 4.0.30319.42000
5 | //
6 | // 对此文件的更改可能导致不正确的行为,如果
7 | // 重新生成代码,则所做更改将丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevitExportGltf.Properties
12 | {
13 |
14 |
15 | ///
16 | /// 强类型资源类,用于查找本地化字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// 返回此类使用的缓存 ResourceManager 实例。
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevitExportGltf.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// 覆盖当前线程的 CurrentUICulture 属性
56 | /// 使用此强类型的资源类的资源查找。
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevitExportGltf.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RevitExportGltf
2 | 主要是Revit的二次开发的插件,其中主要是基于Revit2018进行的,实现从Revit中把建筑模型导出来,使用的是GLTF格式的编码。(这个是好用的至少是至今发现上最好用最实用,也是参考然后大改过的 比如解决了Node、纹理丢失、压缩等等问题的项目)
3 |
4 | 运行操作:
5 | 直接双击运行插件,然后选择需要导出的格式与路径,导出格式包括gltf 与glb二进制这些;
6 |
7 | 运行成功还有返回的信息,导出的格式以及文件等等;
8 |
9 |
10 |
11 | 主要使用了RevitAPI.dll 与RevitAPIUI.dll 来Revit的二次开发,其中 : //add-in manger 只读模式
12 |
13 | 使用了SharpGLTF库,SharpGLTF是一个100%.NET标准库,旨在支持Khronos Group glTF 2.0文件格式。 所以使用SharpGLTF生成gltf、glb数据; 该库分为两个主要软件包: SharpGLTF.Core提供读/写文件支持,以及对glTF模型的低级别访问。 SharpGLTF.Toolkit提供了方便的实用程序来帮助创建,操纵和评估glTF模型。
14 |
15 | simple example gltf保存为glb格式: var model = SharpGLTF.Schema2.ModelRoot.Load("model.gltf"); model.SaveGLB("model.glb");
16 |
17 | IExportContext接口在数据导出中,执行如下的顺序: 将revit的数据解析为我们自己的数据需要继承重写IExportContext就能revit文件进行数据导出和数据转换; * 接口在数据导出中,无链接模型执行如下的顺序: * Start -> OnViewBegin -> onElementBegin -> OnInstanceBegin ->OnMaterial ->OnLight * ->OnFaceBegin OnPolymesh -> OnFaceEnd -> OnInstanceEnd-> OnElementEnd
18 | \* ->OnViewEnd ->IsCanceled ->Finish、 * 假如有链接模型在执行完非链接的OnElementBegin以后,执行OnLinkBegin,然后执行链接模型里的OnElementBegin……依次类推
19 |
20 | 依赖环境:Autodesk.RevitAPi Autodesk.Revit.UI 安装nodejs 使用工具:使用npm 安装gltf-pipeline配置系统环境
21 |
22 | 参考资料:
23 |
24 | gltf (作者本人的博客) 介绍https://blog.csdn.net/chenweiyu11962/article/details/110949110
25 |
26 | gltf格式 https://zhuanlan.zhihu.com/p/65265611
27 |
28 | 解决材质的问题 https://zhuanlan.zhihu.com/p/80465384
29 |
30 | revit 二开环境配置 https://static.app.yinxiang.com/embedded-web/profile/#/join?guid=1e6bb87f-5eb1-4654-aeb5-22c3cb67431c&channel=copylink&shardId=s61&ownerId=22360100
31 |
--------------------------------------------------------------------------------
/RevitExportGltf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {8A3DC89A-101F-4410-B1F1-3D209E1A28B1}
8 | Library
9 | RevitExportGltf
10 | RevitExportGltf
11 | v4.7.2
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 | true
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 |
41 |
42 | ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
43 |
44 |
45 | libs\Revit2018\RevitAPI.dll
46 |
47 |
48 | libs\Revit2018\RevitAPIUI.dll
49 |
50 |
51 | libs\SharpGLTF\SharpGLTF.Core.dll
52 |
53 |
54 | libs\SharpGLTF\SharpGLTF.Toolkit.dll
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | 4.0
67 |
68 |
69 | libs\Revit2018\UIFrameworkServices.dll
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | MSBuild:Compile
82 | Designer
83 |
84 |
85 | App.xaml
86 | Code
87 |
88 |
89 |
90 |
91 | MainWindow.xaml
92 | Code
93 |
94 |
95 |
96 |
97 | Code
98 |
99 |
100 | True
101 | True
102 | Resources.resx
103 |
104 |
105 | True
106 | Settings.settings
107 | True
108 |
109 |
110 | ResXFileCodeGenerator
111 | Resources.Designer.cs
112 |
113 |
114 |
115 |
116 |
117 |
118 | SettingsSingleFileGenerator
119 | Settings.Designer.cs
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/RevitExportGltf.md:
--------------------------------------------------------------------------------
1 | # RevitExportGltf
2 | 主要是Revit的二次开发的插件,其中主要是基于Revit2018进行的,实现从Revit中把建筑模型导出来,使用的是GLTF格式的编码。
3 |
4 | 运行操作:
5 | 直接双击运行插件,然后选择需要导出的格式与路径,导出格式包括gltf 与glb二进制这些;
6 |
7 |
8 |
9 |
10 |
11 | 运行成功如下图,还有返回的信息:
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 主要使用了RevitAPI.dll 与RevitAPIUI.dll 来Revit的二次开发,其中 : //add-in manger 只读模式
20 |
21 | 使用了SharpGLTF库,SharpGLTF是一个100%.NET标准库,旨在支持Khronos Group glTF 2.0文件格式。 所以使用SharpGLTF生成gltf、glb数据; 该库分为两个主要软件包: SharpGLTF.Core提供读/写文件支持,以及对glTF模型的低级别访问。 SharpGLTF.Toolkit提供了方便的实用程序来帮助创建,操纵和评估glTF模型。
22 |
23 | simple example gltf保存为glb格式: var model = SharpGLTF.Schema2.ModelRoot.Load("model.gltf"); model.SaveGLB("model.glb");
24 |
25 | IExportContext接口在数据导出中,执行如下的顺序: 将revit的数据解析为我们自己的数据需要继承重写IExportContext就能revit文件进行数据导出和数据转换; * 接口在数据导出中,无链接模型执行如下的顺序: * Start -> OnViewBegin -> onElementBegin -> OnInstanceBegin ->OnMaterial ->OnLight * ->OnFaceBegin OnPolymesh -> OnFaceEnd -> OnInstanceEnd-> OnElementEnd
26 | \* ->OnViewEnd ->IsCanceled ->Finish、 * 假如有链接模型在执行完非链接的OnElementBegin以后,执行OnLinkBegin,然后执行链接模型里的OnElementBegin……依次类推
27 |
28 | 依赖环境:Autodesk.RevitAPi Autodesk.Revit.UI 安装nodejs 使用工具:使用npm 安装gltf-pipeline配置系统环境
29 |
30 | 参考资料:
31 |
32 | gltf (作者本人的博客) 介绍https://blog.csdn.net/chenweiyu11962/article/details/110949110
33 |
34 | gltf格式 https://zhuanlan.zhihu.com/p/65265611
35 |
36 | 解决材质的问题 https://zhuanlan.zhihu.com/p/80465384
--------------------------------------------------------------------------------
/RevitExportGltf.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30309.148
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RevitExportGltf", "RevitExportGltf\RevitExportGltf.csproj", "{8A3DC89A-101F-4410-B1F1-3D209E1A28B1}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {8A3DC89A-101F-4410-B1F1-3D209E1A28B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {8A3DC89A-101F-4410-B1F1-3D209E1A28B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {8A3DC89A-101F-4410-B1F1-3D209E1A28B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {8A3DC89A-101F-4410-B1F1-3D209E1A28B1}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {6AC9E9B5-FF67-4BB3-BF5D-D29664EAC0CD}
24 | EndGlobalSection
25 | GlobalSection(SubversionScc) = preSolution
26 | Svn-Managed = True
27 | Manager = AnkhSVN2019 - Subversion Support for Visual Studio
28 | EndGlobalSection
29 | EndGlobal
30 |
--------------------------------------------------------------------------------
/RevitExportGltf/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/RevitExportGltf/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/RevitExportGltf/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace RevitExportGltf
4 | {
5 | ///
6 | /// App.xaml 的交互逻辑
7 | ///
8 | public partial class App : Application
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/RevitExportGltf/Command.cs:
--------------------------------------------------------------------------------
1 | /**************************************************************************
2 | Copyright:MyCompany
3 |
4 | Author: chenwy
5 |
6 | Date:2020-7-31
7 |
8 | Description:Provide Revit export 3D file in gltf format
9 |
10 | HistoryRecord:
11 | **************************************************************************/
12 |
13 | using Autodesk.Revit.Attributes;
14 | using Autodesk.Revit.DB;
15 | using Autodesk.Revit.UI;
16 | using System.IO;
17 | using System.Windows.Forms;
18 |
19 | namespace RevitExportGltf
20 | {
21 | [Transaction(TransactionMode.Manual)]
22 | class Command : IExternalCommand
23 | {
24 |
25 | public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
26 | {
27 | //以导出当前视图
28 | UIApplication uiapp = commandData.Application;
29 | UIDocument uidoc = uiapp.ActiveUIDocument;
30 | Autodesk.Revit.ApplicationServices.Application app = uiapp.Application;
31 | Document doc = uidoc.Document;
32 |
33 | //没打开文档
34 | if (null == doc)
35 | {
36 | message = "Please open the project.";
37 | return Result.Failed;
38 | }
39 |
40 | //没有打开文档
41 | if (null == uidoc)
42 | {
43 | message = "Please run this command in an active project document.";
44 | return Result.Failed;
45 | }
46 |
47 | //3D视图下
48 | View3D view = doc.ActiveView as View3D;
49 | if (null == view)
50 | {
51 | message = "Please run this command in a 3D view.";
52 | return Result.Failed;
53 | }
54 |
55 | //保存导出的文件 包括过滤器gltf与glb格式
56 | System.Windows.Forms.SaveFileDialog sdial = new System.Windows.Forms.SaveFileDialog();
57 | sdial.Filter = "gltf|*.gltf|glb|*.glb";
58 | if (sdial.ShowDialog() == DialogResult.OK)
59 | {
60 | string filename = sdial.FileName;
61 | string directory = Path.GetDirectoryName(filename) + "\\"; ;
62 | //默认值减面为等级8
63 | int combobox_value = 8;
64 | //拿到revit的doc CustomExporter 用户自定义导出
65 | RevitExportGltfContext context = new RevitExportGltfContext(doc, sdial.FileName, combobox_value);
66 | using (CustomExporter exporter = new CustomExporter(doc, context))
67 | {
68 | //是否包括Geom对象
69 | exporter.IncludeGeometricObjects = false;
70 | exporter.ShouldStopOnError = true;
71 | //导出3D模型
72 | exporter.Export(view);
73 | }
74 |
75 | System.Diagnostics.Process p = new System.Diagnostics.Process();
76 | p.StartInfo.FileName = "cmd.exe";
77 | p.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
78 | p.StartInfo.RedirectStandardInput = true; //接受来自调用程序的输入信息
79 | p.StartInfo.RedirectStandardOutput = true; //由调用程序获取输出信息
80 | p.StartInfo.RedirectStandardError = true; //重定向标准错误输出
81 | p.StartInfo.CreateNoWindow = true;//不显示程序窗口
82 | p.Start();//启动程序
83 | //使用gltf pipeline命令行工具
84 | //向cmd窗口发送输入信息 (node.js已经是配置好了系统环境变量)
85 | //string str = @"cd D:\cmder";
86 | //p.StandardInput.WriteLine(str);
87 |
88 | //将GLTF转换为glb二进制 压缩纹理与bin顶点
89 | string glbName = Path.GetFileNameWithoutExtension(sdial.FileName) + "(Draco)" + ".glb";
90 | string glbstr = string.Format("gltf-pipeline.cmd gltf-pipeline -i {0} -o {1}", sdial.FileName, Path.GetDirectoryName(sdial.FileName) + "\\" + glbName);
91 | p.StandardInput.WriteLine(glbstr);
92 |
93 |
94 | //gltf-pipeline.c md gltf-pipeline -i model.gltf -o modelDraco.gltf -d
95 | //运用Draco算法将GLTF压缩 压缩纹理与bin顶点是json文件
96 | string gltfDracoName = Path.GetFileNameWithoutExtension(sdial.FileName) + "(Draco)" + ".gltf";
97 | string gltfDraco = string.Format("gltf-pipeline.cmd gltf-pipeline -i {0} -o {1} -d", sdial.FileName, Path.GetDirectoryName(sdial.FileName) + "\\" + gltfDracoName);
98 | p.StandardInput.WriteLine(gltfDraco);
99 |
100 | //gltf - pipeline - i model.gltf - t
101 | //压缩bin二进制为base64编码,但是保留纹理
102 | string gltfTextureName = Path.GetFileNameWithoutExtension(sdial.FileName) + "(Texture)" + ".gltf";
103 | string gltfTexture = string.Format("gltf-pipeline.cmd gltf-pipeline -i {0} -o {1} -t", sdial.FileName, Path.GetDirectoryName(sdial.FileName) + "\\" + gltfTextureName);
104 | p.StandardInput.WriteLine(gltfTexture);
105 |
106 | p.StandardInput.AutoFlush = true;
107 | p.StandardInput.WriteLine("exit");
108 |
109 | //获取cmd窗口的输出信息
110 | string output = p.StandardOutput.ReadToEnd();
111 | System.Windows.MessageBox.Show(output);
112 | }
113 | return Result.Succeeded;
114 | }
115 |
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/RevitExportGltf/Containers.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace RevitExportGltf
6 | {
7 |
8 |
9 | ///
10 | /// Container for holding a strict set of items
11 | /// that is also addressable by a unique ID.
12 | ///
13 | /// The type of item contained.
14 | class IndexedDictionary
15 | {
16 | private Dictionary _dict = new Dictionary();
17 | public List List { get; } = new List();
18 | public string CurrentKey { get; private set; }
19 | public Dictionary Dict
20 | {
21 | get
22 | {
23 | var output = new Dictionary();
24 | foreach (var kvp in _dict)
25 | {
26 | output.Add(kvp.Key, List[kvp.Value]);
27 | }
28 | return output;
29 | }
30 | }
31 |
32 | ///
33 | /// The most recently accessed item (not effected by GetElement()).
34 | ///
35 | public T CurrentItem
36 | {
37 | get { return List[_dict[CurrentKey]]; }
38 | }
39 |
40 | ///
41 | /// The index of the most recently accessed item (not effected by GetElement()).
42 | ///
43 | public int CurrentIndex
44 | {
45 | get { return _dict[CurrentKey]; }
46 | }
47 |
48 | ///
49 | /// Add a new item to the list, if it already exists then the
50 | /// current item will be set to this item.
51 | ///
52 | /// Unique identifier for the item.
53 | /// The item to add.
54 | /// true if item did not already exist.
55 | public bool AddOrUpdateCurrent(string uuid, T elem)
56 | {
57 | if (!_dict.ContainsKey(uuid))
58 | {
59 | List.Add(elem);
60 | _dict.Add(uuid, (List.Count - 1));
61 | CurrentKey = uuid;
62 | return true;
63 | }
64 |
65 | CurrentKey = uuid;
66 | return false;
67 | }
68 |
69 | ///
70 | /// Check if the container already has an item with this key.
71 | ///
72 | /// Unique identifier for the item.
73 | ///
74 | public bool Contains(string uuid)
75 | {
76 | return _dict.ContainsKey(uuid);
77 | }
78 |
79 | ///
80 | /// Returns the index for an item given it's unique identifier.
81 | ///
82 | /// Unique identifier for the item.
83 | /// index of item or -1
84 | public int GetIndexFromUUID(string uuid)
85 | {
86 | if (!Contains(uuid)) throw new Exception("Specified item could not be found.");
87 | return _dict[uuid];
88 | }
89 |
90 | ///
91 | /// Returns an item given it's unique identifier.
92 | ///
93 | /// Unique identifier for the item
94 | /// the item
95 | public T GetElement(string uuid)
96 | {
97 | int index = GetIndexFromUUID(uuid);
98 | return List[index];
99 | }
100 |
101 | ///
102 | /// Returns as item given it's index location.
103 | ///
104 | /// The item's index location.
105 | /// the item
106 | public T GetElement(int index)
107 | {
108 | if (index < 0 || index > List.Count - 1) throw new Exception("Specified item could not be found.");
109 | return List[index];
110 | }
111 | }
112 |
113 | ///
114 | /// From Jeremy Tammik's RvtVa3c exporter:
115 | /// https://github.com/va3c/RvtVa3c
116 | /// A vertex lookup class to eliminate
117 | /// duplicate vertex definitions.
118 | ///
119 | class VertexLookupXyz : Dictionary
120 | {
121 | ///
122 | /// Define equality for Revit XYZ points.
123 | /// Very rough tolerance, as used by Revit itself.
124 | ///
125 | class XyzEqualityComparer : IEqualityComparer
126 | {
127 | const double _sixteenthInchInFeet = 1.0 / (16.0 * 12.0);
128 |
129 | public bool Equals(XYZ p, XYZ q)
130 | {
131 | return p.IsAlmostEqualTo(q, _sixteenthInchInFeet);
132 | }
133 |
134 | public int GetHashCode(XYZ p)
135 | {
136 | return Util.PointString(p).GetHashCode();
137 | }
138 | }
139 |
140 | public VertexLookupXyz() : base(new XyzEqualityComparer())
141 | {
142 | }
143 |
144 | ///
145 | /// Return the index of the given vertex,
146 | /// adding a new entry if required.
147 | ///
148 | public int AddVertex(XYZ p)
149 | {
150 | return ContainsKey(p)
151 | ? this[p]
152 | : this[p] = Count;
153 | }
154 | }
155 |
156 | ///
157 | /// From Jeremy Tammik's RvtVa3c exporter:
158 | /// https://github.com/va3c/RvtVa3c
159 | /// An integer-based 3D point class.
160 | ///
161 | class PointInt : IComparable
162 | {
163 | public long X { get; set; }
164 | public long Y { get; set; }
165 | public long Z { get; set; }
166 |
167 | ///
168 | /// Consider a Revit length zero
169 | /// if is smaller than this.
170 | ///
171 | const double _eps = 1.0e-9;
172 |
173 | ///
174 | /// Conversion factor from feet to millimetres.
175 | ///
176 | const double _feet_to_mm = 25.4 * 12;
177 |
178 | ///
179 | /// Conversion a given length value
180 | /// from feet to millimetre.
181 | ///
182 | static long ConvertFeetToMillimetres(double d)
183 | {
184 | if (0 < d)
185 | {
186 | return _eps > d
187 | ? 0
188 | : (long)(_feet_to_mm * d + 0.5);
189 | }
190 | else
191 | {
192 | return _eps > -d
193 | ? 0
194 | : (long)(_feet_to_mm * d - 0.5);
195 | }
196 | }
197 |
198 | public PointInt(XYZ p, bool switch_coordinates)
199 | {
200 | X = ConvertFeetToMillimetres(p.X);
201 | Y = ConvertFeetToMillimetres(p.Y);
202 | Z = ConvertFeetToMillimetres(p.Z);
203 |
204 | if (switch_coordinates)
205 | {
206 | X = -X;
207 | long tmp = Y;
208 | Y = Z;
209 | Z = tmp;
210 | }
211 | }
212 |
213 | public int CompareTo(PointInt a)
214 | {
215 | long d = X - a.X;
216 | if (0 == d)
217 | {
218 | d = Y - a.Y;
219 | if (0 == d)
220 | {
221 | d = Z - a.Z;
222 | }
223 | }
224 | return (0 == d) ? 0 : ((0 < d) ? 1 : -1);
225 | }
226 | }
227 |
228 | ///
229 | /// From Jeremy Tammik's RvtVa3c exporter:
230 | /// https://github.com/va3c/RvtVa3c
231 | /// A vertex lookup class to eliminate
232 | /// duplicate vertex definitions.
233 | ///
234 | class VertexLookupInt : Dictionary
235 | {
236 | ///
237 | /// Define equality for integer-based PointInt.
238 | ///
239 | class PointIntEqualityComparer : IEqualityComparer
240 | {
241 | public bool Equals(PointInt p, PointInt q)
242 | {
243 | return 0 == p.CompareTo(q);
244 | }
245 |
246 | public int GetHashCode(PointInt p)
247 | {
248 | return (p.X.ToString()
249 | + "," + p.Y.ToString()
250 | + "," + p.Z.ToString())
251 | .GetHashCode();
252 | }
253 | }
254 |
255 | public VertexLookupInt() : base(new PointIntEqualityComparer())
256 | {
257 | }
258 |
259 | ///
260 | /// Return the index of the given vertex,
261 | /// adding a new entry if required.
262 | ///
263 | public int AddVertex(PointInt p)
264 | {
265 | return ContainsKey(p)
266 | ? this[p]
267 | : this[p] = Count;
268 | }
269 | }
270 | }
271 |
--------------------------------------------------------------------------------
/RevitExportGltf/Docume/Revit导出gltf工具说明文档.md:
--------------------------------------------------------------------------------
1 | # Revit导出gltf工具说明文档
2 |
3 | ### 1.性能优化-使用压缩工具
4 |
5 | 推荐使用gltf或者glb来加载模型。如果有大量外部模型,一定要结合使用gltf-pipeline与Draco。
6 | 这很重要,有时候我们获得的gltf模型文件后,我们可以轻易的压缩图片;但有些scene.bin文件可以达到100M或200M以上,模型多了之后会很大程度影响使用体验。
7 | 结合使用gltf-pipeline与Draco,可以有效的压缩文件甚至在10M以下!
8 |
9 | 原因:为什么需要压缩gltf,原始的gltf格式包含三部分”gltf格式文件“、”bin二进制几何数据“、”纹理贴图“;3D模型的顶点压缩文件会体积减少但是GPU压力变大!纹理贴图压缩会导致体积变大 但是更方便传输等等。
10 |
11 | ##### Draco简介
12 |
13 | Draco 由谷歌 Chrome 媒体团队设计,旨在大幅加速 3D 数据的编码、传输和解码。因为研发团队的 Chrome 背景,这个开源算法的首要应用对象是浏览器。但既然谷歌把它开源,现在全世界的开发者可以去探索 Draco 在其他场景的应用,比如说非网页端。目前,谷歌提供了它的两个版本: JavaScript 和 C++。
14 |
15 | Draco 可以被用来压缩 mesh 和点云数据。它还支持压缩点( compressing points),连接信息,纹理协调,颜色信息,法线( normals)以及其他与几何相关的通用属性。谷歌官方发布的 Draco Mesh 文件压缩率,它大幅优于 ZIP。
16 |
17 | 谷歌宣称,若使用 Draco,含 3D 图像的应用,其文件大小能大幅缩小,并不在视觉保真度上做妥协。对于用户来说,这意味着 app/PC桌面应用 下载会更快,浏览器的 3D 图像载入得更快,VR 和 AR 画面的传输只需要占用原先一小部分的带宽、渲染得更快并且看起来画质清晰。
18 |
19 | 同时Cesium1.44开始支持解析draco压缩算法的gltf/glb模型,将模型使用具有draco算法的工具进行压缩,例如blender等,Cesium加载模型时,进行模型的解析。
20 | 对比使用draco算法压缩的模型,模型的数据量变小了相当多,这样会提高网络上的传输速度。在3D Tiles的大批量模型中,使用这一算法进行提前压缩,可以大大的减少网络传输的数据量。
21 | [Draco压缩gltf与3Dtiles的Mesh](https://cesium.com/blog/2018/04/09/draco-compression/)
22 |
23 | ### 2.压缩工具的安装
24 |
25 | 这里使用的是gltf-pipeline开源压缩工具,这个现阶段使用很多也是非常的成熟的工具;由于gltf-pipeline是依赖于node.js的环境所以需要先安装node.js。
26 |
27 | ##### 1.安装node.js
28 |
29 | [下载地址](https://nodejs.org/zh-cn/#home-downloadhead)
30 | [安装教程](https://www.runoob.com/nodejs/nodejs-install-setup.html)
31 |
32 | *特别说明npm工具已经在node.js 的windows中继承了不需要安装*
33 |
34 | ---
35 |
36 | ##### 2.安装gltf-pipeline压缩工具
37 |
38 | ```shell
39 | npm install -g gltf-pipeline
40 | ```
41 | 然后配置为系统环境就是要在CMD命令下能运行以下的命令:
42 | Converting a glTF to glb
43 |
44 | ```shell
45 | gltf-pipeline -i model.gltf -o model.glb
46 | gltf-pipeline -i model.gltf -b
47 | ```
48 |
49 | Converting a glTF to Draco glTF
50 | ```shell
51 | gltf-pipeline -i model.gltf -o modelDraco.gltf -d
52 | ```
53 | ---
54 |
55 | Saving separate textures
56 | ```shell
57 | gltf-pipeline -i model.gltf -o modelTexture.gltf -t
58 | ```
59 |
60 | ##### 3.Revit导出Gltf
61 | 先打开Revit->打开某个项目->切换为3D视图->附加模块->外部工具->点击add-in manager ->选择对应的loaded command ->双击运行或者点击底下“Run”按钮
62 |
63 | ### 4.导出模型生成的文件
64 |
65 | 如果运行成功会在选定的目录下生成如下的文件,其中各个文件的作用如下:
66 |
67 | 生成的gltf格式文件:
68 | | 文件名称 | 文件类型 | 说明 |
69 | | :---- | :---- | :---- | :---- | :---- |
70 | | model | gltf | 这是标准的gltf文件通过images 与buffers分别的uri来获取同层目录 下的bin与带纹理贴图的材质|
71 | | bin | binary file | 主要是gltf中保存的几何数据包括顶点、顶点索引、uv坐标、法向量坐标等等 |
72 | | model(材质贴图) | png | 主要是gltf中需要链接到的带有纹理贴图的材质 |
73 | | model(Texture) | gltf |原model.gltf文件把.bin文件进行顶点的压缩进gltf中去但是保留了带有纹理贴图的材质注意如果模型没有纹理贴图的就没有该文件夹 |
74 | | model(Draco) | gltf |原model.gltf文件把.bin文件进行顶点的压缩进gltf中同时也对纹理进行压缩进gltf并且使用base64编码表示 ,特别注意gltf它本身是json文件|
75 | | model(Draco) | glb |与model(Draco).gltf相似但是 glb不再是json而是binary file保存|
76 |
77 | ### 5.如何打开gltf格式的3D模型
78 |
79 | - 可以使用VScode打开,只需要安装vscode 的**gltf tools**插件就可以;
80 | - 同时也可以安装官方推荐查看器[gltf-view](https://github.com/donmccurdy/three-gltf-viewer/releases/tag/v1.5.1)
--------------------------------------------------------------------------------
/RevitExportGltf/Docume/binFilePrint.txt:
--------------------------------------------------------------------------------
1 | 16.66 0 37.02 16.66 0 2.72 16.66 9.19 2.72 16.66 9.19 37.02 16 0 37.02 16 9.19 37.02 16 9.19 2.72 16 0 2.72 16.66 0 2.72 16.66 0 37.02 16 0 37.02 16 0 2.72 16.66 9.19 2.72 16.66 0 2.72 16 0 2.72 16 9.19 2.72 16.66 9.19 37.02 16.66 9.19 2.72 16 9.19 2.72 16 9.19 37.02 16.66 0 37.02 16.66 9.19 37.02 16 9.19 37.02 16 0 37.02
2 | ***********vertexBuffer*******第1次*********
3 | 3 0 2 1 2 0 6 7 5 4 5 7 8 9 10 10 11 8 12 13 14 14 15 12 16 17 18 18 19 16 20 21 22 22 23 20
4 | *************indexBuffer********第1次*********
5 | 0 0 34.3 0 34.3 9.19 0 9.19 0 0 0 9.19 -34.3 9.19 -34.3 0 34.3 0.33 0 0.33 0 -0.33 34.3 -0.33 -0.33 9.19 -0.33 0 0.33 0 0.33 9.19 0 -0.33 34.3 -0.33 34.3 0.33 0 0.33 0.33 0 0.33 9.19 -0.33 9.19 -0.33 0
6 | **************uvBuffer*********第1次*********
7 |
--------------------------------------------------------------------------------
/RevitExportGltf/Docume/丢失有纹理贴图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/RevitExportGltf/Docume/丢失有纹理贴图.png
--------------------------------------------------------------------------------
/RevitExportGltf/Docume/效果图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/RevitExportGltf/Docume/效果图.png
--------------------------------------------------------------------------------
/RevitExportGltf/ObjectData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.ComponentModel;
5 |
6 | namespace RevitExportGltf
7 | {
8 | class ObjectData : INotifyPropertyChanged
9 | {
10 |
11 | ///
12 | /// 子项
13 | ///
14 | private ObservableCollection _children = new ObservableCollection();
15 | public ObservableCollection Children
16 | {
17 | get { return _children; }
18 | set
19 | {
20 | _children = value;
21 | }
22 | }
23 |
24 | public ObjectData()
25 | {
26 | _children = new ObservableCollection();
27 | _isExpanded = false;
28 | _isChecked = true;
29 | _isEnabled = true;
30 | }
31 |
32 | public string ElementName { set; get; }
33 | public string ElementId { set; get; }
34 | public string SimilarObjectID { set; get; }
35 | public List ElementLocation { set; get; }
36 | public string ElementVertices { set; get; }
37 | public string ElementNormal { set; get; }
38 | public string ElementArea { set; get; }
39 | public string ElementVolum { set; get; }
40 | public string VertexIndices { set; get; }
41 |
42 |
43 |
44 |
45 |
46 | public string SimilarToJson()
47 | {
48 | string s = string.Format
49 | ("\n \"ElementLocation\":{0},"
50 | + "\n \"ElementNormal\":{1}",
51 | "\"" + ElementLocation + "\"",
52 | "\"" + ElementNormal + "\"");
53 | return "\n{" + s + "\n}" + ",";
54 | }
55 | public string CurrentToJson()
56 | {
57 | string s = string.Format
58 | ("\n \"ElementName\":{0},"
59 | + "\n \"ElementId\":{1},"
60 | + "\n \"ElementLocation\":{2},"
61 | + "\n \"ElementVertices\":{3},"
62 | + "\n \"VertexIndices\":{4},"
63 | + "\n \"ElementNormal\":{5},"
64 | + "\n \"ElementArea\":{6},"
65 | + "\n \"ElementVolum\":{7},"
66 | + "\n \"SimilarObject\":{8}",
67 | "\"" + ElementName + "\"",
68 | "\"" + ElementId + "\"",
69 | "\"" + ElementLocation + "\"",
70 | "\"" + ElementVertices + "\"",
71 | "\"" + VertexIndices + "\"",
72 | "\"" + ElementNormal + "\"",
73 | "\"" + ElementArea + "\"",
74 | "\"" + ElementVolum + "\"",
75 | SimilarEleJson());
76 | return "\n{" + s + "\n}" + ",";
77 | }
78 | public string SimilarEleJson()
79 | {
80 | string s = null;
81 | foreach (ObjectData child in Children)
82 | {
83 | s += child.SimilarToJson();
84 | }
85 | return "[" + s + "\n]";
86 | }
87 |
88 | public string ToJson()
89 | {
90 | //string s = string.Format
91 | // ("\n \"Name\":{0},"
92 | // + "\n \"Children\":{1}",
93 | // "\"" + ElementName + "\"",
94 | // ChildrenToJson2());
95 | //return "\n{" + s + "\n}"+",";
96 |
97 | string s = null;
98 | s += CurrentToJson();
99 | return s;
100 | }
101 |
102 |
103 |
104 |
105 |
106 | ///
107 | /// 选中状态
108 | ///
109 | public bool _isChecked;
110 | public bool IsChecked
111 | {
112 | get
113 | {
114 | return _isChecked;
115 | }
116 | set
117 | {
118 | if (value != _isChecked)
119 | {
120 | _isChecked = value;
121 | NotifyPropertyChanged("IsChecked");
122 | if (_isChecked)
123 | {
124 | foreach (ObjectData child in Children)
125 | {
126 | child.IsEnabled = true;
127 | }
128 | }
129 | else
130 | {
131 | foreach (ObjectData child in Children)
132 | {
133 | child.IsEnabled = false;
134 | }
135 | }
136 | }
137 | }
138 | }
139 |
140 | ///
141 | /// 可见行
142 | ///
143 | private bool _isEnabled;
144 | public bool IsEnabled
145 | {
146 | get { return _isEnabled; }
147 | set
148 | {
149 | if (value != _isEnabled)
150 | {
151 | _isEnabled = value;
152 | NotifyPropertyChanged("IsEnabled");
153 | if (_isEnabled)
154 | {
155 | foreach (ObjectData child in Children)
156 | {
157 | child.IsEnabled = true;
158 | }
159 | }
160 | else
161 | {
162 | foreach (ObjectData child in Children)
163 | {
164 | child.IsEnabled = false;
165 | }
166 | }
167 |
168 |
169 | }
170 | }
171 | }
172 | ///
173 | /// 折叠状态
174 | ///
175 | private bool _isExpanded;
176 | public bool IsExpanded
177 | {
178 | get { return _isExpanded; }
179 | set
180 | {
181 | if (value != _isExpanded)
182 | {
183 | //折叠状态改变
184 | _isExpanded = value;
185 | NotifyPropertyChanged("IsExpanded");
186 | }
187 | }
188 | }
189 |
190 | ///
191 | /// 设置所有子项的选中状态
192 | ///
193 | ///
194 | public void SetChildrenChecked(bool isChecked)
195 | {
196 | foreach (ObjectData child in Children)
197 | {
198 | child.IsChecked = IsChecked;
199 | child.SetChildrenChecked(IsChecked);
200 | }
201 | }
202 |
203 | ///
204 | /// 设置所有子项展开状态
205 | ///
206 | ///
207 | public void SetChildrenExpanded(bool isExpanded)
208 | {
209 | foreach (ObjectData child in Children)
210 | {
211 | child.IsExpanded = isExpanded;
212 | child.SetChildrenExpanded(isExpanded);
213 | }
214 | }
215 |
216 | ///
217 | /// 属性改变事件
218 | ///
219 | public event PropertyChangedEventHandler PropertyChanged;
220 | private void NotifyPropertyChanged(String info)
221 | {
222 | if (PropertyChanged != null)
223 | {
224 | PropertyChanged(this, new PropertyChangedEventArgs(info));
225 | }
226 | }
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/RevitExportGltf/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 | using System.Windows;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("RevitExportGltf")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RevitExportGltf")]
13 | [assembly: AssemblyCopyright("Copyright © 2020")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | //若要开始生成可本地化的应用程序,请设置
23 | //.csproj 文件中的 CultureYouAreCodingWith
24 | //例如,如果您在源文件中使用的是美国英语,
25 | //使用的是美国英语,请将 设置为 en-US。 然后取消
26 | //对以下 NeutralResourceLanguage 特性的注释。 更新
27 | //以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
28 |
29 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
30 |
31 |
32 | [assembly: ThemeInfo(
33 | ResourceDictionaryLocation.None, //主题特定资源词典所处位置
34 | //(未在页面中找到资源时使用,
35 | //或应用程序资源字典中找到时使用)
36 | ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
37 | //(未在页面中找到资源时使用,
38 | //、应用程序或任何主题专用资源字典中找到时使用)
39 | )]
40 |
41 |
42 | // 程序集的版本信息由下列四个值组成:
43 | //
44 | // 主版本
45 | // 次版本
46 | // 生成号
47 | // 修订号
48 | //
49 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
50 | //通过使用 "*",如下所示:
51 | // [assembly: AssemblyVersion("1.0.*")]
52 | [assembly: AssemblyVersion("1.0.0.0")]
53 | [assembly: AssemblyFileVersion("1.0.0.0")]
54 |
--------------------------------------------------------------------------------
/RevitExportGltf/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本: 4.0.30319.42000
5 | //
6 | // 对此文件的更改可能导致不正确的行为,如果
7 | // 重新生成代码,则所做更改将丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevitExportGltf.Properties
12 | {
13 |
14 |
15 | ///
16 | /// 强类型资源类,用于查找本地化字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// 返回此类使用的缓存 ResourceManager 实例。
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RevitExportGltf.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// 覆盖当前线程的 CurrentUICulture 属性
56 | /// 使用此强类型的资源类的资源查找。
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/RevitExportGltf/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/RevitExportGltf/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace RevitExportGltf.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/RevitExportGltf/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/RevitExportGltf/RevitExportGltf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {8A3DC89A-101F-4410-B1F1-3D209E1A28B1}
8 | Library
9 | RevitExportGltf
10 | RevitExportGltf
11 | v4.7.2
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 | true
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 |
41 |
42 | ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
43 |
44 |
45 | ..\libs\Revit2020\RevitAPI.dll
46 |
47 |
48 | ..\libs\Revit2020\RevitAPIUI.dll
49 |
50 |
51 | libs\SharpGLTF\SharpGLTF.Core.dll
52 |
53 |
54 | libs\SharpGLTF\SharpGLTF.Toolkit.dll
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | 4.0
67 |
68 |
69 | ..\libs\Revit2020\UIFrameworkServices.dll
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | MSBuild:Compile
82 | Designer
83 |
84 |
85 | App.xaml
86 | Code
87 |
88 |
89 |
90 |
91 | MainWindow.xaml
92 | Code
93 |
94 |
95 |
96 |
97 | Code
98 |
99 |
100 | True
101 | True
102 | Resources.resx
103 |
104 |
105 | True
106 | Settings.settings
107 | True
108 |
109 |
110 | ResXFileCodeGenerator
111 | Resources.Designer.cs
112 |
113 |
114 |
115 |
116 |
117 |
118 | SettingsSingleFileGenerator
119 | Settings.Designer.cs
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/RevitExportGltf/Util.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace RevitExportGltf
7 | {
8 | static class Util
9 | {
10 | ///
11 | /// c# 的扩展方法
12 | ///
13 | ///
14 | ///
15 | public static string Point(this XYZ p)
16 | {
17 | return string.Format("{0}", "{1}", "{2}", Math.Round(p.X, 2), Math.Round(p.Y, 2), Math.Round(p.Z, 2));
18 | }
19 |
20 |
21 | public static int[] GetVec3MinMax(List vec3)
22 | {
23 | int minVertexX = int.MaxValue;
24 | int minVertexY = int.MaxValue;
25 | int minVertexZ = int.MaxValue;
26 | int maxVertexX = int.MinValue;
27 | int maxVertexY = int.MinValue;
28 | int maxVertexZ = int.MinValue;
29 | for (int i = 0; i < vec3.Count; i += 3)
30 | {
31 | if (vec3[i] < minVertexX) minVertexX = vec3[i];
32 | if (vec3[i] > maxVertexX) maxVertexX = vec3[i];
33 |
34 | if (vec3[i + 1] < minVertexY) minVertexY = vec3[i + 1];
35 | if (vec3[i + 1] > maxVertexY) maxVertexY = vec3[i + 1];
36 |
37 | if (vec3[i + 2] < minVertexZ) minVertexZ = vec3[i + 2];
38 | if (vec3[i + 2] > maxVertexZ) maxVertexZ = vec3[i + 2];
39 | }
40 | return new int[] { minVertexX, maxVertexX, minVertexY, maxVertexY, minVertexZ, maxVertexZ };
41 | }
42 |
43 | public static long[] GetVec3MinMax(List vec3)
44 | {
45 | long minVertexX = long.MaxValue;
46 | long minVertexY = long.MaxValue;
47 | long minVertexZ = long.MaxValue;
48 | long maxVertexX = long.MinValue;
49 | long maxVertexY = long.MinValue;
50 | long maxVertexZ = long.MinValue;
51 | for (int i = 0; i < (vec3.Count / 3); i += 3)
52 | {
53 | if (vec3[i] < minVertexX) minVertexX = vec3[i];
54 | if (vec3[i] > maxVertexX) maxVertexX = vec3[i];
55 |
56 | if (vec3[i + 1] < minVertexY) minVertexY = vec3[i + 1];
57 | if (vec3[i + 1] > maxVertexY) maxVertexY = vec3[i + 1];
58 |
59 | if (vec3[i + 2] < minVertexZ) minVertexZ = vec3[i + 2];
60 | if (vec3[i + 2] > maxVertexZ) maxVertexZ = vec3[i + 2];
61 | }
62 | return new long[] { minVertexX, maxVertexX, minVertexY, maxVertexY, minVertexZ, maxVertexZ };
63 | }
64 |
65 | public static float[] GetVec3MinMax(List vec3)
66 | {
67 |
68 | List xValues = new List();
69 | List yValues = new List();
70 | List zValues = new List();
71 | for (int i = 0; i < vec3.Count; i++)
72 | {
73 | if ((i % 3) == 0) xValues.Add(vec3[i]);
74 | if ((i % 3) == 1) yValues.Add(vec3[i]);
75 | if ((i % 3) == 2) zValues.Add(vec3[i]);
76 | }
77 |
78 | float maxX = xValues.Max();
79 | float minX = xValues.Min();
80 | float maxY = yValues.Max();
81 | float minY = yValues.Min();
82 | float maxZ = zValues.Max();
83 | float minZ = zValues.Min();
84 |
85 | return new float[] { minX, maxX, minY, maxY, minZ, maxZ };
86 | }
87 |
88 | public static int[] GetScalarMinMax(List scalars)
89 | {
90 | int minFaceIndex = int.MaxValue;
91 | int maxFaceIndex = int.MinValue;
92 | for (int i = 0; i < scalars.Count; i++)
93 | {
94 | int currentMin = Math.Min(minFaceIndex, scalars[i]);
95 | if (currentMin < minFaceIndex) minFaceIndex = currentMin;
96 |
97 | int currentMax = Math.Max(maxFaceIndex, scalars[i]);
98 | if (currentMax > maxFaceIndex) maxFaceIndex = currentMax;
99 | }
100 | return new int[] { minFaceIndex, maxFaceIndex };
101 | }
102 |
103 | public static float[] GetUVMinMax(List vec3)
104 | {
105 |
106 | List xValues = new List();
107 | List yValues = new List();
108 | for (int i = 0; i < vec3.Count; i++)
109 | {
110 | if ((i % 2) == 0) xValues.Add(vec3[i]);
111 | if ((i % 2) == 1) yValues.Add(vec3[i]);
112 | }
113 | float maxX = xValues.Max();
114 | float minX = xValues.Min();
115 | float maxY = yValues.Max();
116 | float minY = yValues.Min();
117 | return new float[] { minX, maxX, minY, maxY };
118 | }
119 |
120 | ///
121 | /// From Jeremy Tammik's RvtVa3c exporter:
122 | /// https://github.com/va3c/RvtVa3c
123 | /// Return a string for a real number
124 | /// formatted to two decimal places.
125 | ///
126 | public static string RealString(double a)
127 | {
128 | return a.ToString("0.##");
129 | }
130 |
131 | ///
132 | /// From Jeremy Tammik's RvtVa3c exporter:
133 | /// https://github.com/va3c/RvtVa3c
134 | /// Return a string for an XYZ point
135 | /// or vector with its coordinates
136 | /// formatted to two decimal places.
137 | ///
138 | public static string PointString(XYZ p)
139 | {
140 | return string.Format("({0},{1},{2})",
141 | RealString(p.X),
142 | RealString(p.Y),
143 | RealString(p.Z));
144 | }
145 |
146 | ///
147 | /// From Jeremy Tammik's RvtVa3c exporter:
148 | /// https://github.com/va3c/RvtVa3c
149 | /// Return an integer value for a Revit Color.
150 | ///
151 | public static int ColorToInt(Color color)
152 | {
153 | return ((int)color.Red) << 16
154 | | ((int)color.Green) << 8
155 | | (int)color.Blue;
156 | }
157 |
158 | ///
159 | /// From Jeremy Tammik's RvtVa3c exporter:
160 | /// https://github.com/va3c/RvtVa3c
161 | /// Extract a true or false value from the given
162 | /// string, accepting yes/no, Y/N, true/false, T/F
163 | /// and 1/0. We are extremely tolerant, i.e., any
164 | /// value starting with one of the characters y, n,
165 | /// t or f is also accepted. Return false if no
166 | /// valid Boolean value can be extracted.
167 | ///
168 | public static bool GetTrueOrFalse(string s, out bool val)
169 | {
170 | val = false;
171 |
172 | if (s.Equals(Boolean.TrueString,
173 | StringComparison.OrdinalIgnoreCase))
174 | {
175 | val = true;
176 | return true;
177 | }
178 | if (s.Equals(Boolean.FalseString,
179 | StringComparison.OrdinalIgnoreCase))
180 | {
181 | return true;
182 | }
183 | if (s.Equals("1"))
184 | {
185 | val = true;
186 | return true;
187 | }
188 | if (s.Equals("0"))
189 | {
190 | return true;
191 | }
192 | s = s.ToLower();
193 |
194 | if ('t' == s[0] || 'y' == s[0])
195 | {
196 | val = true;
197 | return true;
198 | }
199 | if ('f' == s[0] || 'n' == s[0])
200 | {
201 | return true;
202 | }
203 | return false;
204 | }
205 |
206 | ///
207 | /// From Jeremy Tammik's RvtVa3c exporter:
208 | /// https://github.com/va3c/RvtVa3c
209 | /// Return a string describing the given element:
210 | /// .NET type name,
211 | /// category name,
212 | /// family and symbol name for a family instance,
213 | /// element id and element name.
214 | ///
215 | public static string ElementDescription(Element e)
216 | {
217 | if (null == e)
218 | {
219 | return "";
220 | }
221 |
222 | // For a wall, the element name equals the
223 | // wall type name, which is equivalent to the
224 | // family name ...
225 |
226 | FamilyInstance fi = e as FamilyInstance;
227 |
228 | string typeName = e.GetType().Name;
229 |
230 | string categoryName = (null == e.Category)
231 | ? string.Empty
232 | : e.Category.Name + " ";
233 |
234 | string familyName = (null == fi)
235 | ? string.Empty
236 | : fi.Symbol.Family.Name + " ";
237 |
238 | string symbolName = (null == fi
239 | || e.Name.Equals(fi.Symbol.Name))
240 | ? string.Empty
241 | : fi.Symbol.Name + " ";
242 |
243 | return string.Format("{0} {1}{2}{3}<{4} {5}>",
244 | typeName, categoryName, familyName,
245 | symbolName, e.Id.IntegerValue, e.Name);
246 | }
247 |
248 | ///
249 | /// From Jeremy Tammik's RvtVa3c exporter:
250 | /// https://github.com/va3c/RvtVa3c
251 | /// Return a dictionary of all the given
252 | /// element parameter names and values.
253 | ///
254 | public static Dictionary GetElementProperties(Element e, bool includeType)
255 | {
256 | IList parameters
257 | = e.GetOrderedParameters();
258 |
259 | Dictionary a = new Dictionary(parameters.Count);
260 |
261 | // Add element category
262 | a.Add("Element Category", e.Category.Name);
263 |
264 | string key;
265 | string val;
266 |
267 | foreach (Parameter p in parameters)
268 | {
269 | key = p.Definition.Name;
270 |
271 | if (!a.ContainsKey(key))
272 | {
273 | if (StorageType.String == p.StorageType)
274 | {
275 | val = p.AsString();
276 | }
277 | else
278 | {
279 | val = p.AsValueString();
280 | }
281 | if (!string.IsNullOrEmpty(val))
282 | {
283 | a.Add(key, val);
284 | }
285 | }
286 | }
287 |
288 | if (includeType)
289 | {
290 | ElementId idType = e.GetTypeId();
291 |
292 | if (ElementId.InvalidElementId != idType)
293 | {
294 | Document doc = e.Document;
295 | Element typ = doc.GetElement(idType);
296 | parameters = typ.GetOrderedParameters();
297 | foreach (Parameter p in parameters)
298 | {
299 | key = "Type " + p.Definition.Name;
300 |
301 | if (!a.ContainsKey(key))
302 | {
303 | if (StorageType.String == p.StorageType)
304 | {
305 | val = p.AsString();
306 | }
307 | else
308 | {
309 | val = p.AsValueString();
310 | }
311 | if (!string.IsNullOrEmpty(val))
312 | {
313 | a.Add(key, val);
314 | }
315 | }
316 | }
317 | }
318 | }
319 | return a;
320 | }
321 | }
322 | }
323 |
--------------------------------------------------------------------------------
/RevitExportGltf/WPF/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/RevitExportGltf/WPF/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace RevitExportGltf
4 | {
5 | ///
6 | /// MainWindow.xaml 的交互逻辑
7 | ///
8 | public partial class MainWindow : Window
9 | {
10 | public MainWindow()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/RevitExportGltf/bin/Dotfuscator1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
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 |
--------------------------------------------------------------------------------
/RevitExportGltf/glTF.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace RevitExportGltf
4 | {
5 | #region glTF格式组成
6 | ///
7 | /// The json serializable glTF file format.
8 | /// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
9 | ///
10 | public struct glTF
11 | {
12 | public glTFAsset asset;
13 | public List scenes;
14 | public List nodes;
15 | public List meshes;
16 | public List buffers;
17 | public List bufferViews;
18 | public List accessors;
19 | public List materials;
20 | public List textures;
21 | public List images;
22 | public List samplers;
23 |
24 | public int defaultScene; //默认场景
25 |
26 | }
27 |
28 | ///
29 | /// 版本
30 | ///
31 | public class glTFAsset
32 | {
33 | public string version = "2.0";
34 | public string minVersion = "2.0";
35 | public string copyright = "2017 (c) Khronos Group";
36 | public string generator = "The raw data exported from the revit plug-in of bimv is organized into gltf format";
37 | }
38 | ///
39 | /// 场景
40 | ///
41 | public class glTFScene
42 | {
43 | public List nodes = new List();
44 | }
45 |
46 | ///
47 | ///场景中的节点
48 | ///
49 | public class glTFNode
50 | {
51 | public string name { get; set; }
52 | ///
53 | /// mesh个数
54 | ///
55 | public int? mesh { get; set; } = null;
56 | ///
57 | /// 矩阵
58 | ///
59 | public List matrix { get; set; }
60 |
61 |
62 | ///
63 | /// 旋转
64 | ///
65 | public List rotation { get; set; }
66 |
67 | ///
68 | /// 平移
69 | ///
70 | public List translation { get; set; }
71 |
72 |
73 | ///
74 | ///
75 | ///
76 | public List children { get; set; }
77 | ///
78 | ///附加属性
79 | ///
80 | // public glTFExtras extras { get; set; }
81 | }
82 |
83 |
84 | ///
85 | /// 网格
86 | ///
87 | public class glTFMesh
88 | {
89 | public string name { get; set; } //与revit的group id 相对应
90 | public List primitives { get; set; }
91 | }
92 |
93 |
94 | ///
95 | /// 属性定义GPU应该在哪里寻找网格和材质数据。
96 | ///
97 | public class glTFMeshPrimitive
98 | {
99 | public glTFAttribute attributes { get; set; } = new glTFAttribute();
100 | public int indices { get; set; }
101 | public int? material { get; set; } = null;
102 | public int mode { get; set; } = 4; // 4 is triangles
103 | }
104 |
105 | public class glTFAttribute
106 | {
107 | ///
108 | ///位置数据访问器的索引。
109 | ///
110 | public int POSITION { get; set; }
111 |
112 | ///
113 | /// 第一组UV坐标
114 | ///
115 | public int TEXCOORD_0 { get; set; }
116 |
117 | //public int NORMAL { get; set; }
118 | }
119 |
120 | ///
121 | ///对二进制数据的位置和大小的引用。
122 | ///
123 | public class glTFBuffer
124 | {
125 | ///
126 | /// The uri of the buffer.
127 | ///
128 | public string uri { get; set; }
129 | ///
130 | /// The total byte length of the buffer.
131 | ///
132 | public int byteLength { get; set; }
133 | }
134 |
135 | ///
136 | /// 对包含矢量或标量数据的缓冲区的分段的引用。
137 | ///
138 | public class glTFBufferView
139 | {
140 | ///
141 | /// 缓冲区的索引。
142 | ///
143 | public int buffer { get; set; }
144 | ///
145 | /// 缓冲区的偏移量(以字节为单位)。
146 | ///
147 | public int byteOffset { get; set; }
148 | ///
149 | /// bufferView的长度,以字节为单位。
150 | ///
151 | public int byteLength { get; set; }
152 | ///
153 | /// GPU缓冲区应该绑定到的目标。
154 | ///
155 | public Targets target { get; set; }
156 | ///
157 | /// A user defined name for this view.
158 | ///
159 | public string name { get; set; }
160 | }
161 |
162 | ///
163 | /// 逻辑数字来区分标量和矢量数组buff。
164 | /// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#buffers-and-buffer-views
165 | ///
166 | public enum Targets
167 | {
168 | ARRAY_BUFFER = 34962, // signals vertex data
169 | ELEMENT_ARRAY_BUFFER = 34963 // signals index or face data
170 | }
171 |
172 | ///
173 | /// 逻辑数值以区分数组buff组件类型。
174 | /// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#accessor-element-size
175 | ///
176 | public enum ComponentType
177 | {
178 | BYTE = 5120,
179 | UNSIGNED_BYTE = 5121,
180 | SHORT = 5122,
181 | UNSIGNED_SHORT = 5123,
182 | UNSIGNED_INT = 5125,
183 | FLOAT = 5126
184 | }
185 |
186 |
187 | ///
188 | /// 对包含特定数据类型的BufferView分段的引用。
189 | ///
190 | public class glTFAccessor
191 | {
192 | ///
193 | ///缓冲视图的索引
194 | ///
195 | public int bufferView { get; set; }
196 | ///
197 | /// 相对于bufferView开始的偏移量(以字节为单位)。
198 | ///
199 | public int byteOffset { get; set; }
200 | ///
201 | /// 属性中组件的数据类型
202 | ///
203 | public ComponentType componentType { get; set; }
204 | ///
205 | /// 此访问器引用的属性数量。
206 | ///
207 | public int count { get; set; }
208 | ///
209 | /// 指定属性是scala、向量还是矩阵
210 | ///
211 | public string type { get; set; }
212 | ///
213 | /// 此属性中每个组件的最大值。
214 | ///
215 | public List max { get; set; }
216 | ///
217 | /// 此属性中每个组件的最小值。
218 | ///
219 | public List min { get; set; }
220 | ///
221 | /// 此访问器的用户定义名称。
222 | ///
223 | public string name { get; set; }
224 | }
225 |
226 |
227 | ///
228 | /// 材质
229 | ///
230 | public class glTFMaterial
231 | {
232 | public string name { get; set; }
233 | public glTFPBR pbrMetallicRoughness { get; set; }
234 | public string alphaMode { get; set; }
235 | public string doubleSided { get; set; }
236 | }
237 |
238 |
239 | public class glTFPBR
240 | {
241 | //材质贴图
242 | public glTFbaseColorTexture baseColorTexture { get; set; }
243 |
244 | //材质颜色索引
245 | public List baseColorFactor { get; set; }
246 | //材质金属性
247 | public float metallicFactor { get; set; }
248 | //材质粗糙度
249 | public float roughnessFactor { get; set; }
250 | }
251 |
252 |
253 | public class glTFbaseColorTexture
254 | {
255 | //贴图索引
256 | public int? index { get; set; } = null;
257 | }
258 |
259 |
260 | ///
261 | /// 每个texture对象可以用于多个材质对象
262 | ///
263 | public class glTFTexture
264 | {
265 | ///
266 | /// glTFImage的索引号
267 | ///
268 | public int? source { get; set; } = null;
269 | ///
270 | /// glTFSampler的索引号
271 | ///
272 | public int? sampler { get; set; } = null;
273 |
274 | }
275 |
276 | public class glTFImage
277 | {
278 | public string uri { get; set; }
279 |
280 | }
281 |
282 | public class glTFSampler
283 | {
284 | public string name;
285 | public float magFilter { get; set; }
286 |
287 | public float minFilter { get; set; }
288 | public float wrapS { get; set; }
289 | public float wrapT { get; set; }
290 | }
291 |
292 |
293 | #endregion
294 |
295 |
296 | #region bin文件
297 | ///
298 | /// A binary data store serialized to a *.bin file
299 | /// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#binary-data-storage
300 | ///
301 | public class GeometryData
302 | {
303 | public List vertices = new List();
304 | public List normals = new List();
305 | public List uvs = new List();
306 | public List index = new List();
307 | }
308 |
309 |
310 | ///
311 | /// *.bin文件
312 | ///
313 | public class glTFBinaryData
314 | {
315 | public List vertexBuffer { get; set; } = new List();
316 | public List indexBuffer { get; set; } = new List();
317 | //public List normalBuffer { get; set; } = new List();
318 |
319 | public List uvBuffer { get; set; } = new List();
320 | public int vertexAccessorIndex { get; set; }
321 | public int indexAccessorIndex { get; set; }
322 |
323 | public int uvAccessorIndex { get; set; }
324 |
325 | //public int normalsAccessorIndex { get; set; }
326 | public string name { get; set; }
327 | }
328 | #endregion
329 |
330 | }
331 |
--------------------------------------------------------------------------------
/RevitExportGltf/libs/Revit2018/RevitAPI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/RevitExportGltf/libs/Revit2018/RevitAPI.dll
--------------------------------------------------------------------------------
/RevitExportGltf/libs/Revit2018/RevitAPIUI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/RevitExportGltf/libs/Revit2018/RevitAPIUI.dll
--------------------------------------------------------------------------------
/RevitExportGltf/libs/Revit2018/UIFrameworkServices.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/RevitExportGltf/libs/Revit2018/UIFrameworkServices.dll
--------------------------------------------------------------------------------
/RevitExportGltf/libs/SharpGLTF/SharpGLTF.Core.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/RevitExportGltf/libs/SharpGLTF/SharpGLTF.Core.dll
--------------------------------------------------------------------------------
/RevitExportGltf/libs/SharpGLTF/SharpGLTF.Toolkit.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/RevitExportGltf/libs/SharpGLTF/SharpGLTF.Toolkit.dll
--------------------------------------------------------------------------------
/RevitExportGltf/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/RevitExportGltfContext.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using Autodesk.Revit.DB.Visual;
3 | using Microsoft.Win32;
4 | using Newtonsoft.Json;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Diagnostics;
8 | using System.IO;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using static RevitExportGltf.Util;
13 |
14 | namespace RevitExportGltf
15 | {
16 |
17 | class RevitExportGltfContext : IExportContext
18 | {
19 | private Document doc;
20 | Element currentElem;
21 | ObjectData RootDatas;
22 | ObjectData InstanceNameData;
23 | ObjectData currentData;
24 | public IndexedDictionary currentDatas { get; }
25 | = new IndexedDictionary();
26 |
27 | public List Scenes = new List();
28 | public IndexedDictionary Nodes { get; } = new IndexedDictionary();
29 | public IndexedDictionary Meshes { get; } = new IndexedDictionary();
30 | public IndexedDictionary Materials { get; } = new IndexedDictionary();
31 |
32 | public IndexedDictionary Textures { get; } = new IndexedDictionary();
33 | public IndexedDictionary Images { get; } = new IndexedDictionary();
34 | public IndexedDictionary Samplers { get; } = new IndexedDictionary();
35 |
36 | public List Buffers { get; } = new List();
37 | public List BufferViews { get; } = new List();
38 | public List Accessors { get; } = new List();
39 |
40 | ///
41 | /// 用于存储顶点/面/法线信息,将被序列化为二进制格式的
42 | /// 用于最终的*.bin文件。
43 | ///
44 | public List binFileData { get; } = new List();
45 |
46 |
47 |
48 | private glTFNode rootNode;
49 | ///
50 | /// 几何图形列表
51 | ///当前正在处理的元素,以材质为键值。这
52 | ///在每个新元素上重新初始化
53 | ///
54 | private IndexedDictionary currentGeometry;
55 | ///
56 | /// 顶点列表
57 | ///
58 | private Stack _transformStack = new Stack();
59 | private Transform CurrentTransform { get { return _transformStack.Peek(); } }
60 |
61 |
62 | private string FileName;
63 | private string directory;
64 | public RevitExportGltfContext(Document document, string fileName)
65 | {
66 | doc = document;
67 | FileName = fileName;
68 | directory = Path.GetDirectoryName(FileName) + "\\";
69 | }
70 |
71 | string textureFolder;
72 | public bool Start()
73 | {
74 | _transformStack.Push(Transform.Identity);
75 |
76 | RootDatas = new ObjectData();
77 |
78 | //场景
79 | glTFScene defaultScene = new glTFScene();
80 | defaultScene.nodes.Add(0);
81 | Scenes.Add(defaultScene);
82 | //节点
83 | rootNode = new glTFNode();
84 | rootNode.name = "rootNode";
85 | rootNode.children = new List();
86 | Nodes.AddOrUpdateCurrent("rootNode", rootNode);
87 |
88 | //通过读取注册表相应键值获取材质库地址
89 | RegistryKey hklm = Registry.LocalMachine;
90 | RegistryKey libraryPath = hklm.OpenSubKey("SOFTWARE\\WOW6432Node\\Autodesk\\ADSKTextureLibrary\\1");
91 | textureFolder = libraryPath.GetValue("LibraryPaths").ToString();
92 | hklm.Close();
93 | libraryPath.Close();
94 |
95 | return true;
96 | }
97 |
98 |
99 | public void Finish()
100 | {
101 | // TODO: [RM] Standardize what non glTF spec elements will go into
102 | // this "BIM glTF superset" and write a spec for it. Gridlines below
103 | // are an example.
104 |
105 | // Add gridlines as gltf nodes in the format:
106 | // Origin {Vec3}, Direction {Vec3}, Length {double}
107 | int bytePosition = 0;
108 | int currentBuffer = 0;
109 |
110 | foreach (var view in BufferViews)
111 | {
112 | if (view.buffer == 0)
113 | {
114 | bytePosition += view.byteLength;
115 | continue;
116 | }
117 |
118 | if (view.buffer != currentBuffer)
119 | {
120 | view.buffer = 0;
121 | view.byteOffset = bytePosition;
122 | bytePosition += view.byteLength;
123 | }
124 | }
125 |
126 | glTFBuffer buffer = new glTFBuffer();
127 | buffer.uri = Path.GetFileNameWithoutExtension(FileName) + ".bin";
128 | buffer.byteLength = bytePosition;
129 | Buffers.Clear();
130 | Buffers.Add(buffer);
131 |
132 |
133 | //写入bin文件
134 | directory = Path.GetDirectoryName(FileName) + "\\";
135 | StreamWriter swObj = new StreamWriter(directory + "binFilePrint.txt");
136 | using (FileStream f = File.Create(directory + buffer.uri))
137 | {
138 | using (BinaryWriter writer = new BinaryWriter(f))
139 | {
140 | var count = 0;
141 | foreach (var bin in binFileData)
142 | {
143 | count++;
144 | foreach (var coord in bin.vertexBuffer)
145 | {
146 | writer.Write((float)coord);
147 | swObj.Write((float)coord + " ");
148 |
149 | }
150 | swObj.Write("\n");
151 | swObj.Write("***********vertexBuffer*******第" + count + "次*********");
152 | swObj.Write("\n");
153 |
154 | // TODO: add writer for normals buffer
155 | foreach (var index in bin.indexBuffer)
156 | {
157 | writer.Write((int)index);
158 | swObj.Write((int)index + " ");
159 | }
160 | swObj.Write("\n");
161 | swObj.Write("*************indexBuffer********第" + count + "次*********");
162 | swObj.Write("\n");
163 |
164 | foreach (var uv in bin.uvBuffer)
165 | {
166 | writer.Write((float)uv);
167 | swObj.Write((float)uv + " ");
168 | }
169 | swObj.Write("\n");
170 | swObj.Write("**************uvBuffer*********第" + count + "次*********");
171 | swObj.Write("\n");
172 | }
173 | }
174 | }
175 | swObj.Close();
176 | //将属性打包到一个可序列化的容器中
177 | glTF model = new glTF();
178 | model.asset = new glTFVersion();
179 | model.scenes = Scenes;
180 | model.nodes = Nodes.List;
181 | model.meshes = Meshes.List;
182 | model.materials = Materials.List;
183 | model.textures = Textures.List;
184 | model.images = Images.List;
185 | model.samplers = Samplers.List;
186 |
187 |
188 | model.buffers = Buffers;
189 | model.bufferViews = BufferViews;
190 | model.accessors = Accessors;
191 |
192 | //写入 *.gltf 文件
193 | string serializedModel = JsonConvert.SerializeObject(model, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
194 | File.WriteAllText(FileName, serializedModel);
195 | }
196 |
197 | bool isHasSimilar;
198 | string center;
199 | int index = 0;
200 | public RenderNodeAction OnElementBegin(ElementId elementId)
201 | {
202 | index = 0;
203 | Element e = doc.GetElement(elementId);
204 | currentElem = doc.GetElement(elementId);
205 | try
206 | {
207 | if ((BuiltInCategory)currentElem.Category.Id.IntegerValue == BuiltInCategory.OST_Cameras ||
208 | currentElem.Category.CategoryType == CategoryType.AnalyticalModel)
209 | {
210 | return RenderNodeAction.Skip;
211 | }
212 |
213 | }
214 | catch
215 | {
216 | Console.WriteLine("currentElem.Category 为null");
217 | }
218 | isHasSimilar = false;
219 | center = null;
220 | if (Nodes.Contains(e.UniqueId))
221 | {
222 | return RenderNodeAction.Skip;
223 | }
224 | try
225 | {
226 |
227 | string CategoryName = currentElem.Category.Name;
228 | string FamilyName = currentElem.get_Parameter(BuiltInParameter.ELEM_FAMILY_PARAM).AsValueString();
229 | if (FamilyName == "")
230 | {
231 | FamilyName = CategoryName;
232 | }
233 | string InstanceName = currentElem.Name;
234 | InstanceNameData = null;
235 | List Names = new List() { CategoryName, FamilyName, InstanceName };
236 | getitem(RootDatas, Names);
237 | if (InstanceNameData == null)
238 | {
239 | return RenderNodeAction.Skip;
240 | }
241 |
242 | }
243 | catch { Console.WriteLine("currentElem.Category 为null"); }
244 |
245 | currentData = new ObjectData();
246 | currentData.ElementId = currentElem.Id.ToString();
247 | currentData.ElementName = currentElem.Name;
248 | try
249 | {
250 | currentData.ElementArea = currentElem.get_Parameter(BuiltInParameter.HOST_AREA_COMPUTED).AsValueString();
251 | currentData.ElementVolum = currentElem.get_Parameter(BuiltInParameter.HOST_VOLUME_COMPUTED).AsValueString();
252 | }
253 | catch
254 | {
255 | Console.WriteLine("currentElem.Category 为null");
256 | }
257 |
258 | try
259 | {
260 |
261 | foreach (ObjectData similar in InstanceNameData.Children)
262 | {
263 | if (similar.ElementArea == currentData.ElementArea && similar.ElementVolum == currentData.ElementVolum && similar.ElementArea != null && similar.ElementVolum != null)
264 | {
265 | if (similar.SimilarObjectID != null)
266 | {
267 | currentData.SimilarObjectID = similar.SimilarObjectID;
268 | }
269 | else
270 | {
271 | currentData.SimilarObjectID = similar.ElementId;
272 | }
273 | similar.Children.Add(currentData);
274 | isHasSimilar = true;
275 | break;
276 | }
277 | }
278 | if (currentData.SimilarObjectID == null)
279 | {
280 | InstanceNameData.Children.Add(currentData);
281 | }
282 | }
283 | catch
284 | {
285 | Console.WriteLine("InstanceNameData 属性不能为null");
286 | }
287 |
288 | currentData.ElementLocation = new List();
289 | if (currentElem.Location is LocationPoint)
290 | {
291 | FamilyInstance family = currentElem as FamilyInstance;
292 | LocationPoint point = currentElem.Location as LocationPoint;
293 | try
294 | {
295 | GetPoints(currentElem);
296 | currentData.ElementLocation.Add(center);
297 | currentData.ElementLocation.Add(family.HandOrientation.Point());
298 | XYZ vect = family.HandOrientation.CrossProduct(family.FacingOrientation);
299 | currentData.ElementLocation.Add(vect.Point());
300 | }
301 | catch
302 | {
303 |
304 | }
305 | }
306 | //新节点
307 | glTFNode newNode = new glTFNode();
308 | newNode.name = e.Name + "[" + e.Id.ToString() + "]";
309 |
310 |
311 | Debug.WriteLine("Finishing...");
312 | //获取构件的任意两个点
313 | //GetPoints(currentElem);
314 | //currentData.ElementLocation = EdgesPoints;
315 | currentDatas.AddOrUpdateCurrent(currentElem.Id.ToString(), currentData);
316 | if (currentData.ElementLocation.Count == 0 || currentData.ElementLocation[0] == null)
317 | {
318 | isHasSimilar = false;
319 | }
320 |
321 |
322 | if (currentElem is Mullion)
323 | {
324 | isHasSimilar = false;
325 | }
326 | if (isHasSimilar == true)
327 | {
328 | List Similarpoints = currentDatas.
329 | GetElement(currentData.SimilarObjectID).ElementLocation;
330 | List CurrentPoints = currentData.ElementLocation;
331 |
332 | string[] p1 = Similarpoints[0].Split(new char[] { ',' });
333 | double x1 = Convert.ToDouble(p1[0]);
334 | double y1 = Convert.ToDouble(p1[1]);
335 | double z1 = Convert.ToDouble(p1[2]);
336 |
337 |
338 | string[] p2 = Similarpoints[1].Split(new char[] { ',' });
339 | double x2 = Convert.ToDouble(p2[0]);
340 | double y2 = Convert.ToDouble(p2[1]);
341 | double z2 = Convert.ToDouble(p2[2]);
342 | XYZ vect1 = new XYZ(x2, y2, z2);
343 |
344 | //当前构件的点
345 | string[] elementPoint1 = CurrentPoints[0].Split(new char[] { ',' });
346 | double px1 = Convert.ToDouble(elementPoint1[0]);
347 | double py1 = Convert.ToDouble(elementPoint1[1]);
348 | double pz1 = Convert.ToDouble(elementPoint1[2]);
349 |
350 | string[] elementPoint2 = CurrentPoints[1].Split(new char[] { ',' });
351 | double px2 = Convert.ToDouble(elementPoint2[0]);
352 | double py2 = Convert.ToDouble(elementPoint2[1]);
353 | double pz2 = Convert.ToDouble(elementPoint2[2]);
354 | XYZ vect2 = new XYZ(px2, py2, pz2);
355 | //平移第一个点
356 | double MoveX = Math.Round(px1 - x1, 2);
357 | double MoveY = Math.Round(py1 - y1, 2);
358 | double MoveZ = Math.Round(pz1 - z1, 2);
359 | //平移第二个点,保留两位小数
360 | //旋转
361 | if (!vect1.IsAlmostEqualTo(vect2))
362 | {
363 | //求旋转角
364 | double Radian = vect1.AngleTo(vect2);
365 | //求旋转轴,求法向量
366 | XYZ Ro = vect1.CrossProduct(vect2);//向量的叉乘,
367 | //vect1和vect2向量共线时,即旋转180度法向量为0,旋转轴无法求出,引用第三个点求
368 | if (Ro.X == 0 && Ro.Y == 0 && Ro.Z == 0)
369 | {
370 | string[] elementPoint3 = Similarpoints[2].Split(new char[] { ',' });
371 | double px3 = Convert.ToDouble(elementPoint3[0]);
372 | double py3 = Convert.ToDouble(elementPoint3[1]);
373 | double pz3 = Convert.ToDouble(elementPoint3[2]);
374 | Ro = new XYZ(px3, py3, pz3);
375 | }
376 |
377 | //向量单位化,求向量的模
378 | double Norm = Math.Sqrt(Ro.X * Ro.X + Ro.Y * Ro.Y + Ro.Z * Ro.Z);
379 | XYZ Unit = new XYZ(Ro.X / Norm, Ro.Y / Norm, Ro.Z / Norm);
380 | ////计算4x4矩阵
381 | ////相同构件位置变化
382 | double[] newPonits = RotateByVector(x1, y1, z1, Unit.X, Unit.Y, Unit.Z, Radian);//算出为(-5200,3000,0),实际为(5200,-3000,0)
383 | MoveX = Math.Round(px1 - newPonits[0], 2);
384 | MoveY = Math.Round(py1 - newPonits[1], 2);
385 | MoveZ = Math.Round(pz1 - newPonits[2], 2);
386 | //左手坐标系下旋转
387 | double x = Math.Round(-Unit.X);
388 | double y = Math.Round(-Unit.Z);
389 | double z = Math.Round(Unit.Y);
390 | double C = Math.Cos(Radian);
391 | double S = Math.Sin(Radian);
392 | newNode.matrix = new List()
393 | {x*x*(1-C)+C, x*y*(1-C)-z*S, x*z*(1-C)+y*S, 0.0,
394 | x*y*(1-C)+z*S, y*y*(1-C)+C, y*z*(1-C)-x*S, 0.0,
395 | x*z*(1-C)-y*S, y*z*(1-C)+x*S, z*z*(1-C)+C, 0.0,
396 | -MoveX, MoveZ, MoveY, 0.0};
397 | }
398 | else
399 | {
400 | newNode.translation = new List() { -MoveX, MoveZ, MoveY, };
401 | }
402 | }
403 | Nodes.AddOrUpdateCurrent(e.Id.ToString(), newNode);
404 | //将此节点的索引添加到根节点子数组中
405 | rootNode.children.Add(Nodes.CurrentIndex);
406 | if (isHasSimilar == true)
407 | {
408 | return RenderNodeAction.Skip;
409 | }
410 |
411 |
412 | //几何元素
413 | currentGeometry = new IndexedDictionary();
414 | return RenderNodeAction.Proceed;
415 | }
416 |
417 |
418 | public void OnMaterial(MaterialNode node)
419 | {
420 | string matName;
421 | ElementId id = node.MaterialId;
422 | glTFMaterial gl_mat = new glTFMaterial();
423 |
424 | if (id != ElementId.InvalidElementId)
425 | {
426 | //从节点构造一个材质
427 | Element m = doc.GetElement(node.MaterialId);
428 | matName = m.Name;
429 |
430 | string texturePath = null;
431 | Asset currentAsset = null;
432 | try
433 | {
434 | //写入材质名、环境反射、漫反射和透明度。
435 | if (node.HasOverriddenAppearance)
436 | {
437 | currentAsset = node.GetAppearanceOverride();
438 | }
439 | else
440 | {
441 | currentAsset = node.GetAppearance();
442 | }
443 | //取得Asset中贴图信息
444 | string textureFile = (FindTextureAsset(currentAsset as AssetProperty)["unifiedbitmap_Bitmap"]
445 | as AssetPropertyString).Value.Split('|')[0];
446 | //用Asset中贴图信息和注册表里的材质库地址得到贴图文件所在位置
447 | texturePath = Path.Combine(textureFolder, textureFile.Replace("/", "\\"));
448 | }
449 | catch
450 | {
451 |
452 | }
453 | //构造材料
454 | gl_mat.name = matName;
455 | glTFPBR pbr = new glTFPBR();
456 | //第四个值是材料的Alpha覆盖率。该alphaMode属性指定如何解释alpha
457 | double alpha = Math.Round(node.Transparency, 2);
458 | if (alpha != 0)
459 | {
460 | gl_mat.alphaMode = "BLEND";
461 | gl_mat.doubleSided = "true";
462 | alpha = 1 - alpha;
463 | }
464 | pbr.metallicFactor = 0f;//金属感强度
465 | pbr.roughnessFactor = 1f;//粗糙感强度
466 | gl_mat.pbrMetallicRoughness = pbr;
467 | Materials.AddOrUpdateCurrent(m.UniqueId, gl_mat);
468 | //写入贴图名称
469 | string textureName = string.Format("{0}.png", m.Name);
470 |
471 |
472 |
473 | //如果贴图文件真实存在,就复制到相应位置
474 | if (File.Exists(texturePath))
475 | {
476 | string dirName = Path.GetFileNameWithoutExtension(FileName) + "(材质贴图)";
477 | string dir = directory + dirName;
478 | if (!Directory.Exists(dir))
479 | {
480 | //如果不存在就创建 dir 文件夹
481 | Directory.CreateDirectory(dir);
482 | }
483 |
484 | File.Copy(texturePath, Path.Combine(dir + "\\" + textureName), true);
485 | glTFImage image = new glTFImage();
486 | //通过 uri定位到图片资源
487 | image.uri = "./" + dirName + "/" + textureName;
488 | Images.AddOrUpdateCurrent(m.UniqueId, image);
489 | //取样器,定义图片的采样和滤波方式
490 | glTFSampler sampler = new glTFSampler();
491 | sampler.magFilter = 9729;
492 | sampler.minFilter = 9987;
493 | sampler.wrapS = 10497;
494 | sampler.wrapT = 10497;
495 | Samplers.AddOrUpdateCurrent(m.UniqueId, sampler);
496 | //贴图信息,使用source和ssampler指向图片和采样器
497 | glTFTexture texture = new glTFTexture();
498 | texture.source = Images.CurrentIndex;
499 | texture.sampler = Samplers.CurrentIndex;
500 | Textures.AddOrUpdateCurrent(m.UniqueId, texture);
501 | //贴图索引
502 | glTFbaseColorTexture bct = new glTFbaseColorTexture();
503 | bct.index = Textures.CurrentIndex;
504 | pbr.baseColorTexture = bct;
505 | }
506 | else
507 | {
508 | try
509 | {
510 | pbr.baseColorFactor = new List() { node.Color.Red / 255f, node.Color.Green / 255f, node.Color.Blue / 255f, (float)alpha / 1f };
511 | }
512 | catch
513 | {
514 |
515 | }
516 | }
517 | }
518 | else
519 | {
520 |
521 | string uuid = string.Format("r{0}g{1}b{2}", node.Color.Red.ToString(), node.Color.Green.ToString(), node.Color.Blue.ToString());
522 | // construct the material
523 | matName = string.Format("MaterialNode_{0}_{1}", Util.ColorToInt(node.Color), Util.RealString(node.Transparency * 100));
524 | gl_mat.name = matName;
525 | glTFPBR pbr = new glTFPBR();
526 | pbr.baseColorFactor = new List() { node.Color.Red / 255f, node.Color.Green / 255f, node.Color.Blue / 255f, 1f };
527 | pbr.metallicFactor = 0f;
528 | pbr.roughnessFactor = 1f;
529 | gl_mat.pbrMetallicRoughness = pbr;
530 | Materials.AddOrUpdateCurrent(uuid, gl_mat);
531 | }
532 | }
533 | public void OnPolymesh(PolymeshTopology polymesh)
534 | {
535 | string vertex_key = Nodes.CurrentKey + "_" + Materials.CurrentKey;
536 | //如果vertex_key是唯一的,添加新的“current”条目
537 | bool isNew = currentGeometry.AddOrUpdateCurrent(vertex_key, new GeometryData());
538 | if (isNew == true)
539 | {
540 | index = 0;
541 | }
542 | //取得UV坐标
543 | IList uvs = polymesh.GetUVs();
544 | //顶点和索引
545 | Transform t = CurrentTransform;
546 | IList pts = polymesh.GetPoints();
547 | pts = pts.Select(p => t.OfPoint(p)).ToList();//矩阵变换
548 | //gltf中导出贴图时顶点数要和UV数、索引位置保持一致
549 | index = currentGeometry.CurrentItem.vertices.Count / 3;
550 | foreach (XYZ point in pts)
551 | {
552 | currentGeometry.CurrentItem.vertices.Add(Math.Round(-point.X, 2).ToString());
553 | currentGeometry.CurrentItem.vertices.Add(Math.Round(point.Z, 2).ToString());
554 | currentGeometry.CurrentItem.vertices.Add(Math.Round(point.Y, 2).ToString());
555 | }
556 | //把UV数据写入文件
557 | foreach (UV uv in uvs)
558 | {
559 | currentGeometry.CurrentItem.uvs.Add(Math.Round(uv.U, 2).ToString());
560 | currentGeometry.CurrentItem.uvs.Add(Math.Round(uv.V, 2).ToString());
561 | }
562 | //导出贴图时顶点数要和UV数保持一致
563 | foreach (PolymeshFacet facet in polymesh.GetFacets())
564 | {
565 | currentGeometry.CurrentItem.index.Add(facet.V1 + index);
566 | currentGeometry.CurrentItem.index.Add(facet.V2 + index);
567 | currentGeometry.CurrentItem.index.Add(facet.V3 + index);
568 | }
569 | }
570 |
571 | public void OnElementEnd(ElementId elementId)
572 | {
573 | try
574 | {
575 | if ((BuiltInCategory)currentElem.Category.Id.IntegerValue == BuiltInCategory.OST_Cameras ||
576 | currentElem.Category.CategoryType == CategoryType.AnalyticalModel)
577 | {
578 | return;
579 | }
580 |
581 | }
582 | catch
583 | {
584 | Console.WriteLine("currentElem.Category 为null");
585 | }
586 | if (isHasSimilar == true)
587 | {
588 | Nodes.CurrentItem.mesh = Meshes.GetIndexFromUUID(currentData.SimilarObjectID);
589 | return;
590 | }
591 | try
592 | {
593 | //如果是rfa族文件就会 currentGeometry.CurrentIndex CurrentItem.vertices key不能为null
594 | if (currentGeometry.CurrentItem.vertices.Count == 0)
595 | {
596 | return;
597 | }
598 | }
599 | catch
600 | {
601 | Console.WriteLine("currentGeometry.CurrentIndex CurrentItem.vertices key不能为null");
602 | }
603 |
604 | Element e = doc.GetElement(elementId);
605 | glTFMesh newMesh = new glTFMesh();
606 | newMesh.primitives = new List();
607 | Meshes.AddOrUpdateCurrent(e.Id.ToString(), newMesh);
608 | Nodes.CurrentItem.mesh = Meshes.CurrentIndex;
609 | // 将currentGeometry对象转换为glTFMeshPrimitives
610 | foreach (KeyValuePair kvp in currentGeometry.Dict)
611 | {
612 | glTFBinaryData elementBinary = AddGeometryMeta(kvp.Value, kvp.Key);
613 | binFileData.Add(elementBinary);
614 | string material_key = kvp.Key.Split('_')[1];
615 | glTFMeshPrimitive primative = new glTFMeshPrimitive();
616 | primative.attributes.POSITION = elementBinary.vertexAccessorIndex;
617 | primative.indices = elementBinary.indexAccessorIndex;
618 | primative.material = Materials.GetIndexFromUUID(material_key);
619 |
620 | //UV坐标
621 | primative.attributes.TEXCOORD_0 = elementBinary.uvAccessorIndex;
622 | Meshes.CurrentItem.primitives.Add(primative);
623 | }
624 | }
625 |
626 | public RenderNodeAction OnInstanceBegin(InstanceNode node)
627 | {
628 | _transformStack.Push(CurrentTransform.Multiply(node.GetTransform()));
629 | return RenderNodeAction.Proceed;
630 | }
631 |
632 | public void OnInstanceEnd(InstanceNode node)
633 | {
634 | _transformStack.Pop();
635 | }
636 |
637 | ///
638 | /// Takes the intermediate geometry data and performs the calculations
639 | /// to convert that into glTF buffers, views, and accessors.
640 | ///
641 | ///
642 | /// Unique name for the .bin file that will be produced.
643 | ///
644 | public glTFBinaryData AddGeometryMeta(GeometryData geomData, string name)
645 | {
646 | // add a buffer
647 | glTFBuffer buffer = new glTFBuffer();
648 | buffer.uri = name + ".bin";
649 | Buffers.Add(buffer);
650 | int bufferIdx = Buffers.Count - 1;
651 |
652 | /**
653 | * Buffer Data
654 | **/
655 | glTFBinaryData bufferData = new glTFBinaryData();
656 | bufferData.name = buffer.uri;
657 | foreach (var coord in geomData.vertices)
658 | {
659 | float vFloat = Convert.ToSingle(coord);
660 | bufferData.vertexBuffer.Add(vFloat);
661 | }
662 | foreach (var index in geomData.index)
663 | {
664 | bufferData.indexBuffer.Add(index);
665 | }
666 | // UV
667 | foreach (var UV in geomData.uvs)
668 | {
669 | float uvFloat = Convert.ToSingle(UV);
670 | bufferData.uvBuffer.Add(uvFloat);
671 | }
672 |
673 | //获取顶点数据的最大值和最小值
674 | float[] vertexMinMax = Util.GetVec3MinMax(bufferData.vertexBuffer);
675 | //获取面片索引数据的最大值和最小值
676 | int[] faceMinMax = Util.GetScalarMinMax(bufferData.indexBuffer);
677 | //获取uv索引数据的最大值和最小值
678 | float[] UVMinMax = Util.GetUVMinMax(bufferData.uvBuffer);
679 |
680 | /**
681 | * BufferViews
682 | **/
683 | // Add a vec3 buffer view
684 | int elementsPerVertex = 3;
685 | int bytesPerElement = 4;
686 | int bytesPerVertex = elementsPerVertex * bytesPerElement;
687 | int numVec3 = (geomData.vertices.Count) / elementsPerVertex;
688 | int sizeOfVec3View = numVec3 * bytesPerVertex;
689 | glTFBufferView vec3View = new glTFBufferView();
690 | vec3View.buffer = bufferIdx;
691 | vec3View.byteOffset = 0;
692 | vec3View.byteLength = sizeOfVec3View;
693 | vec3View.target = Targets.ARRAY_BUFFER;
694 | BufferViews.Add(vec3View);
695 | int vec3ViewIdx = BufferViews.Count - 1;
696 |
697 | // Add a faces / indexes buffer view
698 | int elementsPerIndex = 1;
699 | int bytesPerIndexElement = 4;
700 | int bytesPerIndex = elementsPerIndex * bytesPerIndexElement;
701 | int numIndexes = geomData.index.Count;
702 | int sizeOfIndexView = numIndexes * bytesPerIndex;
703 | glTFBufferView facesView = new glTFBufferView();
704 | facesView.buffer = bufferIdx;
705 | facesView.byteOffset = vec3View.byteLength;
706 | facesView.byteLength = sizeOfIndexView;
707 | facesView.target = Targets.ELEMENT_ARRAY_BUFFER;
708 | BufferViews.Add(facesView);
709 | int facesViewIdx = BufferViews.Count - 1;
710 |
711 |
712 | // TODO: Add a uv buffer view
713 | int elementsPerUV = 2;
714 | int bytesPerElementUV = 4;
715 | int bytesPerUV = elementsPerUV * bytesPerElementUV;
716 | int numUV = (geomData.uvs.Count) / elementsPerUV;
717 | int sizeOfVec3Viewuv = numUV * bytesPerUV;
718 | glTFBufferView UVView = new glTFBufferView();
719 | UVView.buffer = bufferIdx;
720 | UVView.byteOffset = vec3View.byteLength + facesView.byteLength;
721 | UVView.byteLength = sizeOfVec3Viewuv;
722 | UVView.target = Targets.ARRAY_BUFFER;
723 | BufferViews.Add(UVView);
724 | int uvViewIdx = BufferViews.Count - 1;
725 |
726 | Buffers[bufferIdx].byteLength = vec3View.byteLength + facesView.byteLength + UVView.byteLength;
727 |
728 | /**
729 | * Accessors
730 | **/
731 | // add a position accessor
732 | glTFAccessor positionAccessor = new glTFAccessor();
733 | positionAccessor.bufferView = vec3ViewIdx;
734 | positionAccessor.byteOffset = 0;
735 | positionAccessor.componentType = ComponentType.FLOAT;
736 | positionAccessor.count = geomData.vertices.Count / elementsPerVertex;
737 | //Vec3顶点或者向量
738 | positionAccessor.type = "VEC3";
739 | positionAccessor.max = new List() { vertexMinMax[1], vertexMinMax[3], vertexMinMax[5] };
740 | positionAccessor.min = new List() { vertexMinMax[0], vertexMinMax[2], vertexMinMax[4] };
741 | Accessors.Add(positionAccessor);
742 | bufferData.vertexAccessorIndex = Accessors.Count - 1;
743 |
744 | // add a face accessor
745 | glTFAccessor faceAccessor = new glTFAccessor();
746 | faceAccessor.bufferView = facesViewIdx;
747 | faceAccessor.byteOffset = 0;
748 | faceAccessor.componentType = ComponentType.UNSIGNED_INT;
749 | faceAccessor.count = numIndexes;
750 | //SCALAR 标量
751 | faceAccessor.type = "SCALAR";
752 | faceAccessor.max = new List() { faceMinMax[1] };
753 | faceAccessor.min = new List() { faceMinMax[0] };
754 | Accessors.Add(faceAccessor);
755 | bufferData.indexAccessorIndex = Accessors.Count - 1;
756 |
757 | // add a UV accessor
758 | glTFAccessor uvsAccessor = new glTFAccessor();
759 | uvsAccessor.bufferView = uvViewIdx;
760 | uvsAccessor.byteOffset = 0;
761 | uvsAccessor.componentType = ComponentType.FLOAT;
762 | uvsAccessor.count = numUV;
763 | //Vec2 是uv坐标
764 | uvsAccessor.type = "VEC2";
765 | uvsAccessor.max = new List() { UVMinMax[1], UVMinMax[3] };
766 | uvsAccessor.min = new List() { UVMinMax[0], UVMinMax[2] };
767 | Accessors.Add(uvsAccessor);
768 | bufferData.uvAccessorIndex = Accessors.Count - 1;
769 |
770 |
771 | return bufferData;
772 | }
773 |
774 | public bool IsCanceled()
775 | {
776 | // This method is invoked many times during the export process.
777 | return false;
778 | }
779 |
780 | public RenderNodeAction OnViewBegin(ViewNode node)
781 | {
782 | return RenderNodeAction.Proceed;
783 | }
784 |
785 | public void OnViewEnd(ElementId elementId)
786 | {
787 | // do nothing
788 | }
789 |
790 | public RenderNodeAction OnLinkBegin(LinkNode node)
791 | {
792 | _transformStack.Push(CurrentTransform.Multiply(node.GetTransform()));
793 | return RenderNodeAction.Proceed;
794 | }
795 |
796 | public void OnLinkEnd(LinkNode node)
797 | {
798 | _transformStack.Pop();
799 | }
800 |
801 | public RenderNodeAction OnFaceBegin(FaceNode node)
802 | {
803 | return RenderNodeAction.Proceed;
804 | }
805 |
806 | public void OnFaceEnd(FaceNode node)
807 | {
808 | // This method is invoked only if the custom exporter was set to include faces.
809 | }
810 |
811 | public void OnRPC(RPCNode node)
812 | {
813 | // do nothing
814 | }
815 |
816 | public void OnLight(LightNode node)
817 | {
818 | // do nothing
819 | }
820 |
821 |
822 | public void getitem(ObjectData Root, List Names)
823 | {
824 | string Name = Names.First();
825 | Names.RemoveAt(0);
826 | if (Root.Children.FirstOrDefault(t => t.ElementName == Name) == null)
827 | {
828 | ObjectData ChildrenData = new ObjectData();
829 | ChildrenData.ElementName = Name;
830 | Root.Children.Add(ChildrenData);
831 | if (Names.Count > 0)
832 | {
833 | getitem(ChildrenData, Names);
834 | }
835 | else
836 | {
837 | InstanceNameData = ChildrenData;
838 | }
839 | }
840 | else
841 | {
842 | ObjectData ChildrenData = Root.Children.FirstOrDefault(t => t.ElementName == Name);
843 | if (Names.Count > 0)
844 | {
845 | getitem(ChildrenData, Names);
846 | }
847 | else
848 | {
849 | InstanceNameData = ChildrenData;
850 | }
851 | }
852 | }
853 |
854 | public void GetPoints(Element element)
855 | {
856 | List points = new List();
857 | Options options = new Options();
858 | GeometryElement geometry = element.get_Geometry(options);
859 | foreach (GeometryObject obj in geometry)
860 | {
861 | if (obj is Solid)
862 | {
863 | Solid solid = obj as Solid;
864 | DownEdge(solid);
865 | if (center != null)
866 | {
867 | break;
868 | }
869 | }
870 | else //取得族实例几何信息的方法
871 | {
872 | GeometryInstance geoInstance = obj as GeometryInstance;
873 | GeometryElement geoElement = geoInstance.GetInstanceGeometry();
874 | foreach (GeometryObject obj2 in geoElement)
875 | {
876 | Solid solid = obj2 as Solid;
877 | DownEdge(solid);
878 | if (center != null)
879 | {
880 | break;
881 | }
882 |
883 | }
884 | }
885 | }
886 | }
887 | public void DownEdge(Solid solid)
888 | {
889 |
890 | if (solid != null)
891 | {
892 | FaceArray faceArray = solid.Faces;
893 | foreach (Face face in faceArray)
894 | {
895 | PlanarFace pf = face as PlanarFace;
896 | if (pf != null && Math.Round(pf.FaceNormal.Z, 2) < 0)
897 | {
898 | EdgeArrayArray edgeArrays = face.EdgeLoops;
899 | foreach (EdgeArray edges in edgeArrays)
900 | {
901 | List ALLpoints = new List();
902 | foreach (Edge edge in edges)
903 | {
904 | List points = new List();
905 | foreach (XYZ point in edge.Tessellate())
906 | {
907 | points.Add(point.Point());
908 | ALLpoints.Add(point.Point());
909 | }
910 | //double LineLongX = (edge.Tessellate()[1].X - edge.Tessellate()[0].X) * 304.8;
911 | //double LineLongY = (edge.Tessellate()[1].Y - edge.Tessellate()[0].Y) * 304.8;
912 | //double LineLongZ = (edge.Tessellate()[1].Z - edge.Tessellate()[0].Z) * 304.8;
913 | //EdgesPoints.AddOrUpdateCurrent
914 | // (Math.Round(Math.Sqrt(LineLongX * LineLongX + LineLongY * LineLongY + LineLongZ * LineLongZ)).ToString(), points);
915 | }
916 | //去除重复顶点
917 | HashSet NeWpoints = new HashSet(ALLpoints);
918 | center = GetCenter(NeWpoints.ToList());
919 | //currentData.ElementLocation.Add(GetCenter(NeWpoints.ToList());
920 | //EdgesPoints.AddOrUpdateCurrent("中心点", new List { (GetCenter(NeWpoints.ToList())) });
921 | //EdgesPoints.AddOrUpdateCurrent("向量", new List { (-pf.FaceNormal).Point() });
922 | break;
923 | }
924 | break;
925 | }
926 | }
927 | }
928 | }
929 |
930 | public string GetCenter(List PLPoint)
931 | {
932 | double SumX = 0;
933 | double SumY = 0;
934 | double SumZ = 0;
935 | for (int i = 0; i < PLPoint.Count; i++)
936 | {
937 | string[] Points = PLPoint[i].Split(new char[] { ',' });
938 |
939 | SumX += Convert.ToDouble(Points[0]);
940 | SumY += Convert.ToDouble(Points[1]);
941 | SumZ += Convert.ToDouble(Points[2]);
942 | }
943 | double Xc = SumX / (PLPoint.Count);
944 | double Yc = SumY / (PLPoint.Count);
945 | double Zc = SumZ / (PLPoint.Count);
946 | return string.Format("{0},{1},{2}", Xc, Yc, Zc);
947 | }
948 | public double[] RotateByVector(double old_x, double old_y, double old_z, double vx, double vy, double vz, double theta)
949 | {
950 | double[] NewPoint = new double[3];
951 | double c = Math.Cos(theta);
952 | double s = Math.Sin(theta);
953 | NewPoint[0] = (vx * vx * (1 - c) + c) * old_x + (vx * vy * (1 - c) - vz * s) * old_y + (vx * vz * (1 - c) + vy * s) * old_z;
954 | NewPoint[1] = (vy * vx * (1 - c) + vz * s) * old_x + (vy * vy * (1 - c) + c) * old_y + (vy * vz * (1 - c) - vx * s) * old_z;
955 | NewPoint[2] = (vx * vz * (1 - c) - vy * s) * old_x + (vy * vz * (1 - c) + vx * s) * old_y + (vz * vz * (1 - c) + c) * old_z;
956 | return NewPoint;
957 | }
958 |
959 | ///
960 | /// 自定义方法,用递归找到包含贴图信息:
961 | ///
962 | ///
963 | ///
964 | private Asset FindTextureAsset(AssetProperty ap)
965 | {
966 | Asset result = null;
967 | if (ap.Type == AssetPropertyType.Asset)
968 | {
969 | if (!IsTextureAsset(ap as Asset))
970 | {
971 | for (int i = 0; i < (ap as Asset).Size; i++)
972 | {
973 | if (null != FindTextureAsset((ap as Asset)[i]))
974 | {
975 | result = FindTextureAsset((ap as Asset)[i]);
976 | break;
977 | }
978 | }
979 | }
980 | else
981 | {
982 | result = ap as Asset;
983 | }
984 | return result;
985 | }
986 | else
987 | {
988 | for (int j = 0; j < ap.NumberOfConnectedProperties; j++)
989 | {
990 | if (null != FindTextureAsset(ap.GetConnectedProperty(j)))
991 | {
992 | result = FindTextureAsset(ap.GetConnectedProperty(j));
993 | }
994 | }
995 | return result;
996 | }
997 | }
998 |
999 | ///
1000 | /// 自定义方法,判断Asset是否包含贴图信息:
1001 | ///
1002 | ///
1003 | ///
1004 | private bool IsTextureAsset(Asset asset)
1005 | {
1006 | AssetProperty assetProprty = GetAssetProprty(asset, "assettype");
1007 | if (assetProprty != null && (assetProprty as AssetPropertyString).Value == "texture")
1008 | {
1009 | return true;
1010 | }
1011 | return GetAssetProprty(asset, "unifiedbitmap_Bitmap") != null;
1012 | }
1013 |
1014 | ///
1015 | /// 自定义方法,根据名字获取对应的AssetProprty:
1016 | ///
1017 | ///
1018 | ///
1019 | ///
1020 | private AssetProperty GetAssetProprty(Asset asset, string propertyName)
1021 | {
1022 | for (int i = 0; i < asset.Size; i++)
1023 | {
1024 | if (asset[i].Name == propertyName)
1025 | {
1026 | return asset[i];
1027 | }
1028 | }
1029 | return null;
1030 | }
1031 | }
1032 | }
1033 |
--------------------------------------------------------------------------------
/Util.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using Autodesk.Revit.DB;
5 |
6 | namespace RevitExportGltf
7 | {
8 | static class Util
9 | {
10 | ///
11 | /// c# 的扩展方法
12 | ///
13 | ///
14 | ///
15 | public static string Point(this XYZ p)
16 | {
17 | return string.Format("{0}", "{1}", "{2}", Math.Round(p.X, 2), Math.Round(p.Y, 2), Math.Round(p.Z, 2));
18 | }
19 |
20 |
21 | public static int[] GetVec3MinMax(List vec3)
22 | {
23 | int minVertexX = int.MaxValue;
24 | int minVertexY = int.MaxValue;
25 | int minVertexZ = int.MaxValue;
26 | int maxVertexX = int.MinValue;
27 | int maxVertexY = int.MinValue;
28 | int maxVertexZ = int.MinValue;
29 | for (int i = 0; i < vec3.Count; i += 3)
30 | {
31 | if (vec3[i] < minVertexX) minVertexX = vec3[i];
32 | if (vec3[i] > maxVertexX) maxVertexX = vec3[i];
33 |
34 | if (vec3[i + 1] < minVertexY) minVertexY = vec3[i + 1];
35 | if (vec3[i + 1] > maxVertexY) maxVertexY = vec3[i + 1];
36 |
37 | if (vec3[i + 2] < minVertexZ) minVertexZ = vec3[i + 2];
38 | if (vec3[i + 2] > maxVertexZ) maxVertexZ = vec3[i + 2];
39 | }
40 | return new int[] { minVertexX, maxVertexX, minVertexY, maxVertexY, minVertexZ, maxVertexZ };
41 | }
42 |
43 | public static long[] GetVec3MinMax(List vec3)
44 | {
45 | long minVertexX = long.MaxValue;
46 | long minVertexY = long.MaxValue;
47 | long minVertexZ = long.MaxValue;
48 | long maxVertexX = long.MinValue;
49 | long maxVertexY = long.MinValue;
50 | long maxVertexZ = long.MinValue;
51 | for (int i = 0; i < (vec3.Count / 3); i += 3)
52 | {
53 | if (vec3[i] < minVertexX) minVertexX = vec3[i];
54 | if (vec3[i] > maxVertexX) maxVertexX = vec3[i];
55 |
56 | if (vec3[i + 1] < minVertexY) minVertexY = vec3[i + 1];
57 | if (vec3[i + 1] > maxVertexY) maxVertexY = vec3[i + 1];
58 |
59 | if (vec3[i + 2] < minVertexZ) minVertexZ = vec3[i + 2];
60 | if (vec3[i + 2] > maxVertexZ) maxVertexZ = vec3[i + 2];
61 | }
62 | return new long[] { minVertexX, maxVertexX, minVertexY, maxVertexY, minVertexZ, maxVertexZ };
63 | }
64 |
65 | public static float[] GetVec3MinMax(List vec3)
66 | {
67 |
68 | List xValues = new List();
69 | List yValues = new List();
70 | List zValues = new List();
71 | for (int i = 0; i < vec3.Count; i++)
72 | {
73 | if ((i % 3) == 0) xValues.Add(vec3[i]);
74 | if ((i % 3) == 1) yValues.Add(vec3[i]);
75 | if ((i % 3) == 2) zValues.Add(vec3[i]);
76 | }
77 |
78 | float maxX = xValues.Max();
79 | float minX = xValues.Min();
80 | float maxY = yValues.Max();
81 | float minY = yValues.Min();
82 | float maxZ = zValues.Max();
83 | float minZ = zValues.Min();
84 |
85 | return new float[] { minX, maxX, minY, maxY, minZ, maxZ };
86 | }
87 |
88 | public static int[] GetScalarMinMax(List scalars)
89 | {
90 | int minFaceIndex = int.MaxValue;
91 | int maxFaceIndex = int.MinValue;
92 | for (int i = 0; i < scalars.Count; i++)
93 | {
94 | int currentMin = Math.Min(minFaceIndex, scalars[i]);
95 | if (currentMin < minFaceIndex) minFaceIndex = currentMin;
96 |
97 | int currentMax = Math.Max(maxFaceIndex, scalars[i]);
98 | if (currentMax > maxFaceIndex) maxFaceIndex = currentMax;
99 | }
100 | return new int[] { minFaceIndex, maxFaceIndex };
101 | }
102 |
103 | public static float[] GetUVMinMax(List vec3)
104 | {
105 |
106 | List xValues = new List();
107 | List yValues = new List();
108 | for (int i = 0; i < vec3.Count; i++)
109 | {
110 | if ((i % 2) == 0) xValues.Add(vec3[i]);
111 | if ((i % 2) == 1) yValues.Add(vec3[i]);
112 | }
113 | float maxX = xValues.Max();
114 | float minX = xValues.Min();
115 | float maxY = yValues.Max();
116 | float minY = yValues.Min();
117 | return new float[] { minX, maxX, minY, maxY };
118 | }
119 |
120 | ///
121 | /// From Jeremy Tammik's RvtVa3c exporter:
122 | /// https://github.com/va3c/RvtVa3c
123 | /// Return a string for a real number
124 | /// formatted to two decimal places.
125 | ///
126 | public static string RealString(double a)
127 | {
128 | return a.ToString("0.##");
129 | }
130 |
131 | ///
132 | /// From Jeremy Tammik's RvtVa3c exporter:
133 | /// https://github.com/va3c/RvtVa3c
134 | /// Return a string for an XYZ point
135 | /// or vector with its coordinates
136 | /// formatted to two decimal places.
137 | ///
138 | public static string PointString(XYZ p)
139 | {
140 | return string.Format("({0},{1},{2})",
141 | RealString(p.X),
142 | RealString(p.Y),
143 | RealString(p.Z));
144 | }
145 |
146 | ///
147 | /// From Jeremy Tammik's RvtVa3c exporter:
148 | /// https://github.com/va3c/RvtVa3c
149 | /// Return an integer value for a Revit Color.
150 | ///
151 | public static int ColorToInt(Color color)
152 | {
153 | return ((int)color.Red) << 16
154 | | ((int)color.Green) << 8
155 | | (int)color.Blue;
156 | }
157 |
158 | ///
159 | /// From Jeremy Tammik's RvtVa3c exporter:
160 | /// https://github.com/va3c/RvtVa3c
161 | /// Extract a true or false value from the given
162 | /// string, accepting yes/no, Y/N, true/false, T/F
163 | /// and 1/0. We are extremely tolerant, i.e., any
164 | /// value starting with one of the characters y, n,
165 | /// t or f is also accepted. Return false if no
166 | /// valid Boolean value can be extracted.
167 | ///
168 | public static bool GetTrueOrFalse(string s, out bool val)
169 | {
170 | val = false;
171 |
172 | if (s.Equals(Boolean.TrueString,
173 | StringComparison.OrdinalIgnoreCase))
174 | {
175 | val = true;
176 | return true;
177 | }
178 | if (s.Equals(Boolean.FalseString,
179 | StringComparison.OrdinalIgnoreCase))
180 | {
181 | return true;
182 | }
183 | if (s.Equals("1"))
184 | {
185 | val = true;
186 | return true;
187 | }
188 | if (s.Equals("0"))
189 | {
190 | return true;
191 | }
192 | s = s.ToLower();
193 |
194 | if ('t' == s[0] || 'y' == s[0])
195 | {
196 | val = true;
197 | return true;
198 | }
199 | if ('f' == s[0] || 'n' == s[0])
200 | {
201 | return true;
202 | }
203 | return false;
204 | }
205 |
206 | ///
207 | /// From Jeremy Tammik's RvtVa3c exporter:
208 | /// https://github.com/va3c/RvtVa3c
209 | /// Return a string describing the given element:
210 | /// .NET type name,
211 | /// category name,
212 | /// family and symbol name for a family instance,
213 | /// element id and element name.
214 | ///
215 | public static string ElementDescription(Element e)
216 | {
217 | if (null == e)
218 | {
219 | return "";
220 | }
221 |
222 | // For a wall, the element name equals the
223 | // wall type name, which is equivalent to the
224 | // family name ...
225 |
226 | FamilyInstance fi = e as FamilyInstance;
227 |
228 | string typeName = e.GetType().Name;
229 |
230 | string categoryName = (null == e.Category)
231 | ? string.Empty
232 | : e.Category.Name + " ";
233 |
234 | string familyName = (null == fi)
235 | ? string.Empty
236 | : fi.Symbol.Family.Name + " ";
237 |
238 | string symbolName = (null == fi
239 | || e.Name.Equals(fi.Symbol.Name))
240 | ? string.Empty
241 | : fi.Symbol.Name + " ";
242 |
243 | return string.Format("{0} {1}{2}{3}<{4} {5}>",
244 | typeName, categoryName, familyName,
245 | symbolName, e.Id.IntegerValue, e.Name);
246 | }
247 |
248 | ///
249 | /// From Jeremy Tammik's RvtVa3c exporter:
250 | /// https://github.com/va3c/RvtVa3c
251 | /// Return a dictionary of all the given
252 | /// element parameter names and values.
253 | ///
254 | public static Dictionary GetElementProperties(Element e, bool includeType)
255 | {
256 | IList parameters
257 | = e.GetOrderedParameters();
258 |
259 | Dictionary a = new Dictionary(parameters.Count);
260 |
261 | // Add element category
262 | a.Add("Element Category", e.Category.Name);
263 |
264 | string key;
265 | string val;
266 |
267 | foreach (Parameter p in parameters)
268 | {
269 | key = p.Definition.Name;
270 |
271 | if (!a.ContainsKey(key))
272 | {
273 | if (StorageType.String == p.StorageType)
274 | {
275 | val = p.AsString();
276 | }
277 | else
278 | {
279 | val = p.AsValueString();
280 | }
281 | if (!string.IsNullOrEmpty(val))
282 | {
283 | a.Add(key, val);
284 | }
285 | }
286 | }
287 |
288 | if (includeType)
289 | {
290 | ElementId idType = e.GetTypeId();
291 |
292 | if (ElementId.InvalidElementId != idType)
293 | {
294 | Document doc = e.Document;
295 | Element typ = doc.GetElement(idType);
296 | parameters = typ.GetOrderedParameters();
297 | foreach (Parameter p in parameters)
298 | {
299 | key = "Type " + p.Definition.Name;
300 |
301 | if (!a.ContainsKey(key))
302 | {
303 | if (StorageType.String == p.StorageType)
304 | {
305 | val = p.AsString();
306 | }
307 | else
308 | {
309 | val = p.AsValueString();
310 | }
311 | if (!string.IsNullOrEmpty(val))
312 | {
313 | a.Add(key, val);
314 | }
315 | }
316 | }
317 | }
318 | }
319 | return a;
320 | }
321 | }
322 | }
323 |
--------------------------------------------------------------------------------
/WPF/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/WPF/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace RevitExportGltf
17 | {
18 | ///
19 | /// MainWindow.xaml 的交互逻辑
20 | ///
21 | public partial class MainWindow : Window
22 | {
23 | public MainWindow()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/glTF.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RevitExportGltf
8 | {
9 | #region glTF格式组成
10 | ///
11 | /// The json serializable glTF file format.
12 | /// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
13 | ///
14 | public struct glTF
15 | {
16 | public glTFVersion asset;
17 | public List scenes;
18 | public List nodes;
19 | public List meshes;
20 | public List buffers;
21 | public List bufferViews;
22 | public List accessors;
23 | public List materials;
24 | public List textures;
25 | public List images;
26 | public List samplers;
27 | }
28 |
29 | ///
30 | /// 版本
31 | ///
32 | public class glTFVersion
33 | {
34 | public string version = "2.0";
35 | }
36 | ///
37 | /// 场景
38 | ///
39 | public class glTFScene
40 | {
41 | public List nodes = new List();
42 | }
43 |
44 | ///
45 | ///场景中的节点
46 | ///
47 | public class glTFNode
48 | {
49 | public string name { get; set; }
50 | ///
51 | /// mesh个数
52 | ///
53 | public int? mesh { get; set; } = null;
54 | ///
55 | /// 矩阵
56 | ///
57 | public List matrix { get; set; }
58 |
59 |
60 | ///
61 | /// 旋转
62 | ///
63 | public List rotation { get; set; }
64 |
65 | ///
66 | /// 平移
67 | ///
68 | public List translation { get; set; }
69 |
70 |
71 | ///
72 | ///
73 | ///
74 | public List children { get; set; }
75 | ///
76 | ///附加属性
77 | ///
78 | // public glTFExtras extras { get; set; }
79 | }
80 |
81 |
82 | ///
83 | /// 网格
84 | ///
85 | public class glTFMesh
86 | {
87 | public List primitives { get; set; }
88 | }
89 |
90 |
91 | ///
92 | /// 属性定义GPU应该在哪里寻找网格和材质数据。
93 | ///
94 | public class glTFMeshPrimitive
95 | {
96 | public glTFAttribute attributes { get; set; } = new glTFAttribute();
97 | public int indices { get; set; }
98 | public int? material { get; set; } = null;
99 | public int mode { get; set; } = 4; // 4 is triangles
100 | }
101 |
102 | public class glTFAttribute
103 | {
104 | ///
105 | ///位置数据访问器的索引。
106 | ///
107 | public int POSITION { get; set; }
108 |
109 | ///
110 | /// 第一组UV坐标
111 | ///
112 | public int TEXCOORD_0 { get; set; }
113 |
114 | //public int NORMAL { get; set; }
115 | }
116 |
117 | ///
118 | ///对二进制数据的位置和大小的引用。
119 | ///
120 | public class glTFBuffer
121 | {
122 | ///
123 | /// The uri of the buffer.
124 | ///
125 | public string uri { get; set; }
126 | ///
127 | /// The total byte length of the buffer.
128 | ///
129 | public int byteLength { get; set; }
130 | }
131 |
132 | ///
133 | /// 对包含矢量或标量数据的缓冲区的分段的引用。
134 | ///
135 | public class glTFBufferView
136 | {
137 | ///
138 | /// 缓冲区的索引。
139 | ///
140 | public int buffer { get; set; }
141 | ///
142 | /// 缓冲区的偏移量(以字节为单位)。
143 | ///
144 | public int byteOffset { get; set; }
145 | ///
146 | /// bufferView的长度,以字节为单位。
147 | ///
148 | public int byteLength { get; set; }
149 | ///
150 | /// GPU缓冲区应该绑定到的目标。
151 | ///
152 | public Targets target { get; set; }
153 | ///
154 | /// A user defined name for this view.
155 | ///
156 | public string name { get; set; }
157 | }
158 |
159 | ///
160 | /// 逻辑数字来区分标量和矢量数组buff。
161 | /// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#buffers-and-buffer-views
162 | ///
163 | public enum Targets
164 | {
165 | ARRAY_BUFFER = 34962, // signals vertex data
166 | ELEMENT_ARRAY_BUFFER = 34963 // signals index or face data
167 | }
168 |
169 | ///
170 | /// 逻辑数值以区分数组buff组件类型。
171 | /// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#accessor-element-size
172 | ///
173 | public enum ComponentType
174 | {
175 | BYTE = 5120,
176 | UNSIGNED_BYTE = 5121,
177 | SHORT = 5122,
178 | UNSIGNED_SHORT = 5123,
179 | UNSIGNED_INT = 5125,
180 | FLOAT = 5126
181 | }
182 |
183 |
184 | ///
185 | /// 对包含特定数据类型的BufferView分段的引用。
186 | ///
187 | public class glTFAccessor
188 | {
189 | ///
190 | ///缓冲视图的索引
191 | ///
192 | public int bufferView { get; set; }
193 | ///
194 | /// 相对于bufferView开始的偏移量(以字节为单位)。
195 | ///
196 | public int byteOffset { get; set; }
197 | ///
198 | /// 属性中组件的数据类型
199 | ///
200 | public ComponentType componentType { get; set; }
201 | ///
202 | /// 此访问器引用的属性数量。
203 | ///
204 | public int count { get; set; }
205 | ///
206 | /// 指定属性是scala、向量还是矩阵
207 | ///
208 | public string type { get; set; }
209 | ///
210 | /// 此属性中每个组件的最大值。
211 | ///
212 | public List max { get; set; }
213 | ///
214 | /// 此属性中每个组件的最小值。
215 | ///
216 | public List min { get; set; }
217 | ///
218 | /// 此访问器的用户定义名称。
219 | ///
220 | public string name { get; set; }
221 | }
222 |
223 |
224 | ///
225 | /// 材质
226 | ///
227 | public class glTFMaterial
228 | {
229 | public string name { get; set; }
230 | public glTFPBR pbrMetallicRoughness { get; set; }
231 | public string alphaMode { get; set; }
232 | public string doubleSided { get; set; }
233 | }
234 |
235 |
236 | public class glTFPBR
237 | {
238 | //材质贴图
239 | public glTFbaseColorTexture baseColorTexture { get; set; }
240 |
241 | //材质颜色索引
242 | public List baseColorFactor { get; set; }
243 | //材质金属性
244 | public float metallicFactor { get; set; }
245 | //材质粗糙度
246 | public float roughnessFactor { get; set; }
247 | }
248 |
249 |
250 | public class glTFbaseColorTexture
251 | {
252 | //贴图索引
253 | public int? index { get; set; } = null;
254 | }
255 |
256 |
257 | ///
258 | /// 每个texture对象可以用于多个材质对象
259 | ///
260 | public class glTFTexture
261 | {
262 | ///
263 | /// glTFImage的索引号
264 | ///
265 | public int? source { get; set; } = null;
266 | ///
267 | /// glTFSampler的索引号
268 | ///
269 | public int? sampler { get; set; } = null;
270 |
271 | }
272 |
273 | public class glTFImage
274 | {
275 | public string uri { get; set; }
276 |
277 | }
278 |
279 | public class glTFSampler
280 | {
281 | public float magFilter { get; set; }
282 |
283 | public float minFilter { get; set; }
284 | public float wrapS { get; set; }
285 | public float wrapT { get; set; }
286 | }
287 |
288 |
289 | #endregion
290 |
291 |
292 | #region bin文件
293 | ///
294 | /// A binary data store serialized to a *.bin file
295 | /// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#binary-data-storage
296 | ///
297 | public class GeometryData
298 | {
299 | public List vertices = new List();
300 | public List normals = new List();
301 | public List uvs = new List();
302 | public List index = new List();
303 | }
304 |
305 |
306 | ///
307 | /// *.bin文件
308 | ///
309 | public class glTFBinaryData
310 | {
311 | public List vertexBuffer { get; set; } = new List();
312 | public List indexBuffer { get; set; } = new List();
313 | //public List normalBuffer { get; set; } = new List();
314 |
315 | public List uvBuffer { get; set; } = new List();
316 | public int vertexAccessorIndex { get; set; }
317 | public int indexAccessorIndex { get; set; }
318 |
319 | public int uvAccessorIndex { get; set; }
320 |
321 | //public int normalsAccessorIndex { get; set; }
322 | public string name { get; set; }
323 | }
324 | #endregion
325 |
326 | }
327 |
--------------------------------------------------------------------------------
/libs/Revit2018/RevitAPI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/libs/Revit2018/RevitAPI.dll
--------------------------------------------------------------------------------
/libs/Revit2018/RevitAPIUI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/libs/Revit2018/RevitAPIUI.dll
--------------------------------------------------------------------------------
/libs/Revit2018/UIFrameworkServices.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/libs/Revit2018/UIFrameworkServices.dll
--------------------------------------------------------------------------------
/libs/Revit2020/RevitAPI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/libs/Revit2020/RevitAPI.dll
--------------------------------------------------------------------------------
/libs/Revit2020/RevitAPIUI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/libs/Revit2020/RevitAPIUI.dll
--------------------------------------------------------------------------------
/libs/Revit2020/UIFrameworkServices.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/libs/Revit2020/UIFrameworkServices.dll
--------------------------------------------------------------------------------
/libs/SharpGLTF/SharpGLTF.Core.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/libs/SharpGLTF/SharpGLTF.Core.dll
--------------------------------------------------------------------------------
/libs/SharpGLTF/SharpGLTF.Toolkit.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/libs/SharpGLTF/SharpGLTF.Toolkit.dll
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/.signature.p7s:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/.signature.p7s
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2007 James Newton-King
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/Newtonsoft.Json.13.0.1.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/Newtonsoft.Json.13.0.1.nupkg
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/lib/net20/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/lib/net20/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/lib/net35/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/lib/net35/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/lib/net40/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/lib/net40/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/lib/net45/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/lib/net45/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.0/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.0/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.3/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/lib/netstandard1.3/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/lib/netstandard2.0/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/lib/netstandard2.0/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/packages/Newtonsoft.Json.13.0.1/packageIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/weiyu666/RevitExportGltf/96a55b45a41660d34b547ecaf4eeb64efc152d6a/packages/Newtonsoft.Json.13.0.1/packageIcon.png
--------------------------------------------------------------------------------