如何在 OpenTK 中为 3D 立方体获取正确的名称堆栈?
How to get the correct name stack in OpenTK for a 3D cube?
我正在尝试在 OpenTK 中绘制一个 3D 立方体(6 个面),然后 select 使用右键单击所需的面。我正在使用 select 函数,并为每张脸分配名称(即 1-6)。但是,当我 运行 我的代码时,即使我右键单击其他面孔,我也无法获得正确的名称堆栈。我刚刚得到同名堆栈(5)。
我不确定 select 函数/ GluPickMatrix 有什么问题。
你知道为什么在这种情况下我无法获得正确的名称堆栈吗?如何获取正确的名称栈?
这是我的代码:
using System;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
namespace OpenTK3D
{
public class Game3D
{
private GameWindow window;
private float zoom;
private bool hasRotationStarted;
private int startX;
private int startY;
private float xRotAngle;
private float yRotAngle;
private bool hasPanningStarted;
private float xTrans;
private float yTrans;
private int BUFSIZE = 512;
public Game3D(GameWindow wd)
{
this.window = wd;
start();
}
public void start()
{
window.Load += loaded;
window.Resize += resize;
window.RenderFrame += renderFrame;
window.MouseDown += mouseLeftPress;
window.MouseUp += mouseRelease;
window.MouseMove += mouseDragEvent;
window.MouseWheel += MouseWheelHandler;
window.MouseDown += wheelPressEvent;
window.MouseUp += wheelReleaseEvent;
window.MouseMove += wheelDragEvent;
window.MouseDown += select;
window.Run(1.0 / 60.0);
}
public void loaded(object o, EventArgs e)
{
GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GL.Enable(EnableCap.DepthTest);
}
public void renderFrame(object o, EventArgs e)
{
GL.LoadIdentity();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Translate(xTrans, yTrans, zoom*3);
GL.Rotate(xRotAngle, 1.0, 0, 0);
GL.Rotate(yRotAngle, 0, 1, 0);
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 1.0, 0.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 0.0, 1.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 1.0, 1.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 0.0, 0.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 1.0, 0.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 0.0, 1.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.End();
window.SwapBuffers();
}
public void resize(object o, EventArgs e)
{
GL.Viewport(0, 0, window.Width, window.Height);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
// the fov must be radian
var matrix = Matrix4.CreatePerspectiveFieldOfView(45.0f*(MathHelper.Pi)/180, window.Width / window.Height, 1.0f, 100.0f);
GL.LoadMatrix(ref matrix);
GL.MatrixMode(MatrixMode.Modelview);
}
private void processHits(int hits, int[] buffer)
{
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);
}
}
private 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);
}
public void select(object o, MouseEventArgs e)
{
var mouse = Mouse.GetState();
if (mouse[MouseButton.Right])
{
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);
var matrix = Matrix4.CreatePerspectiveFieldOfView(45.0f * (MathHelper.Pi) / 180, window.Width / window.Height, 1.0f, 100.0f);
GL.LoadMatrix(ref matrix);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.LoadName(1);
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 1.0, 0.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.End();
GL.LoadName(2);
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 0.0, 1.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.End();
GL.LoadName(3);
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 1.0, 1.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.End();
GL.LoadName(4);
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 0.0, 0.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.End();
GL.LoadName(5);
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 1.0, 0.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.End();
GL.LoadName(6);
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 0.0, 1.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.End();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
GL.Flush();
hits = GL.RenderMode(RenderingMode.Render);
processHits(hits, buffer);
}
}
public void mouseLeftPress(object sender, MouseEventArgs e)
{
if (e.Mouse.LeftButton == ButtonState.Pressed)
{
hasRotationStarted = true;
startX = e.Mouse.X;
startY = e.Mouse.Y;
}
}
public void mouseRelease(object sender, MouseEventArgs e)
{
if (e.Mouse.LeftButton == ButtonState.Released)
{
hasRotationStarted = false;
}
}
public void mouseDragEvent(object sender, MouseEventArgs e)
{
if (hasRotationStarted == true && e.Mouse.X != e.Mouse.Y)
{
xRotAngle = xRotAngle + (e.Mouse.Y - startY);
yRotAngle = yRotAngle + (e.Mouse.X - startX);
startX = e.Mouse.X;
startY = e.Mouse.Y;
}
}
public void MouseWheelHandler(object sender, MouseWheelEventArgs e)
{
var xBoundary = 10.0;
if (e.Delta > 0)
{
zoom += 0.1f * (float)xBoundary;
}
if (e.Delta < 0)
{
zoom -= 0.1f * (float)xBoundary;
}
}
public void wheelPressEvent(object sender, MouseEventArgs e)
{
if (e.Mouse.MiddleButton == ButtonState.Pressed)
{
hasPanningStarted = true;
startX = e.Mouse.X;
startY = e.Mouse.Y;
}
}
public void wheelReleaseEvent(object sender, MouseEventArgs e)
{
if (e.Mouse.MiddleButton == ButtonState.Released)
{
hasPanningStarted = false;
}
}
public void wheelDragEvent(object sender, MouseEventArgs e)
{
if (hasPanningStarted == true)
{
xTrans = xTrans + 2 * (e.Mouse.X - startX);
yTrans = yTrans - 2 * (e.Mouse.Y - startY);
startX = e.Mouse.X;
startY = e.Mouse.Y;
}
}
}
}
这是主要功能:
using System;
using OpenTK;
namespace OpenTK3D
{
class Program
{
static void Main(string[] args)
{
var window = new GameWindow(500, 500);
var gm = new Game3D(window);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Press enter to finish...");
Console.ReadLine();
}
}
}
这是我在 运行 执行此代码后得到的输出:
有 2 个问题:
GL.LoadMatrix
loads an matrix and overwrites the existing matrix. If you want to concatenate a matrix with the current matrix, you need to use GL.MultMatrix
投影矩阵设置不够。您还必须设置模型视图矩阵。由于设置了模型视图矩阵,所以在GL.MatrixMode(MatrixMode.Modelview)
.
之后去掉GL.LoadIdentity
就可以了
# [...]
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GluPickMatrix(e.Mouse.X, viewPort[3] - e.Mouse.Y, 5.0, 5.0, viewPort);
var matrix = Matrix4.CreatePerspectiveFieldOfView(45.0f * (MathHelper.Pi) / 180, window.Width / window.Height, 1.0f, 100.0f);
GL.MultMatrix(ref matrix); # <-- GL.MultMatrix insterad of GL.LoadMatrix
GL.MatrixMode(MatrixMode.Modelview);
# GL.LoadIdentity(); <-- delete this
# [...]
我正在尝试在 OpenTK 中绘制一个 3D 立方体(6 个面),然后 select 使用右键单击所需的面。我正在使用 select 函数,并为每张脸分配名称(即 1-6)。但是,当我 运行 我的代码时,即使我右键单击其他面孔,我也无法获得正确的名称堆栈。我刚刚得到同名堆栈(5)。
我不确定 select 函数/ GluPickMatrix 有什么问题。
你知道为什么在这种情况下我无法获得正确的名称堆栈吗?如何获取正确的名称栈?
这是我的代码:
using System;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
namespace OpenTK3D
{
public class Game3D
{
private GameWindow window;
private float zoom;
private bool hasRotationStarted;
private int startX;
private int startY;
private float xRotAngle;
private float yRotAngle;
private bool hasPanningStarted;
private float xTrans;
private float yTrans;
private int BUFSIZE = 512;
public Game3D(GameWindow wd)
{
this.window = wd;
start();
}
public void start()
{
window.Load += loaded;
window.Resize += resize;
window.RenderFrame += renderFrame;
window.MouseDown += mouseLeftPress;
window.MouseUp += mouseRelease;
window.MouseMove += mouseDragEvent;
window.MouseWheel += MouseWheelHandler;
window.MouseDown += wheelPressEvent;
window.MouseUp += wheelReleaseEvent;
window.MouseMove += wheelDragEvent;
window.MouseDown += select;
window.Run(1.0 / 60.0);
}
public void loaded(object o, EventArgs e)
{
GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GL.Enable(EnableCap.DepthTest);
}
public void renderFrame(object o, EventArgs e)
{
GL.LoadIdentity();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Translate(xTrans, yTrans, zoom*3);
GL.Rotate(xRotAngle, 1.0, 0, 0);
GL.Rotate(yRotAngle, 0, 1, 0);
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 1.0, 0.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 0.0, 1.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 1.0, 1.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 0.0, 0.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 1.0, 0.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.End();
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 0.0, 1.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.End();
window.SwapBuffers();
}
public void resize(object o, EventArgs e)
{
GL.Viewport(0, 0, window.Width, window.Height);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
// the fov must be radian
var matrix = Matrix4.CreatePerspectiveFieldOfView(45.0f*(MathHelper.Pi)/180, window.Width / window.Height, 1.0f, 100.0f);
GL.LoadMatrix(ref matrix);
GL.MatrixMode(MatrixMode.Modelview);
}
private void processHits(int hits, int[] buffer)
{
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);
}
}
private 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);
}
public void select(object o, MouseEventArgs e)
{
var mouse = Mouse.GetState();
if (mouse[MouseButton.Right])
{
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);
var matrix = Matrix4.CreatePerspectiveFieldOfView(45.0f * (MathHelper.Pi) / 180, window.Width / window.Height, 1.0f, 100.0f);
GL.LoadMatrix(ref matrix);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
GL.LoadName(1);
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 1.0, 0.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.End();
GL.LoadName(2);
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 0.0, 1.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.End();
GL.LoadName(3);
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 1.0, 1.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.End();
GL.LoadName(4);
GL.Begin(BeginMode.Quads);
GL.Color3(1.0, 0.0, 0.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.End();
GL.LoadName(5);
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 1.0, 0.0);
GL.Vertex3(10.0, 10.0, -10.0);
GL.Vertex3(10.0, -10.0, -10.0);
GL.Vertex3(-10.0, -10.0, -10.0);
GL.Vertex3(-10.0, 10.0, -10.0);
GL.End();
GL.LoadName(6);
GL.Begin(BeginMode.Quads);
GL.Color3(0.0, 0.0, 1.0);
GL.Vertex3(10.0, 10.0, 10.0);
GL.Vertex3(10.0, -10.0, 10.0);
GL.Vertex3(-10.0, -10.0, 10.0);
GL.Vertex3(-10.0, 10.0, 10.0);
GL.End();
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
GL.Flush();
hits = GL.RenderMode(RenderingMode.Render);
processHits(hits, buffer);
}
}
public void mouseLeftPress(object sender, MouseEventArgs e)
{
if (e.Mouse.LeftButton == ButtonState.Pressed)
{
hasRotationStarted = true;
startX = e.Mouse.X;
startY = e.Mouse.Y;
}
}
public void mouseRelease(object sender, MouseEventArgs e)
{
if (e.Mouse.LeftButton == ButtonState.Released)
{
hasRotationStarted = false;
}
}
public void mouseDragEvent(object sender, MouseEventArgs e)
{
if (hasRotationStarted == true && e.Mouse.X != e.Mouse.Y)
{
xRotAngle = xRotAngle + (e.Mouse.Y - startY);
yRotAngle = yRotAngle + (e.Mouse.X - startX);
startX = e.Mouse.X;
startY = e.Mouse.Y;
}
}
public void MouseWheelHandler(object sender, MouseWheelEventArgs e)
{
var xBoundary = 10.0;
if (e.Delta > 0)
{
zoom += 0.1f * (float)xBoundary;
}
if (e.Delta < 0)
{
zoom -= 0.1f * (float)xBoundary;
}
}
public void wheelPressEvent(object sender, MouseEventArgs e)
{
if (e.Mouse.MiddleButton == ButtonState.Pressed)
{
hasPanningStarted = true;
startX = e.Mouse.X;
startY = e.Mouse.Y;
}
}
public void wheelReleaseEvent(object sender, MouseEventArgs e)
{
if (e.Mouse.MiddleButton == ButtonState.Released)
{
hasPanningStarted = false;
}
}
public void wheelDragEvent(object sender, MouseEventArgs e)
{
if (hasPanningStarted == true)
{
xTrans = xTrans + 2 * (e.Mouse.X - startX);
yTrans = yTrans - 2 * (e.Mouse.Y - startY);
startX = e.Mouse.X;
startY = e.Mouse.Y;
}
}
}
}
这是主要功能:
using System;
using OpenTK;
namespace OpenTK3D
{
class Program
{
static void Main(string[] args)
{
var window = new GameWindow(500, 500);
var gm = new Game3D(window);
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("Press enter to finish...");
Console.ReadLine();
}
}
}
这是我在 运行 执行此代码后得到的输出:
有 2 个问题:
GL.LoadMatrix
loads an matrix and overwrites the existing matrix. If you want to concatenate a matrix with the current matrix, you need to useGL.MultMatrix
投影矩阵设置不够。您还必须设置模型视图矩阵。由于设置了模型视图矩阵,所以在
之后去掉GL.MatrixMode(MatrixMode.Modelview)
.GL.LoadIdentity
就可以了
# [...]
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
GL.LoadIdentity();
GluPickMatrix(e.Mouse.X, viewPort[3] - e.Mouse.Y, 5.0, 5.0, viewPort);
var matrix = Matrix4.CreatePerspectiveFieldOfView(45.0f * (MathHelper.Pi) / 180, window.Width / window.Height, 1.0f, 100.0f);
GL.MultMatrix(ref matrix); # <-- GL.MultMatrix insterad of GL.LoadMatrix
GL.MatrixMode(MatrixMode.Modelview);
# GL.LoadIdentity(); <-- delete this
# [...]