Search code examples
xtk

Finding world coordinates from screen coordinates


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!!


Solution

  • 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.