Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

 
Advanced search

1075932 Posts in 44152 Topics- by 36119 Members - Latest Member: Royalhandstudios

December 29, 2014, 04:13:55 PM
TIGSource ForumsDeveloperTechnical (Moderators: Glaiel-Gamer, ThemsAllTook)GL ortho center of screen mousePicking
Pages: [1]
Print
Author Topic: GL ortho center of screen mousePicking  (Read 399 times)
nikki
Level 10
*****


View Profile Email
« on: May 28, 2013, 05:04:41 AM »

So after a long day of hacking my own subprime camera class, I went for openGL routines instead.
within minutes I had the behaviour I was after (zooming in on the mouse position)

I did it like this
Code:
GL.Viewport(0, 0, ClientRectangle.Width, ClientRectangle.Height);
            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();
            GL.Ortho(     
        centerX - ( width / 2.0 ),
        centerX + ( width / 2.0 ),
        centerY - ( height / 2.0 ),
        centerY + ( height / 2.0 ),
        -1,
        1     
       );

    GL.MatrixMode(MatrixMode.Modelview);



the actual zooming in on te center is done in this fuction
Code:
void HandleWheelChanged (object sender, OpenTK.Input.MouseWheelEventArgs e)
{


var my = 600 - e.Y;
var mx = e.X;

double x = (mx / (double)(WIDTH)) - 0.5;
double y = (my / (double)(HEIGHT)) - 0.5;

double preX = (x * width);
double preY = (y * height);

double zoomFactor = 1.5;
if (e.Delta > 0) {
width/=zoomFactor;
height/=zoomFactor;
}
if( e.Delta < 0 )
        {
            // zoom out
            width *= zoomFactor;
            height *= zoomFactor;
        }

double postX = ( x * width );
double postY = ( y * height );
centerX += ( preX - postX );
centerY += ( preY - postY );

scaleX = 1.0/(width/WIDTH);
scaleY = 1.0/(height/HEIGHT);
Console.WriteLine("width:{0}, scaleX:{1}",width,scaleX);
OnResize(null);

        }

all of this is fine and dandy, bu now my mousepicking routines are not working anymore.
I had thought I just needed to plug in the centreX, centreY and scaleX, scaleY to get it working.
but the output is changing radically.

Code:
public float[] ScreenToLocal (float x, float y, Camera cam)
{

ms.Vector2 point =  new ms.Vector2(x, y);

var cx = (float)cam.CenterX;
var cy = (float)cam.CenterY;
var sx = (float)cam.ScaleX;
var sy = (float)cam.ScaleY;


ms.Matrix viewMatrix = ms.Matrix.CreateTranslation(-source.Width/2,-source.Height/2, 0f ) *
ms.Matrix.CreateRotationZ((float)GM.DegreeToRadian(source.Rotation)) *
ms.Matrix.CreateScale(sx,sy, 1f) *
ms.Matrix.CreateTranslation(source.Position.X+source.Width/2, source.Position.Y+source.Height/2, 0f );


viewMatrix =  ms.Matrix.Invert(viewMatrix);

ms.Vector2 rotatedPoint = ms.Vector2.Transform(point, viewMatrix);

return new float[]{rotatedPoint.X, rotatedPoint.Y};
}

as you can see I hacked a little in the CreateTranslation call; but I don't really get it, I've tried swapping around all vaiables and am pulling out hairs here.

Am I missing something or just pain silly?
Logged
Polly
Level 4
****


View Profile
« Reply #1 on: May 28, 2013, 06:09:59 AM »

You're making it more difficult then it really is .. in pseudo-code

Code:
float x, y, sinA, cosA;

x = camera.zoom / aspect_ratio;
y = camera.zoom;

sinA = sin(camera.angle);
cosA = cos(camera.angle);

// Matrix is initialized as identity, so 0xA and 0xF are 1.0

matrix[0x0] =  cosA * x;
matrix[0x1] =  sinA * y;
matrix[0x4] = -sinA * x;
matrix[0x5] =  cosA * y;
matrix[0xC] = (-camera.x * cosA + camera.y * sinA) * camera.zoom / aspect_ratio;
matrix[0xD] = (-camera.x * sinA - camera.y * cosA) * camera.zoom;

// Mouse input coordinates are in -1 to 1 range vertically, and -1 to 1 * aspect_ratio horizontally

x = (mouse.x * cosA + mouse.y * sinA) / camera.zoom + camera.x;
y = (mouse.y * cosA - mouse.x * sinA) / camera.zoom + camera.y;

The x / y values contain the mouse coordinates in world-space.
Logged
nikki
Level 10
*****


View Profile Email
« Reply #2 on: May 28, 2013, 06:17:41 AM »

yeah, I have that talent..

what I don't get in your example (thanks btw)
is the use of matrix.

apart from filling it, you don't use it ?
Logged
Polly
Level 4
****


View Profile
« Reply #3 on: May 28, 2013, 11:03:22 AM »

what I don't get in your example (thanks btw)
is the use of matrix.

apart from filling it, you don't use it ?

It's the view & projection matrix ( in one ). So either use glLoadMatrixf() or pass it to your shader.

What the result looks like when automating the camera variables ..



+ I know you trying to do the zoom on cursor thing, but this shows the mouse to world coordinates with all variables in play changing.
Logged
nikki
Level 10
*****


View Profile Email
« Reply #4 on: May 28, 2013, 11:38:55 AM »

After swearing for a full day.
I'm there

Code:

        public Point ConvertScreenToWorldCoords(int x, int y)
        {
            int[] viewport = new int[4];
            Matrix4 modelViewMatrix, projectionMatrix;
            GL.GetFloat(GetPName.ModelviewMatrix, out modelViewMatrix);
            GL.GetFloat(GetPName.ProjectionMatrix, out projectionMatrix);
            GL.GetInteger(GetPName.Viewport, viewport);
            Vector2 mouse;
            mouse.X = x;
         mouse.Y = y;
Vector4 vector = UnProject(ref projectionMatrix, modelViewMatrix, new Size(viewport[2], viewport[3]), mouse);
            Point coords = new Point((int)vector.X, (int)vector.Y);
            return coords;
        }
        public static Vector4 UnProject(ref Matrix4 projection, Matrix4 view, Size viewport, Vector2 mouse)
        {
            Vector4 vec;

            vec.X = 2.0f * mouse.X / (float)viewport.Width - 1;
            vec.Y = 2.0f * mouse.Y / (float)viewport.Height - 1;
            vec.Z = 0;
            vec.W = 1.0f;


            Matrix4 viewInv = Matrix4.Invert(view);
            Matrix4 projInv = Matrix4.Invert(projection);


            Vector4.Transform(ref vec, ref projInv, out vec);
            Vector4.Transform(ref vec, ref viewInv, out vec);


            if (vec.W > float.Epsilon || vec.W < float.Epsilon)
            {
                vec.X /= vec.W;
                vec.Y /= vec.W;
                vec.Z /= vec.W;
            }

            return vec;
        }

is that a heavy operation to do though ?pulling the Matrix like GL.GetFloat(GetPName.ModelviewMatrix, out modelViewMatrix);

anyway off to make the rotations happen again
Logged
Polly
Level 4
****


View Profile
« Reply #5 on: May 28, 2013, 11:44:41 AM »

is that a heavy operation to do though ?pulling the Matrix like GL.GetFloat(GetPName.ModelviewMatrix, out modelViewMatrix);

It's not that bad .. but not necessary either ( as shown in my example .. that's literally all you need math wise ). You main performance offenders* are the Matrix4.Invert calls though ( 80 additions & 192 multiplications per call ).

*Not that it really matters, since you're probably only calling this once per frame .. but it's definitely the slow / lazy route.
Logged
nikki
Level 10
*****


View Profile Email
« Reply #6 on: May 28, 2013, 11:55:59 AM »

I didn't get how to use your example.
Since I have something working now  I have a fresher head , and I know now to set that Matrix perhabs I'll get further.

Cool that you know that about the calls, me I am just scared of stuff like
new Matrix4(m0,m1,m2,m3,m4,m5,m6,m7,m etc);

the thing I posted is actually someone elses errored code (in a forum) that I fixed somehow.

I'll try it out!



Logged
Polly
Level 4
****


View Profile
« Reply #7 on: May 28, 2013, 12:04:21 PM »

Cool that you know that about the calls

Simply check your framework / library source. Or use google .. first result of "Matrix4.Invert" is;

Code:
Matrix4 Matrix4::Inverse() const
{
    //
    // Inversion by Cramer's rule.  Code taken from an Intel publication
    //
    double Result[4][4];
    double tmp[12]; /* temp array for pairs */
    double src[16]; /* array of transpose source matrix */
    double det; /* determinant */
    /* transpose matrix */
    for (UINT i = 0; i < 4; i++)
    {
        src[i + 0 ] = (*this)[i][0];
        src[i + 4 ] = (*this)[i][1];
        src[i + 8 ] = (*this)[i][2];
        src[i + 12] = (*this)[i][3];
    }
    /* calculate pairs for first 8 elements (cofactors) */
    tmp[0] = src[10] * src[15];
    tmp[1] = src[11] * src[14];
    tmp[2] = src[9] * src[15];
    tmp[3] = src[11] * src[13];
    tmp[4] = src[9] * src[14];
    tmp[5] = src[10] * src[13];
    tmp[6] = src[8] * src[15];
    tmp[7] = src[11] * src[12];
    tmp[8] = src[8] * src[14];
    tmp[9] = src[10] * src[12];
    tmp[10] = src[8] * src[13];
    tmp[11] = src[9] * src[12];
    /* calculate first 8 elements (cofactors) */
    Result[0][0] = tmp[0]*src[5] + tmp[3]*src[6] + tmp[4]*src[7];
    Result[0][0] -= tmp[1]*src[5] + tmp[2]*src[6] + tmp[5]*src[7];
    Result[0][1] = tmp[1]*src[4] + tmp[6]*src[6] + tmp[9]*src[7];
    Result[0][1] -= tmp[0]*src[4] + tmp[7]*src[6] + tmp[8]*src[7];
    Result[0][2] = tmp[2]*src[4] + tmp[7]*src[5] + tmp[10]*src[7];
    Result[0][2] -= tmp[3]*src[4] + tmp[6]*src[5] + tmp[11]*src[7];
    Result[0][3] = tmp[5]*src[4] + tmp[8]*src[5] + tmp[11]*src[6];
    Result[0][3] -= tmp[4]*src[4] + tmp[9]*src[5] + tmp[10]*src[6];
    Result[1][0] = tmp[1]*src[1] + tmp[2]*src[2] + tmp[5]*src[3];
    Result[1][0] -= tmp[0]*src[1] + tmp[3]*src[2] + tmp[4]*src[3];
    Result[1][1] = tmp[0]*src[0] + tmp[7]*src[2] + tmp[8]*src[3];
    Result[1][1] -= tmp[1]*src[0] + tmp[6]*src[2] + tmp[9]*src[3];
    Result[1][2] = tmp[3]*src[0] + tmp[6]*src[1] + tmp[11]*src[3];
    Result[1][2] -= tmp[2]*src[0] + tmp[7]*src[1] + tmp[10]*src[3];
    Result[1][3] = tmp[4]*src[0] + tmp[9]*src[1] + tmp[10]*src[2];
    Result[1][3] -= tmp[5]*src[0] + tmp[8]*src[1] + tmp[11]*src[2];
    /* calculate pairs for second 8 elements (cofactors) */
    tmp[0] = src[2]*src[7];
    tmp[1] = src[3]*src[6];
    tmp[2] = src[1]*src[7];
    tmp[3] = src[3]*src[5];
    tmp[4] = src[1]*src[6];
    tmp[5] = src[2]*src[5];

    tmp[6] = src[0]*src[7];
    tmp[7] = src[3]*src[4];
    tmp[8] = src[0]*src[6];
    tmp[9] = src[2]*src[4];
    tmp[10] = src[0]*src[5];
    tmp[11] = src[1]*src[4];
    /* calculate second 8 elements (cofactors) */
    Result[2][0] = tmp[0]*src[13] + tmp[3]*src[14] + tmp[4]*src[15];
    Result[2][0] -= tmp[1]*src[13] + tmp[2]*src[14] + tmp[5]*src[15];
    Result[2][1] = tmp[1]*src[12] + tmp[6]*src[14] + tmp[9]*src[15];
    Result[2][1] -= tmp[0]*src[12] + tmp[7]*src[14] + tmp[8]*src[15];
    Result[2][2] = tmp[2]*src[12] + tmp[7]*src[13] + tmp[10]*src[15];
    Result[2][2] -= tmp[3]*src[12] + tmp[6]*src[13] + tmp[11]*src[15];
    Result[2][3] = tmp[5]*src[12] + tmp[8]*src[13] + tmp[11]*src[14];
    Result[2][3] -= tmp[4]*src[12] + tmp[9]*src[13] + tmp[10]*src[14];
    Result[3][0] = tmp[2]*src[10] + tmp[5]*src[11] + tmp[1]*src[9];
    Result[3][0] -= tmp[4]*src[11] + tmp[0]*src[9] + tmp[3]*src[10];
    Result[3][1] = tmp[8]*src[11] + tmp[0]*src[8] + tmp[7]*src[10];
    Result[3][1] -= tmp[6]*src[10] + tmp[9]*src[11] + tmp[1]*src[8];
    Result[3][2] = tmp[6]*src[9] + tmp[11]*src[11] + tmp[3]*src[8];
    Result[3][2] -= tmp[10]*src[11] + tmp[2]*src[8] + tmp[7]*src[9];
    Result[3][3] = tmp[10]*src[10] + tmp[4]*src[8] + tmp[9]*src[9];
    Result[3][3] -= tmp[8]*src[9] + tmp[11]*src[10] + tmp[5]*src[8];
    /* calculate determinant */
    det=src[0]*Result[0][0]+src[1]*Result[0][1]+src[2]*Result[0][2]+src[3]*Result[0][3];
    /* calculate matrix inverse */
    det = 1.0f / det;

    Matrix4 FloatResult;
    for (UINT i = 0; i < 4; i++)
    {
        for (UINT j = 0; j < 4; j++)
        {
            FloatResult[i][j] = float(Result[i][j] * det);
        }
    }
    return FloatResult;

    //
    // Inversion by LU decomposition, alternate implementation
    //
    /*int i, j, k;

    for (i = 1; i < 4; i++)
    {
        _Entries[0][i] /= _Entries[0][0];
    }

    for (i = 1; i < 4; i++)
    {
        for (j = i; j < 4; j++)
        {
            float sum = 0.0;
            for (k = 0; k < i; k++)
            {
                sum += _Entries[j][k] * _Entries[k][i];
            }
            _Entries[j][i] -= sum;
        }
        if (i == 4-1) continue;
        for (j=i+1; j < 4; j++)
        {
            float sum = 0.0;
            for (int k = 0; k < i; k++)
                sum += _Entries[i][k]*_Entries[k][j];
            _Entries[i][j] =
               (_Entries[i][j]-sum) / _Entries[i][i];
        }
    }

    //
    // Invert L
    //
    for ( i = 0; i < 4; i++ )
    {
        for ( int j = i; j < 4; j++ )
        {
            float x = 1.0;
            if ( i != j )
            {
                x = 0.0;
                for ( int k = i; k < j; k++ )
                    x -= _Entries[j][k]*_Entries[k][i];
            }
            _Entries[j][i] = x / _Entries[j][j];
        }
    }

    //
    // Invert U
    //
    for ( i = 0; i < 4; i++ )
    {
        for ( j = i; j < 4; j++ )
        {
            if ( i == j ) continue;
            float sum = 0.0;
            for ( int k = i; k < j; k++ )
                sum += _Entries[k][j]*( (i==k) ? 1.0f : _Entries[i][k] );
            _Entries[i][j] = -sum;
        }
    }

    //
    // Final Inversion
    //
    for ( i = 0; i < 4; i++ )
    {
        for ( int j = 0; j < 4; j++ )
        {
            float sum = 0.0;
            for ( int k = ((i>j)?i:j); k < 4; k++ ) 
                sum += ((j==k)?1.0f:_Entries[j][k])*_Entries[k][i];
            _Entries[j][i] = sum;
        }
    }*/
}

Not exactly the best invert function i've seen, but just to give you a idea Smiley
Logged
Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic