Aframe - How to render HUD on top of everything else - aframe

The A-Frame camera docs say to create a HUD like this:
<a-entity camera look-controls>
<a-entity geometry="primitive: plane; height: 0.2; width: 0.2" position="0 0 -1"
material="color: gray; opacity: 0.5"></a-entity>
</a-entity>
However, this causes the HUD element to be clipped by in-game objects. Normally HUDs are rendered on a separate layer above all the other game objects. Is there a simple way to fix this?

You have to:
Set renderer.sortObjects = true;
Set a the render order of the entity this.el.object3D.renderOrder = 100;
Disable the material depth test material.depthTest = false;
I created a simple overlay component that easily applies the above to any entity.
AFRAME.registerComponent("overlay", {
dependencies: ['material'],
init: function () {
this.el.sceneEl.renderer.sortObjects = true;
this.el.object3D.renderOrder = 100;
this.el.components.material.material.depthTest = false;
}
});
<a-entity camera look-controls wasd-controls position="0 1.6 0">
<a-plane id="hud" overlay rotation="0 0 0" position="0 0 -2" width="1" height="1" color="purple" shadow></a-plane>
</a-entity>
Example on glitch

Related

How do I use checkpoint controls in A-Frame?

I am new to A-Frame and still trying to figure everything out! I'm currently constructing a 3D space and would like to create a guided experience for visitors by providing dots on the floor for them to click and be transported to that position. I found this code online which is perfect but I can't get it to work.
Here is the link to my project on Glitch: https://glitch.com/~museum-exhibit-demo
This is the code for my camera:
<a-entity position="1.8 -1.1 3" rotation="0 90 0" id="pov">
<a-camera universal-controls="movementControls: checkpoint" checkpoint-controls="mode: animate">
<a-entity cursor position="0 0 -1" geometry="primitive: ring; radiusInner: 0.01; radiusOuter: 0.015;" material="color: #CCC; shader: flat;"> </a-entity>
</a-camera>
</a-entity>
And this is the code for the cylinder:
<a-cylinder checkpoint radius="0.1.5" height="0.01" position="-0.164 0.111 2.363" color="#39BB82"></a-cylinder>
Can anyone spot where I'm going wrong?
UPDATE:
I just read the current source of aframe-extra and it seems that nothing is broken! In fact there was a backward-incompatible change in the new versions. Rather than the old syntax of:
universal-controls="movementControls: checkpoint;"
Now this new syntax should be used:
movement-controls="controls: checkpoint;"
But keep in mind that since version 3.2.7, the movement offset is calculated on all 3 XYZ axis and therefore the camera will move to the center of the checkpoint. If you want to preserve the height (y) then simply add the code below above line 83:
targetPosition.y = position.y;
Here is a complete working example:
<html>
<head>
<meta charset="utf-8">
<title>Checkpoint Control with AFrame 1.2.0</title>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras#v6.1.1/dist/aframe-extras.min.js"></script>
</head>
<body>
<a-scene stats>
<!-- CAMERA -->
<a-entity position="0 0 0" id="pov">
<a-camera camera="active: true; spectator: false;" look-controls="pointerLockEnabled:true" movement-controls="controls: checkpoint;" checkpoint-controls="mode: animate; animateSpeed: 10" wasd-controls="enabled: false;" position="0 1.6 22">
<a-cursor></a-cursor>
</a-camera>
</a-entity>
<!-- CHECKPOINTS -->
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 20" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 16" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 12" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 8" color="#FF0000"></a-cylinder>
</a-scene>
</body>
</html>
Information below this line is not valid anymore.
As Piotr already mentioned, the new releases of Aframe-Extra are somehow broken!
Using an older version everything will work again.
Below is a working example with Aframe-extra version 3.2.7.
Once the page is fully loaded, click on the screen to lock the cursor, then point the cursor (tiny ring) at a red circle and click.
I also noted few additional options just in case:
spectator: false (switch between 1st and 3rd person view)
pointerLockEnabled:true (hide the mouse)
mode: animate (the other option is teleport)
animateSpeed: 10 (well... adjusts the animation speed)
wasd-controls="enabled: false;" (otherwise user can move around via WASD/arrow keys)
Code:
<html>
<head>
<meta charset="utf-8">
<title>Checkpoint Control with AFrame 1.2.0</title>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras#v3.2.7/dist/aframe-extras.min.js"></script>
</head>
<body>
<a-scene stats>
<!-- CAMERA -->
<a-entity position="0 0 0" id="pov">
<a-camera camera="active: true; spectator: false;" look-controls="pointerLockEnabled:true" universal-controls="movementControls: checkpoint;" checkpoint-controls="mode: animate; animateSpeed: 10" wasd-controls="enabled: false;" position="0 1.6 22">
<a-cursor></a-cursor>
</a-camera>
</a-entity>
<!-- CHECKPOINTS -->
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 20" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 16" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 12" color="#FF0000"></a-cylinder>
<a-cylinder checkpoint radius="0.5" height="0.01" position="0 0 8" color="#FF0000"></a-cylinder>
</a-scene>
</body>
</html>
This won't answer the question, but should solve your problem.
You can substitute the checkpoint-controls with a simple animation system:
you click on a cylinder
you animate the camera from the current position to the cylinder
Which could be implemented like this:
// use a system to keep a global track if we are already moving
AFRAME.registerSystem('goto', {
init: function() {
this.isMoving = false
}
})
// this component will have the actual logic
AFRAME.registerComponent('goto', {
init: function() {
let camRig = document.querySelector('#rig')
// upon click - move the camera
this.el.addEventListener('click', e => {
// check if we are already moving
if (this.system.isMoving) return;
// lock other attempts to move
this.system.isMoving = true
// grab the positions
let targetPos = this.el.getAttribute("position")
let rigPos = camRig.getAttribute("position")
// set the animation attributes.
camRig.setAttribute("animation", {
"from": rigPos,
"to": AFRAME.utils.coordinates.stringify({x: targetPos.x, y: rigPos.y, z: targetPos.z}),
"dur": targetPos.distanceTo(rigPos) * 750
})
camRig.emit('go')
})
// when the animation is finished - update the "shared" variable
camRig.addEventListener('animationcomplete', e=> {
this.system.isMoving = false
})
}
})
with a setup like this:
<!-- Camera with locked movement --/>
<a-entity id="rig" animation="property: position; startEvents: go">
<a-camera look-controls wasd-controls-enabled="false"></a-camera>
<a-entity>
<!-- Cylinder node --/>
<a-cylinder goto></a-cylinder>
You can see it working in this glitch.

Raycaster camera with a-sky intersects with cursor

I just started developing with a-frame, please excuse if the answer is obvious.
In my project I would like to get the position of a-sky where the user is looking at. Therefor I implemented a raycaster within the camera, which works fine so far.
HTML
<a-camera listener>
<a-entity raycaster="far: 1000" position="0 -0.9 0" rotation="0 0 0"></a-entity>
</a-camera>
<a-sky follow-intersection
id="sky"
src="#skybox-image">
</a-sky>
TS
AFRAME.registerComponent("follow-intersection", {
init: function() {
this.el.addEventListener("raycaster-intersected", evt => {
this.intersectingRaycaster = evt.detail.el.components.raycaster;
});
this.el.addEventListener("raycaster-intersected-cleared", () => {
this.intersectingRaycaster = null;
});
},
tick: function(t) {
if (!this.intersectingRaycaster) {
return;
}
const intersection = this.intersectingRaycaster.getIntersection(this.el);
if (intersection) {
let point = intersection.uv;
console.log(point.x, point.y);
}
So far this works fine, the problem is that after I set the cursor in the scene (which is needed for the project)
<a-scene
cursor="rayOrigin: listener"
>
I always get the intersections with the cursor, which are not wanted.
How can I only get the intersections of the camera? Thank you!
I don't think the cursor in a-scene is needed. You could just do:
<a-camera listener>
<a-entity cursor raycaster="far: 1000" position="0 -0.9 0" rotation="0 0 0"></a-entity>
</a-camera>

AFrame - Change controls type using setAttribute

I would like to remove the twoway-motion component from the entity player, and replace it with the progressive-controls component, using setAttribute.
While the removeAttribute works fine for removing the twoway-motion, the setAttribute does not add the progressive-controls.
<a-entity id="player" networked="template:#avatar-template;showLocalTemplate:false;"
camera spawn-in-circle="radius:3;"
position="0 1.3 0"
wasd-controls
look-controls
twoway-motion="speed: 35">
<a-entity cursor="fuse: true; fuseTimeout: 500"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03"
material="color: black; shader: flat"
id="defaultCursor">
</a-entity>
</a-entity>
<script>
var playerEl = document.getElementById('player');
var cursorEl = document.getElementById('defaultCursor');
playerEl.removeChild(cursorEl);
playerEl.removeAttribute('twoway-motion');
playerEl.setAttribute('progressive-controls');
</script>
the setAttribute(name, value) requires a value.
To add the component, just use setAttribute('progressive-controls', '') to add it with the default schema

A-Frame using teleport-controls with shake.js events

I want to use fernandojsg's teleport controls on my A-Frame project, but the way I want to use them is with shake.js, one shake to make the teleport line appear and another one to actually teleport where you selected.
I've seen the documentations and came across the startEvents and endEvent properties, and I want to map them into the shake event... for me it sounds like I have to create a custom component to do this, but I wanted to seek help first, to see if this is possible without doing it.
So far I've made this (glitch.com/ link) but it doesn't work so far (please note that I've got some other libraries there that make use of shake, mousedown, and similar events... my plan is to activate or deactivate them depending on how the user wants to move)
<a-entity id="player" wasd-controls tap-to-walk>
<a-camera id="eyes" position="-.5 1.5 0" camera="" look-controls="" mouse-cursor="">
<a-entity id="cursor" cursor="fuse: false;"
position="0 0 -1"
geometry="primitive: ring; radiusInner: 0.015; radiusOuter: 0.019"
material="color: white; shader: flat"
raycaster="far: 5; interval: 1000; objects: .clickable">
</a-entity>
<a-entity id="texto" text="value:Hola;align:center" position="0 -.3 -0.5"></a-entity>
<a-plane position="0 .7 -1" material="transparent: true; opacity: 0.5; color: #ffec04; shader:flat;" scale="1 0.2 1"></a-plane>
</a-camera>
<a-entity
teleport-controls="cameraRig: #player; teleport-origins: #eyes; startEvents:['shake','mousedown']"> </a-entity>
<a-entity id="step" sound="src: #step1"></a-entity>
</a-entity>
Thanks...
Yes you will need a some JS or a custom component to get shake.js and teleport controls to work together for two reasons:
shake.js emits its events outside the A-Frame scene on window where teleport-controls is not listening
shake.js only emits one event type, and you need to differentiate for startEvents and endEvents
But it doesn't need to be very complicated:
AFRAME.registerComponent('shake-listener', {
init: function () {
var targetEl = this.el
var count = 0
// you could also initialize the shake instance here
window.addEventListener('shake', function () {
if (++count % 2) {
targetEl.emit('shakestart')
} else {
targetEl.emit('shakeend')
}
})
}
})
Then add shake-listener to the same entity as teleport-controls="startEvents: shakestart; endEvents: shakeend"

a-frame: Unable to change camera position and rotation angle

I am using the a-frame components for a WebVR application. The camera has look-controls with a cursor to let the user pick an object. And when the event is fired I wish to change the camera position. This is what I have done. A camera is defined in the scene.
<a-entity id="cam" camera="userHeight: 1.6" look-controls>
<a-entity cursor="fuse: true; fuseTimeout: 500" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03" material="color: black; shader: flat">
</a-entity>
</a-entity>
I have a box with a listener as follows
<a-box box-listener color="tomato" position="1 0 3" depth="1" height="1" width="1"></a-box>
When the user moves the cursor to the box and holds for half a second, the event gets fired. The event script is as follows:
AFRAME.registerComponent('box-listener', {
init: function() {
this.el.addEventListener('click', function(evt) {
var cam = document.getElementById("cam");
var campos = cam.getAttribute("position");
campos.x = 1; // some random change.
var camrot = cam.getAttribute("rotation");
camrot.x = 0;
camrot.y = 0;
camrot.z = 0; // setting it back to looking straight ahead
var look = cam.getAttribute("look-controls");
look.enabled = false;
cam.setAttribute('look-controls',look);
cam.setAttribute("position", campos);
cam.setAttribute("rotation", camrot);
look.enabled = true;
cam.setAttribute('look-controls',look);
});
}
});
By putting logs I find that the values are getting updated in the camera element however nothing changes on the screen.
where am I going wrong? Does the camera element need to be refreshed?
Thanks,
Raj

Resources