<p>(I don't have enough rep yet to add a comment)</p>
<p>@pmw1234's explanation and solution work well. However, instead of writing out the perspective matrix by hand to handle the [0,1] Z-range of vulkan clip space, I found it easier to simply define <code>GLM_FORCE_DEPTH_ZERO_TO_ONE</code> for my project, e.g. in CMake, adding the line:</p>
<pre><code>target_compile_definitions(&lt;target_name&gt; PUBLIC GLM_FORCE_DEPTH_ZERO_TO_ONE)
</code></pre>
<p>In summary, I could define my camera's projection matrix as the following, given the viewport's width and height, the &quot;zoom&quot; value for the camera, and the near/far plane:</p>
<pre class="lang-cpp prettyprint-override"><code>glm::mat4 proj = glm::perspective(glm::radians(Zoom), 
    static_cast&lt;float&gt;(ScreenWidth) / ScreenHeight, Near, Far);
proj[1][1] *= -1;
</code></pre>

CC BY-SA 4.0
2022-11-29T01:05:20.533Z
2022-11-29T01:05:20.533Z
deadbird11
<p>If you are using the GLM library, you can define <code>GLM_FORCE_DEPTH_ZERO_TO_ONE</code>, as deabird11 said.</p>
<p>But you can also call specific functions suited for the projection of each API.</p>
<ul>
<li>For OpenGL call: <code>glm::perspectiveRH_NO</code> or <code>glm::perspectiveNO</code>, or simply <code>glm::perspective</code></li>
<li>For Vulkan call: <code>glm::perspectiveRH_ZO</code> or <code>glm::perspectiveZO</code></li>
</ul>
<p>This could be useful if you are making an engine that supports both OpenGL and Vulkan (using a define would lock you to use one convention).</p>
<p>You still need to invert the Y: <code>proj[1][1] *= -1;</code> for Vulkan. After all, GLM is designed for OpenGL.</p>
<p>I recommend reading this article for a good explanation on the differences between OpenGL and Vulkan coordinate systems: <a href="https://johannesugb.github.io/gpu-programming/why-do-opengl-proj-matrices-fail-in-vulkan" rel="nofollow noreferrer">https://johannesugb.github.io/gpu-programming/why-do-opengl-proj-matrices-fail-in-vulkan</a>.</p>

CC BY-SA 4.0
2023-11-16T11:56:19.273Z
2023-11-16T13:47:59.827Z
2023-11-16T13:47:59.827Z
user1754322
<p>Note that there is a little extra info here to (hopefully) provide the info need to understand the answer at the end. Plus I don't know of any sources that gives all the solutions in one place....</p>
<p>Vulkan clip space has [1, -1] for the y axis where OpenGL has [-1, 1] so just multiplying the perspective matrix [1][1] value by -1 will &quot;correct&quot; the OpenGL matrix to work with Vulkan. All it really does is flip the y axis.
(or you can also use gl_Postion.y *= -1)</p>
<p>As of Vulkan 1.1 negative values are allowed when setting up the viewport which gives a fairly natural solution to the same problem.</p>
<p>For the depth range:
Vulkan has a [0, 1] range for the Z axis in NDC space where OpenGL has [-1, 1] range (by default). There are a couple ways to handle this. You can remap the OpenGL range to the Vulkan range fairly easily with:</p>
<pre><code>gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0;
</code></pre>
<p>The other option is to modify the perspective matrix to match up with Vulkan. The Vulkan approach (which is also used in directx) maps to floating point numbers better since floating point numbers have more accuracy near zero. Also, some depth conversion code is simplified using a range of [0,1]. Finally, using a range [0,1] allows for &quot;reverse Z&quot; (improving floating point number distribution)</p>
<p>Here is some code for generating a Vulkan friendly perspective matrix. Note that this code looks a lot simpler then what GLM uses because it expects a symmetric frustum. This code is copied from the FGED website...mostly</p>
<pre><code>mat4 MakeProjectionMatrix(float fovy_rads, float s, float near, float far)
{
    float g = 1.0f / tan(fovy_rads * 0.5);
    float k = far / (far - near);

    return mat4(g / s,  0.0f,   0.0f,   0.0f,
                 0.0f,  g,      0.0f,   0.0f,
                 0.0f,  0.0f,   k,      -near * k,
                 0.0f,  0.0f,   1.0f,   0.0f);
}
</code></pre>
<p>(This solution does not flip the y-axis.)</p>
<p>Finally: A perspective matrix setup for OpenGL will work in Vulkan but it has limitations. The y axis will be flipped and objects falling in the [0,1] range will be visible. But objects falling in the [-1,0) range will not. Since Vulkan has a depth range of [0,1] it is easy to get the &quot;illusion&quot; that it is fully functional since the camera will appear to map correctly to the full depth range.</p>

CC BY-SA 4.0
2022-01-11T11:27:56.780Z
2023-11-16T15:09:53.187Z
2023-11-16T15:09:53.187Z
pmw1234
<p>Hi I have a slight confusion in using the opengl perspective matrix in vulkan.
glm's perspective matrix works directly in vulkan just by multiplying the &quot;[1,1 term by -1 but when I compared the formula for creation of perspective matrix for both the apis.</p>
<p>opengl one here:<a href="http://www.songho.ca/opengl/gl_projectionmatrix.html" rel="nofollow noreferrer">http://www.songho.ca/opengl/gl_projectionmatrix.html</a></p>
<p>vulkan here:<a href="https://www.youtube.com/watch?v=U0_ONQQ5ZNM" rel="nofollow noreferrer">https://www.youtube.com/watch?v=U0_ONQQ5ZNM</a>( at 12:10)</p>
<p>and I see 2 differences:
1st at 1,1
2nd at 2,3: here is my doubt(opengl's is 2 times the one in vulkan.</p>
<p>So how does glm's matrix works for my vulkan program just by correcting [1,1 location?
Please do correct me if I am making some mistake in understanding the differences in matrix.</p>
<p>openglMarix talking about:<a href="https://i.sstatic.net/hcIFm.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/hcIFm.jpg" alt="enter image description here" /></a></p>

CC BY-SA 4.0
2022-01-11T04:46:22.137Z
Could you excerpt the specific formulas you're talking about and put them in your question? There are multiple formulas in the page you linked and the youtube video, and I don't know which ones you mean exactly. That said, the difference in [2][3] sounds related to depth range. Vulkan uses a 0 to 1 final depth range and OpenGL is −1 to 1.
Nathan Reed
<opengl><mathematics><vulkan>
vulkan perspective matrix vs opengl perspective matrix
VersesDev
# vulkan perspective matrix vs opengl perspective matrix

(Asked by: username_0 on 2022-01-10)

Hi I have a slight confusion in using the opengl perspective matrix in vulkan.
glm's perspective matrix works directly in vulkan just by multiplying the "[1,1 term by -1 but when I compared the formula for creation of perspective matrix for both the apis.

opengl one here:<http://www.songho.ca/opengl/gl_projectionmatrix.html>

vulkan here:<https://www.youtube.com/watch?v=U0_ONQQ5ZNM>( at 12:10)

and I see 2 differences:
1st at 1,1
2nd at 2,3: here is my doubt(opengl's is 2 times the one in vulkan.

So how does glm's matrix works for my vulkan program just by correcting [1,1 location?
Please do correct me if I am making some mistake in understanding the differences in matrix.

openglMarix talking about:[![enter image description here](https://i.sstatic.net/hcIFm.jpg)](https://i.sstatic.net/hcIFm.jpg)

**Tags:** opengl, mathematics, vulkan

> **Comments:**
> **username_1**: Could you excerpt the specific formulas you're talking about and put them in your question? There are multiple formulas in the page you linked and the youtube video, and I don't know which ones you mean exactly. That said, the difference in [2][3] sounds related to depth range. Vulkan uses a 0 to 1 final depth range and OpenGL is −1 to 1.  

---

## 3 answers

### Answer by username_4 on 2022-01-11. Score: 4 | Accepted answer

Note that there is a little extra info here to (hopefully) provide the info need to understand the answer at the end. Plus I don't know of any sources that gives all the solutions in one place....

Vulkan clip space has [1, -1] for the y axis where OpenGL has [-1, 1] so just multiplying the perspective matrix [1][1] value by -1 will "correct" the OpenGL matrix to work with Vulkan. All it really does is flip the y axis.
(or you can also use gl\_Postion.y \*= -1)

As of Vulkan 1.1 negative values are allowed when setting up the viewport which gives a fairly natural solution to the same problem.

For the depth range:
Vulkan has a [0, 1] range for the Z axis in NDC space where OpenGL has [-1, 1] range (by default). There are a couple ways to handle this. You can remap the OpenGL range to the Vulkan range fairly easily with:

```
gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0;

```

The other option is to modify the perspective matrix to match up with Vulkan. The Vulkan approach (which is also used in directx) maps to floating point numbers better since floating point numbers have more accuracy near zero. Also, some depth conversion code is simplified using a range of [0,1]. Finally, using a range [0,1] allows for "reverse Z" (improving floating point number distribution)

Here is some code for generating a Vulkan friendly perspective matrix. Note that this code looks a lot simpler then what GLM uses because it expects a symmetric frustum. This code is copied from the FGED website...mostly

```
mat4 MakeProjectionMatrix(float fovy_rads, float s, float near, float far)
{
    float g = 1.0f / tan(fovy_rads * 0.5);
    float k = far / (far - near);

    return mat4(g / s,  0.0f,   0.0f,   0.0f,
                 0.0f,  g,      0.0f,   0.0f,
                 0.0f,  0.0f,   k,      -near * k,
                 0.0f,  0.0f,   1.0f,   0.0f);
}

```

(This solution does not flip the y-axis.)

Finally: A perspective matrix setup for OpenGL will work in Vulkan but it has limitations. The y axis will be flipped and objects falling in the [0,1] range will be visible. But objects falling in the [-1,0) range will not. Since Vulkan has a depth range of [0,1] it is easy to get the "illusion" that it is fully functional since the camera will appear to map correctly to the full depth range.


---

### Answer by username_2 on 2022-11-29. Score: 4

(I don't have enough rep yet to add a comment)

@username_4's explanation and solution work well. However, instead of writing out the perspective matrix by hand to handle the [0,1] Z-range of vulkan clip space, I found it easier to simply define `GLM_FORCE_DEPTH_ZERO_TO_ONE` for my project, e.g. in CMake, adding the line:

```
target_compile_definitions(<target_name> PUBLIC GLM_FORCE_DEPTH_ZERO_TO_ONE)

```

In summary, I could define my camera's projection matrix as the following, given the viewport's width and height, the "zoom" value for the camera, and the near/far plane:

```cpp
glm::mat4 proj = glm::perspective(glm::radians(Zoom), 
    static_cast<float>(ScreenWidth) / ScreenHeight, Near, Far);
proj[1][1] *= -1;

```


---

### Answer by username_3 on 2023-11-16. Score: 3

If you are using the GLM library, you can define `GLM_FORCE_DEPTH_ZERO_TO_ONE`, as deabird11 said.

But you can also call specific functions suited for the projection of each API.

* For OpenGL call: `glm::perspectiveRH_NO` or `glm::perspectiveNO`, or simply `glm::perspective`
* For Vulkan call: `glm::perspectiveRH_ZO` or `glm::perspectiveZO`

This could be useful if you are making an engine that supports both OpenGL and Vulkan (using a define would lock you to use one convention).

You still need to invert the Y: `proj[1][1] *= -1;` for Vulkan. After all, GLM is designed for OpenGL.

I recommend reading this article for a good explanation on the differences between OpenGL and Vulkan coordinate systems: <https://johannesugb.github.io/gpu-programming/why-do-opengl-proj-matrices-fail-in-vulkan>.


---

