So, I went and read the spec on the gltf file format. Took a bit but it was pretty straightforward and I was able to fix my file by editing it directly. I have attached the fixed file. While I now know what the problem is, fixing it in the pre-existing gltfexporter might be hard…I am going to take a look though.
I will for sure explain the problem and my solution here in detail, so that even if I don’t fix it hopefully it helps someone else fix it?
The main problem is that multiple primitives refer back to the same bufferView. From the skunk file:
"primitives": [
{
"mode": 4,
"attributes": {
"POSITION": 0,
"NORMAL": 1,
"COLOR_0": 2,
"TEXCOORD_0": 3
},
"material": 0
},
{
"mode": 4,
"attributes": {
"POSITION": 0,
"NORMAL": 1,
"COLOR_0": 2,
"TEXCOORD_0": 3
},
"material": 1
}
]
You can see that both primitives use bufferView 3 for the texcoords. I did write a script that went through buffer view 3 and validated that all the uvs are in fact in there. However, the uvs for the entire model are in there. I’ll be the first to admit I am not an expert at webgl and graphics buffers in general, but intuitively it felt wrong for both of these separate primitives to use the same texcoords (and in fact same position, normal, and color) index.
It would seem to me that instead, each primitive needs its own set of indexes for position, normal, color, and texcoords. For instance the skunk model has 96 uv entries in its array. However only the 0-47 apply to the first primitive, the next primitive needs to grab 48-95. In the current implementation, idk how the render would know that for primitive 2, use bufferView 3, but start halfway through it…same for position, normal, color, etc. (again not an expert, just seems wrong)
So, I split them out. I created a new buffer view for position, a new buffer view for normal, a new buffer view for color, and a new buffer view for texcoords. Now each primitive gets its own set of buffer views.
So buffer views go from:
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 576,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteOffset": 576,
"byteLength": 576,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteOffset": 1152,
"byteLength": 576,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteOffset": 1728,
"byteLength": 384,
"target": 34962,
"byteStride": 8
}
to
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 288,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteOffset": 288,
"byteLength": 288,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteOffset": 576,
"byteLength": 288,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteOffset": 864,
"byteLength": 288,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteOffset": 1152,
"byteLength": 288,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteOffset": 1440,
"byteLength": 288,
"target": 34962,
"byteStride": 12
},
{
"buffer": 0,
"byteOffset": 1728,
"byteLength": 192,
"target": 34962,
"byteStride": 8
},
{
"buffer": 0,
"byteOffset": 1920,
"byteLength": 192,
"target": 34962,
"byteStride": 8
}
There are twice as many buffer views now, but each is half the length of the old one. Effectively giving me two separate views into the buffer for each attribute. Of course I had to update the accessors and indexes in the primitives as well. You can see the final result in the attached file.
I do get validation errors on min/max, because those are no longer correct since half the values now live in a different accessor, but thats a simple fix and does not stop the model from rendering correctly.
Now each primitive gets its own set of buffer views, with primitive two’s buffer views starting half way into the original larger one
On a separate note, it seems like the primitives come out on the wrong order, causing the one on the bottom to be drawn over the one at the top, so I swapped their order, leaving my primitive array looking like:
"primitives": [
{
"mode": 4,
"attributes": {
"POSITION": 1,
"NORMAL": 3,
"COLOR_0": 5,
"TEXCOORD_0": 7
},
"material": 1
},
{
"mode": 4,
"attributes": {
"POSITION": 0,
"NORMAL": 2,
"COLOR_0": 4,
"TEXCOORD_0": 6
},
"material": 0
}
]
Hopefully that helps somewhat to clear up whats going on? Hard to explain via post, and also, I only started reading about this file format last night so I could have something wrong, but the file does render correctly now.
model (2).gltf (63.5 KB)