├── .gitignore
├── Images
├── 1.JPG
└── 2.JPG
├── LICENSE
├── README.md
├── Revit2Gltf.Plugin
├── AddinApplication.cs
├── Commands
│ └── ExportToGltfCommand.cs
├── PackageContents.xml
├── PluginController.cs
├── Properties
│ └── AssemblyInfo.cs
├── Resources
│ └── icons8-upload-to-cloud-32.png
├── Revit2Gltf.Plugin.csproj
├── Revit2Gltf.addin
└── packages.config
├── Revit2Gltf.sln
├── Revit2Gltf
├── AssetPropertyDescriptor.cs
├── AssimpUtilities.cs
├── CentroidVolume.cs
├── Configuration.cs
├── Enums.cs
├── Extensions.cs
├── GeometryExtensions.cs
├── MaterialUtilities.cs
├── Properties
│ └── AssemblyInfo.cs
├── RenderAppearanceDescriptor.cs
├── Resources
│ └── icons8-upload-to-cloud-32.png
├── Revit2Gltf.csproj
├── SafenedFilename.cs
├── TextureBundle.cs
└── packages.config
└── ThirdParty
├── API
├── 2015
│ ├── RevitAPI.dll
│ ├── RevitAPIIFC.dll
│ └── RevitAPIUI.dll
├── 2016
│ ├── RevitAPI.dll
│ ├── RevitAPIIFC.dll
│ └── RevitAPIUI.dll
├── 2017
│ ├── RevitAPI.dll
│ ├── RevitAPIIFC.dll
│ └── RevitAPIUI.dll
├── 2018
│ ├── RevitAPI.dll
│ ├── RevitAPIIFC.dll
│ └── RevitAPIUI.dll
├── 2019
│ ├── RevitAPI.dll
│ ├── RevitAPIIFC.dll
│ └── RevitAPIUI.dll
└── 2020
│ ├── RevitAPI.dll
│ ├── RevitAPIIFC.dll
│ └── RevitAPIUI.dll
└── Snappy
├── Crc32C.NET.dll
└── Snappy.NET.dll
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 |
--------------------------------------------------------------------------------
/Images/1.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/Images/1.JPG
--------------------------------------------------------------------------------
/Images/2.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/Images/2.JPG
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Revit2Gltf
2 | Open source converter and plugin for Revit files to gLTF. Created by [Cityzenith](http://www.cityzenith.com) for seeding digital twins.
3 |
4 | 
5 |
6 | ## Why gLTF?
7 | gLTF is a portable 3d object schema produced by Khronos Group which combines high performance, portability and human-readability.
8 | Its accepted by many softwares and can be used in JS 3d viewers such as Three and Babylon.
9 |
10 | gLTFs consist of two key parts:
11 |
12 | - myfile.gltf <- Contains the model's heirarchy and metadata in JSON.
13 |
14 | - myfile.bin <- A binary of the model's geometry ("buffer"), intended to be efficiently compressed for portability and performance. This is explicitly referred to in the .gltf file, so don't change the name of this file without changing the reference in the .gltf file!
15 |
16 | and...
17 |
18 | - everythingelse <- Your textures and linked files specified within the .gltf
19 |
20 | You can add further compression with processes such as [DRACO](https://google.github.io/draco/)
21 |
22 | ## How to use
23 |
24 | ### Exporting a gLTF
25 | - Clone the repository
26 | - Restore NuGet packages
27 | - Build the solution
28 | - Hit the Export To Gltf button in the Cityzenith tab and you'll have your GLTF.
29 | - Enjoy it!
30 |
31 | ### Adding gLTF export to your plugin
32 | - Include the Revit2Gltf library in your solution (NuGet package coming soon!)
33 | - Use the ExportToGltf method to convert your document to a gltf model.
34 | - Use Assimp.Net's library to access and modify the contents of the gltf model while loaded into memory.
35 |
36 | ## Caveats
37 | - Tested only in Revit 2016 (Licenses are expensive!) but should work 99% perfectly on other platforms. Compiler conditionals are set up for breaking API changes such as in Revit 2020
38 | - Not all colors and textures are exported correctly. If you take a close look inside the sausage you'll see why - a lot of digging around with magic strings to get at these resources. Although we will gradually improve this, guidance welcomed here
39 |
40 | #### Maintained by Leland Jobson (gh: lelandjobson)
41 |
--------------------------------------------------------------------------------
/Revit2Gltf.Plugin/AddinApplication.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.UI;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Revit2Gltf.Plugin
9 | {
10 | class AddinApplication : IExternalApplication
11 | {
12 | public static PluginController Controller;
13 |
14 | public Result OnStartup(UIControlledApplication application)
15 | {
16 | Controller = new PluginController(application);
17 | return Result.Succeeded;
18 | }
19 |
20 | public Result OnShutdown(UIControlledApplication application)
21 | {
22 | return Result.Succeeded;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Revit2Gltf.Plugin/Commands/ExportToGltfCommand.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.Attributes;
2 | using Autodesk.Revit.DB;
3 | using Autodesk.Revit.UI;
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 |
13 | namespace Revit2Gltf.Plugin.Commands
14 | {
15 | ///
16 | ///
17 | ///
18 | [Transaction(TransactionMode.Manual)]
19 | class ExportToGltfCommand : IExternalCommand
20 | {
21 | ///
22 | ///
23 | ///
24 | ///
25 | ///
26 | ///
27 | ///
28 | Result IExternalCommand.Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
29 | {
30 | if (!TryGetActiveDocument(commandData, out Autodesk.Revit.DB.Document docToExport)) { return Result.Failed; }
31 | if (!TryGetDefaultView(docToExport, out View viewToExport)) { return Result.Failed; }
32 |
33 |
34 | // Grab doc name
35 | string docName = Path.GetFileNameWithoutExtension(docToExport.Title);
36 |
37 | // Prep FBX export
38 | var vs = new ViewSet();
39 | vs.Insert(viewToExport);
40 |
41 | // Grab configuration
42 | var configuration = ConfigurationManager.ActiveConfiguration;
43 |
44 | // Create a new folder for the export
45 | configuration.ExportFilePathRoot = $"C:/Cityzenith/{docName}";
46 | if (!Directory.Exists(configuration.ExportFilePathRoot))
47 | {
48 | Directory.CreateDirectory(configuration.ExportFilePathRoot);
49 | }
50 |
51 | // Export FBX file
52 | docToExport.Export(
53 | configuration.ExportFilePathRoot,
54 | docName,
55 | vs,
56 | new FBXExportOptions()
57 | {
58 | LevelsOfDetailValue = 15,
59 | UseLevelsOfDetail = true,
60 | WithoutBoundaryEdges = true
61 | }
62 | );
63 |
64 |
65 |
66 | // Check that file was created successfully
67 | var fbxFileName = configuration.ExportFilePathRoot + "/" + docName + ".fbx";
68 | if (!System.IO.File.Exists(fbxFileName)) { return Result.Failed; }
69 | var fbxModel = AssimpUtilities.LoadFbx(fbxFileName);
70 |
71 | // Get conversions between local ids
72 | var localToUniqueIdMap = docToExport.ExportableElements()
73 | .ToDictionary(e => e.Id.ToString(), e => e.UniqueId.ToString());
74 |
75 | // Replace auto-generated element names in Fbx with unqiue ids from revit doc
76 | AssimpUtilities.ReplaceNamesWithUniqueIds(fbxModel, localToUniqueIdMap);
77 |
78 | // Create textures subfolder
79 | string textureDirPath = configuration.ExportFilePathRoot + '/' + "Textures";
80 | if (!Directory.Exists(textureDirPath)) { Directory.CreateDirectory(textureDirPath); }
81 |
82 | var bundles = MaterialUtilities.GetTextureBundles(docToExport, out var paths);
83 | foreach (var b in bundles)
84 | {
85 | // Create material
86 | var assimpMaterial = AssimpUtilities.ConvertToAssimpMaterial(b, docToExport);
87 |
88 | // Add material to model and assign
89 | AssimpUtilities.AddAndAssignMaterial(
90 | fbxModel,
91 | assimpMaterial,
92 | docToExport.ExportableElements().Where(e =>
93 | {
94 | var id = e.GetMaterialIds(false).FirstOrDefault();
95 | if (id != null && id == b.Material.Id) { return true; }
96 | return false;
97 | })
98 | .Select(e => e.UniqueId.ToString())
99 | .ToHashSet()
100 | , out bool utilized);
101 |
102 | if (!utilized) { continue; }
103 |
104 | // Copy textures into textures folder
105 | foreach (var path in b.TexturePaths.Values)
106 | {
107 | string destination = $"{textureDirPath}/{path.SafeFileName}";
108 | try
109 | {
110 | File.Copy(path.FileLocation, destination, true);
111 | }
112 | catch (Exception e)
113 | {
114 | // This is likely due to duplicate materials copied in.
115 | // This could also be an access issue, but less commonly.
116 | //Logger.LogException("Error in copying textures: ", e);
117 | }
118 | }
119 | }
120 |
121 | // Grab all element data
122 | var paramData = docToExport.SiphonElementParamValues(out var legend);
123 | var combined = paramData.Values.Combine();
124 | JsonConvert.SerializeObject(combined).WriteToFile($"{configuration.ExportFilePathRoot}/Params.json");
125 | JsonConvert.SerializeObject(legend).WriteToFile($"{configuration.ExportFilePathRoot}/Legend.json");
126 |
127 | // Write out gltf
128 | AssimpUtilities.SaveToGltf(fbxModel, $"{configuration.ExportFilePathRoot}", docName);
129 |
130 | // Delete .FBX
131 | File.Delete(fbxFileName);
132 |
133 | // Let em know!
134 | TaskDialog dlg = new TaskDialog("Export Successful");
135 | dlg.MainInstruction = $"Gltf file exported successfully: \n\n {configuration.ExportFilePathRoot}";
136 | dlg.Show();
137 |
138 | Process.Start(configuration.ExportFilePathRoot);
139 |
140 | return Result.Succeeded;
141 | }
142 |
143 | private bool TryGetDefaultView(Document docToExport, out View viewToExport)
144 | {
145 | // view to export
146 | viewToExport = null;
147 | //#if !REVIT2020
148 | viewToExport = docToExport.GetOrCreateDefault3DView();
149 | //#else
150 | // viewToExport = AddinApplication.UIController.GetCurrentView(docToExport);
151 | //#endif
152 | if (viewToExport == null)
153 | {
154 | return false;
155 | }
156 |
157 | // Set view settings
158 | using (var tr = new Transaction(docToExport))
159 | {
160 | tr.Start("Changing view settings to realistic");
161 | viewToExport.DetailLevel = ViewDetailLevel.Fine;
162 | viewToExport.DisplayStyle = DisplayStyle.Realistic;
163 | tr.Commit();
164 | }
165 |
166 | return true;
167 | }
168 |
169 | private bool TryGetActiveDocument(ExternalCommandData commandData, out Document docToExport)
170 | {
171 | // document to export
172 | docToExport = commandData.Application.ActiveUIDocument.Document;
173 | if (docToExport == null)
174 | {
175 | return false;
176 | }
177 | return true;
178 | }
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/Revit2Gltf.Plugin/PackageContents.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 |
--------------------------------------------------------------------------------
/Revit2Gltf.Plugin/PluginController.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using Autodesk.Revit.UI;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Media.Imaging;
10 |
11 | namespace Revit2Gltf.Plugin
12 | {
13 | internal class PluginController
14 | {
15 | private const string RibbonTabName = "Cityzenith";
16 | private const string SWPRibbonPanelName = "Revit To Gltf";
17 | private const string ExportButtonName = " Export To Gltf ";
18 |
19 | private static string _thisAssemblyPath = Assembly.GetExecutingAssembly().Location;
20 |
21 | ///
22 | /// The export button
23 | ///
24 | PushButton Btn_Export { get; set; }
25 |
26 |
27 | public PluginController(UIControlledApplication application)
28 | {
29 | CreateUI(application);
30 | }
31 |
32 | private void CreateUI(UIControlledApplication application)
33 | {
34 | application.ViewActivated += Application_ViewActivated;
35 |
36 | try
37 | {
38 | application.CreateRibbonTab(RibbonTabName);
39 | }
40 | // This exception is usually thrown because the
41 | // ribbontab of the same name already exists.
42 | catch { }
43 |
44 | RibbonPanel panel = application.CreateRibbonPanel(RibbonTabName, SWPRibbonPanelName);
45 |
46 | AddExportButton();
47 |
48 | #region Button Fns
49 | void AddExportButton()
50 | {
51 | PushButtonData pbd = new PushButtonData(
52 | "ExportToGltf",
53 | ExportButtonName,
54 | _thisAssemblyPath,
55 | "Revit2Gltf.Plugin.Commands.ExportToGltfCommand");
56 | Btn_Export = panel.AddItem(pbd) as PushButton;
57 | Btn_Export.ToolTip = "Exports the 3D view to GLTF";
58 | Btn_Export.LargeImage = new BitmapImage(new Uri("pack://application:,,,/Revit2Gltf.Plugin;component/Resources/icons8-upload-to-cloud-32.png"));
59 | Btn_Export.Enabled = true;
60 | }
61 | #endregion
62 | }
63 |
64 | private void Application_ViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs e)
65 | {
66 | Btn_Export.Enabled = e.CurrentActiveView is View3D;
67 | }
68 |
69 |
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Revit2Gltf.Plugin/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Revit2Gltf.Plugin")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Revit2Gltf.Plugin")]
13 | [assembly: AssemblyCopyright("Copyright © 2021")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("e10817ac-cb7f-4c86-921f-19d047426a3b")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Revit2Gltf.Plugin/Resources/icons8-upload-to-cloud-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/Revit2Gltf.Plugin/Resources/icons8-upload-to-cloud-32.png
--------------------------------------------------------------------------------
/Revit2Gltf.Plugin/Revit2Gltf.Plugin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {E10817AC-CB7F-4C86-921F-19D047426A3B}
8 | Library
9 | Properties
10 | Revit2Gltf.Plugin
11 | Revit2Gltf.Plugin
12 | v4.7.2
13 | 512
14 | true
15 |
16 |
17 |
18 |
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | TRACE;DEBUG;REVIT2016
24 | prompt
25 | 4
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE;REVIT2016
32 | prompt
33 | 4
34 |
35 |
36 | true
37 | bin\Debug2016\
38 | TRACE;DEBUG;REVIT2016
39 | full
40 | AnyCPU
41 | 7.3
42 | prompt
43 | MinimumRecommendedRules.ruleset
44 |
45 |
46 | bin\Release2016\
47 | TRACE;REVIT2016
48 | true
49 | pdbonly
50 | AnyCPU
51 | 7.3
52 | prompt
53 | MinimumRecommendedRules.ruleset
54 |
55 |
56 | true
57 | bin\Debug2019\
58 | TRACE;DEBUG;REVIT2019
59 | full
60 | AnyCPU
61 | 7.3
62 | prompt
63 | MinimumRecommendedRules.ruleset
64 |
65 |
66 |
67 | ..\packages\AssimpNet.4.1.0\lib\net40\AssimpNet.dll
68 |
69 |
70 | ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
71 |
72 |
73 |
74 | ..\ThirdParty\API\2016\RevitAPI.dll
75 | False
76 |
77 |
78 | ..\ThirdParty\API\2015\RevitAPIIFC.dll
79 | False
80 |
81 |
82 | ..\ThirdParty\API\2016\RevitAPIUI.dll
83 | False
84 |
85 |
86 | ..\ThirdParty\API\2016\RevitAPI.dll
87 | False
88 |
89 |
90 | ..\ThirdParty\API\2016\RevitAPIIFC.dll
91 | False
92 |
93 |
94 | ..\ThirdParty\API\2016\RevitAPIUI.dll
95 | False
96 |
97 |
98 | ..\ThirdParty\API\2017\RevitAPI.dll
99 | False
100 |
101 |
102 | ..\ThirdParty\API\2017\RevitAPIIFC.dll
103 | False
104 |
105 |
106 | ..\ThirdParty\API\2017\RevitAPIUI.dll
107 | False
108 |
109 |
110 | ..\ThirdParty\API\2018\RevitAPI.dll
111 | False
112 |
113 |
114 | ..\ThirdParty\API\2018\RevitAPIIFC.dll
115 | False
116 |
117 |
118 | ..\ThirdParty\API\2018\RevitAPIUI.dll
119 | False
120 |
121 |
122 | ..\ThirdParty\API\2019\RevitAPI.dll
123 | False
124 |
125 |
126 | ..\ThirdParty\API\2019\RevitAPIIFC.dll
127 | False
128 |
129 |
130 | ..\ThirdParty\API\2019\RevitAPIUI.dll
131 | False
132 |
133 |
134 | ..\ThirdParty\API\2020\RevitAPI.dll
135 | False
136 |
137 |
138 | ..\ThirdParty\API\2020\RevitAPIIFC.dll
139 | False
140 |
141 |
142 | ..\ThirdParty\API\2020\RevitAPIUI.dll
143 | False
144 |
145 |
146 | ..\ThirdParty\Snappy\Snappy.NET.dll
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 | {ad5ae38a-3bde-4fb0-88f6-1f4133566ab5}
174 | Revit2Gltf
175 |
176 |
177 |
178 |
179 |
180 | echo Configuration: $(Configuration)
181 |
182 | if $(Configuration) == Debug2016 goto Debug2016
183 | if $(Configuration) == Release2016 goto Release2016
184 | if $(Configuration) == Debug2017 goto Debug2017
185 | if $(Configuration) == Release2017 goto Release2017
186 | if $(Configuration) == Debug2019 goto Debug2019
187 | if $(Configuration) == Release2019 goto Release2019
188 |
189 |
190 | :Debug2016
191 | echo Copying results to 2016
192 |
193 | xcopy "$(TargetDir)*" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2016\" /y /c /i
194 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\PackageContents.xml" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\" /i /y /c
195 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\Revit2Gltf.addin" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2016\" /i /y /c
196 | goto exit
197 |
198 | :Release2016
199 | echo Copying results to 2016
200 |
201 | xcopy "$(TargetDir)*" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2016\" /y /c /i
202 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\PackageContents.xml" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\" /i /y /c
203 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\Revit2Gltf.addin" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2016\" /i /y /c
204 | goto exit
205 |
206 | :Debug2017
207 | echo Copying results to 2017
208 |
209 | xcopy "$(TargetDir)*" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2017\" /y /c /i
210 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\PackageContents.xml" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\" /i /y /c
211 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\Revit2Gltf.addin" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2017\" /i /y /c
212 | goto exit
213 |
214 | :Release2017
215 | echo Copying results to 2017
216 |
217 | xcopy "$(TargetDir)*" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2017\" /y /c /i
218 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\PackageContents.xml" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\" /i /y /c
219 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\Revit2Gltf.addin" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2017\" /i /y /c
220 | goto exit
221 |
222 | :Debug2019
223 | echo Copying results to 2019
224 |
225 | xcopy "$(TargetDir)*" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2019\" /y /c /i
226 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\PackageContents.xml" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\" /i /y /c
227 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\Revit2Gltf.addin" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2019\" /i /y /c
228 | goto exit
229 |
230 | :Release2019
231 | echo Copying results to 2019
232 |
233 | xcopy "$(TargetDir)*" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2019\" /y /c /i
234 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\PackageContents.xml" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\" /i /y /c
235 | xcopy "$(SolutionDir)Revit2Gltf.Plugin\Revit2Gltf.addin" "C:\ProgramData\Autodesk\ApplicationPlugins\Revit2Gltf.bundle\Contents\x64\R2019\" /i /y /c
236 | goto exit
237 |
238 | :exit
239 |
240 |
241 |
242 |
243 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
244 |
245 |
246 |
247 |
--------------------------------------------------------------------------------
/Revit2Gltf.Plugin/Revit2Gltf.addin:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Revit2Gltf
5 | .\Revit2Gltf.Plugin.dll
6 | 22d6f9f5-f3db-4adc-bf44-13a0db48c9d2
7 | Revit2Gltf.Plugin.AddinApplication
8 | 1e26ac03-d9a8-4136-82d9-2ebd8edda8be
9 | Cityzenith, Leland Jobson
10 | www.cityzenith.com
11 |
12 |
--------------------------------------------------------------------------------
/Revit2Gltf.Plugin/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Revit2Gltf.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30204.135
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Revit2Gltf", "Revit2Gltf\Revit2Gltf.csproj", "{AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Revit2Gltf.Plugin", "Revit2Gltf.Plugin\Revit2Gltf.Plugin.csproj", "{E10817AC-CB7F-4C86-921F-19D047426A3B}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug2016|Any CPU = Debug2016|Any CPU
14 | Debug2019|Any CPU = Debug2019|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | Release2016|Any CPU = Release2016|Any CPU
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Debug2016|Any CPU.ActiveCfg = Debug2016|Any CPU
22 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Debug2016|Any CPU.Build.0 = Debug2016|Any CPU
23 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Debug2019|Any CPU.ActiveCfg = Debug2019|Any CPU
24 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Debug2019|Any CPU.Build.0 = Debug2019|Any CPU
25 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Release2016|Any CPU.ActiveCfg = Release2016|Any CPU
28 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}.Release2016|Any CPU.Build.0 = Release2016|Any CPU
29 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
30 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
31 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Debug2016|Any CPU.ActiveCfg = Debug2016|Any CPU
32 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Debug2016|Any CPU.Build.0 = Debug2016|Any CPU
33 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Debug2019|Any CPU.ActiveCfg = Debug2019|Any CPU
34 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Debug2019|Any CPU.Build.0 = Debug2019|Any CPU
35 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Release2016|Any CPU.ActiveCfg = Release2016|Any CPU
38 | {E10817AC-CB7F-4C86-921F-19D047426A3B}.Release2016|Any CPU.Build.0 = Release2016|Any CPU
39 | EndGlobalSection
40 | GlobalSection(SolutionProperties) = preSolution
41 | HideSolutionNode = FALSE
42 | EndGlobalSection
43 | GlobalSection(ExtensibilityGlobals) = postSolution
44 | SolutionGuid = {AA549948-D401-4848-872E-9F9C7CACBF4C}
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/Revit2Gltf/AssetPropertyDescriptor.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | #if REVIT2019 || REVIT2020
3 | using Autodesk.Revit.DB.Visual;
4 | #else
5 | using Autodesk.Revit.Utility;
6 | #endif
7 | using System;
8 | using System.Collections.Generic;
9 | using System.ComponentModel;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 |
15 |
16 | namespace Revit2Gltf
17 | {
18 | ///
19 | /// A description of a property consists of a name, its attributes and value
20 | /// here AssetPropertyPropertyDescriptor is used to wrap AssetProperty
21 | /// to display its name and value in PropertyGrid
22 | ///
23 | internal class AssetPropertyPropertyDescriptor : PropertyDescriptor
24 | {
25 | #region Fields
26 | ///
27 | /// A reference to an AssetProperty
28 | ///
29 | private AssetProperty m_assetProperty;
30 |
31 | ///
32 | /// The type of AssetProperty's property "Value"
33 | /// m
34 | private Type m_valueType;
35 |
36 | ///
37 | /// The value of AssetProperty's property "Value"
38 | ///
39 | private Object m_value;
40 | #endregion
41 |
42 | #region Properties
43 | ///
44 | /// Property to get internal AssetProperty
45 | ///
46 | public AssetProperty AssetProperty
47 | {
48 | get { return m_assetProperty; }
49 | }
50 | #endregion
51 |
52 | #region override Properties
53 | ///
54 | /// Gets a value indicating whether this property is read-only
55 | ///
56 | public override bool IsReadOnly
57 | {
58 | get
59 | {
60 | return true;
61 | }
62 | }
63 |
64 | ///
65 | /// Gets the type of the component this property is bound to.
66 | ///
67 | public override Type ComponentType
68 | {
69 | get
70 | {
71 | return m_assetProperty.GetType();
72 | }
73 | }
74 |
75 | ///
76 | /// Gets the type of the property.
77 | ///
78 | public override Type PropertyType
79 | {
80 | get
81 | {
82 | return m_valueType;
83 | }
84 | }
85 | #endregion
86 |
87 | ///
88 | /// Public class constructor
89 | ///
90 | /// the AssetProperty which a AssetPropertyPropertyDescriptor instance describes
91 | public AssetPropertyPropertyDescriptor(AssetProperty assetProperty)
92 | : base(assetProperty.Name, new Attribute[0])
93 | {
94 | m_assetProperty = assetProperty;
95 | }
96 |
97 | #region override methods
98 | ///
99 | /// Compares this to another object to see if they are equivalent
100 | ///
101 | /// The object to compare to this AssetPropertyPropertyDescriptor.
102 | ///
103 | public override bool Equals(object obj)
104 | {
105 | AssetPropertyPropertyDescriptor other = obj as AssetPropertyPropertyDescriptor;
106 | return other != null && other.AssetProperty.Equals(m_assetProperty);
107 | }
108 |
109 | ///
110 | /// Returns the hash code for this object.
111 | /// Here override the method "Equals", so it is necessary to override GetHashCode too.
112 | ///
113 | ///
114 | public override int GetHashCode()
115 | {
116 | return m_assetProperty.GetHashCode();
117 | }
118 |
119 | ///
120 | /// Resets the value for this property of the component to the default value.
121 | ///
122 | /// The component with the property value that is to be reset to the default value.
123 | public override void ResetValue(object component)
124 | {
125 |
126 | }
127 |
128 | ///
129 | /// Returns whether resetting an object changes its value.
130 | ///
131 | /// The component to test for reset capability.
132 | /// true if resetting the component changes its value; otherwise, false.
133 | public override bool CanResetValue(object component)
134 | {
135 | return false;
136 | }
137 |
138 | /// G
139 | /// Determines a value indicating whether the value of this property needs to be persisted.
140 | ///
141 | /// The component with the property to be examined for persistence.
142 | /// true if the property should be persisted; otherwise, false.
143 | public override bool ShouldSerializeValue(object component)
144 | {
145 | return false;
146 | }
147 |
148 | /////
149 | ///// Gets the current value of the property on a component.
150 | /////
151 | ///// The component with the property for which to retrieve the value.
152 | ///// The value of a property for a given component.
153 | //public override object GetValue(object component)
154 | //{
155 | // Tuple typeAndValue = GetTypeAndValue(m_assetProperty, 0);
156 | // m_value = typeAndValue.Item2;
157 | // m_valueType = typeAndValue.Item1;
158 |
159 | // return m_value;
160 | //}
161 |
162 | //private static Tuple GetTypeAndValue(AssetProperty assetProperty, int level)
163 | //{
164 | // Object theValue;
165 | // Type valueType;
166 | // //For each AssetProperty, it has different type and value
167 | // //must deal with it separately
168 | // try
169 | // {
170 | // if (assetProperty is AssetPropertyBoolean)
171 | // {
172 | // AssetPropertyBoolean property = assetProperty as AssetPropertyBoolean;
173 | // valueType = typeof(AssetPropertyBoolean);
174 | // theValue = property.Value;
175 | // }
176 | // else if (assetProperty is AssetPropertyDistance)
177 | // {
178 | // AssetPropertyDistance property = assetProperty as AssetPropertyDistance;
179 | // valueType = typeof(AssetPropertyDistance);
180 | // theValue = property.Value;
181 | // }
182 | // else if (assetProperty is AssetPropertyDouble)
183 | // {
184 | // AssetPropertyDouble property = assetProperty as AssetPropertyDouble;
185 | // valueType = typeof(AssetPropertyDouble);
186 | // theValue = property.Value;
187 | // }
188 | // else if (assetProperty is AssetPropertyDoubleArray2d)
189 | // {
190 | // //Default, it is supported by PropertyGrid to display Double []
191 | // //Try to convert DoubleArray to Double []
192 | // AssetPropertyDoubleArray2d property = assetProperty as AssetPropertyDoubleArray2d;
193 | // valueType = typeof(AssetPropertyDoubleArray2d);
194 | // theValue = GetSystemArrayAsString(property.Value);
195 | // }
196 | // else if (assetProperty is AssetPropertyDoubleArray3d)
197 | // {
198 | // AssetPropertyDoubleArray3d property = assetProperty as AssetPropertyDoubleArray3d;
199 | // valueType = typeof(AssetPropertyDoubleArray3d);
200 | // theValue = GetSystemArrayAsString(property.GetValueAsDoubles());
201 | // }
202 | // else if (assetProperty is AssetPropertyDoubleArray4d)
203 | // {
204 | // AssetPropertyDoubleArray4d property = assetProperty as AssetPropertyDoubleArray4d;
205 | // valueType = typeof(AssetPropertyDoubleArray4d);
206 | // theValue = GetSystemArrayAsString(property.Value);
207 | // }
208 | // else if (assetProperty is AssetPropertyDoubleMatrix44)
209 | // {
210 | // AssetPropertyDoubleMatrix44 property = assetProperty as AssetPropertyDoubleMatrix44;
211 | // valueType = typeof(AssetPropertyDoubleMatrix44);
212 | // theValue = GetSystemArrayAsString(property.Value);
213 | // }
214 | // else if (assetProperty is AssetPropertyEnum)
215 | // {
216 | // AssetPropertyEnum property = assetProperty as AssetPropertyEnum;
217 | // valueType = typeof(AssetPropertyEnum);
218 | // theValue = property.Value;
219 | // }
220 | // else if (assetProperty is AssetPropertyFloat)
221 | // {
222 | // AssetPropertyFloat property = assetProperty as AssetPropertyFloat;
223 | // valueType = typeof(AssetPropertyFloat);
224 | // theValue = property.Value;
225 | // }
226 | // else if (assetProperty is AssetPropertyInteger)
227 | // {
228 | // AssetPropertyInteger property = assetProperty as AssetPropertyInteger;
229 | // valueType = typeof(AssetPropertyInteger);
230 | // theValue = property.Value;
231 | // }
232 | // else if (assetProperty is AssetPropertyReference)
233 | // {
234 | // AssetPropertyReference property = assetProperty as AssetPropertyReference;
235 | // valueType = typeof(AssetPropertyReference);
236 | // theValue = "REFERENCE"; //property.Type;
237 | // }
238 | // else if (assetProperty is AssetPropertyString)
239 | // {
240 | // AssetPropertyString property = assetProperty as AssetPropertyString;
241 | // valueType = typeof(AssetPropertyString);
242 | // theValue = property.Value;
243 | // }
244 | // else if (assetProperty is AssetPropertyTime)
245 | // {
246 | // AssetPropertyTime property = assetProperty as AssetPropertyTime;
247 | // valueType = typeof(AssetPropertyTime);
248 | // theValue = property.Value;
249 | // }
250 | // else
251 | // {
252 | // valueType = typeof(String);
253 | // theValue = "Unprocessed asset type: " + assetProperty.GetType().Name;
254 | // }
255 |
256 | // if (assetProperty.NumberOfConnectedProperties > 0)
257 | // {
258 |
259 | // String result = "";
260 | // result = theValue.ToString();
261 |
262 | // IList properties = assetProperty.GetAllConnectedProperties();
263 |
264 | // foreach (AssetProperty property in properties)
265 | // {
266 | // if (property is Asset)
267 | // {
268 | // // Nested?
269 | // Asset asset = property as Asset;
270 | // int size = asset.Size;
271 | // for (int i = 0; i < size; i++)
272 | // {
273 | // AssetProperty subproperty = asset[i];
274 | // Tuple valueAndType = GetTypeAndValue(subproperty, level + 1);
275 | // String indent = "";
276 | // if (level > 0)
277 | // {
278 | // for (int iLevel = 1; iLevel <= level; iLevel++)
279 | // indent += " ";
280 | // }
281 | // result += "\n " + indent + "- connected: name: " + subproperty.Name + " | type: " + valueAndType.Item1.Name +
282 | // " | value: " + valueAndType.Item2.ToString();
283 | // }
284 | // }
285 | // }
286 |
287 | // theValue = result;
288 | // }
289 | // }
290 | // catch
291 | // {
292 | // return null;
293 | // }
294 | // return new Tuple(valueType, theValue);
295 | //}
296 |
297 | ///
298 | /// Sets the value of the component to a different value.
299 | /// For AssetProperty, it is not allowed to set its value, so here just return.
300 | ///
301 | /// The component with the property value that is to be set.
302 | /// The new value.
303 | public override void SetValue(object component, object value)
304 | {
305 | return;
306 | }
307 | #endregion
308 |
309 | ///
310 | /// Convert Autodesk.Revit.DB.DoubleArray to Double [].
311 | /// For Double [] is supported by PropertyGrid.
312 | ///
313 | /// the original Autodesk.Revit.DB.DoubleArray
314 | /// The converted Double []
315 | private static Double[] GetSystemArray(DoubleArray doubleArray)
316 | {
317 | double[] values = new double[doubleArray.Size];
318 | int index = 0;
319 | foreach (Double value in doubleArray)
320 | {
321 | values[index++] = value;
322 | }
323 | return values;
324 | }
325 |
326 | private static String GetSystemArrayAsString(DoubleArray doubleArray)
327 | {
328 | double[] values = GetSystemArray(doubleArray);
329 |
330 | String result = "";
331 | foreach (double d in values)
332 | {
333 | result += d;
334 | result += ",";
335 | }
336 |
337 | return result;
338 | }
339 |
340 | public override string ToString()
341 | {
342 | return base.Name;
343 | }
344 |
345 | public override object GetValue(object component)
346 | {
347 | //throw new NotImplementedException();
348 | return null;
349 | }
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/Revit2Gltf/AssimpUtilities.cs:
--------------------------------------------------------------------------------
1 | using Assimp;
2 | using Assimp.Configs;
3 | using Autodesk.Revit.DB;
4 | #if REVIT2017 || REVIT2016 || REVIT2015
5 | using Autodesk.Revit.Utility;
6 | #endif
7 | using System;
8 | using System.Collections.Generic;
9 | using System.ComponentModel;
10 | using System.IO;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 | using Material = Assimp.Material;
15 | using RevitMaterial = Autodesk.Revit.DB.Material;
16 |
17 | #if REVIT2018 || REVIT2019 || REVIT2020
18 | using Autodesk.Revit.DB.Visual;
19 | using Revit2Gltf;
20 | #endif
21 |
22 | namespace Revit2Gltf
23 | {
24 | public static class AssimpUtilities
25 | {
26 | public const string UnknownObjectName = "Unknown Revit Object";
27 |
28 |
29 | public static float GetOpacity(this RevitMaterial mat)
30 | {
31 | return (Math.Abs(mat.Transparency - 100) * 1f / 100f);
32 | }
33 |
34 | public static Color4D ToColor4D(this RevitMaterial mat)
35 | {
36 | var color = mat.Color.IsValid ? mat.Color : new Color(0, 0, 0);
37 | return new Color4D(color.Red * 1f / 255f, color.Green * 1f / 255f, color.Blue * 1f / 255f, mat.GetOpacity());
38 | }
39 |
40 | public static Color4D ColorFromAssetDoubleArray4d(AssetPropertyDoubleArray4d prop)
41 | {
42 | #if REVIT2019 || REVIT2020
43 | var colorValues = prop.GetValueAsDoubles()?.ToList() ?? new List();
44 | if (colorValues != null && colorValues.Count > 3)
45 | {
46 | return new Color4D(
47 | (float)colorValues[0],
48 | (float)colorValues[1],
49 | (float)colorValues[2],
50 | (float)colorValues[3]);
51 | }
52 | else
53 | {
54 | // Default return if invalid
55 | return new Color4D(200);
56 | }
57 | #else
58 | return new Color4D(
59 | (float)prop.Value.get_Item(0),
60 | (float)prop.Value.get_Item(1),
61 | (float)prop.Value.get_Item(2),
62 | (float)prop.Value.get_Item(3));
63 | #endif
64 | }
65 |
66 | public static T GetAssetProperty(this Asset a, string key) where T : AssetProperty
67 | {
68 | #if REVIT2019 || REVIT2020
69 | return a.FindByName(key) as T;
70 | #else
71 | return a[key] as T;
72 | #endif
73 | }
74 |
75 | public static Assimp.Material ConvertToAssimpMaterial(TextureBundle bundle, Document doc)
76 | {
77 | // Create new material with base props
78 | // from the Revit material
79 | var newmat = new Assimp.Material()
80 | {
81 | Opacity = bundle.Material.GetOpacity(),
82 | Reflectivity = 0f,
83 | Name = bundle.Material.Name,
84 | ColorDiffuse = bundle.Material.ToColor4D()
85 | };
86 |
87 | // Extract base properties from revit material
88 | ElementId appearanceAssetId = bundle.Material.AppearanceAssetId;
89 | AppearanceAssetElement appearanceAsset = doc.GetElement(appearanceAssetId) as AppearanceAssetElement;
90 | Asset renderingAsset = appearanceAsset.GetRenderingAsset();
91 | RenderAppearanceDescriptor rad
92 | = new RenderAppearanceDescriptor(renderingAsset);
93 | PropertyDescriptorCollection collection = rad.GetProperties();
94 | List orderableCollection = new List(collection.Count);
95 |
96 | List allPropNames = orderableCollection.Select(f => f.Name).ToList();
97 |
98 | foreach (PropertyDescriptor descr in collection)
99 | {
100 | orderableCollection.Add(descr);
101 | switch (descr.Name)
102 | {
103 | #region Notes
104 |
105 | // The commented out properties aren't in use yet,
106 | // but do work with revit materials as expected.
107 |
108 | //case "texture_UScale":
109 | // var uScale = renderingAsset["texture_UScale"] as AssetPropertyDouble;
110 | // break;
111 | //case "texture_VScale":
112 | // break;
113 | //case "texture_UOffset":
114 | // break;
115 | //case "texture_VOffset":
116 | // break;
117 | //case "texture_RealWorldScaleX":
118 | // var xScale = renderingAsset["texture_RealWorldScaleX"] as AssetPropertyDistance;
119 | // break;
120 | //case "texture_RealWorldScaleY":
121 | // break;
122 |
123 | #endregion
124 |
125 | case "generic_diffuse":
126 | var prop = renderingAsset.GetAssetProperty("generic_diffuse");
127 | newmat.ColorDiffuse = ColorFromAssetDoubleArray4d(prop);
128 | break;
129 | case "glazing_reflectance":
130 | // This is glass, so we should reduce the transparency.
131 | var refl = renderingAsset.GetAssetProperty("glazing_reflectance");
132 | if (refl == null)
133 | {
134 | var reflFloat = renderingAsset.GetAssetProperty("glazing_reflectance");
135 | newmat.Reflectivity = reflFloat?.Value ?? 0f;
136 | }
137 | else
138 | {
139 | newmat.Reflectivity = (float)refl.Value;
140 | }
141 | newmat.Opacity = Math.Abs(0f - newmat.Reflectivity);
142 | break;
143 | case "common_Tint_color":
144 | // Tint shouldn't be used if generic diffuse is set
145 | if (
146 | renderingAsset.GetAssetProperty("generic_diffuse") != null
147 | ) { continue; }
148 | var tintProp = renderingAsset.GetAssetProperty("common_Tint_color");
149 | newmat.ColorDiffuse = ColorFromAssetDoubleArray4d(tintProp);
150 | break;
151 | default:
152 | break;
153 | }
154 | }
155 |
156 | // Set textures
157 | foreach (var tx in bundle.TexturePaths)
158 | {
159 | // Get the filename
160 | var txFileName = tx.Value.SafeFileName;
161 | if (tx.Key == RevitTextureType.Color)
162 | {
163 | newmat.TextureDiffuse = new TextureSlot(
164 | $"Textures/{txFileName}",
165 | TextureType.Diffuse,
166 | 0, // Texture index in the material
167 | TextureMapping.Box,
168 | 0, //
169 | 0.5f, // Blend mode
170 | TextureOperation.Add,
171 | TextureWrapMode.Clamp,
172 | TextureWrapMode.Clamp,
173 | 0 // Flags,
174 | );
175 | }
176 | else if (tx.Key == RevitTextureType.Bump)
177 | {
178 | newmat.TextureHeight = new TextureSlot(
179 | $"Textures/{txFileName}",
180 | TextureType.Diffuse,
181 | 0, // Texture index in the material
182 | TextureMapping.Box,
183 | 0, //
184 | 0.5f, // Blend mode
185 | TextureOperation.Add,
186 | TextureWrapMode.Clamp,
187 | TextureWrapMode.Clamp,
188 | 0 // Flags,
189 | );
190 | }
191 | }
192 | return newmat;
193 | }
194 |
195 | public static void AddAndAssignMaterial(
196 | Scene model,
197 | Assimp.Material mat,
198 | HashSet uniqueIdsOfElementsWithMat,
199 | out bool utilized
200 | )
201 | {
202 | utilized = false;
203 |
204 | // If no elements in the model use this material,
205 | // don't bother.
206 | if (uniqueIdsOfElementsWithMat.Count == 0) { return; }
207 |
208 | int matIndex = model.MaterialCount;
209 | foreach (var mesh in model.Meshes)
210 | {
211 | if (uniqueIdsOfElementsWithMat.Contains(mesh.Name))
212 | {
213 | mesh.MaterialIndex = matIndex;
214 | utilized = true;
215 | }
216 | }
217 | if (utilized)
218 | {
219 | //Logger.LogInfo($"Adding material {mat.Name} to gltf.");
220 | model.Materials.Add(mat);
221 | }
222 | else
223 | {
224 | //Logger.LogInfo($"Won't add material {mat.Name} to gltf " +
225 | // $"because no objects utilize it.");
226 | }
227 | }
228 |
229 | public static void ReplaceNamesWithUniqueIds(Scene model, Dictionary localToUniqueIdMap)
230 | {
231 | foreach (var node in model.RootNode.GetNodes())
232 | {
233 | node.Name = GetUniqueIdFromNodeName(node.Name);
234 | }
235 | foreach (var mesh in model.Meshes)
236 | {
237 | mesh.Name = GetUniqueIdFromNodeName(mesh.Name);
238 | }
239 |
240 | string GetUniqueIdFromNodeName(string nodeName)
241 | {
242 | // Fragment the node name to get the local id of the element
243 | // in the brackets
244 | string[] fragments = nodeName.Split(new char[] { '[', ']' });
245 |
246 | string result = fragments.Length > 1 ?
247 | localToUniqueIdMap.ContainsKey(fragments[1]) ?
248 | localToUniqueIdMap[fragments[1]] :
249 | fragments[1]
250 | :
251 | fragments.FirstOrDefault() ?? UnknownObjectName;
252 |
253 | return result;
254 | }
255 | }
256 |
257 |
258 | public static IEnumerable GetNodes(this Node root)
259 | {
260 | if (!root.HasChildren) { yield break; }
261 | foreach (var childNode in root.Children)
262 | {
263 | yield return childNode;
264 | if (childNode.HasChildren)
265 | {
266 | foreach (var childChildNode in GetNodes(childNode))
267 | {
268 | yield return childChildNode;
269 | }
270 | }
271 | }
272 | yield break;
273 | }
274 |
275 | public static Scene LoadFbx(string fileName)
276 | {
277 | //Create a new importer
278 | using (var importer = new AssimpContext())
279 | {
280 | //This is how we add a configuration (each config is its own class)
281 | NormalSmoothingAngleConfig config = new NormalSmoothingAngleConfig(66.0f);
282 | importer.SetConfig(config);
283 |
284 | //This is how we add a logging callback
285 | LogStream logstream = new LogStream(delegate (String msg, String userData) {
286 | Console.WriteLine(msg);
287 | });
288 | logstream.Attach();
289 |
290 | //Import the model. All configs are set. The model
291 | //is imported, loaded into managed memory. Then the unmanaged memory is released, and everything is reset.
292 | Scene model = importer.ImportFile(fileName, PostProcessPreset.TargetRealTimeMaximumQuality);
293 |
294 | return model;
295 | }
296 | }
297 |
298 | public static bool TryRemoveFile(string fileName, TimeSpan pause, int tries = 5)
299 | {
300 | if (pause == default(TimeSpan))
301 | {
302 | // Default to 1 second
303 | pause = TimeSpan.FromSeconds(1);
304 | }
305 | while (tries > 0)
306 | {
307 | try
308 | {
309 | File.Delete(fileName);
310 | return true;
311 | }
312 | catch (Exception e)
313 | {
314 | //Logger.LogException("TryRemoveFile failed: ", e);
315 | tries--;
316 | }
317 | }
318 | return false;
319 | }
320 |
321 | public static bool SaveToGltf(this Scene model, string path, string fileName)
322 | {
323 | try
324 | {
325 | using (var importer = new AssimpContext())
326 | {
327 | string outputFilePath = $"{path}/{fileName}.gltf";
328 | if (importer.ExportFile(model, outputFilePath, "gltf2"))
329 | {
330 | // Replace the buffer path to a relative one.
331 | string gltf = File.ReadAllText(outputFilePath);
332 | gltf = gltf.Replace(path + '/', "");
333 | File.WriteAllText(outputFilePath, gltf);
334 | return true;
335 | }
336 | else
337 | {
338 | return false;
339 | }
340 | }
341 | }
342 | catch (Exception e)
343 | {
344 | //Logger.LogException("Error in saving gltf: ", e);
345 | return false;
346 | }
347 |
348 | }
349 | }
350 | }
351 |
--------------------------------------------------------------------------------
/Revit2Gltf/CentroidVolume.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Revit2Gltf
9 | {
10 | public class CentroidVolume
11 | {
12 | public const int CoordinateRoundingDecimals = 3;
13 | public const int VolumeRoundingDecimals = 3;
14 |
15 | public string Centroid_Str =>
16 | $"{Math.Round(Centroid.X, CoordinateRoundingDecimals)}," +
17 | $"{Math.Round(Centroid.Y, CoordinateRoundingDecimals)}," +
18 | $"{Math.Round(Centroid.Z, CoordinateRoundingDecimals)}";
19 | public string Volume_Str => Math.Round(Volume, VolumeRoundingDecimals).ToString();
20 |
21 | public XYZ Centroid { get; set; } = XYZ.Zero;
22 | public double Volume { get; set; } = 0;
23 |
24 | public CentroidVolume() { }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Revit2Gltf/Configuration.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Revit2Gltf
9 | {
10 | ///
11 | /// Configures the export.
12 | ///
13 | public class Configuration
14 | {
15 | ///
16 | /// Categories of Revit elements which will
17 | /// be exported.
18 | ///
19 | public List ExportedCategories;
20 |
21 | ///
22 | /// Name applied to elements whose name cannot
23 | /// be ascertained.
24 | ///
25 | public string UnknownObjectName;
26 |
27 | ///
28 | /// Where the gltf files will inevitably be exported to.
29 | ///
30 | public string ExportFilePathRoot = "C:/Cityzenith";
31 |
32 |
33 | public Configuration()
34 | {
35 |
36 | }
37 |
38 | public static Configuration Default = new Configuration()
39 | {
40 | UnknownObjectName = "Unknown Revit Object",
41 | ExportedCategories = new List()
42 | {
43 | BuiltInCategory.OST_Walls,
44 | BuiltInCategory.OST_Floors,
45 | BuiltInCategory.OST_Doors,
46 | BuiltInCategory.OST_Windows,
47 | BuiltInCategory.OST_CurtainWallMullions,
48 | BuiltInCategory.OST_CurtainWallPanels,
49 | BuiltInCategory.OST_EdgeSlab,
50 | BuiltInCategory.OST_Rooms,
51 | BuiltInCategory.OST_Ceilings,
52 | BuiltInCategory.OST_Furniture,
53 | BuiltInCategory.OST_FurnitureSystems,
54 | BuiltInCategory.OST_Assemblies,
55 | BuiltInCategory.OST_Columns,
56 | BuiltInCategory.OST_Casework,
57 | BuiltInCategory.OST_Site,
58 | BuiltInCategory.OST_Stairs,
59 | BuiltInCategory.OST_StructuralColumns,
60 | BuiltInCategory.OST_StructuralFraming,
61 | BuiltInCategory.OST_Views,
62 | BuiltInCategory.OST_Truss
63 | }
64 | };
65 | }
66 |
67 | ///
68 | /// Light singleton posessing the active
69 | /// configuration of the exporter.
70 | ///
71 | public static class ConfigurationManager
72 | {
73 | public static Configuration ActiveConfiguration = Configuration.Default;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Revit2Gltf/Enums.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 Revit2Gltf
8 | {
9 | public enum RevitTextureType
10 | {
11 | Unknown = -1,
12 | Color,
13 | Bump
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Revit2Gltf/Extensions.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Revit2Gltf
10 | {
11 | public static class Extensions
12 | {
13 | public static Dictionary ToFilenamePathDictionarySafe(this IEnumerable fullPaths)
14 | {
15 | Dictionary output = new Dictionary();
16 | foreach(var p in fullPaths)
17 | {
18 | var fn = Path.GetFileNameWithoutExtension(p);
19 | if (output.ContainsKey(fn)) { continue; }
20 | output.Add(fn, p);
21 | }
22 | return output;
23 | }
24 |
25 | public static void WriteToFile(this string file, string path)
26 | {
27 | System.IO.File.WriteAllText(path, file);
28 | }
29 |
30 | public static Dictionary> Combine(this IEnumerable>> set)
31 | {
32 | var output = new Dictionary>();
33 |
34 | foreach(var d in set)
35 | {
36 | foreach(var kv in d)
37 | {
38 | if (!output.ContainsKey(kv.Key))
39 | {
40 | output.Add(kv.Key, kv.Value);
41 | }
42 | }
43 |
44 | }
45 |
46 | return output;
47 | }
48 |
49 | public static FilteredElementCollector ExportableElements(this Document doc)
50 | {
51 | var catsToExport =
52 | ConfigurationManager.ActiveConfiguration.ExportedCategories;
53 |
54 | List ids
55 | = new List(catsToExport)
56 | .ConvertAll(c
57 | => new ElementId((int)c));
58 |
59 | FilterCategoryRule r
60 | = new FilterCategoryRule(ids);
61 |
62 | ElementParameterFilter f
63 | = new ElementParameterFilter(r, true);
64 |
65 | // Use a logical OR of category filters
66 |
67 | IList a
68 | = new List(catsToExport.Count);
69 |
70 | foreach (BuiltInCategory bic in catsToExport)
71 | {
72 | a.Add(new ElementCategoryFilter(bic));
73 | }
74 |
75 | LogicalOrFilter categoryFilter
76 | = new LogicalOrFilter(a);
77 |
78 | // Run the collector
79 |
80 | FilteredElementCollector els
81 | = new FilteredElementCollector(doc)
82 | .WhereElementIsNotElementType()
83 | .WhereElementIsViewIndependent()
84 | .WherePasses(categoryFilter);
85 |
86 | return els;
87 | }
88 |
89 | static Options DefaultExportGeometryOptions = new Options()
90 | {
91 | DetailLevel = ViewDetailLevel.Medium,
92 | IncludeNonVisibleObjects = true
93 | };
94 |
95 | ///
96 | /// Return parameter data for all
97 | /// elements of all the given categories
98 | ///
99 | public static Dictionary>>
100 | SiphonElementParamValues(
101 | this Document doc,
102 | out Dictionary legend,
103 | bool calculateCentroids = true,
104 | List cats = null)
105 | {
106 | if(cats == null)
107 | {
108 | cats = ConfigurationManager.ActiveConfiguration.ExportedCategories;
109 | }
110 |
111 | // Set up the return value dictionary
112 | var map_cat_to_uid_to_param_values
113 | = new Dictionary>>();
116 |
117 | // One top level dictionary per category
118 | foreach (BuiltInCategory cat in cats)
119 | {
120 | map_cat_to_uid_to_param_values.Add(
121 | cat.Description(),
122 | new Dictionary>());
124 | }
125 |
126 | // Collect all required elements
127 | var els = doc.ExportableElements();
128 |
129 | // Retrieve parameter data for each element
130 | var legendReversed = new Dictionary();
131 | legendReversed.Add("Category", 0);
132 | if (calculateCentroids)
133 | {
134 | legendReversed.Add("Centroid", 1);
135 | }
136 |
137 | foreach (Element e in els)
138 | {
139 | Category cat = e.Category;
140 | if (null == cat)
141 | {
142 | continue;
143 | }
144 | Dictionary param_values = GetParamValues(e, ref legendReversed);
145 |
146 | if (calculateCentroids &&
147 | e.TryGetCentroid(DefaultExportGeometryOptions, out var c))
148 | {
149 | param_values.Add("1", c.Centroid_Str);
150 | }
151 |
152 | BuiltInCategory bic = (BuiltInCategory)
153 | (e.Category.Id.IntegerValue);
154 |
155 | string catkey = bic.Description();
156 | string uniqueId = e.UniqueId.ToString();
157 |
158 | map_cat_to_uid_to_param_values[catkey].Add(
159 | uniqueId, param_values);
160 | }
161 |
162 | legend = legendReversed.ToDictionary(kv => kv.Value, kv => kv.Key);
163 |
164 |
165 | return map_cat_to_uid_to_param_values;
166 | }
167 |
168 | public static string Description(
169 | this BuiltInCategory bic)
170 | {
171 | //string s = bic.ToString().ToLower();
172 | //s = s.Substring(4);
173 | //s = s.Substring(0, s.Length - 1);
174 | //return s;
175 | return bic.ToString().ToLower();
176 | }
177 |
178 | ///
179 | /// Return all the parameter values
180 | /// deemed relevant for the given element
181 | /// in string form.
182 | ///
183 | static Dictionary GetParamValues(Element e, ref Dictionary paramLegend)
184 | {
185 | // Two choices:
186 | // Element.Parameters property -- Retrieves
187 | // a set containing all the parameters.
188 | // GetOrderedParameters method -- Gets the
189 | // visible parameters in order.
190 |
191 | IList ps = e.GetOrderedParameters();
192 |
193 | List param_values = new List(
194 | ps.Count);
195 |
196 |
197 | var paramList =
198 | ps
199 | .Where(p => p.HasValue && !String.IsNullOrEmpty(p.AsValueString()));
200 | Dictionary output = new Dictionary();
201 | output.Add("0", e.Category.Name);
202 |
203 | foreach (var p in paramList)
204 | {
205 | var key = GetLegendValue(p,ref paramLegend).ToString();
206 | if (!output.ContainsKey(key))
207 | {
208 | output.Add(key, p.AsValueString());
209 | }
210 | }
211 | return output;
212 |
213 | int GetLegendValue(Parameter p, ref Dictionary lgd)
214 | {
215 | string n = p.Definition.Name;
216 | if (!lgd.ContainsKey(n))
217 | {
218 | int c = lgd.Count;
219 | lgd.Add(n, c);
220 | return c;
221 | }
222 | return lgd[n];
223 | }
224 |
225 | }
226 |
227 | public static View3D GetOrCreateDefault3DView(this Document doc)
228 | {
229 | var view3d = new FilteredElementCollector(doc)
230 | .OfClass(typeof(View3D))
231 | .Cast()
232 | .Where(v => v.Name.ToUpper() == "{3D}")
233 | .FirstOrDefault();
234 |
235 | if (view3d == null)
236 | {
237 | // Create a new 3d view (rare)
238 | // Grab the view family type.
239 | var vft = new FilteredElementCollector(doc)
240 | .OfClass(typeof(ViewFamilyType))
241 | .Cast()
242 | .Where(v => v.ViewFamily == ViewFamily.ThreeDimensional)
243 | .FirstOrDefault();
244 |
245 | using (var tr = new Transaction(doc))
246 | {
247 | tr.Start("Create 3D view for export to gltf");
248 | try
249 | {
250 | view3d = View3D.CreateIsometric(doc, vft.Id);
251 | tr.Commit();
252 | }
253 | catch (Exception e)
254 | {
255 | tr.RollBack();
256 | }
257 | }
258 | }
259 |
260 | return view3d;
261 | }
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/Revit2Gltf/GeometryExtensions.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Revit2Gltf
9 | {
10 | public static class GeometryExtensions
11 | {
12 | public static bool TryGetCentroidVolume(this Solid s, out CentroidVolume cv)
13 | {
14 | cv = null;
15 | try
16 | {
17 | if (null != s
18 | && 0 < s.Faces.Size
19 | && SolidUtils.IsValidForTessellation(s)
20 | && (null != (cv = new CentroidVolume()
21 | {
22 | Centroid = s.ComputeCentroid(),
23 | Volume = s.Volume
24 | }
25 | )))
26 | {
27 | return true;
28 | }
29 | }
30 | catch (Exception e)
31 | {
32 | }
33 | return false;
34 | }
35 |
36 | ///
37 | /// Calculate centroid for all non-empty solids
38 | /// found for the given element. Family instances
39 | /// may have their own non-empty solids, in which
40 | /// case those are used, otherwise the symbol geometry.
41 | /// The symbol geometry could keep track of the
42 | /// instance transform to map it to the actual
43 | /// project location. Instead, we ask for
44 | /// transformed geometry to be returned, so the
45 | /// resulting solids are already in place.
46 | ///
47 | public static bool TryGetCentroid(
48 | this Element e,
49 | Options opt,
50 | out CentroidVolume cvol)
51 | {
52 | cvol = null;
53 | GeometryElement geo = e.get_Geometry(opt);
54 | CentroidVolume combined = new CentroidVolume();
55 |
56 | if (null == geo) { return false; }
57 |
58 | // List of pairs of centroid, volume for each solid
59 |
60 | List a
61 | = new List();
62 |
63 | if (e is FamilyInstance)
64 | {
65 | geo = geo.GetTransformed(
66 | Transform.Identity);
67 | }
68 |
69 | GeometryInstance inst = null;
70 |
71 | foreach (GeometryObject obj in geo)
72 | {
73 | if (!TryGetCentroidVolume(obj as Solid, out var cv)) { continue; }
74 | a.Add(cv);
75 | inst = obj as GeometryInstance;
76 | }
77 |
78 | if (0 == a.Count && null != inst)
79 | {
80 | geo = inst.GetSymbolGeometry();
81 |
82 | foreach (GeometryObject obj in geo)
83 | {
84 | if (!TryGetCentroidVolume(obj as Solid, out var cv)) { continue; }
85 | a.Add(cv);
86 | }
87 | }
88 |
89 | // Get the total centroid from the partial
90 | // contributions. Each contribution is weighted
91 | // with its associated volume, which needs to
92 | // be factored out again at the end.
93 |
94 | try
95 | {
96 | if (0 < a.Count)
97 | {
98 | combined = new CentroidVolume();
99 | bool unweighted = false;
100 |
101 | // Revit may give us volumes of 0.
102 | // In which case we will not do a
103 | // weighted calculation, which will
104 | // throw a divide by zero exception.
105 | foreach (CentroidVolume cv2 in a)
106 | {
107 | if (cv2.Volume == 0)
108 | {
109 | unweighted = true;
110 | break;
111 | }
112 | }
113 | if (unweighted)
114 | {
115 | foreach (var cv2 in a)
116 | {
117 | combined.Centroid += cv2.Centroid;
118 | }
119 | combined.Centroid /= a.Count;
120 | }
121 | else
122 | {
123 | foreach (var cv2 in a)
124 | {
125 | combined.Centroid += cv2.Volume * cv2.Centroid;
126 | combined.Volume += cv2.Volume;
127 | }
128 | combined.Centroid /= (a.Count == 0 ? 1 : a.Count) * (combined.Volume == 0 ? 1 : combined.Volume);
129 | }
130 | }
131 | } catch(Exception ex)
132 | {
133 | combined = null;
134 | }
135 | cvol = combined;
136 | return combined != null && combined != default(CentroidVolume);
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/Revit2Gltf/MaterialUtilities.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using Autodesk.Revit.UI;
3 | #if REVIT2019 || REVIT2020
4 | using Autodesk.Revit.DB.Visual;
5 | #else
6 | using Autodesk.Revit.Utility;
7 | #endif
8 | using System;
9 | using System.Collections.Generic;
10 | using System.IO;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace Revit2Gltf
16 | {
17 | public static class MaterialUtilities
18 | {
19 | ///
20 | /// Keywords inside of asset attribute
21 | /// names which indicate what kind of
22 | /// texture they are.
23 | /// Thank you Revit
24 | /// for being such a pain in the ass.
25 | ///
26 | public static Dictionary> TextureTypeKeywords =
27 | new Dictionary>()
28 | {
29 | {
30 | RevitTextureType.Color, new List()
31 | {
32 | "color",
33 | "diffuse",
34 | "unifiedbitmapschema"
35 | }
36 | },
37 | {
38 | RevitTextureType.Bump, new List()
39 | {
40 | "bm_map",
41 | "bump",
42 | "pattern_map"
43 | }
44 | }
45 | };
46 |
47 | public static string TexturesPathRoot =
48 | $"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)}" +
49 | @"\Common Files\Autodesk Shared\Materials\Textures".Replace("\\\\", "\\");
50 |
51 | public static Dictionary RevitTextures =
52 | Directory.GetFiles(TexturesPathRoot, "*", SearchOption.AllDirectories)
53 | .ToFilenamePathDictionarySafe();
54 |
55 | private static Dictionary> _bundleCache =
56 | new Dictionary>();
57 | private static Dictionary> _texturePathCache =
58 | new Dictionary>();
59 |
60 | public static bool TryGetTextureTypeFromAssetName(string assetName, out RevitTextureType t)
61 | {
62 | t = RevitTextureType.Unknown;
63 | string lowerCaseName = assetName.ToLower();
64 | foreach (var kv in TextureTypeKeywords)
65 | {
66 | foreach (var val in kv.Value)
67 | {
68 | if (lowerCaseName.Contains(val))
69 | {
70 | t = kv.Key;
71 | return true;
72 | }
73 | }
74 | }
75 | return false;
76 | }
77 |
78 | public static List GetTextureBundles(Document doc, out List paths)
79 | {
80 |
81 | if (_bundleCache.ContainsKey(doc.PathName))
82 | {
83 | paths = _texturePathCache[doc.PathName];
84 | return _bundleCache[doc.PathName];
85 | }
86 | _texturePathCache.Add(doc.PathName, new List());
87 |
88 | // Find materials
89 | FilteredElementCollector fec = new FilteredElementCollector(doc).OfClass(typeof(Material));
90 |
91 | // Convert materials to bundles
92 | List bundles = new List();
93 | foreach (var m in fec.Cast())
94 | {
95 | try
96 | {
97 | var bundle = new TextureBundle(m);
98 |
99 | ElementId appearanceAssetId = m.AppearanceAssetId;
100 | AppearanceAssetElement appearanceAssetElem
101 | = doc.GetElement(appearanceAssetId)
102 | as AppearanceAssetElement;
103 |
104 | if (appearanceAssetElem == null) { continue; }
105 |
106 | Asset asset = appearanceAssetElem
107 | .GetRenderingAsset();
108 |
109 | if (asset == null) { continue; }
110 |
111 | for (int assetIdx = 0; assetIdx < asset.Size; assetIdx++)
112 | {
113 | AssetProperty aProperty = asset[assetIdx];
114 | if (aProperty.NumberOfConnectedProperties < 1) { continue; }
115 |
116 | Asset connectedAsset = aProperty
117 | .GetConnectedProperty(0) as Asset;
118 |
119 | // See if there is a path associated.
120 | #if REVIT2018 || REVIT2019 || REVIT2020
121 | // This line is 2018.1 & up because of the
122 | // property reference to UnifiedBitmap
123 | // .UnifiedbitmapBitmap. In earlier versions,
124 | // you can still reference the string name
125 | // instead: "unifiedbitmap_Bitmap"
126 | AssetPropertyString path = connectedAsset.FindByName(
127 | UnifiedBitmap.UnifiedbitmapBitmap)
128 | as AssetPropertyString;
129 | #else
130 | AssetPropertyString path =
131 | connectedAsset["unifiedbitmap_Bitmap"] as AssetPropertyString;
132 | #endif
133 | // If there is no asset path, nothing to pursue (Empty field)
134 | if (path == null || String.IsNullOrEmpty(path.Value)) { continue; }
135 |
136 | // See what kind of texture it is.
137 | if (TryGetTextureTypeFromAssetName(connectedAsset.Name, out var t))
138 | {
139 | // This will be a relative path to the
140 | // built -in materials folder, addiitonal
141 | // render appearance folder, or an
142 | // absolute path.
143 | string assetName = Path.GetFileNameWithoutExtension(path.Value);
144 |
145 | // Ensure that we have a valid texture path.
146 | if (RevitTextures.ContainsKey(assetName))
147 | {
148 | bundle.TexturePaths.Add(t, new SafenedFilename(RevitTextures[assetName]));
149 | }
150 | else
151 | {
152 | //Logger.LogError(
153 | // $"Found asset outisde of Revit material lib: {path.Value}. Could not add to export"
154 | // );
155 | }
156 | }
157 | }
158 |
159 | // Return the bundle we created.
160 | bundles.Add(bundle);
161 | }
162 | catch (Exception e)
163 | {
164 | //Logger.LogException("Error in bundle creation: ", e);
165 | }
166 | }
167 |
168 | var bundleList = bundles.Where(b => b != null).ToList();
169 | _bundleCache.Add(doc.PathName, bundleList);
170 | paths = _texturePathCache[doc.PathName];
171 |
172 | return bundleList;
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/Revit2Gltf/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Revit2Gltf")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Revit2Gltf")]
13 | [assembly: AssemblyCopyright("Copyright © 2021")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("ad5ae38a-3bde-4fb0-88f6-1f4133566ab5")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Revit2Gltf/RenderAppearanceDescriptor.cs:
--------------------------------------------------------------------------------
1 | #if REVIT2019 || REVIT2020
2 | using Autodesk.Revit.DB.Visual;
3 | #else
4 | using Autodesk.Revit.Utility;
5 | #endif
6 | using System;
7 | using System.Collections.Generic;
8 | using System.ComponentModel;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace Revit2Gltf
14 | {
15 | ///
16 | /// supplies dynamic custom type information for an Asset while it is displayed in PropertyGrid.
17 | ///
18 | internal class RenderAppearanceDescriptor : ICustomTypeDescriptor
19 | {
20 | #region Fields
21 | ///
22 | /// Reference to Asset
23 | ///
24 | Asset m_asset;
25 |
26 | ///
27 | /// Asset's property descriptors
28 | ///
29 | PropertyDescriptorCollection m_propertyDescriptors;
30 | #endregion
31 |
32 | #region Constructors
33 | ///
34 | /// Initializes Asset object
35 | ///
36 | /// an Asset object
37 | public RenderAppearanceDescriptor(Asset asset)
38 | {
39 | m_asset = asset;
40 | GetAssetProperties();
41 | }
42 |
43 | #endregion
44 |
45 | #region Methods
46 | #region ICustomTypeDescriptor Members
47 |
48 | ///
49 | /// Returns a collection of custom attributes for this instance of Asset.
50 | ///
51 | /// Asset's attributes
52 | public AttributeCollection GetAttributes()
53 | {
54 | return TypeDescriptor.GetAttributes(m_asset, false);
55 | }
56 |
57 | ///
58 | /// Returns the class name of this instance of Asset.
59 | ///
60 | /// Asset's class name
61 | public string GetClassName()
62 | {
63 | return TypeDescriptor.GetClassName(m_asset, false);
64 | }
65 |
66 | ///
67 | /// Returns the name of this instance of Asset.
68 | ///
69 | /// The name of Asset
70 | public string GetComponentName()
71 | {
72 | return TypeDescriptor.GetComponentName(m_asset, false);
73 | }
74 |
75 | ///
76 | /// Returns a type converter for this instance of Asset.
77 | ///
78 | /// The converter of the Asset
79 | public TypeConverter GetConverter()
80 | {
81 | return TypeDescriptor.GetConverter(m_asset, false);
82 | }
83 |
84 | ///
85 | /// Returns the default event for this instance of Asset.
86 | ///
87 | /// An EventDescriptor that represents the default event for this object,
88 | /// or null if this object does not have events.
89 | public EventDescriptor GetDefaultEvent()
90 | {
91 | return TypeDescriptor.GetDefaultEvent(m_asset, false);
92 | }
93 |
94 | ///
95 | /// Returns the default property for this instance of Asset.
96 | ///
97 | /// A PropertyDescriptor that represents the default property for this object,
98 | /// or null if this object does not have properties.
99 | public PropertyDescriptor GetDefaultProperty()
100 | {
101 | return TypeDescriptor.GetDefaultProperty(m_asset, false);
102 | }
103 |
104 | ///
105 | /// Returns an editor of the specified type for this instance of Asset.
106 | ///
107 | /// A Type that represents the editor for this object.
108 | /// An Object of the specified type that is the editor for this object,
109 | /// or null if the editor cannot be found.
110 | public object GetEditor(Type editorBaseType)
111 | {
112 | return TypeDescriptor.GetEditor(m_asset, editorBaseType, false);
113 | }
114 |
115 | ///
116 | /// Returns the events for this instance of Asset using the specified attribute array as a filter.
117 | ///
118 | /// An array of type Attribute that is used as a filter.
119 | /// An EventDescriptorCollection that represents the filtered events for this Asset instance.
120 | public EventDescriptorCollection GetEvents(Attribute[] attributes)
121 | {
122 | return TypeDescriptor.GetEvents(m_asset, attributes, false);
123 | }
124 |
125 | ///
126 | /// Returns the events for this instance of Asset.
127 | ///
128 | /// An EventDescriptorCollection that represents the events for this Asset instance.
129 | public EventDescriptorCollection GetEvents()
130 | {
131 | return TypeDescriptor.GetEvents(m_asset, false);
132 | }
133 |
134 | ///
135 | /// Returns the properties for this instance of Asset using the attribute array as a filter.
136 | ///
137 | /// An array of type Attribute that is used as a filter.
138 | /// A PropertyDescriptorCollection that
139 | /// represents the filtered properties for this Asset instance.
140 | public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
141 | {
142 | return m_propertyDescriptors;
143 | }
144 |
145 | ///
146 | /// Returns the properties for this instance of Asset.
147 | ///
148 | /// A PropertyDescriptorCollection that represents the properties
149 | /// for this Asset instance.
150 | public PropertyDescriptorCollection GetProperties()
151 | {
152 | return m_propertyDescriptors;
153 | }
154 |
155 | ///
156 | /// Returns an object that contains the property described by the specified property descriptor.
157 | ///
158 | /// A PropertyDescriptor that represents the property whose owner is to be found.
159 | /// Asset object
160 | public object GetPropertyOwner(PropertyDescriptor pd)
161 | {
162 | return m_asset;
163 | }
164 | #endregion
165 |
166 | ///
167 | /// Get Asset's property descriptors
168 | ///
169 | private void GetAssetProperties()
170 | {
171 | if (null == m_propertyDescriptors)
172 | {
173 | m_propertyDescriptors = new PropertyDescriptorCollection(new AssetPropertyPropertyDescriptor[0]);
174 | }
175 | else
176 | {
177 | return;
178 | }
179 |
180 | //For each AssetProperty in Asset, create an AssetPropertyPropertyDescriptor.
181 | //It means that each AssetProperty will be a property of Asset
182 | for (int index = 0; index < m_asset.Size; index++)
183 | {
184 | AssetProperty assetProperty = m_asset[index];
185 | if (null != assetProperty)
186 | {
187 | AssetPropertyPropertyDescriptor assetPropertyPropertyDescriptor = new AssetPropertyPropertyDescriptor(assetProperty);
188 | m_propertyDescriptors.Add(assetPropertyPropertyDescriptor);
189 | }
190 | }
191 | }
192 | #endregion
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/Revit2Gltf/Resources/icons8-upload-to-cloud-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/Revit2Gltf/Resources/icons8-upload-to-cloud-32.png
--------------------------------------------------------------------------------
/Revit2Gltf/Revit2Gltf.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {AD5AE38A-3BDE-4FB0-88F6-1F4133566AB5}
8 | Library
9 | Properties
10 | Revit2Gltf
11 | Revit2Gltf
12 | v4.7.2
13 | 512
14 | true
15 |
16 |
17 |
18 |
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | TRACE;DEBUG;REVIT2016
24 | prompt
25 | 4
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE;REVIT2016
32 | prompt
33 | 4
34 |
35 |
36 | true
37 | bin\Debug2016\
38 | TRACE;DEBUG;REVIT2016
39 | full
40 | AnyCPU
41 | 7.3
42 | prompt
43 | MinimumRecommendedRules.ruleset
44 |
45 |
46 | bin\Release2016\
47 | TRACE;REVIT2016
48 | true
49 | pdbonly
50 | AnyCPU
51 | 7.3
52 | prompt
53 | MinimumRecommendedRules.ruleset
54 |
55 |
56 | true
57 | bin\Debug2019\
58 | TRACE;DEBUG;REVIT2019
59 | full
60 | AnyCPU
61 | 7.3
62 | prompt
63 | MinimumRecommendedRules.ruleset
64 |
65 |
66 |
67 | ..\packages\AssimpNet.4.1.0\lib\net40\AssimpNet.dll
68 |
69 |
70 | ..\ThirdParty\API\2015\RevitAPI.dll
71 | False
72 |
73 |
74 | ..\ThirdParty\API\2015\RevitAPIIFC.dll
75 | False
76 |
77 |
78 | ..\ThirdParty\API\2015\RevitAPIUI.dll
79 | False
80 |
81 |
82 | ..\ThirdParty\API\2016\RevitAPI.dll
83 | False
84 |
85 |
86 | ..\ThirdParty\API\2016\RevitAPIIFC.dll
87 | False
88 |
89 |
90 | ..\ThirdParty\API\2016\RevitAPIUI.dll
91 | False
92 |
93 |
94 | ..\ThirdParty\API\2017\RevitAPI.dll
95 | False
96 |
97 |
98 | ..\ThirdParty\API\2017\RevitAPIIFC.dll
99 | False
100 |
101 |
102 | ..\ThirdParty\API\2017\RevitAPIUI.dll
103 | False
104 |
105 |
106 | ..\ThirdParty\API\2018\RevitAPI.dll
107 | False
108 |
109 |
110 | ..\ThirdParty\API\2018\RevitAPIIFC.dll
111 | False
112 |
113 |
114 | ..\ThirdParty\API\2018\RevitAPIUI.dll
115 | False
116 |
117 |
118 | ..\ThirdParty\API\2019\RevitAPI.dll
119 | False
120 |
121 |
122 | ..\ThirdParty\API\2019\RevitAPIIFC.dll
123 | False
124 |
125 |
126 | ..\ThirdParty\API\2019\RevitAPIUI.dll
127 | False
128 |
129 |
130 | ..\ThirdParty\API\2020\RevitAPI.dll
131 | False
132 |
133 |
134 | ..\ThirdParty\API\2020\RevitAPIIFC.dll
135 | False
136 |
137 |
138 | ..\ThirdParty\API\2020\RevitAPIUI.dll
139 | False
140 |
141 |
142 | ..\ThirdParty\Snappy\Snappy.NET.dll
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
175 |
176 |
177 |
178 |
--------------------------------------------------------------------------------
/Revit2Gltf/SafenedFilename.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Text.RegularExpressions;
7 | using System.Threading.Tasks;
8 |
9 | namespace Revit2Gltf
10 | {
11 | ///
12 | /// Removes whitespace and special characters
13 | /// from a filename to make it safe for upload and
14 | /// access in storage
15 | ///
16 | public class SafenedFilename
17 | {
18 |
19 | private static readonly Regex sWhitespace = new Regex(@"\s+", RegexOptions.Compiled);
20 | private static readonly Regex sSpecialChars = new Regex("[^a-zA-Z0-9_.]+", RegexOptions.Compiled);
21 |
22 | public readonly string FileLocation;
23 | public readonly string SafeFileName;
24 |
25 | public SafenedFilename(string path)
26 | {
27 | FileLocation = path;
28 | SafeFileName = RemoveSpecialCharacters(Path.GetFileNameWithoutExtension(path), Path.GetExtension(path));
29 | }
30 |
31 | static string RemoveSpecialCharacters(string fileName, string ext)
32 | {
33 | string output;
34 | output = sSpecialChars.Replace(fileName, "");
35 | output = sWhitespace.Replace(output, "");
36 | output = Path.GetFileNameWithoutExtension(output);
37 | output = output.Replace(".", "_") + ext;
38 | return output;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Revit2Gltf/TextureBundle.cs:
--------------------------------------------------------------------------------
1 | using Autodesk.Revit.DB;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Revit2Gltf
9 | {
10 | ///
11 | /// Combines
12 | ///
13 | public class TextureBundle
14 | {
15 | ///
16 | /// Full paths to the textures associated with this material.
17 | ///
18 | public Dictionary TexturePaths
19 | = new Dictionary();
20 |
21 | ///
22 | /// The material.
23 | ///
24 | public readonly Material Material;
25 |
26 | public TextureBundle(Material m)
27 | {
28 | Material = m;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Revit2Gltf/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ThirdParty/API/2015/RevitAPI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2015/RevitAPI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2015/RevitAPIIFC.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2015/RevitAPIIFC.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2015/RevitAPIUI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2015/RevitAPIUI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2016/RevitAPI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2016/RevitAPI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2016/RevitAPIIFC.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2016/RevitAPIIFC.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2016/RevitAPIUI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2016/RevitAPIUI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2017/RevitAPI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2017/RevitAPI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2017/RevitAPIIFC.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2017/RevitAPIIFC.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2017/RevitAPIUI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2017/RevitAPIUI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2018/RevitAPI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2018/RevitAPI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2018/RevitAPIIFC.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2018/RevitAPIIFC.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2018/RevitAPIUI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2018/RevitAPIUI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2019/RevitAPI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2019/RevitAPI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2019/RevitAPIIFC.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2019/RevitAPIIFC.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2019/RevitAPIUI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2019/RevitAPIUI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2020/RevitAPI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2020/RevitAPI.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2020/RevitAPIIFC.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2020/RevitAPIIFC.dll
--------------------------------------------------------------------------------
/ThirdParty/API/2020/RevitAPIUI.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/API/2020/RevitAPIUI.dll
--------------------------------------------------------------------------------
/ThirdParty/Snappy/Crc32C.NET.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/Snappy/Crc32C.NET.dll
--------------------------------------------------------------------------------
/ThirdParty/Snappy/Snappy.NET.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/twinup/Revit2Gltf/b7c475aea4eead0c05816afe60a7eb184fca9c15/ThirdParty/Snappy/Snappy.NET.dll
--------------------------------------------------------------------------------