3

There's many answers to this problem, but I'm not sure that they all work with XTK, such as seeing multiple answers for this in Three.JS, but of course XTK and Three.JS don't have the same API obviously. Using a ray and Matrix seemed very similar to many other solutions for other frameworks, but I'm still not grasping a possible solution here. For now just finding the coordinates X, Y, and Z and recording them into Console.Log is fine, later I was hoping to create a caption/tooltip to display the information, but there is other ways to display it also. But can someone at least tell me if this is possible to use a ray to collide with the objects? I'm not sure how collision works in XTK with meshes or any other files. Any hints right now would be great!!

Karijuana
  • 314
  • 1
  • 2
  • 13
  • 1
    This is also the info I've learned from my research. So basically we do a Unproject function to convert 2d to 3d. Wherever our mouse is on the screen ( from my caption/tooltip idea ) , that is where a ray is cast perpendicular to our "screen" in the "3d world". Then we find the closest triangle to where the ray intersects, giving us our 3d coordinates. No? – Karijuana Jul 18 '12 at 17:08
  • 1
    Are you sure the ray is cast perpendical to the screen ? I thought it was cast in the direction given by the product of the (x,y) coordinates on the screen by the inverse projection-view matrix. And so when you've the direction, you try to find the intersection with the object's triangles by using dichotomy (and if possible bounding boxes to faster it) – Ricola3D Jul 23 '12 at 08:15
  • I need it too so I'll try something too. – Ricola3D Jul 23 '12 at 08:20
  • 1
    Your last comment is correct, If I do cast a ray perpendicular to the screen, the ray would be cast at an incorrect angle resulting in an offset. – Karijuana Jul 23 '12 at 17:00

2 Answers2

4

Here is my function to unproject in xtk. Please tell me if you see mistakes. Now with the resulting point and the camera position I should be able to find my intersections. To make the computation faster for the following step, I'll call it in a pick event and so I'll only have to try the intersections with a given object. If I've time i'll also try with testing the bounding boxes.

Nota bene : the last lines are not required, I could work on the ray instead of the point.

X.camera3D.prototype.unproject = function (x,y) {

  // get the 4x4 model-view matrix
  var mvMatrix = this._view;

  // create the 4x4 projection matrix from the flatten gl version
  var pMatrix = new X.matrix(4,4);
  for (var i=0 ; i<16 ; i++) {
    pMatrix.setValueAt(i - 4*Math.floor(i/4), Math.floor(i/4), this._perspective[i]);
  }
  // compute the product and inverse it
  var mvpMatrxix = pMatrix.multiply(mwMatrix); /** Edit : wrong product corrected **/
  var inverse_mvpMatrix = mvpMatrxix.getInverse();
  if (!goog.isDefAndNotNull(inverse_mvpMatrix)) throw new Error("Could not inverse the transformation matrix.");

  // check if x & y are map in [-1,1] interval (required for the computations)
  if (x<-1 || x>1 || y<-1 || y>1) throw new Error("Invalid x or y coordinate, it must be between -1 and 1");

  // fill the 4x1 normalized (in [-1,1]⁴) vector of the point of the screen in word camera world's basis
  var point4f = new X.matrix(4,1);
  point4f.setValueAt(0, 0, x);
  point4f.setValueAt(1, 0, y);
  point4f.setValueAt(2, 0, -1.0); // 2*?-1, with ?=0 for near plan and ?=1 for far plan
  point4f.setValueAt(3, 0, 1.0); // homogeneous coordinate arbitrary set at 1

  // compute the picked ray in the world's basis in homogeneous coordinates
  var ray4f = inverse_mvpMatrix.multiply(point4f);
  if (ray4f.getValueAt(3,0)==0) throw new Error("Ray is not valid.");
  // return in not-homogeneous coordinates to compute the 3D direction vector
  var point3f = new X.matrix(3,1);
  point3f.setValueAt(0, 0, ray4f.getValueAt(0, 0) / ray4f.getValueAt(3, 0) );
  point3f.setValueAt(1, 0, ray4f.getValueAt(1, 0) / ray4f.getValueAt(3, 0) );
  point3f.setValueAt(2, 0, ray4f.getValueAt(2, 0) / ray4f.getValueAt(3, 0) );
  return point3f;
};

Edit

Here, in my repo, you can find functions in camera3D.js and renderer3D.js for efficient 3D picking in xtk.

Ricola3D
  • 2,402
  • 17
  • 16
  • I realize the concept you used is perfect here, but I'm a fairly new to programming so I'm not completely sure that this would work correctly. I'm sure Haehn would like to review this. – Karijuana Jul 23 '12 at 13:48
  • This looks great, did you test it? If yes, can you send a pull request please? – haehn Jul 24 '12 at 13:55
  • I'm testing but for the moment it doesn't seem to give the good ray (I plot the camera position and a ray going from there in the computed direction to test) – Ricola3D Jul 24 '12 at 14:43
  • I think i've the point : this unproject is good but i've to trace my test cylinder and sphere translated of -renderer3D._center no? – Ricola3D Jul 24 '12 at 15:10
  • I believe that's correct, I spent a week on this and you write a code in a day, great work haha – Karijuana Jul 24 '12 at 15:13
  • A day ? No-no, I spent my full monday on it (and I studied it in High School) because the following codes (ray-AABB intersection and get3point) gave no result and I thought my unproject correct. Now the issue is : with translating of the scene's bounding box center I get a perfect 1st shot, but the others are drawn at wrong places.. while at every double click I read the scene center and camera position again.. – Ricola3D Jul 24 '12 at 15:20
  • Okay I see, my issue will be to do with the operations made in the shaders. My unproject is good but tracing it will not give good results since the shaders translate the vertex before applying model-view and projection matrices. So normaly I can try the next step. It's crazy, every day I figure a bit more how hard it should have been to make such a framework ! – Ricola3D Jul 24 '12 at 15:34
  • That makes sense, and thanks to Haehn for making this! I haven't even started High School, I have a while before getting pretty advanced – Karijuana Jul 24 '12 at 15:40
  • Well let's continue on Github untill the issue is solved : https://github.com/xtk/X/issues/78 – Ricola3D Jul 25 '12 at 09:08
2

right now this is not easily possible. I guess you could grab the view matrix of the camera to calculate the position. If you do so, it would be great to bring it back into XTK as built-in functionality!

Currently, only object picking is possible like this (r is a X.renderer3D):

/**
* Picks an object at a position defined by display coordinates. If
* X.renderer3D.config['PICKING_ENABLED'] is FALSE, this function always returns
* -1.
*
* @param {!number} x The X-value of the display coordinates.
* @param {!number} y The Y-value of the display coordinates.
* @return {number} The ID of the found X.object or -1 if no X.object was found.
*/
var pick = r.pick($X, $Y);
haehn
  • 967
  • 1
  • 6
  • 19
  • Alright, I'll keep looking in to it and get back to ya if I find a solution. – Karijuana Jul 18 '12 at 14:27
  • I found another JS library on Github that handles matrix and vector operations. Both of those are needed for the "screen coords. to worlds coords." issue right now. It's explained why they're needed in the comment I put under the question. https://github.com/toji/gl-matrix – Karijuana Jul 18 '12 at 18:33
  • yes to test you can use these but also, in XTK we use the google closure library which has a lot of vec and mat operations as well – haehn Jul 19 '12 at 14:52