1

Can anyone please explain the world to screen function (c#) to me? I want to understand what it does, how to use it and what I need to use it. So far I know, that it converts 3d vectors to 2d vectors, that then can be shown on the monitor. Now I want to know the steps needed to show a 3d point as a drawing on the screen. Thx in advance :)

darude_cod3r
  • 91
  • 3
  • 11
  • 1
    Do you have any specific framework/engine in mind (MonoGame, SharpDX, Unity3d, etc) in which context you would like to understand this? The reason I'm asking this is because there are different approaches to this depending on how different frames of references are defined. – Jaanus Varus Jun 11 '15 at 10:15
  • I want to make a simple overlay for assault cube, that draws rectangles around players. – darude_cod3r Jun 11 '15 at 10:40

1 Answers1

2

I am going to assume that your desired screen space runs from top to bottom so that {0, 0} is top left and {screenWidth, screenHeight} is bottom right. I am also going to assume that normalized device coordinates are in the range of [{-1, -1, 0}, {1, 1, 1}].


The first thing you wanna do, is convert your 3D world coordinates into what are known as Normalized Device Coordinates (NDC for short). This is an intermediary step which simplifies the mapping to ScreenSpace.

Normalized Device Coordinates are used to measure relative positions on the monitor. These are not pixel coordinates. The center of the screen is always 0, the top is always 1 and the bottom is always -1. The left side is always -1 and the right side is always 1.

Knowing view and projection matrices, the transformation is following:

Vector3 pointInNdc = Vector3.Transform(pointInWorld, view * projection);

To understand how this transformation works, you could take a look at the source code of Paradox Game Engine for example.

Once the coordinate is normalized, you want to map it into Screen Space:

  1. To find the X coordinate, move it from range [-1,1] -> [0,2] by adding 1 to it and dividing it by 2 to move it from range [0,2] -> [0,1]. Multiply that by screen width and you have the X coordinate in Screen Space.

float screenX = (pointInNdc.X + 1) / 2f * screenWidth;

  1. Finding Y coordinate is similar, but instead of adding 1, you need to subtract pointInNdc.Y from 1 to invert the coordinate upside down (move from Y running bottom to top to Y running top to bottom)

float screenY = (1 - pointInNdc.Y) / 2f * screenHeight;

There you have both X and Y coordinates of Screen Space. There are many great articles out there (such as this one) which describe this exact same process and also how to go back from ScreenToWorld.


Here is the full listing of WorldToScreen:

Vector2 WorldToScreen(Vector3 pointInWorld, Matrix view, Matrix projection, int screenWidth, int screenHeight)
{
    Vector3 pointInNdc = Vector3.Transform(pointInWorld, view * projection);
    float screenX = (pointInNdc.X + 1) / 2f * screenWidth;
    float screenY = (1 - pointInNdc.Y) / 2f * screenHeight;
    return new Vector2(screenX, screenY);
}
Jaanus Varus
  • 3,508
  • 3
  • 31
  • 49