Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conflict with... cursor="rayOrigin: mouse" #148

Closed
dreinstein10 opened this issue Aug 2, 2017 · 27 comments
Closed

Conflict with... cursor="rayOrigin: mouse" #148

dreinstein10 opened this issue Aug 2, 2017 · 27 comments

Comments

@dreinstein10
Copy link

First of all, congratulations for your great work, it's awesome.

The latest a-frame version 0.6.1 now includes Mayognaise "aframe-mouse-cursor-component" which works fine on its own. I'm trying to integrate this component into aframe-ar by adding: cursor="rayOrigin: mouse" on the a-marker-camera but I get this error:

three.js:15179 Uncaught TypeError: Cannot read property 'count' of undefined
at Lt.Object.assign.raycast (three.js:15179)
at Xn (three.js:39252)
at jn.intersectObjects (three.js:39329)
at i.tick (raycaster.js:167)
at a-scene.js:517
at Array.forEach ()
at HTMLElement.value (a-scene.js:515)
at HTMLElement.value (a-scene.js:562)
at HTMLElement.render (bind.js:12)
at e (a-scene.js:459)

This is the code I'm using:

<html>
  <head>
    <script src="https://aframe.io/releases/0.6.1/aframe.min.js"></script>
    <script src="https://rawgit.com/jeromeetienne/ar.js/master/aframe/build/aframe-ar.js"></script>
    <script>
      THREEx.ArToolkitContext.baseURL = 'https://rawgit.com/jeromeetienne/ar.js/master/three.js/'
    </script>
  </head>
  <body>
    <a-scene  embedded artoolkit='sourceType: webcam;'>
      <a-box position="0 0 0" rotation="30 30 0" color="skyblue"
             event-set__enter="_event: mouseenter; material.color: yellowgreen; scale: 3 1 1"
             event-set__leave="_event: mouseleave; material.color: skyblue; scale: 1 1 1">
        <a-animation attribute="rotation" begin="click" dur="500" fill="backwards" to="30 30 360"></a-animation>
      </a-box>
      <a-marker-camera  preset='hiro'  cursor="rayOrigin: mouse"> </a-marker-camera>
    </a-scene>
  </body>
</html>

Everything works fine until I add... cursor="rayOrigin: mouse". I guess this is not currently supported because it's a new aframe component, but I was wondering if anyone else has tried to use it with success. And if not, where can I start digging into to try to fix this issue?

Thanks in advance
Keep up the awesomeness !

@JonathanWade
Copy link

I cam to post the exact same issue so +1 on this. Happens both on desktop chrome and iOS11 Safari.

@jeromeetienne
Copy link
Owner

here this is due to the camera having a custom projection matrix. and this being trouble with three.js. aka this is a complex hairy problem to fix.

that said here people just want to be able to click on object. and this one could be provided more easily! let me reread this issue under this angle :)

@jeromeetienne
Copy link
Owner

jeromeetienne commented Aug 2, 2017

@dreinstein10 sorry i dunno the cursor= stuff. can you provide me a simple example of it working in webvr. Just for me to quickly learn more about this component. i have the feeling it will be faster for resolving this issue

update: no more need. i did my homework see below. thanks :)

@jeromeetienne
Copy link
Owner

from here - https://mayognaise.github.io/aframe-mouse-cursor-component/basic/index.html

<html>
  <head>
    <script src="../build.js"></script>
    <link rel="stylesheet" type="text/css" href="../common.css"/>
  </head>
  <body>
    <a-scene>
      <a-box position="0 3.5 -2" rotation="30 30 0" color="skyblue"
             event-set__enter="_event: mouseenter; material.color: yellowgreen; scale: 3 1 1"
             event-set__leave="_event: mouseleave; material.color: skyblue; scale: 1 1 1">
        <a-animation attribute="rotation" begin="click" dur="500" fill="backwards" to="30 30 360"></a-animation>
      </a-box>

      <a-sky color="pink"></a-sky>

      <a-entity position="0 1.8 4">
        <a-entity camera look-controls mouse-cursor>
          <a-cursor fuse="true" color="yellow"></a-cursor>
        </a-entity>
      </a-entity>

      </a-entity>
    </a-scene>
    <div class="spacer"></div>
    <div class="spacer2"></div>
  </body>
</html>

@jeromeetienne
Copy link
Owner

ok so i got a lead...

Currently aframe-mouse-cursor-component use the rendering camera to do the raycasting. This is perfect in a normal case. But here it trigger an issue in three.js raycasting and how it interfere with the AR camera calibration. So we need to work around that. and this can be done if aframe-mouse-cursor-component can use the camera we would specify and not the rendering camera.

hello @mayognaise, are you following all this ? :)

@jeromeetienne
Copy link
Owner

@JonathanWade
Copy link

JonathanWade commented Aug 2, 2017

@jeromeetienne This has slightly changed (hence that cursor= part) as A-Frame 0.6.1 from 15 days ago has rolled the functionality in with a similar, but not duplicate implementation to @mayognaise 's component 0.6.1 Release notes

See this pull request

@dreinstein10
Copy link
Author

Hi @dmarcos, do you know about this ?

@db2crush
Copy link

Hi,
I also got this error..
Is this problem solved?

@kareraisu
Copy link

Also got bit by this. Dear @jeromeetienne, could you make any progress thus far?

@JamesBotterill
Copy link

This is afflicting me also

@sameekhan
Copy link

Having issues with this as well. Got to the end of my MVP and realized I have to choose between click functionality on mobile and the camera lol. @jeromeetienne let me know if I can help in anyway.

@javismiles
Copy link

javismiles commented Dec 7, 2017

any progress here?, need to be able to detect a click on an element urgently, but so far clicks are detected across the entire canvas and screen, how could we detect a click on an specific element triggered by the marker?

@mrturck
Copy link

mrturck commented Dec 21, 2017

I was able to workaround this issue by using event-set-component in addition to mouse-cursor-component. Was able to set visual properties, although no luck with running functions from clicks.

Ex using:
a-frame 0.7.1,
event-set-component (4.0.0)
mouse-cursor-component
a-frame-ar

I use javascript to create a box with the mouse click functionality

var box = document.createElement('a-box');
plane.setAttribute('event-set__down','_event: mousedown; scale: 2 2 2')
scene.appendChild(box);

@perrychen901105
Copy link

perrychen901105 commented Feb 6, 2018

Hello, I am facing the same problem, I want to click on the object, but it is not work. Here are my code.
<a-marker preset='custom' type='pattern' url='./assets/pattern-marker.patt'> <a-obj-model class="link" src="#object" mtl="#material" color="#FF0000" scale="0.02 0.02 0.02" position="0 0 0" rotation="-90 0 0" changescene__click="event: click; linkto: page"></a-obj-model> </a-marker> <a-entity position="0 0 0"> <a-entity camera look-controls mouse-cursor> <a-cursor id="cursor" fuse="true" color="yellow" raycaster="objects: .link"> </a-cursor> </a-entity> </a-entity>

and the click js is,
`AFRAME.registerComponent('changescene', {
schema: {
event: {type: 'string', default: ''},
linkto: {type: 'string', default: ''}
},

multiple: true,

init: function () {
var self = this;
},

update: function () {
var data = this.data;
var el = this.el;
if (data.event) {
console.log("googd");
el.addEventListener(data.event, function () {
console.log("click successful");
alert("clicked");
});
}
}
});`
Thanks.

@Yggdragstyle
Copy link

Hello,

I search an solution for this problem, and I have try to use a Three.js raytracer for get a clickable element. But I' noob, so I grope and I fail...

this is my function : (in orign I code in Coffee Script, but I translate for you in es6 (more and less))

AFRAME.registerComponent( 'clickable-ar', {

init: () => {

		document.addEventListener('click', () => {
							
			raycaster = new THREE.Raycaster()
			mouse = new THREE.Vector2()

			mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1
			mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1


			# raycaster.setFromCamera( mouse.clone(), AFRAME.scenes[0].camera )
			# objects = raycaster.intersectObjects( AFRAME.scenes[0].sceneEl.children )

			# position = {x: 0, y: 0, z: 0} and  direction = {x: 0, y: 0, z: -1} )
			raycaster.set( AFRAME.scenes[0].camera.position, AFRAME.scenes[0].camera.getWorldDirection() )
			elts = raycaster.intersectObject( this, true )

			for( elt in elts ) {
				elt.click(); 
			}
	});
}

});

I' want to know if I'm in a good way, or it's ridiculus ? And any suggestion..

Sorry for my very bad English.. I'm French :P
And thank you for your contribution !
Ygg.

@enquel
Copy link

enquel commented Apr 10, 2018

Hi guys.
After a real nightmare session I've managed to get AFrame fuse cursor working with marker-camera. It stopped disappearing on marker found.

It's kind of hack/exploit, but works really well. Below only the parts that matter (please note there is no hyphen in a-marker-camera):

<a-marker camera preset='hiro'> <a-plane id="buttRegion1" scale="1 1 1" position="0 0 0" opacity="1" rotation="-90 0 0" width="1" height="1" color="#7BC8A4">
  </a-plane> </a-marker camera> 

<a-entity camera></a-entity>
    <a-entity cursor="fuse: true;"
                         position="0 0 -1"
                         scale="0.02 0.02 0.02"
                         geometry="primitive: ring"
                         material="color: black; shader: flat">
                   <a-animation begin="click" easing="ease-in" attribute="scale" dur="150"
                                fill="forwards" from="0.02 0.02 0.02" to="0.03 0.03 0.3"></a-animation>
                   <a-animation begin="cursor-fusing" easing="ease-in" attribute="scale" dur="1500"
                                fill="backwards" from="0.03 0.03 0.03" to="0.02 0.02 0.02"></a-animation>
               </a-entity>

and for the event, in my case, this:

<script>
   document.querySelector('#buttRegion1').addEventListener("click", function(e)
   {
      console.log("buttRegion1");
       window.location.href = './Video1/index.html';
       this.style.display = 'none';
   }, false);
 </script>

@nicolocarpignoli
Copy link
Collaborator

i'm closing this, as we got a working solutions. also topic seems obsolete.

@Steakeye
Copy link

Steakeye commented Aug 6, 2018

@nicolocarpignoli: If @enquel's workaround/hack was working before, it isn't now!
image

@nicolocarpignoli
Copy link
Collaborator

This PR has been closed due to inactivity. Please open a new, updated issue if the problem or the question is still relevant.

@taime
Copy link

taime commented Nov 12, 2019

Everything became extremely slow, when adding rayOrigin: mouse
(I need to handle click event on 3D-model - that's why I use rayOrigin: mouse)

@AndrewChildersClark
Copy link

so it looks like no one has really figured this out still. I got it working in react web ar, but does not work well. Triggering animations by clicking entities has some issues with recognizing the click. the raycaster is not fine tuned enough. Please I hope someone finally figures this out, or updates ar.js. I wish I could be of more help. I will post my react example when I have some time to do a write up.

@kvabakoma
Copy link

kvabakoma commented Mar 31, 2020

I got it working with a hacky solution. It is far from perfect but test users didn't notice anything.

The problem
As far as I understand the problem is that arjs uses a different projection matrix than the actual rendering camera, so when you initiate a mouse raycast it is not aimed properly as it uses a camera with different properties.
None of the solutions I found online seemed to work on a mobile.

The ugly solution
My logic was that a raycast originating from the cursor (center) should aim at the same direction no matter the camera projection matrix. So when a user clicks anywhere on the screen we can send a raycast from the cursor and then calculate the offset using the collision point, distance and angle.

  1. Create a large plane as a child of the <a-marker and give it the .collidable class
  2. When the user clicasdks on the screen send a raycast from the cursor
  3. Detect the collision point on the plane
  4. Calculate the actual desired collision position (get where the user clicked on the screen, multiply it by a distance factor and place it on the plane accordingly - this is your raycast hit)
  5. Cycle through your real collidable objects and check if the distance between the new hitpoint and the the collidbale is bellow your threshold.

HTML:

<a-scene embedded renderer=" colorManagement: true;  logarithmicDepthBuffer: true" arjs="debugUIEnabled: false;  detectionMode: mono_and_matrix; patternRatio: 0.5" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false">
      <a-marker id="marker" type="barcode" value="5" smooth="true" marker-detected keep-model-visible>
        <a-plane raycaster-listen class="collidable" color="#CCC" height="20" width="20" rotation="-90 0 0" material="opacity:0.001"></a-plane>
      </a-marker>

      <a-box scale=".1 .1 .1" id="debug-box"></a-box>
      <a-entity camera>
        <a-entity id="ray-rot-x">
          <a-entity raycaster="objects: .collidable; showLine: false; far: 30; useWorldCoordinates: true" id="ray-rot-y"></a-entity>
        </a-entity>
        <a-entity cursor="fuse: false" position="0 0 -1" geometry="primitive: ring; radiusInner: 0.02; radiusOuter: 0.03" material="color: white; shader: flat; opacity:.05"> </a-entity>
      </a-entity>
    </a-scene>

JS:

AFRAME.registerComponent("raycaster-listen", {
  init: function () {
    // Use events to figure out what raycaster is listening so we don't have to
    // hardcode the raycaster.
    let el = this.el;
    let myRaycaster;

    let canvas = this.el.sceneEl.canvas;
    let clickPosUpdated = new THREE.Vector3();
    let distanceMultiplierX = 0.6;
    let distanceMultiplierY = 0.45;
    let isMobile = this.el.sceneEl.isMobile;

    this.el.addEventListener("raycaster-intersected", (evt) => {
      this.raycaster = evt.detail.el;
      myRaycaster = this.raycaster;
    });
    this.el.addEventListener("raycaster-intersected-cleared", (evt) => {
      this.raycaster = null;
      myRaycaster = null;
    });

    canvas.addEventListener("touchstart", function (evt) {
      console.log(evt);
      // GET MOUSE XY
      var _canvasSize = canvas.getBoundingClientRect(),
        w = _canvasSize.width,
        h = _canvasSize.height,
        offsetW = _canvasSize.left,
        offsetH = _canvasSize.top;
      var cx = void 0,
        cy = void 0;
      if (isMobile) {
        var touches = evt.touches;
        if (!touches || touches.length !== 1) {
          return;
        }
        var touch = touches[0];
        cx = touch.clientX;
        cy = touch.clientY;
      } else {
        cx = evt.clientX;
        cy = evt.clientY;
      }
      cx = cx - offsetW;
      cy = cy - offsetH;
      var mouseX = (cx / w) * 2 - 1;
      var mouseY = -(cy / h) * 2 + 1;

      // RAYCAST
      let intersection = myRaycaster.components.raycaster.getIntersection(el);
      if (!intersection) {
        return;
      }
      // console.log(intersection.point);

      // CALCULATE UDPATED POS
      clickPosUpdated.x = intersection.point.x + intersection.distance * distanceMultiplierX * mouseX;
      clickPosUpdated.y = intersection.point.y + intersection.distance * distanceMultiplierY * mouseY;
      clickPosUpdated.z = intersection.point.z;
      console.log("clickPosUpdated", clickPosUpdated);

      // SET DEBUG BOX
      debugBox.setAttribute("position", clickPosUpdated);
    });
  },
});

Left to do: calculate the Z offset based on the angle of the collision / rotation of the marker.

EDIT: fixed the code. it seemed I had uploaded a wrong version.

@dmarcos
Copy link

dmarcos commented Mar 31, 2020 via email

@kvabakoma
Copy link

What’s the difference about the ar.js camera? - I never found out. I based my assumption on jeromme etiene's comment saying that this is "due to the camera having a custom projection matrix.".

Has the cursor ever worked? - the cursor seems to work fine if it is not setup with rayOrigin: mouse

When did it break? - I've only tried it in the past month

I had a job for a client where users had to tap on moving objects in arjs. The default a-frame implementation (cursor="rayOrigin: mouse") did not work with arjs. I looked all over the Internet for solutions and did not find anything working on mobile (there was smth for desktop though). This topic was the closest I got to an explanation or solution to the issue.

In one of the earlier comments jeromme etiene says that this is "due to the camera having a custom projection matrix.". Based on this I tried to inspect the three scene and see if I can do anything about the camera. I failed and never really got to the bottom of the problem.

Pressed by the project's timeline I tried a few workarounds and the one I've written above gave decent results so I shared it :)

@nicolocarpignoli
Copy link
Collaborator

@kvabakoma Hi There! I tried your code.

There is debugBox variable not specified when trying to access to it (I think a querySelector is missed). I have to dig on it better, in general. Did you have finished it?

Also, I suggest you all to continue discussing this on this PR, on the new Repo, this one has been deprecated: AR-js-org/AR.js#66

@kvabakoma
Copy link

kvabakoma commented Apr 10, 2020

@nicolocarpignoli thanks for pointing out the code ain't working. It seems I've put a wrong version. I've updated my previous post with what should be working.
You can also see a demo here: link - it uses ontouchstart so you should test it on mobile or in dev tools by emulating a phone.
Marker: https://github.com/artoolkit/artoolkit5/blob/master/doc/patterns/Matrix%20code%203x3%20(72dpi)/5.png
Will share it on the other thread as well. Cheers :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests