Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf SharpGL-使用选择和拾取检测OpenGL元素上的鼠标单击_Wpf_Opengl_Sharpgl - Fatal编程技术网

Wpf SharpGL-使用选择和拾取检测OpenGL元素上的鼠标单击

Wpf SharpGL-使用选择和拾取检测OpenGL元素上的鼠标单击,wpf,opengl,sharpgl,Wpf,Opengl,Sharpgl,我正在使用SharpGL库在WPF中实现一个2D图形。我已经在屏幕上画了一些基本对象,我需要检测鼠标在这些对象上的点击 我看了一个OpenGL教程,介绍了如何在图形对象上执行选择和拾取,但我没能让它正常工作。 在我的测试应用程序中,我在屏幕上绘制了三个三角形,当鼠标点击时,我在GL\u SELECT模式中绘制了相同的三个三角形,希望检测是否有任何三角形被点击。我不确定这是不是正确的方法。命中测试总是返回选择缓冲区中的所有元素 我知道PickMatrix中的宽度和高度参数不正确,我也不确定那里的正

我正在使用SharpGL库在WPF中实现一个2D图形。我已经在屏幕上画了一些基本对象,我需要检测鼠标在这些对象上的点击

我看了一个OpenGL教程,介绍了如何在图形对象上执行选择和拾取,但我没能让它正常工作。 在我的测试应用程序中,我在屏幕上绘制了三个三角形,当鼠标点击时,我在
GL\u SELECT
模式中绘制了相同的三个三角形,希望检测是否有任何三角形被点击。我不确定这是不是正确的方法。命中测试总是返回选择缓冲区中的所有元素

我知道PickMatrix中的宽度和高度参数不正确,我也不确定那里的正确值是多少。是整个视图的宽度和高度吗

private void OpenGLControl_OpenGLDraw(object sender, SharpGL.SceneGraph.OpenGLEventArgs args)
{
    ////  Get the OpenGL object.
    OpenGL gl = args.OpenGL;

    //set background to white
    gl.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);

    ////  Clear the color and depth buffer.
    gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
    DrawScene();
    gl.Flush();
}

private void DrawScene()
{
    OpenGL gl = openGLControl.OpenGL;
    gl.Color(1.0, 0.0, 0.0);
    DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6);

    gl.Color(0.0, 1.0, 0.0);
    DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2);

    gl.Color(0.0, 0.0, 1.0);
    DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2);
}

private void SelectObjects(double mouseDownX, double mouseDownY)
{
    OpenGL gl = openGLControl.OpenGL;
    int BUFSIZE = 512;

    uint[] selectBuf = new uint[BUFSIZE];

    gl.SelectBuffer(BUFSIZE, selectBuf);
    gl.RenderMode(OpenGL.GL_SELECT);

    gl.InitNames();
    gl.PushName(0);

    int[] viewport = new int[4];
    gl.GetInteger(OpenGL.GL_VIEWPORT, viewport);
    
    //how to define the width and height of an element?
    gl.PickMatrix(mouseDownX, (double)(viewport[3] - mouseDownY), 50.0, 50.0, viewport);

    gl.LoadIdentity();

    gl.LoadName(1);
    gl.Color(1.0, 0.0, 0.0);
    DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6);

    gl.LoadName(2);
    gl.Color(0.0, 1.0, 0.0);
    DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2);

    gl.LoadName(3);
    gl.Color(0.0, 0.0, 1.0);
    DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2);

    gl.Flush(); 
    int hits = gl.RenderMode(OpenGL.GL_RENDER);
    processHits(hits, selectBuf);
}

private void processHits(int hits, uint[] buffer)
{
    uint bufferIterator = 0;
    for (uint i = 0; i < hits; i++)
    {
        uint numberOfNamesInHit = buffer[bufferIterator];
        Console.WriteLine("hit: " + i + " number of names in hit " + numberOfNamesInHit);

        uint lastNameIndex = bufferIterator + 2 + numberOfNamesInHit;
        for (uint j = bufferIterator + 3; j <= lastNameIndex; j++)
        {
            Console.WriteLine("Name is " + buffer[j]);
        }

        bufferIterator = bufferIterator + numberOfNamesInHit + 3;
    }
}

private void OnMouseClick(object sender, MouseEventArgs e)
{
    System.Windows.Point position = e.GetPosition(this);
    SelectObjects(position.X, position.Y); 
}
private void OpenGLControl\u OpenGLDraw(对象发送方,SharpGL.SceneGraph.OpenGLEventArgs args)
{
////获取OpenGL对象。
OpenGL=args.OpenGL;
//将背景设置为白色
gl.ClearColor(1.0f、1.0f、1.0f、1.0f);
////清除颜色和深度缓冲区。
gl.Clear(OpenGL.gl_COLOR_BUFFER_BIT | OpenGL.gl_DEPTH_BUFFER_BIT);
DrawScene();
gl.Flush();
}
私有场景()
{
OpenGL=openGLControl.OpenGL;
gl.颜色(1.0,0.0,0.0);
牵引三角(-0.2,0.6,0.0,0.8,0.2,0.6);
gl.颜色(0.0,1.0,0.0);
牵引三角(-0.2,0.2,0.0,0.4,0.2,0.2);
gl.颜色(0.0,0.0,1.0);
牵引三角(-0.2,-0.2,0.0,0.0,0.2,-0.2);
}
private void SelectObjects(双鼠标向下移动,双鼠标向下移动)
{
OpenGL=openGLControl.OpenGL;
int BUFSIZE=512;
uint[]选择buf=新uint[BUFSIZE];
总账选择缓冲区(BUFSIZE,selectBuf);
渲染模型(OpenGL.gl\u选择);
gl.InitNames();
总帐名称(0);
int[]视口=新int[4];
GetInteger(OpenGL.gl_视口,视口);
//如何定义元素的宽度和高度?
gl.PickMatrix(mouseDownX,(双)(视口[3]-mouseDownY),50.0,50.0,视口);
gl.LoadIdentity();
总帐货物名称(1);
gl.颜色(1.0,0.0,0.0);
牵引三角(-0.2,0.6,0.0,0.8,0.2,0.6);
总帐装载名称(2);
gl.颜色(0.0,1.0,0.0);
牵引三角(-0.2,0.2,0.0,0.4,0.2,0.2);
总帐装载名称(3);
gl.颜色(0.0,0.0,1.0);
牵引三角(-0.2,-0.2,0.0,0.0,0.2,-0.2);
gl.Flush();
int hits=gl.RenderMode(OpenGL.gl\u RENDER);
processHits(hits,选择buf);
}
私有void processHits(int hits,uint[]缓冲区)
{
uint缓冲迭代器=0;
对于(uint i=0;i对于(uint j=bufferIterator+3;j宽度和高度是拾取区域的大小(以像素为单位)。对于检测鼠标指针下的对象,1x1应该可以(您希望检测1像素乘以1像素的屏幕矩形下的内容)

gluPickMatrix
用拾取矩阵更新(乘以)当前矩阵。您的
PickMatrix
后跟
LoadIdentity
没有任何意义,因为
glLoadIdentity
将当前矩阵重置为identity

为了使示例正常工作,在渲染之前,请设置矩阵:

glLoadIdentity();
setupMyProjMatrix();
选择前,设置相同的矩阵,并与拾取矩阵相乘:

glLoadIdentity();
glPickMatrix();
setupMyProjMatrix();
在您的示例中,
setupMyProjMatrix()
不起任何作用

无论如何,您应该避免在opengl中使用拾取。这是一个不推荐使用的功能(在现代gl中删除),速度非常慢,有时还不太可靠,具体取决于供应商。您应该自己计算命中测试

你不应该,永远不要查询任何gl(glGet家族)。这会引起CPU暂停


抱歉英语不好。

正如Olivier所说,避免使用不推荐的功能。相反,您可以通过两种不同的方式进行挑选:

  • 通过光线测试运行所有前向多边形进行拾取,从视点通过像素中心(在近平面距离处)发射光线直到它碰到多边形或超出选择范围。对于复杂场景,此解决方案的缩放效果不太好,但实现起来相当简单,并且在处理透明度等方面提供了一定程度的灵活性

  • 您还可以通过将具有颜色id的所有对象渲染到屏幕外纹理来在视图空间中进行拾取。然后,您可以简单地读取选择2D坐标的像素值,并将颜色id映射回该选择坐标下的对象。缺点是拾取多个对象比较困难,并且渲染的batch必须有适当的消隐和着色设置。好处是这个解决方案依赖于分辨率,而不是太多的场景复杂度


感谢您的解释,我删除了glloadIdentity行,效果很好:)