From 1b3cb44dcc68f07655c46bd183f287dcfb002f31 Mon Sep 17 00:00:00 2001 From: Will Eastcott Date: Sun, 15 Dec 2024 13:48:54 +0000 Subject: [PATCH 1/5] Add skinning support to glTF exporter --- src/extras/exporters/gltf-exporter.js | 58 +++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/extras/exporters/gltf-exporter.js b/src/extras/exporters/gltf-exporter.js index 4f75620002a..eee852816e2 100644 --- a/src/extras/exporters/gltf-exporter.js +++ b/src/extras/exporters/gltf-exporter.js @@ -139,6 +139,7 @@ class GltfExporter extends CoreExporter { cameras: [], entities: [], materials: [], + skins: [], textures: [], // entry: { node, meshInstances} @@ -200,6 +201,11 @@ class GltfExporter extends CoreExporter { if (buffers.indexOf(indexBuffer) < 0) { buffers.push(indexBuffer); } + + // Collect skin + if (mesh.skin && resources.skins.indexOf(mesh.skin) < 0) { + resources.skins.push(mesh.skin); + } }); }; @@ -472,6 +478,12 @@ class GltfExporter extends CoreExporter { const entityMeshInstance = resources.entityMeshInstances.find(e => e.node === entity); if (entityMeshInstance) { node.mesh = resources.entityMeshInstances.indexOf(entityMeshInstance); + + // Add skin reference if this node has a skinned mesh + const meshInstance = entityMeshInstance.meshInstances[0]; + if (meshInstance && meshInstance.mesh.skin) { + node.skin = resources.skins.indexOf(meshInstance.mesh.skin); + } } if (entity.children.length > 0) { @@ -619,6 +631,11 @@ class GltfExporter extends CoreExporter { primitive.indices = idx; } + // Add skin reference if mesh is skinned + if (mesh.skin) { + primitive.skin = resources.skins.indexOf(mesh.skin); + } + return primitive; } @@ -730,6 +747,46 @@ class GltfExporter extends CoreExporter { return arrayBuffer; } + writeSkins(resources, json) { + if (resources.skins.length > 0) { + json.skins = resources.skins.map((skin) => { + // Create float32 array for inverse bind matrices + const matrices = new Float32Array(skin.inverseBindPose.length * 16); + for (let i = 0; i < skin.inverseBindPose.length; i++) { + const ibm = skin.inverseBindPose[i]; + matrices.set(ibm.data, i * 16); + } + + // Create buffer view for matrices + const matrixBuffer = matrices.buffer; + GltfExporter.writeBufferView(resources, json, matrixBuffer); + resources.buffers.push(matrixBuffer); + const bufferView = resources.bufferViewMap.get(matrixBuffer); + + // Create accessor for inverse bind matrices + const accessor = { + bufferView: bufferView[0], + componentType: 5126, // FLOAT + count: skin.inverseBindPose.length, + type: 'MAT4' + }; + const accessorIndex = json.accessors.push(accessor) - 1; + + // Find joint nodes by bone names + const joints = skin.boneNames.map(boneName => { + const node = resources.entities.find(entity => entity.name === boneName); + return resources.entities.indexOf(node); + }); + + // Create skin + return { + inverseBindMatrices: accessorIndex, + joints: joints + }; + }); + } + } + buildJson(resources, options) { const promises = this.convertTextures(resources.textures, options); @@ -761,6 +818,7 @@ class GltfExporter extends CoreExporter { this.writeMeshes(resources, json, options); this.writeMaterials(resources, json); this.writeNodes(resources, json, options); + this.writeSkins(resources, json); await this.writeTextures(resources, textureCanvases, json, options); // delete unused properties From c3e9a2faa7abd07fc1e096ee7348e2816a16dd42 Mon Sep 17 00:00:00 2001 From: Will Eastcott Date: Sun, 15 Dec 2024 13:53:41 +0000 Subject: [PATCH 2/5] Move writeSkins function up a bit --- src/extras/exporters/gltf-exporter.js | 80 +++++++++++++-------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/src/extras/exporters/gltf-exporter.js b/src/extras/exporters/gltf-exporter.js index eee852816e2..678a60dc1e7 100644 --- a/src/extras/exporters/gltf-exporter.js +++ b/src/extras/exporters/gltf-exporter.js @@ -639,6 +639,46 @@ class GltfExporter extends CoreExporter { return primitive; } + writeSkins(resources, json) { + if (resources.skins.length > 0) { + json.skins = resources.skins.map((skin) => { + // Create float32 array for inverse bind matrices + const matrices = new Float32Array(skin.inverseBindPose.length * 16); + for (let i = 0; i < skin.inverseBindPose.length; i++) { + const ibm = skin.inverseBindPose[i]; + matrices.set(ibm.data, i * 16); + } + + // Create buffer view for matrices + const matrixBuffer = matrices.buffer; + GltfExporter.writeBufferView(resources, json, matrixBuffer); + resources.buffers.push(matrixBuffer); + const bufferView = resources.bufferViewMap.get(matrixBuffer); + + // Create accessor for inverse bind matrices + const accessor = { + bufferView: bufferView[0], + componentType: 5126, // FLOAT + count: skin.inverseBindPose.length, + type: 'MAT4' + }; + const accessorIndex = json.accessors.push(accessor) - 1; + + // Find joint nodes by bone names + const joints = skin.boneNames.map(boneName => { + const node = resources.entities.find(entity => entity.name === boneName); + return resources.entities.indexOf(node); + }); + + // Create skin + return { + inverseBindMatrices: accessorIndex, + joints: joints + }; + }); + } + } + convertTextures(srcTextures, options) { const textureOptions = { @@ -747,46 +787,6 @@ class GltfExporter extends CoreExporter { return arrayBuffer; } - writeSkins(resources, json) { - if (resources.skins.length > 0) { - json.skins = resources.skins.map((skin) => { - // Create float32 array for inverse bind matrices - const matrices = new Float32Array(skin.inverseBindPose.length * 16); - for (let i = 0; i < skin.inverseBindPose.length; i++) { - const ibm = skin.inverseBindPose[i]; - matrices.set(ibm.data, i * 16); - } - - // Create buffer view for matrices - const matrixBuffer = matrices.buffer; - GltfExporter.writeBufferView(resources, json, matrixBuffer); - resources.buffers.push(matrixBuffer); - const bufferView = resources.bufferViewMap.get(matrixBuffer); - - // Create accessor for inverse bind matrices - const accessor = { - bufferView: bufferView[0], - componentType: 5126, // FLOAT - count: skin.inverseBindPose.length, - type: 'MAT4' - }; - const accessorIndex = json.accessors.push(accessor) - 1; - - // Find joint nodes by bone names - const joints = skin.boneNames.map(boneName => { - const node = resources.entities.find(entity => entity.name === boneName); - return resources.entities.indexOf(node); - }); - - // Create skin - return { - inverseBindMatrices: accessorIndex, - joints: joints - }; - }); - } - } - buildJson(resources, options) { const promises = this.convertTextures(resources.textures, options); From df4adf6ff24320b9a17796869ab094c2b85103a7 Mon Sep 17 00:00:00 2001 From: Will Eastcott Date: Sun, 15 Dec 2024 13:57:54 +0000 Subject: [PATCH 3/5] Lint fixes --- src/extras/exporters/gltf-exporter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extras/exporters/gltf-exporter.js b/src/extras/exporters/gltf-exporter.js index 678a60dc1e7..b8881125ee6 100644 --- a/src/extras/exporters/gltf-exporter.js +++ b/src/extras/exporters/gltf-exporter.js @@ -478,7 +478,7 @@ class GltfExporter extends CoreExporter { const entityMeshInstance = resources.entityMeshInstances.find(e => e.node === entity); if (entityMeshInstance) { node.mesh = resources.entityMeshInstances.indexOf(entityMeshInstance); - + // Add skin reference if this node has a skinned mesh const meshInstance = entityMeshInstance.meshInstances[0]; if (meshInstance && meshInstance.mesh.skin) { @@ -665,7 +665,7 @@ class GltfExporter extends CoreExporter { const accessorIndex = json.accessors.push(accessor) - 1; // Find joint nodes by bone names - const joints = skin.boneNames.map(boneName => { + const joints = skin.boneNames.map((boneName) => { const node = resources.entities.find(entity => entity.name === boneName); return resources.entities.indexOf(node); }); From 8c0b883bee8c037c0fe95f93c98fd7e2dcbde93e Mon Sep 17 00:00:00 2001 From: Will Eastcott Date: Sun, 15 Dec 2024 14:21:23 +0000 Subject: [PATCH 4/5] Remove skin property from geometry --- src/extras/exporters/gltf-exporter.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/extras/exporters/gltf-exporter.js b/src/extras/exporters/gltf-exporter.js index b8881125ee6..e9a78e10dbe 100644 --- a/src/extras/exporters/gltf-exporter.js +++ b/src/extras/exporters/gltf-exporter.js @@ -631,11 +631,6 @@ class GltfExporter extends CoreExporter { primitive.indices = idx; } - // Add skin reference if mesh is skinned - if (mesh.skin) { - primitive.skin = resources.skins.indexOf(mesh.skin); - } - return primitive; } From ee1c850681b8d7ea544c406b61fa131dfd9f70ae Mon Sep 17 00:00:00 2001 From: Will Eastcott Date: Mon, 16 Dec 2024 13:42:41 +0000 Subject: [PATCH 5/5] Use getComponentType --- src/extras/exporters/gltf-exporter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extras/exporters/gltf-exporter.js b/src/extras/exporters/gltf-exporter.js index e9a78e10dbe..b347d281e4c 100644 --- a/src/extras/exporters/gltf-exporter.js +++ b/src/extras/exporters/gltf-exporter.js @@ -653,7 +653,7 @@ class GltfExporter extends CoreExporter { // Create accessor for inverse bind matrices const accessor = { bufferView: bufferView[0], - componentType: 5126, // FLOAT + componentType: getComponentType(TYPE_FLOAT32), count: skin.inverseBindPose.length, type: 'MAT4' };