Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aframe - Clone object3D within Entity

Using a-frame, I load in an obj model which contains about 114 people meshes using <a-assets>. I then want to find a specific mesh within that array which I will then clone() many times throughout the scene. Using plain old three.js I am able to do this with minimal effort, but I can't seem to find a way to do this in the <a-entity> structure. I have tried this.el.sceneEl.appendChild() but that errors out saying parameter 1 is not a node; I also tried this.el.sceneEl.add(), but that errors out with Trying to add an element that doesn't have an object3D. Any thoughts on the best approach to solving this issue?

people.js

AFRAME.registerComponent('people', {
    schema: {
        samplePerson: {default: {}}
    },

    init: function () {
        var el = this.el;

        // Listen for when the model is loaded
        el.sceneEl.addEventListener('model-loaded', this.loadPersonModel.bind(this));
    },

    loadPersonModel: function () {

        // Update all meshes from the object3D which is made up with 114 child meshes
        this.el.object3DMap.mesh.children.forEach(function (obj) {
            obj.material.color = new THREE.Color(0xff0000);
            obj.visible = false;
        });

        // Get a sample person for which we will instantiate all over the place
        this.data.samplePerson = this.el.object3D.getObjectByName("people_silhouette73");

        // Clone ten people throughout the scene
        for (var i = 0; i < 10; i++) {
            console.log(this.data.samplePerson);
            if (this.data.samplePerson) {
                var clone = this.data.samplePerson.clone();
                clone.visible = true;

                // Randomly position the object
                clone.position.x += Math.random() * 10;
                clone.position.y += 0.01;
                clone.position.z = -300 + Math.random() * 25;

                // Add the object to the scene
                this.el.sceneEl.appendChild(clone);
            }
        }
   }
});

index.html

<a-scene>
    <a-assets>
        <a-asset-item id="people-obj" src="./assets/obj/silhouette_people_lowpoly_obj.obj"
                  name="testname"></a-asset-item>
    </a-assets>
    <a-entity obj-model="obj: #people-obj;" obj-name="person" people></a-entity>
    </a-entity>
</a-scene>
like image 272
hotshotiguana Avatar asked Sep 04 '26 09:09

hotshotiguana


1 Answers

I would approach this in two steps. First, load the model and hide it (or ideally remove it from the scene entirely). Second, have one or more extra entities that extract parts of the object that they need:

<a-entity obj-model="obj: #people-obj;" id="group" visible="false"></a-entity>
<a-entity position="0 0 0"
          model-subset="target: #group;
                        name: person1;"></a-entity>
<a-entity position="3 0 0"
          model-subset="target: #group;
                        name: person2;"></a-entity>
<a-entity position="6 0 0"
          model-subset="target: #group;
                        name: person3;"></a-entity>

Then defining the model-subset component:

AFRAME.registerComponent('model-subset', {
  schema: {
    target: {default: '', type: 'selector'},
    name: {default: ''}
  },
  init: function () {
    var el = this.el;
    var data = this.data;
    data.target.addEventListener('model-loaded', function (e) {
      var model = e.detail.model;
      var subset = model.getObjectByName(data.name);
      el.setObject3D('mesh', subset.clone());
    });
  },
  update: function () { /* ... */ },
  remove: function () { /* ... */ }
});
like image 167
Don McCurdy Avatar answered Sep 06 '26 23:09

Don McCurdy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!