Reputation: 3593
What I need to do is click somewhere on my OpenGL viewport and have an object render in that spot. I already know the basic stuff, i.e. creating the window, detecting mouse clicks, getting the click coordinates and draw objects. The missing link I have is getting the coordinates right. I need to determine what the (X,Y) point I click on the screen means openGL world coordinates. I am aware of a GLUT function called gluUnProject, but due to technical reasons I can't use GLUT. I've checked many algorithms to make my own unproject function by hand:
http://schabby.de/picking-opengl-ray-tracing/ http://collagefactory.blogspot.mx/2010/03/gluunproject-source-code.html OpenGL Math - Projecting Screen space to World space coords
And others, but none worked, when I clicked on the screen the object was drawn in weird places. I'm not even sure what I'm looking for here, I don't know if what I'm trying to implement is Picking, or Raycasting or Raypicking or something else. Does anyone know the algorithm I'm looking for?
EDIT: I'm adding a screen capture, I marked the spot where I clicked and, as you can see, the sphere is drawing in a different place. http://img23.imageshack.us/img23/4738/proofxd.jpg I'm also adding my opengl source code:
/**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;
}
Upvotes: 0
Views: 2188
Reputation: 2065
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
This is what I use in my engine
Upvotes: 0
Reputation: 8756
GLU and GLUT aren't the same thing. GLU functionality should be present on any reasonably modern OpenGL installation.
For what it's worth, the implementation of gluUnProject is actually spelled out in its man page.
Upvotes: 1