adityatan's picture

3D to 2D Coordinate Transformation

Hi all,

I have read some explanation on the internet regarding 3D to 2D coordinate transformations. However, as a newbie, after implementing some of the tutorials, I still don't quite get it.

Does anyone of you have an example of the application of coordinate transformations? Specifically, how does the depth changes as you rotate your views in gl_Control1?

FYI, I simply want to make a 3D canvas where the users can draw nodes by clicking on the canvas.

Thank you! Any kind of relevant comment is greatly appreciated!



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
adityatan's picture

Also, is there any way we can obtain the 2D coordinates of our 3D world?

I mean, even if we plot points, say at (1,1,1), when we rotate and translate, the coordinates on the canvas is not 3D--it's simply some (x,y). That's what I mean by the "2D coordinates of our 3D world."

Sorry if I ask a lot of questions. Thanks


james_lohr's picture

Yes, you can multiply transformation matrices in software to obtain the final 2D coordinates as displayed on the screen using gluProject. Or, if you want more optimal performance you can do it yourself and possibly simplify the transformation if, for example, you're not using the full range of transformations.

However, judging by your posts I think you're slightly misunderstanding the bigger picture: ordinarily one would specify the 3D coordinates of the world, specify any model view and projection transformations and then have hardware translate this to screen coordinates.

Perhaps what you're really wanting to do is to translate 2D input (screen x,y - e.g. clicking on a 2D rendering of a 3D world) into 3D coordinates (x,y.z coordinates in your 3D world).

Unfortunately this is impossible: Any one point in the 2D rendering of your 3d world has infinitely many possible positions in 3d space. You need to provide additional information: for example, the depth of point, or possibly do something clever such as defaulting to the depth of the top-most surface the point is over.

You need to decide what exactly it is that you want to do, since there are many different ways to specify a point in 3d space from a 2d input. Perhaps have a quick play with a few 3d editing tools to get an idea of how they do it, and decide on what you think would be the most appropriate method for your application. A common method is to have two orthogonal display windows, for example one in the X,Y plane and the other in the X,Z plane.

adityatan's picture

Whenever I think of 3D canvas, I immediately think about Google SketchUp; you can click anywhere pressing a button to force your cursor mouse to only go at certain planes.

But I understand your point that it is not easy, especially whenever I specify the depth from the origin, when I rotate or translate my 3D world, the origin changes and the ratio of the depth also changes. It's messy.

Please let me know if you have any other relevant info that I need to know.

Thank you.


brodo's picture

Sorry for hijacking this thread, but I basically have got exactly the same question and I don't really feel that it has been answered before, so I'll just ask it here.

Coming more from an XNA point of view, I kind of missed the unproject method to retrieve 3D coords from 2D coords. I am aware of the solutions available in the forums, but they didn't work right away for me, so I felt I just had to try and implement it myself to get it working and (more importantly) to fully understand what was going on.

As a first step, I wanted to calculate the screen coords for a given vector myself (and then, as a second step, invert the calculation to go the other way round). However, this very first (and seemingly trivial) step is already the one that I'm failing at. I assumed that I could just take a Vector3 and transform it using the world, the modelview and the projection matrix:

World (in the the basic entity class):

        public Vector3 Position = new Vector3();
        public Vector3 Rotation = new Vector3();
        public Vector3 Scale = new Vector3(1,1,1);
        public Matrix4 World
                return Matrix4.Scale(Scale) * Matrix4.CreateRotationX(Rotation.X) * Matrix4.CreateRotationY(Rotation.Y) * Matrix4.CreateRotationZ(Rotation.Z) * Matrix4.CreateTranslation(Position);

modelview (recalculated each frame):
modelview = Matrix4.LookAt(CamPos, camTarget, Vector3.UnitY);

projection (in the OnResize method):
projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, Width / (float)Height, 1.0f, 64.0f);


            Vector3 tempVector = center.Position;
            tempVector = Vector3.Transform(tempVector, center.World);
            tempVector = Vector3.Transform(tempVector, modelview);
            tempVector = Vector3.Transform(tempVector, projection);

I did expect tempVector's x/y fields to contain the screen coordinates and its z field to be the distance from the cam, be it normalized (-1 to 1 or 0 to 1) or absolute (0 to window width/height and nearClip to farClip). However, the coordinates clearly aren't the screen coordinates as zooming out or in, with the drawn object shifting its screen position towards the window borders, does not result in any change of tempVector's x and y fields but only of its z field, as if the perspective isn't even part of the calculation. So, my question is just what the title of this thread is asking for: how to I calculate the object's 2D coords manually? I'm really kind of stuck and any help would be appreciated. Thanks in advance.

I think I got it...

            Vector4 tempVector = new Vector4(center.Position, 1);
            tempVector = Vector4.Transform(tempVector, center.World);
            tempVector = Vector4.Transform(tempVector, modelview);
            tempVector = Vector4.Transform(tempVector, projection);
            tempVector.Xy /= tempVector.W;

Now I only have to go the other way round...

ERP's picture

I answered this question or one similar to it here.

But there is an unproject in the GLUT library if that's all you need.