You need to enable JavaScript to run this app. OpenTK实现拾取功能时无法获取正确名称栈及点击缩放异常问题
优惠活动
大模型
产品
解决方案
定价
更多

OpenTK实现拾取功能时无法获取正确名称栈及点击缩放异常问题

问题根因

1. 点击后屏幕异常放大

你在select方法中修改投影矩阵后没有正确恢复矩阵状态:

  • 你先将矩阵模式切换到MatrixMode.Projection并调用GL.PushMatrix()保存原始投影状态
  • 后续切换到了MatrixMode.Modelview模式,结束拾取时调用的GL.PopMatrix()实际弹出的是模型视图矩阵栈,投影矩阵栈的拾取状态没有被弹出,导致后续正常渲染时一直使用拾取模式下的缩放投影矩阵,画面就会异常放大。

2. 点击永远返回名称1

OpenGL不允许在glBegin/glEnd块内部调用glLoadName,你把两个物体的GL.LoadName调用都放在了同一个GL.Begin(BeginMode.Quads)和GL.End()之间,第二个GL.LoadName(2)调用无效,两个矩形都绑定了名称1,所以拾取结果永远是1。

修正代码

只需修改select方法中的两处错误即可:

public void select(object o, MouseEventArgs e)
{
    var buffer = new int[BUFSIZE];
    var viewPort = new int[4];
    int hits;
    GL.GetInteger(GetPName.Viewport, viewPort);
    GL.SelectBuffer(BUFSIZE, buffer);
    GL.RenderMode(RenderingMode.Select);

    GL.InitNames();
    GL.PushName(0);
    GL.MatrixMode(MatrixMode.Projection);
    GL.PushMatrix();
    GL.LoadIdentity();

    GluPickMatrix(e.Mouse.X, viewPort[3] - e.Mouse.Y, 5.0, 5.0, viewPort);  
    GL.Ortho(-50.0, 50.0, -50.0, 50.0, -100.0, 100.0);             
    GL.MatrixMode(MatrixMode.Modelview);
    GL.LoadIdentity();
    
    // 修正:将LoadName放到Begin外部,每个物体单独用Begin/End包裹
    GL.LoadName(1);
    GL.Begin(BeginMode.Quads);
    GL.Color3(1.0, 1.0, 0.0);
    GL.Vertex3(-5.0, -5.0, -80.0);
    GL.Vertex3(5.0, -5.0, -80.0);
    GL.Vertex3(5.0, 5.0, -80.0);
    GL.Vertex3(-5.0, 5.0, -80.0);
    GL.End();

    GL.LoadName(2);
    GL.Begin(BeginMode.Quads);
    GL.Color3(1.0, 0.0, 0.0);
    GL.Vertex3(-10.0, -10.0, -80.0);
    GL.Vertex3(0.0, -10.0, -80.0);
    GL.Vertex3(0.0, 0.0, -80.0);
    GL.Vertex3(-10.0, 0.0, -80.0);
    GL.End();
    
    // 修正:先切回Projection模式再弹出矩阵,恢复原始投影状态
    GL.MatrixMode(MatrixMode.Projection);
    GL.PopMatrix();
    GL.MatrixMode(MatrixMode.Modelview); // 切回默认模型视图模式,不影响后续渲染

    GL.Flush();

    hits = GL.RenderMode(RenderingMode.Render);
    Console.WriteLine("hit: {0}", hits);

    if (hits>0)
    {
        int choose = buffer[3];
        int depth = buffer[1];
        for (int i=0;i<hits;i++)
        {
            if (buffer[i * 4 + 1] < depth)
            {
                choose = buffer[i * 4 + 3];
                depth = buffer[i * 4 + 1];
            }
        }
        Console.WriteLine("choosen: {0}", choose);
    }     
}

内容的提问来源于stack exchange,提问作者maantarng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 11:15:02