I've just added the laser pointer to the right hand in my A-Frame scene and it's pointing in the wrong direction.
A-frame Laser pointing 45deg to the left
In this image I am pointing at the blue box above the tower using an Oculus Touch controller. As you can see the hand is pointing correctly and feels like it matches my real life hand position quite well but the laser is going about 45deg to the left.
Here is my code:
<a-entity id="cameraRig" position="-25 -10 138" rotation="0 -25 0">
<a-entity id="head" camera="near: 0.1; far: 10000" wasd-controls look-controls></a-entity>
<a-entity id="teleHand" hand-controls="left" teleport-controls="cameraRig: #cameraRig; teleportOrigin: #head; type: parabolic; button: trigger; collisionEntities: #terrain, #bridgeFull"></a-entity>
<a-entity id="pointerHand" hand-controls="right" laser-controls></a-entity>
Is there a way I can reposition the laser? Ideally to come out of the pointing fingure but if not then just pointing in the right direction will do?
Update: I just tried raycaster="showLine: true" instead and this does point in the correct direction so it appears to be a bug with the laser component. I could use the raycaster and write my own collision logic but would much prefer to use the mouse events that you get with the laser.
Second Update: Just discovered if I add both the raycaster and cursor component I get the exact same functionality as adding the laser component but with the raycast pointing in the correct direction.
This has solved the problem I have but will leave this here as I'm sure others will run into this problem until the laser component is fixed.
I've filed an issue here https://github.com/aframevr/aframe/issues/3396
For clarity I was using v0.7.1 of A-frame
Okay, so to post the answer here. hand-controls and laser-controls aren't meant to mix. Hand controls is more for 6DoF and laser-controls is more if you want to support both 3DoF and 6DoF. Laser-controls will set its own raycaster properties on controllerconnected event.
To set your own raycaster properties:
AFRAME.registerComponent('force-raycaster', {
schema: {
direction: {type: 'vec3'},
origin: {type: 'vec3'}
},
init: function () {
this.el.addEventListener('controllerconnected', {
// Wait for laser-controls to set its raycaster properties.
setTimeout(() {
this.el.setAttribute('raycaster', this.data);
}, 50);
});
}
});
<a-entity laser-controls hand-controls force-raycaster="direction: 0 0 -1; origin: 0 -0.1 0">
Related
I am looking to add a piece of text to the camera on an A-frame scene which will act as a link to transfer to a non-VR page.
<a-entity camera look-controls position="0 0 0">
<a-cursor visible="false">
</a-cursor>
<a-entity text="value: Galleries; color: black; width: 2;" position="-0.25 0.7 -1" onClickLink>
</a-entity>
</a-entity>
The onClickLink function is registered and uses window.location.href = "https://www.google.com"; to change page as suggested in the docs.
I have created a gallery, and want to give users a simple UI link at the top to take them back to a list of other galleries - however - in the example above the onClickLink function just gets applied to the whole scene rather than only the piece of text. I guess it has maybe been applied to its parent - the camera - so any click counts as firing the event? Or do I need to add something to the event to determine what object was clicked? I'm not sure how raycasting would work on something in the top left corner of the camera?
I do not want to use a 3D object in the scene, and I similarly don't want to use the Link portal entity that will be placed in the scene (I did try going down this route similar to the above, and it again just applied the link to the entire scene rather than on clicking the link itself).
Is there a way to achieve what I'm after?
You can use standard html elements and a-frame element to gather and use Css (position: fixed; z-index: 999) to bring it forward to the top but to create an external html link I share part of my code hope you find the idea, you can use jquery(or pure javascript) to add click event to your a-frame objest, but first add below code to <a-camera tag:
raycaster="far: 10000; objects: .clickable"
then add "clickable" class name to any A-frame object you want to be clicked by user
<a-image visible=true id="web" class="clickable external" src="#imgweb" alpha-test="0.5" position="-0.14 -0.9 0" height="0.18" width="0.18"></a-image>
and then like any html dom object you can access to aframe objects by javascript:
window.onload = function() {
$(".external").each(function(index) {
$(this).on("click", function() {
console.log(this.id + ' Pushed');
switch (this.id.toLowerCase()) {
case 'web':
window.open("http://www.farsix.com/");
break;
case 'instagram':
window.open("https://www.instagram.com/");
break;
default:
console.log("Unknown Link!");
};
});
});
};
For my A-Frame project I want the player to move forward without depending on any controllers or keyboards. The player should always be moving forward, and should be able to decide the direction by looking around (without changing the z value). Using look-controls on the camera and movement-controls (from aframe-extras) on the rig gives this behavior, apart from the fact that it still depends on a controller. How can I implement auto walk in A-Frame?
<a-entity id="rig" movement-controls>
<a-entity id="camera" position="0 1.7 0" camera look-controls>
</a-entity>
If you are using the movement-control component, you can add your own "controls". As the doc say, all you have to do is to name it with a "-controls" suffix (see https://github.com/n5ro/aframe-extras/tree/master/src/controls#customizing-movement-controls ). This is the code for a simple "autowalk" custom controls component for "movement-controls":
AFRAME.registerComponent('autowalk-controls', {
isVelocityActive: function () {
return true;
},
getVelocityDelta: function () {
return new THREE.Vector3(0, 0, -1);
}
});
And you can simply use it by adding it to the controls proprety of "movement-controls" like that:
movement-controls="controls: autowalk"
I pasted the code from A-Frame's hello world sample scene, directly from their GitHub homepage, into this CodePen.
The scene looks fine when I view it on desktop, and even when I view it on my phone. But when I view it on my phone AND click the VR headset button (at lower right), the entire scene renders behind me! (As if the z-axis were suddenly flipped!)
Here is a CodePen with an even simpler example:
<a-scene>
<a-sphere position="0 1.25 -5" radius="1.25" color="green"></a-sphere>
<a-sphere position="0 1.25 5" radius="1.25" color="red"></a-sphere>
</a-scene>
That is, a green sphere 5 units in front of the camera, and a red sphere 5 units behind the camera. When viewed from my desktop or my phone (a Samsung Galaxy S7 Edge, which is VR capable) in regular mode I see the green sphere, but when I view the scene from my phone in VR mode, I see the red sphere (and have to turn around, looking behind me) to see the green sphere.
What's going on? Do you see the same thing? And how do I solve this problem?!?
The root problem (as #PiotrAdamMilewski suggested) is that my phone was taking on the gyroscope's orientation upon entering VR mode. The solution is to aim the camera at the scene when the user puts on their VR headset - this ensures that the user will be looking exactly where you want when their VR experience begins.
HTML (Angular 8):
<a-scene #scene>
<!-- ... -->
<a-entity #cameraParent>
<a-entity camera look-controls pointerLockEnabled #camera>
</a-entity>
</a-entity>
</a-scene>
JavaScript (TypeScript):
#ViewChild('scene', { static : true }) scene;
#ViewChild('cameraParent', { static : true }) cameraParent;
#ViewChild('camera', { static : true }) camera;
// ...
this.scene.nativeElement.addEventListener('enter-vr', ()=> {
const camera = this.camera.nativeElement;
const cameraParent = this.cameraParent.nativeElement;
cameraParent.object3D.rotation.x = -camera.object3D.rotation.x;
cameraParent.object3D.rotation.y = -camera.object3D.rotation.y;
cameraParent.object3D.rotation.z = -camera.object3D.rotation.z;
});
Notice the camera is wrapped in a container, and that we rotate the camera's container (by the reverse of the camera angle) rather than the camera itself. Props to #PiotrAdamMilewski for helping me identify the root cause, and to #RomanMahotskyi for suggesting this implementation. Teamwork makes the dream work!
Using Aframe how I can change the camera rotation manually so it works on mobile and still use look-controls?
I've tried via the html attribute like so:
document
.querySelector('[camera]')
.setAttribute('rotation', { x: 0, y: deg, z: 0 })
This works fine on desktop however on mobile the look-controls component seems to reset the camera rotation to previous value.
I've setup a demo the issue here, which changes rotation & disables look-controls. Then I set a timeout which re-ables look-controls after 1 sec. https://embed.plnkr.co/WA1rKucPk0cGffrbfrTh/
Pressing any of the html buttons rotates you to a an object and disables the look-controls. 1 sec later the control are re-abled. If you try this on mobile, you'll notice the camera rotates, then 1 sec its reverts when the look-controls are enabled.
Is there some offset I need to reset on mobile too, the lookcontrols.yawObject perhaps?
Put the camera inside an entity:
<a-entity rotation="0 0 0">
<a-camera></a-camera>
</a-entity>
Then rotate the entity instead of the camera.
you need to change the look-controls.js a little bit to make it works,because when on mobile it will not get rotation attribute from the camera entity
function updateOrientation in look-controls.js:
if (sceneEl.isMobile) {
// On mobile, do camera rotation with touch events and sensors.
rotation.x = radToDeg(hmdEuler.x) + radToDeg(pitchObject.rotation.x);
rotation.y = radToDeg(hmdEuler.y) + radToDeg(yawObject.rotation.y);
rotation.z = radToDeg(hmdEuler.z);
}
I'm copying straight from the A-Frame documentation on RayCaster but I'm still not getting it right. I want the collider to occur when the camera connects with the cube.
Here's the github link for context.
<a-entity geometry="primitive: box" class="collidable"
position="1 2.5 0"></a-entity>
AFRAME.registerComponent('collider-check', {
dependencies: ['raycaster'],
init: function () {
this.el.addEventListener('raycaster-intersected', function () {
console.log('Player hit something!');
});
}
});
raycaster-intersected event is a ray from camera to cursor position, if the ray hit something, it will trigger raycaster-intersected event. collider event is more like checking distance between camera and something collidable, you can look at this component sphere-collider.js then, register your own collider-check component.