Accessing children of children in ThreeJS
I've been learning ThreeJs and boy did I get stuck trying to call my files.
Let me start by explaining what I wanted to do! i have 3 models to display on a page, as people scroll a different emoji should be displayed, like small sections, classic webapge way.
I imported these models from blender in one gltb file to improve performance, and theorically, save time, two of the objects are groups and the other is a mesh. There's nothing else in the import.
However after using gltf loader to load my models I can't find a way to access them to accomodate them in the positions and rotations I want them to be at. Please help.
I loaded my scene:
gltfLoader.load(
'EMOJIS.gltf',
(gltf) =>
{
gltf.scene.scale.set(0.25, 0.25, 0.25)
gltf.scene.position.set(0, 0, 0)
mixer = new THREE.AnimationMixer(gltf.scene)
scene.add(gltf.scene)
}
After that I checked my log to reach for the objects
console.log(scene)
console.log(scene.children)
console.log(scene.children[3])
The first and second log show as follows:
I realized that I should reach the children of the scene's children to get my 3 emojis: heart, peach, heartEyes. I thought I could just call scene.children[3].children[0] for example. and call the heart object emoji But I cant call them? I have tried many ways but it always shows as undefined.
console.log(scene.children) shows an array from 0 to 3, in the [3] slot I can see the emoji elements I want, but calling console.log(scene.children[3]) shows undefined, how can I access the group I want?
Calling
var heart = scene.getObjectByName( "heart", true );
or calling by their ID (which are 16, 15 and 23) shows undefined as well.
All help is very much appreciated.
EDIT:
After putting time-stamps on my consolde debug I realized its been calling the gltf loader after calling my object references for the emojis, but I'm unsure why even this is happening or how to set them up in the correct order? the gltf loader is on the top of the script and the subsequent calls various lines below, shouldn't it run correctly? Is is because of the time the model takes to load? how can i fix that?
The code:
gltfLoader.load(
'EMOJIS.gltf',
(gltf) => {
gltf.scene.scale.set(0.5, 0.5, 0.5)
gltf.scene.position.set(0, 0, 0)
scene.add(gltf.scene)
// Animation
mixer = new THREE.AnimationMixer(gltf.scene)
gui.add(gltf.scene.position, 'y').min(-3).max(3).step(0.01).name('position y')
gui.add(gltf.scene.position, 'x').min(-3).max(3).step(0.01).name('position x')
gui.add(gltf.scene.position, 'z').min(-3).max(3).step(0.01).name('position z')
//gltf.scene.children[2].material.roughness = 1
gltf.scene.children[0].position.x = 2
gltf.scene.children[1].position.x = - 2
gltf.scene.children[2].position.x = 2
gltf.scene.children[0].position.y = - objectsDistance * 0
gltf.scene.children[1].y = - objectsDistance * 1
gltf.scene.children[2].y = - objectsDistance * 2
console.log("Emoji Inside Loader, Line 99")
console.log(gltf.scene.children[0])
/*
var heart = gltf.scene.getObjectByName("heart", true);
var heartEyes = gltf.scene.getObjectByName("heartEyes", true);
var peach = gltf.scene.getObjectByName("peach", true); */
// loop through all children and create a property
// for every child based on it's name
gltf.scene.children.forEach((item) => {
emoji[item.name] = item;
})
// then you can access every child through
// the named property of the shirt object
console.log("emoji array")
console.log(emoji.peach)
console.log(emoji.heart)
console.log(emoji.heart.rotation)
console.log(emoji.heartEyes)
loaded = true;
}
)
console.log("Main scene")
console.log(scene)
console.log(scene.children)
console.log(scene.children[6])
console.log("Emoji outside of the loader, line 133?")
console.log(emoji)
console.log(emoji[heart])
console.log(emoji[0])
console.log(emoji.name[heart])
console.log("--- --- ---")
The debug:
Solution 1:
I had some trouble accessing the children of a shirt model, so I created an object with the names of the children (as named in Blender) as properties for easier access. Maybe this will help you:
// prepare shirt (js) object
let shirt = {};
... after importing the gltf ...
scene.add(gltf.scene);
// loop through all children and create a property
// for every child based on it's name
gltf.scene.children.forEach((item) => {
shirt[item.name] = item;
});
// then you can access every child through
// the named property of the shirt object
shirt.Back.children[0].material = shirtMat;
shirt.Sleeves.children[0].material = shirtMat;
shirt.Front.children[0].material = shirtMat;
shirt.Front.children[1].material = buttonMat;
shirt.CollarClassic.children[0].material = shirtMat;
shirt.CollarCut.children[0].material = shirtMat;
shirt.CollarCut.visible = false;
shirt.CollarButton.children[0].material = shirtMat;
shirt.CollarButton.children[1].material = buttonMat;
shirt.CollarButton.visible = false;
... etc