关于图形:如何使OpenGL对象在鼠标单击时显示?

How do I make opengl objects appear on mouse click?

我需要做的是单击OpenGL视区中的某个位置,并在该位置进行对象渲染。我已经知道基本的东西,例如创建窗口、检测鼠标点击、获取点击坐标和绘制对象。我丢失的链接就是得到正确的坐标。我需要确定我在屏幕上单击的(x,y)点意味着OpenGL世界坐标。我知道一个叫做glunproject的glut函数,但是由于技术原因,我不能使用glut。我已经检查了许多算法,手工生成了自己的未经处理的函数:

http://schaby.de/picking-opengl-ray-tracing/http://collagefactory.blogspot.mx/2010/03/glunproject-source-code.htmlOpenGL Math-将屏幕空间投影到世界空间坐标

还有其他的,但都没用,当我点击屏幕时,物体被画到了奇怪的地方。我甚至不确定我要在这里寻找什么,我不知道我要实现的是选择,还是光线投射或光线拾取或其他什么。有人知道我要找的算法吗?

编辑:我正在添加一个屏幕截图,我标记了我单击的位置,如您所见,球体正在另一个地方绘制。网址:http://img23.imageshack.us/img23/4738/proofxd.jpg我还添加了我的OpenGL源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
    /**OPENGL**/
    private void GLC_display_Load(object sender, EventArgs e)
    {
        //CONTEXT
        GL.ClearColor(Color.LightGray);
        GL.Enable(EnableCap.Texture2D);
        GL.Enable(EnableCap.Blend);
        GL.Enable(EnableCap.DepthTest);
        GL.Enable(EnableCap.CullFace);
        GL.CullFace(CullFaceMode.Back);
        GL.Enable(EnableCap.Blend);
        GL.DepthFunc(DepthFunction.Always);    
        GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
        GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest);
        SetupViewport();
    }


    private void SetupViewport()
    {
        GL.Clear(ClearBufferMask.ColorBufferBit);
        GL.ShadeModel(ShadingModel.Smooth);
        float aspectRatio = (float)GLC_display.Width / (float)GLC_display.Height;
        GL.Viewport(0, 0, GLC_display.Width, GLC_display.Height);
        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadIdentity();
        OpenTK.Matrix4 perspective = OpenTK.Matrix4.CreatePerspectiveFieldOfView((float)(System.Math.PI / 4f), aspectRatio, 0.1f, 2000f);
        GL.MultMatrix(ref perspective);
        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadIdentity();
    }

    private void GLC_display_Resize(object sender, EventArgs e)
    {
        SetupViewport();
        GLC_display.Invalidate();
    }

    private void GLC_display_Paint(object sender, EventArgs e)
    {

        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        Matrix4 lookat = Matrix4.LookAt(posVector, eyeVector, Vector3.UnitY);
        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadMatrix(ref lookat);
        GL.Color3(Color.Red);
        //GL.PushMatrix();
        //GL.Translate(new Vector3(10f,3f,5f));
        //Geometry.drawSphere(5, 20);
        //GL.PopMatrix();

        foreach (Vector3 coord in clicks)
        {
            Console.WriteLine("List:"+coord.ToString());
            //GL.Color3(0f, 1f, 0f);
            GL.PushMatrix();
            GL.Translate(coord);
            Geometry.drawSphere(5, 20);
            GL.PopMatrix();
        }
        GLC_display.SwapBuffers();
    }

    public Vector3 unProjectInput(Vector2 mouse)
    {
        Vector4 result;
        int[] view = new int[4];
        GL.GetInteger(GetPName.Viewport, view);

        mouse.Y = view[3] - mouse.Y;
        result.X = (2f*((float)(mouse.X - view[0])/view[2])) - 1f;
        result.Y = (2f*((float)(mouse.Y - view[1]) / view[3])) - 1f;
        result.Z = 0f;
        result.W = 1f;

        double[] projection = new double[16];
        GL.GetDouble(GetPName.ProjectionMatrix, projection);
        Matrix4 Projection = new Matrix4((float)projection[0], (float)projection[1], (float)projection[2], (float)projection[3],
                                                   (float)projection[4], (float)projection[5], (float)projection[6], (float)projection[7],
                                                   (float)projection[8], (float)projection[9], (float)projection[10], (float)projection[11],
                                                   (float)projection[12], (float)projection[13], (float)projection[14], (float)projection[15]);
        double[] modelViewMatrix = new double[16];
        GL.GetDouble(GetPName.ModelviewMatrix, modelViewMatrix);
        Matrix4 MV = new Matrix4((float)modelViewMatrix[0], (float)modelViewMatrix[1], (float)modelViewMatrix[2], (float)modelViewMatrix[3],
                                                   (float)modelViewMatrix[4], (float)modelViewMatrix[5], (float)modelViewMatrix[6], (float)modelViewMatrix[7],
                                                   (float)modelViewMatrix[8], (float)modelViewMatrix[9], (float)modelViewMatrix[10], (float)modelViewMatrix[11],
                                                   (float)modelViewMatrix[12], (float)modelViewMatrix[13], (float)modelViewMatrix[14], (float)modelViewMatrix[15]);

        Matrix4 iMVP = Matrix4.Invert(Matrix4.Mult(MV, Projection));
        result = Vector4.Transform(result, iMVP);

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

        return result.Xyz;
    }


GLU和GLUT不一样。任何合理现代化的OpenGL安装都应该具有GLU功能。

对于它的价值,glunproject的实现实际上在其手册页中进行了详细说明。


1
2
3
4
5
6
7
8
9
vec3f cameraPos=camera->position();
vec3f objectPos=vec3f(
    (float)(mousePos.x)/(videoProperties.w)*2-1,
    1,
    (float)(((videoProperties.h)-mousePos.y))/(videoProperties.h)*2-1);
objectPos.x/=(videoProperties.h)/(videoProperties.w);
objectPos*=distance;
objectPos+=cameraPos;
objectPos*=camera->transformation();//may need to inverse this depending on your camera system

这是我在发动机里用的