A-frame click event doesn't work for object intersecting cursor when entering VR - aframe

I have created an A-frame scene, and I am using a large invisible sphere to catch any mouse click to change an image. This works perfectly before entering VR mode, however, on entering VR mode, the click events are not caught until you look away from the object and look back.
From reading the documentation my guess is that this isn't counting the cursor as intersecting the object if it starts the scene in that position?
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
<script>
AFRAME.registerComponent('clickhandler', {
init: function () {
this.el.addEventListener('mousedown', function (evt) {
document.querySelector("#sky").setAttribute("src", "photo1.jpg");
});
}
});
</script>
<a-scene embedded background="color: black">
<a-entity camera look-controls position="0 0 0">
<a-cursor visible="false"></a-cursor>
</a-entity>
<a-sky id="sky" src="photo-initial.jpg"></a-sky>
<a-entity id="circle" cursor-listener geometry="primitive: circle; radius: 25" visible="false" material="color: blue" clickhandler position="-2.5 0.25 -1.5" rotation="0 15 0"></a-entity>
</a-scene>
So when this scene starts, the image is in front of the view, a large invisible sphere fills the whole view - from the browser, I can immediately click to trigger the click event. But if I reload the page and go straight into VR and click, nothing happens until I click to look 180 degrees away, and then look back. Then if I click, the event triggers.

Related

OnClick on model in AFrame-AR.js scene

I am working on an Augmented reality scene using Aframe and ARJS. I am currently rendering obj models when the marker is detected. My requirement is to be able to click on individual models upon rendering and manipulate them. For some reason onclick doesnt seem to be working on aframe model entities but it works fine on other primitive entities like box . This is my approach -
AFRAME.registerComponent('cursor-listener', {
init: function () {
this.el.addEventListener('click', function (evt) {
console.log('I was clicked at: ', evt.detail.intersection.point);
});
}
});
</script>
</head>
<body>
<a-scene embedded arjs='trackingMethod: best; debugUIEnabled: false;' foo>
<a-assets>
<a-asset-item id="crate-obj" src="model.obj"></a-asset-item>
<a-asset-item id="crate-mtl" src="model.mtl"></a-asset-item>
<img id="texture" src="brick.jpg">
</a-assets>
<a-marker preset='hiro'>
<a-entity ><a-obj-model class="collidable" cursor-listener id="animated-marker" src="#crate-obj" position="0 -1.6 0" mtl="#crate-mtl" rotation="-90 0 0" scale="0.004 0.004 0.004" material="" obj-model=""></a-obj-model></a-entity>
//onclick doesn't work
<a-entity material=" src: url(box.png) " class="collidable" cursor-
listener position="0 -1 0"></a-entity> //onclick works here
</a-marker>
<a-camera-static/>
</a-scene>
</body>
</html>
Is there anything I might be overlooking ? Or is there any other way to achieve this requirement.Thanks.
You need to use the cursor component, since the click event is based on raytracing in 3D.
<a-marker preset='hiro' cursor='rayOrigin: mouse'></a-marker>

Register every click in a-scene

I would like to develop an app in aframe, where every click would be registered and would lead me to next picture (a-sky). Currently I have a picture to which I bind the link. I used this as base example and develop from that.
<a-scene>
<a-assets>
<img id="home" crossorigin="anonymous" src="media/home1600.png">
<img id="back" crossorigin="anonymous" src="media/back1600.png">
<img id="forward" crossorigin="anonymous" src="media/forward1600.png">
<!-- other pictures ... -->
<!-- Image link template to be reused. -->
<script id="link" type="text/html">
<a-entity class="link"
geometry="primitive: plane; width: 0.25; height: 0.25;"
material="shader: flat; src: ${thumb};"
event-set__1="_event: mousedown; scale: 1 1 1"
event-set__2="_event: mouseup; scale: 1.2 1.2 1"
set-image="on: click; target: #image-360; src: ${src}; action: ${action}"
sound="on: click; src: #click-sound"></a-entity>
</script>
</a-assets>
<!-- 360-degree image. -->
<!-- Dynamically create a-sky in javascript -->
<a-sky id="image-360" radius="10" src="#pic0" phi-start="275"></a-sky>
<input type="hidden" id="pic_num" value="0">
<!-- Image links. -->
<a-entity id="links" layout="type: line; margin: 0.4" position="0 -1 -2.5">
<!-- prepare new links for each action -->
<a-entity id="back" template="src: #link" data-src="" data-thumb="#back" data-action="back"></a-entity>
<a-entity id="home" template="src: #link" data-src="" data-thumb="#home" data-action="home"></a-entity>
<a-entity id="forward" template="src: #link" data-src="" data-thumb="#forward" data-action="forward"></a-entity>
</a-entity>
</a-scene>
I really don't like those navigation icons, and as I don't know how to make them more attractive I want to remove them. I want to register forward action when you click anywhere (not just on the forward thumb).
I'm wondering if it is possible to register event click on the a-scene component? I was trying this but without any luck.
If You want to click on the sphere and get the action of clicking on forward, just add the event to Your a-sky entity:
set-image="on: click; target: #image-360; action: forward"
it should look like this:
<a-sky id="image-360" radius="10" src="#pic0" phi-start="275"
set-image="on: click; target: #image-360; action: forward"
></a-sky>
Not sure how much You've changed the set-image component though. Hope it handles the src somehow.
UPDATE
i forgot You whitelisted Your raycaster, the entity should look like this:
<a-sky id="image-360" class="link" radius="10" src="#pic0" phi-start="275"
set-image="on: click; target: #image-360; action: forward"
></a-sky>
keep in mind, this set-image here is not the same as it is on the thumbnails. They DONT share data. If You want to manage image changing on the thumbnails AND the sphere/sky, You need to listen for the clicks on the sphere, within the set-image component on one thumbnail ( so ONE entity manages the whole swapping system ), or one entity wrapping the thumnails and sky, or just make a component attached to the scene.
Btw i've BUTCHERED Your code, check out the fiddle, with clicks working on the sphere. https://jsfiddle.net/af9qgdw0/ it works on a sphere, i think the raycaster might have a lenght limit, ( though it says its infinite on the docs ), check this out: A-Frame cursor listener on sky element not firing
UPDATE 2
OP want's to perform click action only when you are not dragging picture. I think the easiest way is to set up a couple of event listeners:
1. Listen to the camera change via
addEventListener('componentchanged', function(evt) {
if (evt.detail.name === 'rotation') {
}
}); whereas evt.detail.newData is the new rotation and evt.detail.oldData is the old rotation.
2. in Your set-image Listen for mousedown and mouseup events. Store the oldData.y when mouse down, then check if the newData is equal to the stored data. Remember to make a check if newData is undefined. If old data is equal to the new one, swap the image forward

What's wrong with my camera collision in A-Frame

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.

A-frame: How to setup wall colliders

Can anyone tell me how to setup wall colliders? I have setup a room using OBJ files for the walls. Many thanks.
Take a look at the source code for Don McCurdy's "Walls" example:
https://sandbox.donmccurdy.com/vr/walls/
Note the addition of the physics component in the a-scene element. This is what gets the magic going.
You need to include the aframe-extras script along with aframe.
For anyone looking for a good solution nowadays, the best I found so far is to use a nav-mesh
The nav-mesh is a simple 3d object that represents the walkable area in your project.
Here is what you'll need:
To generate the nav-mesh, use the plugin https://github.com/donmccurdy/aframe-inspector-plugin-recast
To move the camera you will not use wasd-controls, but aframe-extras's movement-controls
How to
Once the plugin is added to the page, follow these steps:
I found it was better to generate without the walls, so I hide the walls first, and make sure the floor ends where the walls would be. Also, keep all objects that user should not be able to pass through in their final place.
In the browser, use ctrl + alt + i to open the inspector
In the bottom part of the inspector, you can change cellSize and cellHeight to 0.1
Export and save it
in the HTML add a new asset:
<a-asset-item id="my-nav-mesh" src="assets/navmesh.gltf"></a-asset-item>
Add a new entity that points to the nav mesh:
<a-entity gltf-model="#my-nav-mesh" nav-mesh position="0 -0.1 0" visible="false"></a-entity>
Add the movement-controls to your camera Rig, with the constrainToNavMesh: true;. Here is how mine ended up:
<a-entity id="rig" movement-controls="constrainToNavMesh: true; speed: 0.8;" position="0 0 26">
<a-entity id="camera"
camera position="0 2.6 0"
look-controls="pointerLockEnabled: true">
<a-cursor></a-cursor>
</a-entity>
Expected Result:
So, by adding the nav-mesh and using the movement-controls instead of WASD, for example, you will make your camera moveable only on the created mesh.
You can also make the mesh invisible (adding visible="false to the nav-mesh entity), and toggle its position on Z so it doesnt feel like a higher plane.
Source
I actually got this information structured from this amazing free youtube video, from Danilo Pasquariello.
https://www.youtube.com/watch?v=Y52czIft9OU
How my project is looking after doing the steps above (I just made the mesh visible again for this screenshot
kinematic-body.js is deprecated.
Don McCurdy encourages the use of teleportation
See this post too: Move camera in aframe with physics engine
aframe inspector plugin didn't work on my project.
I did that temporary
<script src="https://aframe.io/releases/0.8.2/aframe.min.js"></script>
<script
src="https://unpkg.com/aframe-aabb-collider-component#^2.2.1/dist/aframe-aabb-collider-component.min.js"></script>
<script src="https://unpkg.com/aframe-event-set-component#3.0.3/dist/aframe-event-set-component.min.js"></script>
<script>
let isStop = false
AFRAME.registerComponent("cam", {
init: function () {
window.addEventListener('keypress', e => {
if (isStop) {
const camera = document.getElementById('camera')
if (e.key === 's' || e.key === 'a' || e.key === 'd') {
camera.setAttribute('wasd-controls-enabled', 'true')
isStop = false
}
}
})
this.el.addEventListener("hitclosest", (e) => {
console.log('ok');
isStop = true
this.el.setAttribute('wasd-controls-enabled', 'false')
})
this.el.addEventListener("hitstart", (e) => {
isStop = true
this.el.setAttribute('wasd-controls-enabled', 'false')
})
}
})
</script>
<a-scene>
<a-entity id="rig" position="0 .5 -1">
<a-camera wasd-controls-enabled="true" cam id="camera" aabb-collider="objects: .collide"
geometry="primitive: box" aabb-collider="objects: a-box">
<a-cursor></a-cursor>
</a-camera>
</a-entity>
<a-box color="blue" class="collide" width='1' height='1' position="0 1.6 -5">
</a-box>
<a-box color="red" class="collide" width='1' height='1' position="2 1.6 -5">
</a-box>
<a-box color="pink" class="collide" width='10' height='1' position="10 1.6 -5">
</a-box>
</a-scene>
Here's ammo, which is a library for aframes.
https://github.com/n5ro/aframe-physics-system/blob/master/AmmoDriver.md#ammo-shape
You could read Collision Filtering for the detailed solution.

A-Frame mouseleave does not change color of cursor

I have an app where the user has to answer a question by clicking the correct area on a collada model - there are 2 options and the user knows that an area is selectable when the cursor turns blue (mouse enters the cylinder, which has visible=false).
The mouse turns blue fine, however where the mouse leaves the cylinder, the cursor color should return to black, but instead it stays blue.
Thanks in advance for your help.
<a-cursor id="myCursor" color="black"></a-cursor>
<a-entity id='questionA' geometry="primitive: cylinder; height: .01; radius: 2.5" material="color:green; opacity: 1" correctAnswer > </a-entity>
var cursorVar = document.getElementById('myCursor');
var questionVar = document.getElementById('questionA');
questionVar.addEventListener('mouseenter', function() {
cursorVar.setAttribute('color', 'blue');
});
questionVar.addEventListener('mouseleave', function() {
cursorVar.setAttribute('color', 'black');
});
The cursor side also emits the event. Try listening to the event from the cursor as a workaround:
cursorEl.addEventListener('mouseleave');
0.3.0 which should be releasing tomorrow or in two days has improvements on the cursor, raycaster, and raycasting against COLLADA models. This includes the ability to limit what the raycaster tests against which would be ideal in the workaround above.
Could be several factors in your bug, I think once 0.3.0 is out, I'd be able to say with more clarity what's happening.
Does this CodePen perform as you expect?
I can't see the problem looking at your code (maybe it's something to do with the cursor primitive). Try replacing the cursor primitive with a manually defined one used in the CodePen link above:
<!-- Camera with gaze cursor -->
<a-entity position="0 1.8 5">
<a-entity camera look-controls wasd-controls>
<a-entity cursor
geometry="primitive: ring; radiusOuter: 0.025;
radiusInner: 0.015; segmentsTheta: 32"
material="color: #283644; shader: flat"
raycaster="far: 30"
position="0 0 -0.75"
id='cursor'>
</a-entity>
</a-entity>
</a-entity>
That said, the raycasting does seem a bit inaccurate (with 0.2.0 at least).

Resources