views:

733

answers:

1

I've implemented a camera (model view) in my 2D opengl application and am having some issues with scaling around a point and also scaling around a point in combination with panning. Both work with the mouse. Panning works with a mouse drag, and scale to point zooms in/out around the current mouse location.

Panning works fine as long as I haven't yet scaled around a point. If I have scaled around a point, then there's an initial "jump" in the panning, but then it works smoothly. Scaling around a point works alright for the first point, but for subsequent points the scene translates once and then after that scaling around the current mouse point works. The scale around point code looks like:

public void scaleToPoint(float scale, float x, float y, float z) {
    root.markAsDirty();
    y = drawableHeight - y - 1;

    // (S(Inverse(T))
    matrix.m03 = -x;
    matrix.m13 = -y;
    matrix.m23 = -z;

    matrix.m00 = matrix.m11 = matrix.m22 = scale;
    matrix.m03 *= matrix.m00;
    matrix.m13 *= matrix.m11;
    matrix.m23 *= matrix.m22;
    matrix.m03 += x;
    matrix.m13 += y;
    matrix.m23 += z;
  }

The panning code just sets the translation component of the matrix. It seems like in both cases I need to undo the previous translation somehow to avoid the jump, but I can't see how. Thanks.

Nick

Added in response to comment:

matrix is a javax.matrix.Matrix4f.

Panning code:

public void pan(Vector3f pan) {
    root.markAsDirty();
    matrix.setTranslation(pan);
}

where matrix.setTranslation sets the translation component of the matrix i.e:

matrix.m03 = trans.x; 
matrix.m13 = trans.y;
matirx.m23 = trans.z;

The matrix is loaded using glLoadMatrix() to set the topmost matrix in the stack. The expected output is a normal smooth pan without the additional jump in the case of panning, and no jump prior to the zoom / scale in the case of the scaling. By jump I mean that the scene shifts unexpectedly. So for example, if the scene is one large square and the mouse is located in the center of the square, the square should move in the direction of the mouse drag while the center of the square remains under the mouse. With the jump, the mouse will begin the center of the square, but the start of the pan will move the scene such that a different part of the square is now under the mouse. The jump in scaling works similarly. The first zoom shifts the scene so that location that was initially under the mouse is now no longer under the mouse.

Note that panning works fine if no scaling around a point has taken place. Panning also works fine if scaling is not around some particular point.

+1  A: 

Your problem is that instead of doing a delta translation, you just set the translation. That works when it just comes to panning, however, when you scale, you don't store the translation due to the scale, and it is erased on the next translation action. So what I would do, instead of setting the translation is I would increment it. So when you drag the mouse, get a delta from 2 gluUnProject calls, then add that delta to the matrix translation values. That will prevent it from erasing the slight translation created by the scale around point action.

So:

public void pan(Vector3f delta_pan)
{
    root.markAsDirty();
    matrix.m03 += delta_pan.x; 
    matrix.m13 += delta_pan.y;
    matirx.m23 += delta_pan.z;
}
Ned