Does uploading a 3d tile to Ion change the mesh at all?

I have a 3d tile that contains a sort of hierarchical lod and uses implicit tiling. I’m manually creating the mesh and subdividing it into a quad tree. Each piece of this quadtree is a glb with specific uvs. After uploading this tileset to ion, and streaming it to Unreal, those mesheshave different uvs from the ones I created and my texturing goes wrong. I can verify this by loading the glb into Unreal manually to see the correct uvs, but once it comes through from Ion it’s different.

Am I missing something obvious about how this is handled when going through Ion?

Hi,

If you uploaded it as 3D Tiles, ion should just host the data as is. However it is possible that during the upload one of the settings was not correct and ion treated it as set of GLB files and tiled them.

Do you have an asset id so that we can look into this further?

Regards,

Mark

Hey Mark, thank you for your reply!

I’m afraid I can’t share the data as it’s self-hosted.

I believe it should have treated it as a 3d tile though, there’s not many options available from what I can see.

Yes, those are the correct settings for uploading the data as a 3D Tileset.

Are you able to try loading a local copy of the 3D Tileset into Unreal? That would help narrow down if it is something with ion or how Cesium for Unreal is handling the GLBs.

I’ve also reached out to our Unreal team to see if they have any suggestions.

Another diagnosis step could be to compare the uploaded GLB and the corresponding downloaded GLB. To my understanding, these should be identical. If they are not, then one can look at what the differences are, and narrow down which of them might cause the wrong texturing.

@mdc9001 @Marco13, thank you both for the suggestions! It has helped me dive into this a bit more. So, I see the issue when I load the tileset locally as well, bypassing Ion, meaning it’s not Ion modifying anything.

I still only see the issue when rendering the mesh as part of the tileset and not if I load the same glb as a static mesh into Unreal, so the search continues. I’ll look a bit closer at what’s happening between loading a tileset and rendering that mesh now, in case that points to anything specific.

Hi @flav!

I work on Cesium for Unreal – just trying to catch up on what’s going on here. If you’re able to share a test model that results in the same behavior, then we could try to reproduce this on our side and hopefully diagnose the issue.

Do you recall tiling your data with any specific settings? For example, Draco compression? It’s possible that there is a bug when trying to decompress the tileset at runtime. It would also be good to confirm that you’re able to view your tileset correctly in the Cesium ion preview (which is built on CesiumJS). That way we can isolate it as an Unreal bug, and not a tilers one.

Thanks!

When encountering ~“unexpected rendering behavior”, it often makes sense to to make sure that the GLB/glTF files are valid, by checking them with the glTF Validator (or, for a whole tileset at once, with the 3D Tiles Validator).

Assuming that they are valid, the validator may still provide some helpful information. Specifically, whether the GLBs use any form of compression (like the Draco compression that Janine mentioned, or maybe meshopt), or any other extension that may affect the texture display (like KHR_texture_transform).

@janine Thank you for your reply. Would it be possible to email this data instead of making public?

There’s no draco compression, the 3d tile is created manually and has a tileset.json, a subtree.json, and all the glb for all lods and all parts of each lod (it’s essentially a hierarchical lod using implicit tiling). This is the folder i upload to Ion (or load locally).

The mesh renders fine in both Ion and Unreal Engine, it’s just the UVs on everything other than the lowest lod (i.e. everything that’s split into more than one mesh) that seem to be broken. Unfortunately it’s not trivial to verify with Ion as a test because as it stands, the tile itself doesn’t have any textures. In both Ion and Unreal it just displays as black by default until a material is added, making it difficult to verify if the UVs are correct or not in Ion.

@Marco13 all glbs show up as green in the glTF validator and there’s no errors reported by the 3d tileset validator either. Here’s an example of the validator for one of the glbs:

{
    "uri": "0.glb",
    "mimeType": "model/gltf-binary",
    "validatorVersion": "2.0.0-dev.3.10",
    "validatedAt": "2025-03-11T15:44:17.869Z",
    "issues": {
        "numErrors": 0,
        "numWarnings": 0,
        "numInfos": 2,
        "numHints": 0,
        "messages": [
            {
                "code": "UNUSED_MESH_TANGENT",
                "message": "Tangents are not used because the material has no normal texture.",
                "severity": 2,
                "pointer": "/meshes/0/primitives/0/attributes/TANGENT"
            },
            {
                "code": "UNUSED_OBJECT",
                "message": "This object may be unused.",
                "severity": 2,
                "pointer": "/meshes/0/primitives/0/attributes/TEXCOORD_0"
            }
        ],
        "truncated": false
    },
    "info": {
        "version": "2.0",
        "generator": "Houdini GLTF 2.0 Exporter",
        "resources": [
            {
                "pointer": "/buffers/0",
                "mimeType": "application/gltf-buffer",
                "storage": "glb",
                "byteLength": 357164
            }
        ],
        "animationCount": 0,
        "materialCount": 0,
        "hasMorphTargets": false,
        "hasSkins": false,
        "hasTextures": false,
        "hasDefaultScene": true,
        "drawCallCount": 1,
        "totalVertexCount": 5169,
        "totalTriangleCount": 7837,
        "maxUVs": 1,
        "maxInfluences": 0,
        "maxAttributes": 5
    }
}

I assume the two infos shouldn’t cause any issues.

Please note, if I just import this glb as a static mesh into Unreal, it shows the UVs I expect. It only seems to render with bad UVs when loaded and rendered as part of a 3d tile.

Since I can reproduce this when loading the 3d tile from a local URL as well, we can likely safely assume it’s not caused in any way by Ion anymore, which means this thread is probably in the wrong subforum now. Apologies.

Hi @flav,

Yes, feel free to email the model to me at janine@cesium.com. I plan to test the model by itself, as well as with Cesium ion’s tilers to see if that makes a difference. If there’s something else I should try, let me know!

1 Like

The part

"code": "UNUSED_OBJECT",
"message": "This object may be unused.",
"severity": 2,
"pointer": "/meshes/0/primitives/0/attributes/TEXCOORD_0"

looks at least suspicious when you say that there is an issue with the texture coordinates. But as far as I understood the description, the goal seems to (roughly) be to load this without textures (and the “unused” texture coordinates), but then assign a texture in Unreal (that should use these texture coordinates)

This touches some details of Unreal that I’m not familiar with - namely, how the texture coordinates from the mesh are wired together with the material that is assigned within Unreal. So until now, I could only make guesses. Maybe some part of the process that converts the GLB into an ‘Unreal Mesh’ omits the texture coordinates, because it realizes that they are unused? That wouldn’t explain why it works when it’s imported manually, though. Hopefully, the issue can be sorted out based on the actual data set :crossed_fingers:

Hi @flav,

Thanks for sending over the test data. I’m seeing the same visual bugs on my end, too.

I believe this is actually a problem that we previously observed here: Buggy texture coordinate generation for raster overlays · Issue #1564 · CesiumGS/cesium-unreal · GitHub. For context, when we drape raster overlays over 3D Tiles in Unreal, we generate a completely new set of texture coordinates to map the raster. It’s not using the original texture coordinates in the glTF, so that’s why you’re seeing correct UVs in one but different UVs in another. When I wrote that Github issue, I couldn’t confirm whether it was just a problem with the user’s own data. However, the fact that this came up again leads me to believe that there’s something genuinely wrong with how we drape raster overlays at runtime.

I’m going to escalate this as a bug to our team so that one of our members can take a closer look. We’ll update this thread when there’s progress. Thank you again!

Best regards,
Janine

1 Like