tags:

views:

140

answers:

2

Hi, I've seen alot of Screen-Coordinate to world coordinate posts, but have not seen the opposite. Is there an easy way of getting screen coordinates from a 3d point, from any angle I view it from? I'm using C++ and opengl

+2  A: 

Screen-coordinates for a vertex is just a result of multiplication such vertex by its projection and modelview matrix:

screen_coordinates = projection_matrix * modelview_matrix * world_coordinates

You can do it by hand (especially if you're using some maths library for doing operations on matrices) or use gluProject, for example:

std::array<GLfloat, 16> projection;
std::array<GLfloat, 16> modelview;
std::array<GLfloat, 3>  screen_coords;

glGetFloatv(GL_PROJECTION_MATRIX, projection.data());
glGetFloatv(GL_MODELVIEW_MATRIX, modelview.data());

gluProject(world_coords[0], world_coords[1], world_coords[2],
    modelview.data(), projection.data(),
    screen_coords.data(), screen_coords.data() + 1, screen_coords.data() + 2);
erjot
Downvote. gluProject does the right thing, but your explanation does not. Multiplying a point with just the modelview matrix and projection matrix gives you the clip space coordinate, but *before* the division by w. It does not give you the screen space coordinate. See bahbar's answer.
Mads Elvheim
To judge whether it gives correct space coordinates or not you need more details about OP's world setup, e.g. I hardly ever use viewport settings for my 2D games. But it seems your crystal ball works flawlessly so thx for downvote :)
erjot
ps. isn't OpenGL's (fixed function pipeline) PROJECTION matrix containg setup for the viewport? and what are the cases you need to explictly divide by w? GLSL is doing it by default.
erjot
@erjot: you use Viewport, whether you know it or not. That's what makes sure you draw to your whole window (and typically something you change if your window changes size). gluProject takes 9 params, not 8. You removed the viewport one... And no, projection does not contain viewport transform. It brings primitives to the [-1:1] cube, as in my post. That's when _clipping_ happens. Before viewport transform. GLSL (I assume you meant the generated shaders?) is certainly not doing w-divide, since it needs to happen after clipping too (the clipper works on homogeneous coordinates).
Bahbar
+2  A: 

erjot's answer is incomplete.

There are 2 additional things to take into account.

  1. with homogeneous = P . M . world, the homogeneous vector is a 4-d vector in homogeneous space. In particular, to bring it back to the [-1:1]^3 cube, you need to divide its first 3 coordinates by homogeneous.w. cube.x = homogeneous.x / homogeneous.w (what some people call the projection divide).
  2. You then need to transform the [-1:1]^3 cube to window coordinates by applying the Viewport transformation to it. window.x = viewport.x + viewport.width * (cube.x+1)/2

In case you care about the final Z, the transformation is not going through viewport, but DepthRange instead.

Bahbar