Scene to USDZ converter

USDZ does not support negative scales, so how with us inverting the global Matrices to account for the different handiness will I work around this?

I guess I have to negate the -scale?

For sure gonna need a file spec cheat sheet.

1 Like

Some time ago i wrote an USDZ export for our app. I had a lot of trouble with it to get some usefull results because of the limitations of the USDZ Viewer in IOS (USDZ itself is very powerfull).

For example the nagative scale. In the end we had to flatten everything and applied transformations to the vertices to avoid any issues … which also means duplicating shared geometries.
There are also some limitiations regarding the PBR but i don’t remember exactly.
Because we had to use the ACII version of USD (didn’t find a documentation for the binary version) and the special zip file for USD is not compressed we ended up with very huge files which couldn’t be loaded on iphone anymore.
… after several issues we dropped the client side export and are now doing it on server side using the official pixar USD library

Also @Kesshi , we do it server side, using GLB to USDZ conversion; there are some things to work around, but overall it worked well takes a few secs if you have a decent machine provisioned for it with a good number of threads for concurrent operations, been running without issues for well over a year.
However, I guess it does take some testing and server-side machine set-up knowledge.
I also presume it will never work very well across mobiles, so I would suggest to others to go the server-side route also for the 1005 reliability factor, you can then used the generated files with caching for x period of time to save regnerations.

Fwiw, here is a peg grammar for usda.

.usda-parser/usda-parser.peggy at main · Kroxilon/usda-parser · GitHub

I read the usd spec some time ago, the ascii format seems like its just a python equivalent of json with refs. Binary version has layout requirements for efficient playback / loading by keeping stuff collocated. Ascii format seems not so different than gltf with variants… at least to my small brain

1 Like

Welp thank you @jeremy-coleman. That helped more than I can explain.

I was able to get my parser to create these results.
Now its time to go back and fix out the rest of the material channels that I ignored for simplicity.

Buuuuuuut, looks like this is “working” now.


  • Fix the texture identification, so it knows to tag it as “raw” vs “sRGB” when its a normal texture.
  • Make sure the texture wrapping values are mapped correctly.
  • Be a Wizard and fix the -1 scaling issues (I have an idea for this one)
  • Add Texture rotation support.
  • Better Alpha blending check.
  • Go back over the Camera parsing part and make sure we have some intelligent conversions for items that do not exist in our engine.
  • Figure out why the textures are not rendering.
  • Figure out why there is a section of missing geometry.

Once I finish up the material stuff, ill spin up a PR.

@sebavan will this be an external thing or should I wrap it into the BJS namespace?


Oooof ok, here is an interesting question.

What channel format is the USDZ looking for in the “roughnessMap” and “metalnessMap” (what a name…).

I’m assuming they are just black and white images or just a single channel.
Now with supporting this it looks like ill need to split up our metallicTexture into two dynamic textures and pass those as the roughness and metalness ( what a name…) maps.

Woot now we are getting some where… just got to do the metal and roughness stuff now and we will have our basic USDZ exporter!

hmmm this makes me wonder if I could make a parse method as well since this is more an export method.

Also need to figure out why it seems to be missing some geo:

Found this

AO, Metallic and Roughness are supported now.

Just got to figure out some oddities and this should be “useable”.

Ours is on the left, ThreeJs on the right.
The color difference is probably the normal texture being encoded in a different space, or it could be we are using AO and the Three js is not. Oooooor its the IOR settings.

Its for sure the AO and or IOR settings, if I remove those it goes back to looking 1 for 1 like the Three.js export.


I would say we put it in the serializer project and we could have the equivalent loader :slight_smile:

Flag it as experimental so at least we can still break it (or mostly fix it without back compat thoughts)

1 Like

Sounds good, I would need to do the parser still but seeing how similar things are it would not be that hard.

the biggest difference is the ao/metallic/roughness stuff.

Really like the work done here. USDZExporter works quite well!
Question: How can we export morph target changes? Leaning quite heavily on it in my product.
Maybe a hint to spec on usd for morphtargets?

Probably we need to calculate it in javascript and set it by hand according to

Hey, this was already looking pretty good !
Any news about the final release of this USDZExporter ?
It would be one of the most useful features up today for Babylon Js.
Thank you so much for this marvelous work :ok_hand:

We would have to revert a bunch of the requested changes and get it back into a working state. Too many code revisions were requested that effected the structure of the output which is now causing the files to be corrupt. It was in a working state at one point though and if we can get it back to that then make incremental changes to it instead. I don’t have the time to sort thorough what went wrong though and don’t know enough about the file type to fix it in the state its in now.