I render a 3D model as points in a viewport with OpenGL. I want to select points by clicking them. To do this, I calculate the position of the 3D point on the 2D window the same way the shader does. These variables are needed:
- Vector4 vector: the 3D position in object space of the point + it's W component. W is always 1 in object space, but gets transformed by the projection matrix. It is then used for the perspective divide.
- Matrix projection and camera (also called modelview): the matrices used to transform from object space to world space and then to 2D clip coordinates.
- Rectangle viewport: the position and size of the viewport on which to project.
- Point mouse: the window position of the mouse click. You get this point directly from the event raised by the operating system.
From then, it's actually not that hard. You do need a method to multiply matrices.
public Point GetPosition(Vector4 vector) { var p = Projection * Camera * vector; //Perspective divide. p.X /= p.W; p.Y /= p.W; //Scale from [-1; 1] to viewport dimensions. p.X = (p.X + 1).Scale(2, viewport.Width); p.Y = -(p.Y - 1).Scale(2, viewport.Height); //For OpenGL, the bottom is the origin. //Adjust to the viewport's position on the window. return new Point((int)p.X + viewport.Left, (int)p.Y + viewport.Top); } var pos = GetPosition(vector); IsSelected = pos.X.Between(mouse.X - 5, mouse.X + 5) && pos.Y.Between(mouse.Y - 5, mouse.Y + 5);