Why does ambient get a duplicate ORM texture instead of using the same assigned to Metalness and Roughness?

Hey all,
I’ve been experimenting with exporting from Max and importing into sandbox and playground, in particularly interested in just understanding the pipeline and the how and what is going on.

For the sake of the question, I export a glTF from Max with AO merged. My result is glTF, bin, normal.png, color.png, and ORM.jpg

On import to sandbox or playground, the inspector shows effectively two textures. 1 is assigned to both metalness and roughness, but ambient gets its own version of the same texture?

So my question is if I pre-pack an ORM texture map -or- more likely have it created during the export from Max with the “Merge AO” option turned on, why does Babylon seemingly duplicate my single texture and use a separate duplicate for the Ambient assignment?

It seems I would be losing the optimization the ORM affords me by increasing my payload?

Thanks!

Are you sure you did not set a texture for the ambient channel in Max? You are saying “ambient” here and not “ambient occlusion”.

Also, it may be easier to look for the problem if you could share a PG.

Thanks for the help.

I am referring to the Ambient Occlusion as “Ambient” to keep with the naming conventions of inspector. Unless I’m really lost I believe the “Ambient” slot if for AO?

I’ll try and get a PG together, but lemme try to explain it another way. I made a box with a single material applied.

I have these files after export:
image

BoxTest.glt
BoxTest.bin

BaseColor.png
Normal.png
AORoughnessMetalness.jpg - (I verified each channel does contain the correct AO in red, Rough in green, and Metal in blue) So texture pack is good.

So in total, I only have 3 texture files.

When I drag into Sandbox, I see 4 textures assigned to my single material.
Metalness and Roughness are both assigned the same texture with the same ID.
My Occlusion or “Ambient” slot is assigned a duplicate with a different ID.

I could be misunderstanding , but to me it looks like the Occlusion slot has a duplicate texture since it is not assigned the same as metalness and roughness with same ID.

You’re right, the “Ambient” section is for the AO part of the model.

In the GLTF2 spec, you don’t have a single slot for Occlusion + Roughness + Metallic. You have:

  • metallicRoughnessTexture for roughness + metallic maps
  • occlusionTexture for the AO map

Now, if the occlusionTexture of the GLTF file points to the same picture than metallicRoughnessTexture, I think it should be shared by both. So try to have a look into your gltf file and see if those two textures really point to the same picture inside the file.

Another possibility is simply that the unique id you see in the inspector is the id for the Texture object and not for the picture itself: you can have (I think?) multiple texture objects that share the same picture underneath.

Only experts will be able to tell if the same picture is really shared by the metallicRoughness and AO textures (I don’t think we can tell by looking at the inspector only).

Ok, after tracing the code, I think I have it.

You really have two Texture instances because there are two different properties in the material, one for each texture.

However, as those two textures are pointing to the same image in the gltf file, the _texture property (which is a InternalTexture type) inside the Texture instance is the same in both cases, so the picture data (they are in the InternalTexture instance) themselves are shared between both textures.

At least that’s what happens for the Alien.gltf file, which also has an ORM texture.

It would be cool to have a unique id inside the InternalTexture class so that we could display it in the inspector and see that even if the unique id of the two textures are different, the internal texture id is the same, but unfortunately there’s no such unique id in InternalTexture.

Ah ha! Thanks for digging in! So everything sounds correct then.

It was a bit confusing coming from an artist perspective, where I am typically connecting those to the material properties, and can visibly see that I am using the same texture file for different properties. We tend to get anxious over seeing an “extra” texture when we were so careful to pack channels to save space.

An interesting point of note: despite it being the same InternalTexture class reference, each unique ID has its own properties that can be manipulated individually. If I were to connect a single texture to multiple properties in Max for example, any change at the root texture level, like offset or angle would affect all properties connected to it, since they are effectively all referencing the same texture. Some might argue this setup has an advantage of manipulating the references independently it would seem.

Thanks again!

That’s the same thing in Babylonjs, but the properties are not defined at the same level: offset / angle, for eg, are not defined at the “picture” level (InternalTexture) but at the texture level (Texture class). So, if you have two different textures pointing to the same internal texture, you can change the offset/angle properties of one independent from the other. If you need that the properties stay in sync, then use a single instance of Texture from start.

Some properties are specific to InternalTexture: sampling mode, invertY, mimap yes/no. So, if you change one of these properties for a texture, then it will be automatically synced with the other texture if they share the same internal texture. You can see this in the inspector: if you change Sampling mode for the roughtness/metallic texture, you will see that the property will also be updated for the ambient occlusion texture as they share the same internal texture object.

2 Likes

+1 on @Evgeni_Popov’s responses :slight_smile:

@Evgeni_Popov Thanks again. Most helpful, and much appreciated. I hope this is helpful to others as well, as it has certainly helped me. Great community here for sure!

@bghgary I second you on that.

2 Likes