Open blairmacintyre opened 8 years ago
Maybe because the default camera is created after the scene is loaded...to check for existing cameras.
There is an event: camera-set-active
. Does that help?
The problem is that I'm running my code in the "loaded" callback; I have set up an event on "camera-set-active" but it wasn't running for the default camera because the event is fired in its "loaded" callback, before my loaded callback is executed ... at least that's what I think is happening, since my handler isn't running for the default camera. To solve this, I also ran the same callback once in my loaded callback, which ran into the problem above.
A bit hard to follow all these callbacks (our fault!). So you can't move code outside the loaded
callback and into the camera-set-active
callback?
I know, it's fun (if confusing)...
I was setting the camera-set-active callback up in loaded ... I only want to check for cameras after the scene is loaded, in case the programmer has created an "ar-camera". I guess I could try a different tack, setting the callback up at init, and watching for an ar-camera, and then creating the ar-camera in loaded.
Although, while this may work, it side steps the larger problem; I don't think the setAttribute command should be raising an error. Perhaps "init" on the node should check if the node is attached to the DOM and check for the existence of a scene (if sceneEl isn't set) and set it (as is done in in AttachedCallback) if it's not set.
You can check for nodeready
which is emitted after attach...but ideally we shouldn't have to do that. If you write your code within components/systems, you should be assured that everything has been set up. I think I'd need full code to give more helpful guidance though.
I really don't want to set up a nodeready
callback on each of these cameras, although I guess I could do that (check if sceneEl
is null, if so set up a callback to do the "active = false" when it's ready). Yuck. :)
The code is my argon-aframe stuff (github.com/argonjs/argon-aframe). The offending code is in the "play" method of ar-scene.js. Right now, the code in the repo is only using a callback on camera-set-active, which isn't getting called for the default camera ... all the time. The weird thing is, it was getting called sometimes, but I discovered it not getting called in a more complex app I was building which starts out with an empty ar-scene and adds to it programmatically.
I replaced the addEventListener in that play method with a function that I set on the listener, and call:
var fixCamera = function () {
var arCameraEl = null;
var cameraEls = self.querySelectorAll('[camera]');
for (i = 0; i < cameraEls.length; i++) {
cameraEl = cameraEls[i];
if (cameraEl.tagName === "AR-CAMERA") {
arCameraEl = cameraEl;
continue;
}
cameraEl.setAttribute('camera', 'active', false);
cameraEl.pause();
}
if (arCameraEl == null) {
var defaultCameraEl = document.createElement('ar-camera');
defaultCameraEl.setAttribute(AR_CAMERA_ATTR, '');
defaultCameraEl.setAttribute(constants.AFRAME_INJECTED, '');
self.appendChild(defaultCameraEl);
}
}
// if there are any cameras aside from the AR-CAMERA loaded,
// make them inactive.
this.addEventListener('camera-set-active', fixCamera);
fixCamera();
The cameraEl.setAttribute('camera', 'active', false);
ends up raising an exception because the cameraEl is set to the default camera, which hasn't had it's attachCallback method called yet, so it's not ready.
Is it feasible to remove invocations of init()
from inside setAttribute()
? This also bit me in #1900.
Another option, specific to this issue, might be some scene-level config to prevent injection of default cameras.
Maybe we can also let it look for data-aframe-camera
...?
Ok, I leveraged the nodeready
event to work around this issue. It's kinda ugly though.
@blairmacintyre working code? please
Seems like there should be a simpler way to allow a-frame users to specify what the "default camera" for a scene should be, rather than them overriding the default camera after it has already been added to the scene.
f.e. <a-scene default-camera="other-type-of-camera">
and if no camera is specified in the HTML, then the first and only camera will be other-type-of-camera
without having overriden some other camera.
In my ar-scene setup, I want to replace the default camera entity with my own "ar-camera" entity, if the user did not create one in the scene.
So, in the scene's "loaded" callback (play method, actually), I grab a list of cameras, and look for an "ar-camera" entity. This is all good.
BUT, I also want to disable any camera that is already there by setting active=false.
The problem is that the camera system ALSO has a "loaded" callback, in which it creates a default camera (if there isn't one) and attaches it to the scene.
Unfortunately, the a-node attachedCallback does not seem to run for these new nodes until after all of the various "loaded" handlers are run. Which means that this.sceneEl in these nodes is not set, so when I call
cameraEl.setAttribute('camera', 'active', false);
on the default camera that the camera system created, it throws an error inside the camera's init method (since setAttribute calls updateComponent which calls init on the uninitialized component (in a-entity.js).It seems that there needs to be something in there to check (during init, I guess?) it's it's attached BUT the attached callback hasn't been called? If so, do the same work (like setting the sceneEl)?