了解glu.PickMatrix()的实现

时间:2013-10-29 18:32:03

标签: opengl matrix opentk picking

我正在开发一个需要对象选择功能的OpenGL项目。我使用OpenTK框架来做到这一点;但OpenTK不支持glu.PickMatrix()方法来定义拾取区域。我最终搜索了它的实现,这就是我得到的:

    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);
    }

我完全不理解这段代码。此外,这不适用于我的以下代码示例:

    //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.InitNames();

        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();
    }

我希望每次点击一个三角形时只有一次点击,但无论我点击哪里,我总是得到2。我怀疑GluPickMatrix的实现有问题,我还没想到。

0 个答案:

没有答案