<p>The z-axis is indeed not correct if you want to transform to the space depicted in the second picture, because you perform no transformations on the z-axis. So your coordinate origin lies in the middle between the top-left-front and the top-left-back vertex. The coordinate range is still -1 to 1. You can easily fix it by applying the same transformation as for the other axis. Introduce a depth to define the coordinate range in the z-direction. Then your correct transformation should be:</p>
<p><span class="math-container">$$
\begin{bmatrix}
x' \\
y' \\
z' \\
1
\end{bmatrix} =
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; width/2 \\
0 &amp; 1 &amp; 0 &amp; height/2 \\
0 &amp; 0 &amp; 1 &amp; depth/2 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
width/2 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; -height/2 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; depth/2 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
$$</span></p>
<p>Multiplication yields the following transformation matrix:</p>
<p><span class="math-container">$$
\begin{bmatrix}
width/2 &amp; 0 &amp; 0 &amp; width/2  \\
0 &amp; -height/2 &amp; 0 &amp; height/2 \\
0 &amp; 0 &amp; depth/2 &amp; depth/2 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$</span></p>
<p>To understand it a bit better it is probably easier to postpone the scaling until the end and look at the different substeps.
Starting in NDC coordinates, we first flip the y-axis using the reflection matrix:</p>
<p><span class="math-container">$$
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; -1 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 1 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$</span></p>
<p>As a result, the point <code>(-1,-1,-1)</code> in the new intermediate coordinate system is the top-left-front point which is <code>(-1, 1,-1)</code> in NDC coordinates. Since we want our coordinates to be in the range <code>(0, x)</code> we translate all vertices in every axis by 1. This moves the origin of the next coordinate system to <code>(-1,-1,-1)</code> in our current intermediate system:</p>
<p><span class="math-container">$$
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; 1 \\
0 &amp; 1 &amp; 0 &amp; 1 \\
0 &amp; 0 &amp; 1 &amp; 1 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$</span></p>
<p>Now the values are in the range <code>(0, 2)</code> and the current coordinate systems' origin is at the NDC coordinates <code>(-1, 1,-1)</code>.</p>
<p>If you multiply both matrices you would get:</p>
<p><span class="math-container">$$
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; 1 \\
0 &amp; -1 &amp; 0 &amp; 1 \\
0 &amp; 0 &amp; 1 &amp; 1 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$</span></p>
<p>All that is left now is to apply the correct scaling. So we need to divide by 2 in every direction and multiply by the corresponding maximum value:</p>
<p><span class="math-container">$$
\begin{bmatrix}
width/2 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; height/2 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; depth/2 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
$$</span></p>
<p>So the final result would be:</p>
<p><span class="math-container">$$
\begin{bmatrix}
x' \\
y' \\
z' \\
1
\end{bmatrix} =
\begin{bmatrix}
width/2 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; height/2 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; depth/2 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; 1 \\
0 &amp; -1 &amp; 0 &amp; 1 \\
0 &amp; 0 &amp; 1 &amp; 1 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
$$</span></p>
<p>If you multiply it, you will get the same transformation matrix as above</p>

CC BY-SA 4.0
2022-06-03T11:19:20.697Z
2022-06-03T11:19:20.697Z
wychmaster
<p>I have a set of vertexes (x, y, z) in normalized device coordinates. Its x, y, and z values are in the range (-1, 1). Normalized device coordinates use the left-handed coordinate system, as shown below</p>
<p><a href="https://i.sstatic.net/fTZhO.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/fTZhO.png" alt="ndc" /></a></p>
<p>I want to convert NDC vertexes into a viewport whose coordinate system looks like this</p>
<p><a href="https://i.sstatic.net/DNW3E.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/DNW3E.png" alt="vp" /></a></p>
<p>It is a standard coordinate system used by most 2D graphics libraries. x starts from the top left corner and goes to the right while y starts from the same corner and goes down. I decided to make z to go into the page. All NDC vertexes must fit inside the dotted rectangular box, shown above.</p>
<p>What is the set of transformation matrixes that converts NDC coordinates <span class="math-container">$(x, y, z, 1)$</span> (note that I am using homogenous coordinates here) to viewport coordinates <span class="math-container">$(x', y', z', 1)$</span>?</p>
<p>This is what I came up with</p>
<p><span class="math-container">$$
\begin{bmatrix}
x' \\
y' \\
z' \\
1
\end{bmatrix} =
\begin{bmatrix}
1 &amp; 0 &amp; 0 &amp; width/2 \\
0 &amp; 1 &amp; 0 &amp; height/2 \\
0 &amp; 0 &amp; 1 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
width/2 &amp; 0 &amp; 0 &amp; 0 \\
0 &amp; -height/2 &amp; 0 &amp; 0 \\
0 &amp; 0 &amp; 1 &amp; 0 \\
0 &amp; 0 &amp; 0 &amp; 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
$$</span></p>
<p>where <span class="math-container">$width$</span> and <span class="math-container">$height$</span> are width and height of viewport. I first scale vertexes to viewport width and height and also flip the y coordinate (notice the minus sign). Then I translate the resulting vertex to fit into the viewport. But I'm not sure if my viewport transformation matrix is correct because I think the resulting z value might be wrong. What should I change here?</p>
<p>—————-</p>
<p>Crossposted in <a href="https://math.stackexchange.com/questions/4461572/what-are-viewport-transformation-matrixes-for-this-coordinate-system">math.stackexchange</a>.</p>

<transformations><linear-algebra>
What are viewport transformation matrixes for this coordinate system?
Jimmy Yang
# What are viewport transformation matrixes for this coordinate system?

(Asked by: username_0 on 2022-05-30)

I have a set of vertexes (x, y, z) in normalized device coordinates. Its x, y, and z values are in the range (-1, 1). Normalized device coordinates use the left-handed coordinate system, as shown below

[![ndc](https://i.sstatic.net/fTZhO.png)](https://i.sstatic.net/fTZhO.png)

I want to convert NDC vertexes into a viewport whose coordinate system looks like this

[![vp](https://i.sstatic.net/DNW3E.png)](https://i.sstatic.net/DNW3E.png)

It is a standard coordinate system used by most 2D graphics libraries. x starts from the top left corner and goes to the right while y starts from the same corner and goes down. I decided to make z to go into the page. All NDC vertexes must fit inside the dotted rectangular box, shown above.

What is the set of transformation matrixes that converts NDC coordinates $(x, y, z, 1)$ (note that I am using homogenous coordinates here) to viewport coordinates $(x', y', z', 1)$?

This is what I came up with

$$
\begin{bmatrix}
x' \\
y' \\
z' \\
1
\end{bmatrix} =
\begin{bmatrix}
1 & 0 & 0 & width/2 \\
0 & 1 & 0 & height/2 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
width/2 & 0 & 0 & 0 \\
0 & -height/2 & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
$$

where $width$ and $height$ are width and height of viewport. I first scale vertexes to viewport width and height and also flip the y coordinate (notice the minus sign). Then I translate the resulting vertex to fit into the viewport. But I'm not sure if my viewport transformation matrix is correct because I think the resulting z value might be wrong. What should I change here?

—————-

Crossposted in [math.stackexchange](https://math.stackexchange.com/questions/4461572/what-are-viewport-transformation-matrixes-for-this-coordinate-system).

**Tags:** transformations, linear-algebra


---

## 1 answers

### Answer by username_1 on 2022-06-03. Score: 1 | Accepted answer

The z-axis is indeed not correct if you want to transform to the space depicted in the second picture, because you perform no transformations on the z-axis. So your coordinate origin lies in the middle between the top-left-front and the top-left-back vertex. The coordinate range is still -1 to 1. You can easily fix it by applying the same transformation as for the other axis. Introduce a depth to define the coordinate range in the z-direction. Then your correct transformation should be:

$$
\begin{bmatrix}
x' \\
y' \\
z' \\
1
\end{bmatrix} =
\begin{bmatrix}
1 & 0 & 0 & width/2 \\
0 & 1 & 0 & height/2 \\
0 & 0 & 1 & depth/2 \\
0 & 0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
width/2 & 0 & 0 & 0 \\
0 & -height/2 & 0 & 0 \\
0 & 0 & depth/2 & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
$$

Multiplication yields the following transformation matrix:

$$
\begin{bmatrix}
width/2 & 0 & 0 & width/2 \\
0 & -height/2 & 0 & height/2 \\
0 & 0 & depth/2 & depth/2 \\
0 & 0 & 0 & 1
\end{bmatrix}
$$

To understand it a bit better it is probably easier to postpone the scaling until the end and look at the different substeps.
Starting in NDC coordinates, we first flip the y-axis using the reflection matrix:

$$
\begin{bmatrix}
1 & 0 & 0 & 0 \\
0 & -1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
$$

As a result, the point `(-1,-1,-1)` in the new intermediate coordinate system is the top-left-front point which is `(-1, 1,-1)` in NDC coordinates. Since we want our coordinates to be in the range `(0, x)` we translate all vertices in every axis by 1. This moves the origin of the next coordinate system to `(-1,-1,-1)` in our current intermediate system:

$$
\begin{bmatrix}
1 & 0 & 0 & 1 \\
0 & 1 & 0 & 1 \\
0 & 0 & 1 & 1 \\
0 & 0 & 0 & 1
\end{bmatrix}
$$

Now the values are in the range `(0, 2)` and the current coordinate systems' origin is at the NDC coordinates `(-1, 1,-1)`.

If you multiply both matrices you would get:

$$
\begin{bmatrix}
1 & 0 & 0 & 1 \\
0 & -1 & 0 & 1 \\
0 & 0 & 1 & 1 \\
0 & 0 & 0 & 1
\end{bmatrix}
$$

All that is left now is to apply the correct scaling. So we need to divide by 2 in every direction and multiply by the corresponding maximum value:

$$
\begin{bmatrix}
width/2 & 0 & 0 & 0 \\
0 & height/2 & 0 & 0 \\
0 & 0 & depth/2 & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
$$

So the final result would be:

$$
\begin{bmatrix}
x' \\
y' \\
z' \\
1
\end{bmatrix} =
\begin{bmatrix}
width/2 & 0 & 0 & 0 \\
0 & height/2 & 0 & 0 \\
0 & 0 & depth/2 & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
1 & 0 & 0 & 1 \\
0 & -1 & 0 & 1 \\
0 & 0 & 1 & 1 \\
0 & 0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x \\
y \\
z \\
1
\end{bmatrix}
$$

If you multiply it, you will get the same transformation matrix as above


---

