Replacing meshes/assets in .glb avatars on react-native #1396
-
I want to basically replace the "hair" asset/mesh in a .glb of an avatar with another "hair" asset that i have in a separate .glb. I am attaching a drive link which contains 2 avatars with different hair assets and also a separate hair asset (it is a cap): Also need to do this in react-native (client-side) so if there's anything particular i need to look out for in that case, would be good to know. Can anyone help out? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
If you install the alpha release of v4 ... yarn add @gltf-transform/core@next @gltf-transform/extensions@next @gltf-transform/functions@next ... there's a new import { NodeIO } from "@gltf-transform/core";
import { ALL_EXTENSIONS } from "@gltf-transform/extensions";
import { copyToDocument, dedup, prune, unpartition } from "@gltf-transform/functions";
// Input.
const io = new NodeIO().registerExtensions(ALL_EXTENSIONS);
const avatarDocument = await io.read("./avatar1.glb");
const capDocument = await io.read("./Avaturn-asset-cap.glb");
// Transfer cap into avatar document.
const srcCapMesh = capDocument
.getRoot()
.listMeshes()
.find((mesh) => mesh.getName() === "Mesh.002");
const map = copyToDocument(avatarDocument, capDocument, [srcCapMesh]);
const dstCapMesh = map.get(srcCapMesh);
// Attach cap to armature and scene graph.
const capNode = avatarDocument
.createNode("avaturn_cap")
.setMesh(dstCapMesh)
.setSkin(avatarDocument.getRoot().listSkins()[0]);
const armature = avatarDocument
.getRoot()
.listNodes()
.find((node) => node.getName() === "Armature");
armature.addChild(capNode);
// Remove hair meshes.
for (const node of avatarDocument.getRoot().listNodes()) {
if (node.getName().startsWith("avaturn_hair")) {
node.dispose();
}
}
// Clean up.
await avatarDocument.transform(prune(), dedup(), unpartition());
// Output.
await io.write("./avatar1+cap.glb", avatarDocument); I've used NodeIO above because I have no experience with React Native, but I imagine you may need to adapt the 'read' step to something like: import RNFS from 'react-native-fs';
const glb = await RNFS.readFile('./avatar2.glb'); // → Buffer
const document = await io.readBinary(glb); glTF Transform has three I/O classes — NodeIO, WebIO, DenoIO — and if none are compatible with React Native then you may need to refer to their implementations to create another. The simplest is DenoIO. The script above places the cap on the character's head, but the forehead does clip through the hat slightly. I believe that's probably a modeling issue, easier addressed in the source file than in the script. As a note to future readers — be aware that this type of operation requires that glTF models be very carefully created to share identical armatures. For two glTF models not originally designed to be combined in this way, the skinning parameters will not match, and there will be nothing I can do to help you, other than to point you to Blender. 🙂 |
Beta Was this translation helpful? Give feedback.
If you install the alpha release of v4 ...
... there's a new
copyToDocument
function that can help considerably with this. To apply the changes described you'll need to do something like: