How to export 3D objects as USDZ on iOS
On-device using iOS’s native frameworks, not using Xcode’s command line tools!
That little detail is huge if you’ve been trying to convert your 3D assets to the recently announced USDZ file format for use in Apple’s ARKit or AR Quick Look.
When I first scoured through every forum post related to this topic I encountered developers saying the same thing over and over:
- It’s not possible on iOS even though the related WWDC states that you can read and write USDZ with SceneKit and ModelIO
- Use Xcode’s usdz_converter tool
Feeling discouraged about iOS’s lack of native support for exporting this file type, I turned to extreme measures of trying to build Pixar’s USD library for iOS, which took me a whole day and late into the night with some good progress but also with several architecture-specific roadblocks left.
Although successfully configuring the USD library to build for iOS is something that would be useful to the community (and is definitely possible), I simply didn’t have enough time to go forward with that approach.
I returned to the drawing board to see if I could force iOS’s ModelIO Framework to export my object as USDZ.
First I export as usdc for as a sanity check.
This works and I’m able to open the file on my MacBook!
What happens if I just change the format of the url to .usdz instead of .usdc, ignoring the fact the the export check failed?
No dice. Strangely, even though the canExportFileExtension returned false, there was no error output from the exportAssetToURL, but the usdz file did not get created anywhere.
To be fair, that was a weak attempt on my part, and we learn MDLAsset is smart enough not to export to something it doesn’t support (EVEN THOUGH IT SHOULD SUPPORT USDZ!)
At this point I know it’s possible to export 3D objects via MDLAsset as usda and usdc, and I know that USDZ is “a zero compression, unencrypted zip archive” that essentially wraps some other USD filetype. Hmmm.
I used a tip found here for extracting the .usdz archive to see the files inside it and inspect the internal usdc file. This file is binary and doesn’t make sense to humans, but there are important keywords in there that might prove to be helpful.
With not much helpful information from the unreadable binary file, I remember another snippet from the USDZ specification that states in the USDZ file Layout section
The only absolute layout requirement a usdz package makes of files within the package is that the data for each file begin at a multiple of 64 bytes from the beginning of the package.
Aha! If I make a text file and copy the contents of the usdc file from earlier and offset the start of the usdc text by a multiple of 64 bytes, it might just work. But... 0 is a multiple of 64... so basically we can just rename the usdc to usdz? YES! It works!
Again, I can open the file on my MacBook.
I can even open it on my iPhone, although it appears iOS doesn’t support per-vertex colors like OSX.
So much headache for such a simple solution, but that’s how it goes sometimes.
Here's a link to the final sample code: https://gist.github.com/elaughli/43a619fbdc294e56c60fab376f37a352
As with any breakthrough we make, this calls for an update to Scandy Pro. Our next update will include a USDZ export option, so you can easily share your 3D scans for your ARKit project or to any AR Quick Look enabled apps, including iMessage!
NOTE: This is a simple use case. The 3D model I used to do this was a single mesh using per-vertex color, no texture maps and materials. It might be possible to set textures and materials to a SceneKit object then converting to MDLAsset and exporting as usda/usdc then modifying them from there, but for now, I’m pleased with this discovery.