Как сделать так, чтобы объекты opengl появлялись при щелчке мышью?
Что мне нужно сделать, так это щелкнуть где-нибудь в моем окне просмотра OpenGL, и в этом месте отобразится объект. Я уже знаю основные вещи: создание окна, обнаружение щелчков мышью, получение координат щелчка и рисование объектов. Недостающая ссылка, которую я имею, получает правильные координаты. Мне нужно определить, что точка (X,Y), которую я нажимаю на экране, означает координаты мира openGL. Мне известна функция GLUT с именем gluUnProject, но по техническим причинам я не могу использовать GLUT. Я проверил много алгоритмов, чтобы сделать свою собственную непроектированную функцию вручную:
http://schabby.de/picking-opengl-ray-tracing/ http://collagefactory.blogspot.mx/2010/03/gluunproject-source-code.html OpenGL Math - проецирование пространства экрана в координаты пространства мира
И другие, но ни одна не работала, когда я нажимал на экран, объект рисовался в странных местах. Я даже не уверен, что я ищу здесь, я не знаю, что я пытаюсь реализовать - это Picking, Raycasting, Raypicking или что-то еще. Кто-нибудь знает алгоритм, который я ищу?
РЕДАКТИРОВАТЬ: я добавляю снимок экрана, я отметил место, где я нажал, и, как вы можете видеть, сфера рисует в другом месте. http://img23.imageshack.us/img23/4738/proofxd.jpg Я также добавляю свой исходный код opengl:
/**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;
}
2 ответа
GLU и GLUT - это не одно и то же. Функциональность GLU должна присутствовать в любой достаточно современной установке OpenGL.
Для чего это стоит, реализация gluUnProject фактически изложена на его странице руководства.
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
Это то, что я использую в своем двигателе