Transform screen coordinates to model coordinates

2020-03-06 03:55发布

问题:

I've got some sort of newbie question.

In my application (processingjs) i use scale() and translate() to allow the user to zoom and scroll through the scene. As long as i keep the scale set to 1.0 i've got no issues. BUT whenever i use the scale (i.e. scale(0.5)) i'm lost...

I need the mouseX and mouseY translated to the scene coordinates, which i use to determine the mouseOver state of the object I draw on the scene.

Can anybody help me how to translate these coordinates? Thanks in advance! /Richard

回答1:

Unfortunately for me this required a code modification. I'll look at submitting this to the Processing.JS code repository at some point, but here's what I did.

First, you'll want to use modelX() and modelY() to get the coordinates of the mouse in world view. That will look like this:

float model_x = modelX(mouseX, mouseY);
float model_y = modelY(mouseX, mouseY);

Unfortunately Processing.JS doesn't seem to calculate the modelX() and modelY() values correctly in a 2D environment. To correct that I changed the functions to be as follows. Note the test for mv.length == 16 and the section at the end for 2D:

p.modelX = function(x, y, z) {
  var mv = modelView.array();
  if (mv.length == 16) {
    var ci = cameraInv.array();
    var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3];
    var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7];
    var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11];
    var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15];
    var ox = 0, ow = 0;
    var ox = ci[0] * ax + ci[1] * ay + ci[2] * az + ci[3] * aw;
    var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw;
    return ow !== 0 ? ox / ow : ox
  }
  // We assume that we're in 2D
  var mvi = modelView.get();
  // NOTE that the modelViewInv doesn't seem to be correct in this case, so
  // having to re-derive the inverse
  mvi.invert();
  return mvi.multX(x, y);
};
p.modelY = function(x, y, z) {
  var mv = modelView.array();
  if (mv.length == 16) {
    var ci = cameraInv.array();
    var ax = mv[0] * x + mv[1] * y + mv[2] * z + mv[3];
    var ay = mv[4] * x + mv[5] * y + mv[6] * z + mv[7];
    var az = mv[8] * x + mv[9] * y + mv[10] * z + mv[11];
    var aw = mv[12] * x + mv[13] * y + mv[14] * z + mv[15];
    var oy = ci[4] * ax + ci[5] * ay + ci[6] * az + ci[7] * aw;
    var ow = ci[12] * ax + ci[13] * ay + ci[14] * az + ci[15] * aw;
    return ow !== 0 ? oy / ow : oy
  }
  // We assume that we're in 2D
  var mvi = modelView.get();
  // NOTE that the modelViewInv doesn't seem to be correct in this case, so
  // having to re-derive the inverse
  mvi.invert();
  return mvi.multY(x, y);
};

I hope that helps someone else who is having this problem.



回答2:

Have you tried another method?

For example, assume that you are in a 2D environment, you can "map" all the frame in a sort of matrix. Something like this:

int fWidth = 30;
int fHeight = 20;
float objWidth = 10;
float objHeight = 10;

void setup(){
  fWidth = 30;
  fHeight = 20;
  objWidth = 10;
  objHeight = 10;
  size(fWidth * objWidth, fHeight * objHeight);
}

In this case you will have a 300*200 frame, but divided in 30*20 sections. This allows you to move in somewhat ordered way your objects.

When you draw an object you have to give his sizes, so you can use objWidth and objHeight.

Here's the deal: you can make a "zoom-method" that edit the value of the object sizes. In this way you drew a smaller/bigger object without editing any frame property.

This is a simple example because of your inaccurate question. You can do it [in more complex ways], in a 3D environment too.