aframevr / aframe

:a: Web framework for building virtual reality experiences.
https://aframe.io/
MIT License
16.61k stars 3.94k forks source link

Specific light setting for specific objects #3887

Open jeffreywys opened 5 years ago

jeffreywys commented 5 years ago

I just wonder is there any way that I can make the ambient light only affect specific objects? For example in Unity, we can make a light setting only for specific layer and this light setting has not effect of objects in other layers.

donmccurdy commented 5 years ago

This isn't supported now — I think at the minimum, we would need it to be implemented in three.js first. See https://github.com/mrdoob/three.js/issues/5180.

You can set emissive values on individual materials, which may give a similar result to what a selective ambient light would.

jeffreywys commented 5 years ago

Okay. Thank you. For example, if I use aframe gltf-model for a .glb file, I don't think I can override its material setting by aframe, right? Base on this, https://github.com/donmccurdy/aframe-extras/issues/167. Instead, I think I can use three.js to change the emissive setting of the glb, right? (Ref: https://discourse.threejs.org/t/glb-modify-material-and-add-emission/4661) Thank you.

donmccurdy commented 5 years ago

That's correct — in three.js (or by writing an A-Frame component to do it) you can still modify emissive on a glTF model.

jeffreywys commented 5 years ago

For the three.js method, I am doing something like this now. I am able to change the emissiveIntensity of 3D object.

        var loader = new THREE.GLTFLoader();
        loader.load(
          'DamagedHelmet/glTF/DamagedHelmet.gltf',
          function(gltf) {

            gltf.scene.name = 'test';
            gltf.scene.position.x = 3;
            gltf.scene.position.y = 0;
            gltf.scene.position.z = 0;
            gltf.scene.traverse(function(child) {
              if (child.isMesh) {
                child.material.emissiveIntensity = 100;
              }
            });

            scene.add(gltf.scene);
          },
          undefined,
          function(e) {
            console.error(e);
          }
        );

However, if I want to change its emissiveIntensity after I load it in the scene, how do I get access to the 3DObject. In other word, how do I use getObjectByName("test") to change its emissiveIntensity outside the loader. Or is there any other way to change the emissiveIntensity outside the loader? Thank you.

jeffreywys commented 5 years ago

And for the A-Frame component method, I also have a same problem about getting access of the emissiveIntensity after aframe loaded the gltf. I can only get to the children array. If I console.log one component of the children array, I will get a undefined result.

 AFRAME.registerComponent('hello-world', {
            init: function () {
                console.log(this.el.object3D.children);
            }
        });
donmccurdy commented 5 years ago

Yes, for example:

var el = document.querySelector('#foo');
el.addEventListener('model-loaded', () => {
  el.object3D.traverse((o) => {
    if (o.isMesh) {
      o.material.emissiveIntensity = 100;
    }
  });
});

See:

donmccurdy commented 5 years ago

You'll need to wait for a model-loaded event before checking the mesh, before that it is not available yet.