1
\$\begingroup\$

I am working on an OpenGL project which requires object selection feature. I use OpenTK framework to do this; however OpenTK doesn't support glu.PickMatrix() method to define the picking region. I ended up googling its implementation and here is what i got:

    void GluPickMatrix(double x, double y, double deltax, double deltay, int[] viewport)
    {
        if (deltax <= 0 || deltay <= 0)
        {
            return;
        }

        GL.Translate((viewport[2] - 2 * (x - viewport[0])) / deltax, (viewport[3] - 2 * (y - viewport[1])) / deltay, 0);
        GL.Scale(viewport[2] / deltax, viewport[3] / deltay, 1.0);
    }

I totally fail to understand this piece of code. Moreover, this doesn't work with my following code sample:

    //selectbuffer
    private int[] _selectBuffer = new int[512];

    private void Init()
    {
        float[] triangleVertices = new float[] { 0.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f };
        float[] _triangleColors = new float[] { 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f };

        GL.GenBuffers(2, _vBO);
        GL.BindBuffer(BufferTarget.ArrayBuffer, _vBO[0]);
        GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(float) * _triangleVertices.Length), _triangleVertices, BufferUsageHint.StaticDraw);
        GL.VertexPointer(3, VertexPointerType.Float, 0, 0);
        GL.BindBuffer(BufferTarget.ArrayBuffer, _vBO[1]);
        GL.BufferData(BufferTarget.ArrayBuffer, new IntPtr(sizeof(float) * _triangleColors.Length), _triangleColors, BufferUsageHint.StaticDraw);
        GL.ColorPointer(3, ColorPointerType.Float, 0, 0);
        GL.EnableClientState(ArrayCap.VertexArray);
        GL.EnableClientState(ArrayCap.ColorArray);

        //Selectbuffer set up
        GL.SelectBuffer(512, _selectBuffer);
    }

    private void glControlWindow_Paint(object sender, PaintEventArgs e)
    {

        GL.Clear(ClearBufferMask.ColorBufferBit);
        GL.Clear(ClearBufferMask.DepthBufferBit);

        float[] eyes = { 0.0f, 0.0f, -10.0f };
        float[] target = { 0.0f, 0.0f, 0.0f };
        Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(0.785398163f, 4.0f / 3.0f, 0.1f, 100f);  //45 degree = 0.785398163 rads
        Matrix4 view = Matrix4.LookAt(eyes[0], eyes[1], eyes[2], target[0], target[1], target[2], 0, 1, 0);
        Matrix4 model = Matrix4.Identity;
        Matrix4 MV = view * model;

        //First Clear Buffers
        GL.Clear(ClearBufferMask.ColorBufferBit);
        GL.Clear(ClearBufferMask.DepthBufferBit);

        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadIdentity();
        GL.LoadMatrix(ref projection);

        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadIdentity();
        GL.LoadMatrix(ref MV);


        GL.Viewport(0, 0, glControlWindow.Width, glControlWindow.Height);
        GL.Enable(EnableCap.DepthTest); //Enable correct Z Drawings
        GL.DepthFunc(DepthFunction.Less); //Enable correct Z Drawings
        GL.MatrixMode(MatrixMode.Modelview);

        GL.PushMatrix();
        GL.Translate(3.0f, 0.0f, 0.0f);
        DrawTriangle();
        GL.PopMatrix();

        GL.PushMatrix();
        GL.Translate(-3.0f, 0.0f, 0.0f);
        DrawTriangle();
        GL.PopMatrix();

        //Finally...
        GraphicsContext.CurrentContext.VSync = true; //Caps frame rate as to not over run GPU
        glControlWindow.SwapBuffers(); //Takes from the 'GL' and puts into control
    }

    private void DrawTriangle()
    {
        GL.BindBuffer(BufferTarget.ArrayBuffer, _vBO[0]);
        GL.VertexPointer(3, VertexPointerType.Float, 0, 0);
        GL.EnableClientState(ArrayCap.VertexArray);
        GL.DrawArrays(BeginMode.Triangles, 0, 3);
        GL.DisableClientState(ArrayCap.VertexArray);
    }

    //mouse click event implementation
    private void glControlWindow_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
    {

        //Enter Select mode. Pretend drawing.
        GL.RenderMode(RenderingMode.Select);

        int[] viewport = new int[4];
        GL.GetInteger(GetPName.Viewport, viewport);
        GL.PushMatrix();
        GL.MatrixMode(MatrixMode.Projection);

        GL.LoadIdentity();

        GluPickMatrix(e.X, e.Y, 5, 5, viewport);

        Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView(0.785398163f, 4.0f / 3.0f, 0.1f, 100f);  // this projection matrix is the same as one in glControlWindow_Paint method.

        GL.LoadMatrix(ref projection);
        GL.MatrixMode(MatrixMode.Modelview);

        int i = 0;
        int hits;

        GL.PushMatrix();
        GL.Translate(3.0f, 0.0f, 0.0f); 
        GL.PushName(i);
        DrawTriangle();
        GL.PopName();
        GL.PopMatrix();

        i++;

        GL.PushMatrix();
        GL.Translate(-3.0f, 0.0f, 0.0f);
        GL.PushName(i);
        DrawTriangle();
        GL.PopName();
        GL.PopMatrix();

        hits = GL.RenderMode(RenderingMode.Render);

        .....hits processing code goes here...

        GL.PopMatrix();

        glControlWindow.Invalidate();
    }

I expect to get only one hit everytime i click inside a triangle, but i always get 2 no matter where i click. I suspect there is something wrong with the implementation of the GluPickMatrix, I haven't figured out yet.

\$\endgroup\$
3
  • \$\begingroup\$ 2 hits for the same triangle or 2 different triangles ? \$\endgroup\$
    – concept3d
    Oct 29 '13 at 19:38
  • \$\begingroup\$ I used 1 vertex object buffer to draw 2 triangles at 2 different location by translating the model coordinate. Is it considered 1 object or 2 different objects ?? \$\endgroup\$
    – stoney78us
    Oct 29 '13 at 21:46
  • 2
    \$\begingroup\$ This question appears to be off-topic because it is solved by a simple mistake cured by debugging. \$\endgroup\$
    – Kromster
    Sep 26 '14 at 5:12
0
\$\begingroup\$

I found out the bug. It should be:
GL.MulMatrix(ref projection)
instead of
GL.LoadMatrix(ref projection)

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.