KhronosGroup / glTF

glTF – Runtime 3D Asset Delivery
Other
7.2k stars 1.14k forks source link

Multiple buffers, duplicate URIs? #2446

Open donmccurdy opened 1 month ago

donmccurdy commented 1 month ago

I came across a file recently containing three buffers, all sharing the same URI:

  "buffers": [
    {
      "uri": "glTF.bin",
      "byteLength": 8160
    },
    {
      "uri": "glTF.bin",
      "byteLength": 8160
    },
    {
      "uri": "glTF.bin",
      "byteLength": 8160
    }
  ],

No validation errors were found, and viewers I tested (three.js, babylon.js, playcanvas) seemed fine, but it did break processing in glTF Transform, which tried to overwrite the buffer repeatedly. The file also contained valid buffer views pointing to each buffer.

My impression is that this is suboptimal, but technically valid, does that seem correct?

javagl commented 1 month ago

I think that there are no constraints that disallow this, so would agree that this is technically valid.

I just created a Triangle with such duplicate buffers:

TriangleDuplicateBuffer.zip

Just for the heck of it, I did two further tests:

I declared them once with "byteLength": 44 (correct) and once with "byteLength": 43 ("wrong"). And interestingly, the validator reports both to have "byteLength": 44. (So it apparently overwrites the declared byte length with the length of the actual .bin file...)

I also thought that it could be difficult to clearly define when two buffer declarations are actually equal. So (locally) I also tried using "uri": "./subdirectory/../Triangle_data.bin", as the URI for the second one. This resolves to the same URI. And in fact, the validator reports this as "uri": "Triangle_data.bin", (i.e. some form of "normalized" version of the URI). But there probably are cases where such a normalization is far more difficult (or maybe even impossible).

So ... when this is allowed, it might raise some questions for implementors. Consider an example like the Triangle.gltf, but with two triangles, each referring to its own accessors and buffer views and buffer. And only on the lowest level - namely, on the level of the uri of the buffer - these buffers are equal. Now, when someone does gltf.meshes[0].primitives[0].attributes["POSITION"].set(0, 1234.567); will this affect both triangles, because the underlying, most raw Buffer objects that have been read from the .bin file are identical because they have the same URI?

(This is probably beyond what the glTF spec can cover. But for things like glTF-Transform, there will be an answer to this question, and regardless what the answer is: It might be different from what someone expects...)

lexaknyazev commented 1 month ago

the validator reports both to have "byteLength": 44. (So it apparently overwrites the declared byte length with the length of the actual .bin file...)

The resources section of the report provides information about the actual resources, in this case the file's byte length.

Thes spec says:

The byte length of the referenced resource MUST be greater than or equal to the buffer.byteLength property.

so it's valid to declare a buffer's byte length less than the actual file.

javagl commented 1 month ago

Yes, but I considered it to be a corner case for establishing any concept of "equality" between buffers: If two buffers with the same uri were be disallowed by the spec, it would raise the question of whether they should also be disallowed when they had different byteLengths.

Even before that, the concept of "equality" can already be difficult for the uri itself. (I'd have to start by looking up whether URIs can have things like fragments here).

When buffers with duplicate URIs are valid, some questions about what "duplicate" means don't even come up. Other details (e.g. whether clients SHOULD or MAY read these .bin files twice, and store the memory twice) are probably too implementation specific to be covered by the spec.

donmccurdy commented 1 month ago

Planned fix in glTF Transform:

No plans to round-trip such files as-is — with multiple buffers pointing to overlapping ranges of the same underlying file — but reading and writing should at least handle the files gracefully.