├── .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 | 20201222165653 8 | 9 | 10 | 11 | 运行成功如下图,还有返回的信息: 12 | 13 | 20201222165214 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 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /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 --------------------------------------------------------------------------------