- Game Name
- N/A

- Anticheat
- N/A

- Tutorial Link
- N/A

- How long you been coding/hacking?
- 4 Years

- Coding Language
- C++ / C#

**What is a view matrix?**

Matrices are used to define the location of things inside a coordinate system as well as how these things are projected onto your screen. There are actually several matrices used in 3D game programming they are:

- Model Matrix
- World Matrix
- View Matrix
- Projection Matrix

A view matrix is 4 Vector3 structures that represents the camera position, it's viewport and frustrum. 3 of these vectors are the rotation matrix, representing the Right, Up & Forward (Look) axes. The other vector encodes the position. It can also be looked at as an array of 16 float values.

3D Game Programming uses view matrices to "transform" vertices of objects. The view matrix is used in our WorldToScreen() function to convert 3D world positions of entities to 2D screen space.

If you want to learn more about View Matrices checkout:

Guide - How to get started with learning ViewMatrix

**Top 3 Best GH Resources for View Matrix & World2Screen (read them!)**

- That thread ^
- This thread
- Tutorial - So what is a viewmatrix anyway and how does a W2S work????

**How does WorldToScreen work?**

You take the 3D world coordinates and do a series of transformations. A transformation is performed by using matrix multiplication. You multiply the vec3 coordinates by a specific matrix and the result is called a transform. The series of transformations is called the transformation pipeline

You go from model vertex data -> eye coordinates -> clip coordinates -> normalized device coordinates -> window coordinates

**The Functions**

For most games, the function is basically identical. We have several variation depending what you need:

- Direct3D World To Screen
- OpenGL WorldToScreen
- Quake / Call of Duty / IdTech engine World2Screen
- Build your own View Matrix
- C++ & C# Versions of these functions

The Direct3D and OpenGL versions are different because each store their rows/columns differently, this is referred to as being row major or column major.

**Necessary functions that you may not already have:**

C++:

```
#define PI 3.1415927f
vec3_t Subtract(vec3_t src, vec3_t dst)
{
vec3_t diff;
diff.x = src.x - dst.x;
diff.y = src.y - dst.y;
diff.z = src.z - dst.z;
return diff;
}
vec3_t Divide(vec3_t src, float num)
{
vec3_t vec;
vec.x = src.x / num;
vec.y = src.y / num;
vec.z = src.z / num;
return vec;
}
float Magnitude(vec3_t vec)
{
return sqrtf(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
}
float DotProduct(vec3_t src, vec3_t dst)
{
return src.x * dst.x + src.y * dst.y + src.z * dst.z;
}
```

**Direct3D World to Screen**

Does not matter if it's D3D9, D3D11, D3D12 they all use the same function. In DirectX the MVP matrix is row major and not column major.

C++:

```
bool WorldToScreen(vec3_t pos, vec2 &screen, float matrix[16], int windowWidth, int windowHeight)
{
//Matrix-vector Product, multiplying world(eye) coordinates by projection matrix = clipCoords
vec4 clipCoords;
clipCoords.x = pos.x*matrix[0] + pos.y*matrix[1] + pos.z*matrix[2] + matrix[3];
clipCoords.y = pos.x*matrix[4] + pos.y*matrix[5] + pos.z*matrix[6] + matrix[7];
clipCoords.z = pos.x*matrix[8] + pos.y*matrix[9] + pos.z*matrix[10] + matrix[11];
clipCoords.w = pos.x*matrix[12] + pos.y*matrix[13] + pos.z*matrix[14] + matrix[15];
if (clipCoords.w < 0.1f)
return false;
//perspective division, dividing by clip.W = Normalized Device Coordinates
vec3_t NDC;
NDC.x = clipCoords.x / clipCoords.w;
NDC.y = clipCoords.y / clipCoords.w;
NDC.z = clipCoords.z / clipCoords.w;
screen.x = (windowWidth / 2 * NDC.x) + (NDC.x + windowWidth / 2);
screen.y = -(windowHeight / 2 * NDC.y) + (NDC.y + windowHeight / 2);
return true;
}
```

**Using Direct3D API for W2S**

This assumes you have a hooked directx9 device. DOES NOT WORK ON ALL GAMES

function:

```
bool WorldToScreen(LPDIRECT3DDEVICE9 pDevice, D3DXVECTOR3* pos, D3DXVECTOR3* out) {
D3DVIEWPORT9 viewPort;
D3DXMATRIX view, projection, world;
pDevice->GetViewport(&viewPort);
pDevice->GetTransform(D3DTS_VIEW, &view);
pDevice->GetTransform(D3DTS_PROJECTION, &projection);
D3DXMatrixIdentity(&world);
D3DXVec3Project(out, pos, &viewPort, &projection, &view, &world);
if (out->z < 1) {
return true;
}
return false;
}
```

calling the function:

calling function:

```
D3DXVECTOR3 pos = { 0.0f,0.0f,0.0f }; //world position to project to screen {x,y,z}
D3DXVECTOR3 screenPos;
if (WorldToScreen(pDevice, &pos, &screenPos)) {
//do stuff here
//screenPos.x , screenPos.y
}
```

**OpenGL WorldToScreen**

The matrix is column major in OpenGL games.

C++:

```
bool WorldToScreen(vec3_t pos, vec3_t &screen, float matrix[16], int windowWidth, int windowHeight)
{
//Matrix-vector Product, multiplying world(eye) coordinates by projection matrix = clipCoords
vec4 clipCoords;
clipCoords.x = pos.x*matrix[0] + pos.y*matrix[4] + pos.z*matrix[8] + matrix[12];
clipCoords.y = pos.x*matrix[1] + pos.y*matrix[5] + pos.z*matrix[9] + matrix[13];
clipCoords.z = pos.x*matrix[2] + pos.y*matrix[6] + pos.z*matrix[10] + matrix[14];
clipCoords.w = pos.x*matrix[3] + pos.y*matrix[7] + pos.z*matrix[11] + matrix[15];
if (clipCoords.w < 0.1f)
return false;
//perspective division, dividing by clip.W = Normalized Device Coordinates
vec3_t NDC;
NDC.x = clipCoords.x / clipCoords.w;
NDC.y = clipCoords.y / clipCoords.w;
NDC.z = clipCoords.z / clipCoords.w;
//Transform to window coordinates
screen.x = (windowWidth / 2 * NDC.x) + (NDC.x + windowWidth / 2);
screen.y = -(windowHeight / 2 * NDC.y) + (NDC.y + windowHeight / 2);
return true;
}
```

**OPENGL C# WorldToScreen**

C#:

```
public static float[] WorldToScreen(byte[] matrix, PlayerEntity entity, int width, int height, POINTS gameWindow, bool foot = true)
{
float m11 = BitConverter.ToSingle(matrix, 0), m12 = BitConverter.ToSingle(matrix, 4), m13 = BitConverter.ToSingle(matrix, 8), m14 = BitConverter.ToSingle(matrix, 12);
float m21 = BitConverter.ToSingle(matrix, 16), m22 = BitConverter.ToSingle(matrix, 20), m23 = BitConverter.ToSingle(matrix, 24), m24 = BitConverter.ToSingle(matrix, 28);
float m31 = BitConverter.ToSingle(matrix, 32), m32 = BitConverter.ToSingle(matrix, 36), m33 = BitConverter.ToSingle(matrix, 40), m34 = BitConverter.ToSingle(matrix, 44);
float m41 = BitConverter.ToSingle(matrix, 48), m42 = BitConverter.ToSingle(matrix, 52), m43 = BitConverter.ToSingle(matrix, 56), m44 = BitConverter.ToSingle(matrix, 60);
float zPos = entity.getZPos(foot);
//multiply vector against matrix
float screenX = (m11 * entity.xPos) + (m21 * entity.yPos) + (m31 * zPos) + m41;
float screenY = (m12 * entity.xPos) + (m22 * entity.yPos) + (m32 * zPos) + m42;
float screenW = (m14 * entity.xPos) + (m24 * entity.yPos) + (m34 * zPos) + m44;
//camera position (eye level/middle of screen)
float camX = width / 2f;
float camY = height / 2f;
//convert to homogeneous position
float x = camX + (camX * screenX / screenW);
float y = camY - (camY * screenY / screenW);
float[] screenPos = { x, y };
//check it is in the bounds to draw
if (screenW > 0.001f //not behind us
&& gameWindow.Left + x > gameWindow.Left && gameWindow.Left + x < gameWindow.Right //not off the left or right of the window
&& gameWindow.Top + y > gameWindow.Top && gameWindow.Top + y < gameWindow.Bottom) //not off the top of bottom of the window
{
return screenPos;
}
return null;
}
```

**Direct3D C# W2S**

C#:

```
public static float[] WorldToScreen(byte[] matrix, PlayerEntity entity, int width, int height, POINTS gameWindow, bool foot = true)
{
float m11 = BitConverter.ToSingle(matrix, 0), m12 = BitConverter.ToSingle(matrix, 16), m13 = BitConverter.ToSingle(matrix, 32), m14 = BitConverter.ToSingle(matrix, 48);
float m21 = BitConverter.ToSingle(matrix, 4), m22 = BitConverter.ToSingle(matrix, 20), m23 = BitConverter.ToSingle(matrix, 36), m24 = BitConverter.ToSingle(matrix, 25);
float m31 = BitConverter.ToSingle(matrix, 8), m32 = BitConverter.ToSingle(matrix, 24), m33 = BitConverter.ToSingle(matrix, 40), m34 = BitConverter.ToSingle(matrix, 56);
float m41 = BitConverter.ToSingle(matrix, 12), m42 = BitConverter.ToSingle(matrix, 28), m43 = BitConverter.ToSingle(matrix, 44), m44 = BitConverter.ToSingle(matrix, 60);
float zPos = entity.getZPos(foot);
//multiply vector against matrix
float screenX = (m11 * entity.xPos) + (m21 * entity.yPos) + (m31 * zPos) + m41;
float screenY = (m12 * entity.xPos) + (m22 * entity.yPos) + (m32 * zPos) + m42;
float screenW = (m14 * entity.xPos) + (m24 * entity.yPos) + (m34 * zPos) + m44;
//camera position (eye level/middle of screen)
float camX = width / 2f;
float camY = height / 2f;
//convert to homogeneous position
float x = camX + (camX * screenX / screenW);
float y = camY - (camY * screenY / screenW);
float[] screenPos = { x, y };
//check it is in the bounds to draw
if (screenW > 0.001f //not behind us
&& gameWindow.Left + x > gameWindow.Left && gameWindow.Left + x < gameWindow.Right //not off the left or right of the window
&& gameWindow.Top + y > gameWindow.Top && gameWindow.Top + y < gameWindow.Bottom) //not off the top of bottom of the window
{
return screenPos;
}
return null;
}
```

**FOV WorldToScreen for Quake / Call of Duty / IdTech engine and more**

C++:

```
//Thanks to c5 for this knowledge
bool WorldToScreen(vec3_t src, vec3_t dst, vec3_t &screen, float fovx, float fovy, float windowWidth, float windowHeight, vec3_t left, vec3_t up, vec3_t forward)
{
vec3_t transform;
float xc, yc;
float px, py;
float z;
px = tan(fovx * PI / 360.0);
py = tan(fovy * PI / 360.0);
transform = Subtract(dst, src);
xc = windowWidth / 2.0;
yc = windowHeight / 2.0;
z = DotProduct(transform, left);
if (z <= 0.1)
{
return false;
}
screen.x = xc - DotProduct(transform, up) *xc / (z*px);
screen.y = yc - DotProduct(transform, forward) *yc / (z*py);
return true;
}
```

C++:

```
struct refdef_t
{
int x, y, width, height;
float fov_x, fov_y;
vec3_t vieworg;
vec3_t viewaxis[3]; // transformation matrix
};
```

**Build your own View Matrix**

Tutorial - Calculate your own ViewProjection matrix

**Additional GH Resources**

Guide - How to get started with learning ViewMatrix

Tutorial - So what is a viewmatrix anyway and how does a W2S work????

Tutorial - Calculate your own ViewProjection matrix

Tutorial - How to Find view Matrix Counter Strike Source setang

**Offsite Resources**

- Rotation formalisms in three dimensions - Wikipedia
- OpenGL - Transformations
- Learn OpenGL, extensive tutorial resource for learning Modern OpenGL
- https://www.terathon.com/gdc07_lengyel.pdf
- Intro to matrix multiplication

Last edited: