<p>It's possible that your quaternion code and/or your use of the <code>lookAt()</code> method might have mistakes. However, the image that you included looks fine to me, and your perspective projection matrix checks out: When applied to a vector <span class="math-container">$(x,y,z,1)^T$</span> and followed by the perspective divide (which happens on the GPU automatically) it maps the view frustum onto the cube <span class="math-container">$[-1,1]^3$</span> in normalised device coordinates (NDCs). Moreover, the <span class="math-container">$z$</span> coordinate is mapped to an affine function of <span class="math-container">$1/z$</span>, which means that by <span class="math-container">$z$</span>-buffering, the GPU will solve the occlusion problem automatically, per fragment, by interpolating <span class="math-container">$1/z$</span> between the vertices of each triangle. There are settings in OpenGL and/or extensions to OpenGL, which choose between competing conventions for the bounds of that NDC cube (I think the difference is in whether <span class="math-container">$z$</span> is between <span class="math-container">$-1$</span> and <span class="math-container">$1$</span> or between <span class="math-container">$0$</span> and <span class="math-container">$1$</span>, and I think that DirectX and OpenGL tend to differ on this, with the DirectX choice being arguably the more sensible one for some reason (floating-point precision and <span class="math-container">$z$</span>-fighting ?) but I don't remember), so you might want to check that your own settings assume the <span class="math-container">$[-1, 1]^3$</span> convention.</p>
<p>This might sound silly and/or obvious, but, if you close one eye and position the other eye where the virtual camera is, relative to the graphics window on your monitor (meaning perpendicularly opposite the exact centre of your window, and at such a distance that the height of the window really does subtend an angle <code>verticalFieldOfView</code> at your eye) then the &quot;perspective distorsion&quot; should no longer seem like a distortion, because (apart from accommodation) this is pretty much how your eye/brain sees the world ! This is assuming that <code>width</code> and <code>height</code> really are in the same ratio as are the actual width and height of the window on your monitor. From this position, if you move your head either towards or away from the monitor, then the perspective will seem increasingly &quot;distorted&quot;. I do this to check my own code.</p>
<p><strong>EDIT:</strong> By &quot;this is pretty much how your eye/brain sees the world&quot; I mean that, if one were to look through a window from inside a building, with one eye closed, keeping the head perfectly still, and draw or paint on the glass of the window exactly what the open eye saw, as if tracing it, then the resulting image on the glass would coincide exactly with what your perspective matrix would produce, given an accurate 3d model of the outside world, with the view frustum positioned and oriented so as to represent the positions of your eye and of the pane of glass. It is in this sense that I claim the perspective projection is &quot;not distorted&quot;.</p>
<p>Note that distinct vertical lines need not be parallel on screen after perspective projection, even though some engineering or artistic projections would have them parallel. Again, the perspective projection is the one that best models what one sees in real life - skyscrapers are the commonly given example of vertical lines seeming to converge.</p>
<p><strong>EDIT:</strong> In the following image is my verification that your matrix is correct. In the small diagrams you can see how the image is projected through a point (your virtual eye) onto a plane (the monitor screen), which imitates the way that a pinhole camera works:</p>
<p><a href="https://i.sstatic.net/8Msh2t5T.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/8Msh2t5T.jpg" alt="Perspective projection" /></a></p>

CC BY-SA 4.0
2024-08-29T19:56:01.087Z
Hello, thank you for the recap and for telling me the trick about closing one eye, I am new to this kind of thing. I eventually decided my implementation was ok, I reached this conclusion some days ago after comparing the image I posted with analogous perspectives rendered by professional software. I decided that if a professional rendering engine can accept these slight distortions, so can I.
Chaos
CC BY-SA 4.0
2024-08-29T23:05:47.407Z
You are welcome, and I do apologise if I was somewhat telling you things you already knew. I am glad that you have resolved your issue ! I think that we still have a slight difference of opinion in that I believe your image, and those of the professional rendering engine, are *not* distorted. If you make a pinhole camera, as I used to do as a child, then you should find the images it produces align exactly with the images your code generates, given a geometrically correct model of the scene. If I am right, then it is good news for you ! But engineers, e.g., may *prefer* orthogonal projections.
Simon
CC BY-SA 4.0
2024-08-29T23:14:16.913Z
BTW I like to measure the graphics window on my monitor with a ruler, and also the distance between my face and the screen, and to set the parameters of my projection matrix accordingly. I have found that this produces images that are particularly convincing. One is used to looking at perspective projections made without obeying these strictures (e.g. looking at a photograph in a magazine from an arbitrary angle), and one is used to appreciating the perspective projection in spite of this. But I have found that getting it right produces a particularly compelling image. Next - depth of field !
Simon
CC BY-SA 4.0
2024-08-29T23:40:35.093Z
PS I added a diagram to my answer, to show what I mean about the perspective projection modeling the behaviour of a pinhole camera.
Simon
CC BY-SA 4.0
2024-08-30T07:47:49.357Z
My engine has support for orthogonal projections and they provide convincing results as well. Now I think I get it, there is no distortion: I am just biased by binocular vision.
Chaos
CC BY-SA 4.0
2024-08-30T09:30:05.593Z
You make an interesting point - it will always look wrong to at least one eye ! Unless we use stereoscopic displays. I sometimes use red-cyan anaglyph, and sometimes convergent or divergent stereo pairs. Maybe for my birthday I'll buy myself a VR headset and a powerful PC to run it ! XD
Simon
CC BY-SA 4.0
2024-08-29T13:52:18.867Z
2024-08-30T23:34:48.810Z
2024-08-30T23:34:48.810Z
Simon
<p>The perspective looks fine. Parallel lines should all cross in one point and they all do. The crossing points of the red lines in the attached picture are your horizon, this could be a little bit lower than it is now (ideally only slightly above the vertical middle of the screen), so maybe you should translate your scene and/or change the look at position of the camera to achieve this. <a href="https://i.sstatic.net/Itdbm1Wk.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/Itdbm1Wk.png" alt="attached picture" /></a></p>

CC BY-SA 4.0
2024-12-03T05:33:30.007Z
2024-12-03T14:07:43.227Z
2024-12-03T14:07:43.227Z
luta
<p>I am trying to implement a UVN free camera for browsing the 3D space of my OpenGL simulation and I noticed the perspective is introducing some sort of distortion. I observed it is more noticeable close to the border of the window and consequently far away from its center.</p>
<p>When inspecting the space employing an orthographic projection I notice no problems but when I switch to the perspective projection something odd happens. I have attached an image of the problem I am experiencing.</p>
<p>Each tile in the image is squared, with edges of length <span class="math-container">$e$</span>, however, when rotating or simply translating the camera I can spot points of view from which tiles appear to be rectangular.</p>
<p>When I remove the plane and draw the three vectors <span class="math-container">$(1, 0, 0)e'$</span>, <span class="math-container">$(0, 1, 0)e'$</span>, and <span class="math-container">$(0, 0, 1)e'$</span> <span class="math-container">$(e'=3*e)$</span>, I can spot perspectives from which the three do not appear to be orthogonal.
I implemented quaternion-based rotation and the problem can be perceived when rotating.
I also tried rotating the camera via the <code>lookAt()</code> method and a pair of angles but the problem is still there.</p>
<p><a href="https://i.sstatic.net/o7dPXCA4.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/o7dPXCA4.png" alt="Funky perspective" /></a></p>
<p>I spent a few days checking my calculations and I couldn't spot anything wrong.
My matrices are computed on the CPU and are row major, when set as uniforms they are transposed.</p>
<p>This is my code for setting up the perspective matrix.</p>
<pre class="lang-cpp prettyprint-override"><code>GLfloat
    VFOV = GLfloat(tan(radians(verticalFieldOfView / GLfloat(2.0)))),
    aspectRatio = GLfloat(width) / GLfloat(height);
Matrix4&lt;GLfloat&gt;::identity();
Matrix4&lt;GLfloat&gt;::elements[0][0] = +1.0f / (VFOV * aspectRatio);
Matrix4&lt;GLfloat&gt;::elements[1][1] = +1.0f / VFOV;
Matrix4&lt;GLfloat&gt;::elements[2][2] = (-Zfar - Znear) / (Znear - Zfar);

Matrix4&lt;GLfloat&gt;::elements[2][3] = +(2.0f * Zfar * Znear) / (Znear - Zfar);
Matrix4&lt;GLfloat&gt;::elements[3][2] = +1.0f;

Matrix4&lt;GLfloat&gt;::elements[3][3] = +GLfloat(0.0);
</code></pre>
<p>The image above has been captured with a FOV=30°.</p>
<p>Translation of the camera is achieved (inefficiently but simply) via the product with the translation matrix (identity with the fourth column having the column vector set to <span class="math-container">$-position$</span> of the camera).</p>
<p>I am not sure whether such distortion can be mitigated by the model, hence I don't know whether I am looking for a bug or I am fighting against a limitation of the camera model.</p>
<p>At this point, I have three questions:</p>
<ol>
<li>Is the distortion I am perceiving due to the perspective?</li>
<li>If it is, is it to be expected (can not be prevented via such a simple model)?</li>
<li>Which model could account for it and correct it?</li>
</ol>
<p>All help is appreciated.</p>

CC BY-SA 4.0
2024-08-25T12:32:13.083Z
Perspective matrices do distort near the edges depending on the FOV, I suggest trying different values for the vertical FOV to see the different distortion amounts.
pmw1234
CC BY-SA 4.0
2024-08-25T19:23:59.703Z
@pmw1234 Thank you for the suggestion, I am giving it a shot. I just checked the presence of the vanishing point of my lines and there is exactly one so the distortion is really due to the FOV.
Chaos
<opengl><projections><perspective>
Is my perspective incorrect?
Chaos
# Is my perspective incorrect?

(Asked by: username_0 on 2024-08-24)

I am trying to implement a UVN free camera for browsing the 3D space of my OpenGL simulation and I noticed the perspective is introducing some sort of distortion. I observed it is more noticeable close to the border of the window and consequently far away from its center.

When inspecting the space employing an orthographic projection I notice no problems but when I switch to the perspective projection something odd happens. I have attached an image of the problem I am experiencing.

Each tile in the image is squared, with edges of length $e$, however, when rotating or simply translating the camera I can spot points of view from which tiles appear to be rectangular.

When I remove the plane and draw the three vectors $(1, 0, 0)e'$, $(0, 1, 0)e'$, and $(0, 0, 1)e'$ $(e'=3\*e)$, I can spot perspectives from which the three do not appear to be orthogonal.
I implemented quaternion-based rotation and the problem can be perceived when rotating.
I also tried rotating the camera via the `lookAt()` method and a pair of angles but the problem is still there.

[![Funky perspective](https://i.sstatic.net/o7dPXCA4.png)](https://i.sstatic.net/o7dPXCA4.png)

I spent a few days checking my calculations and I couldn't spot anything wrong.
My matrices are computed on the CPU and are row major, when set as uniforms they are transposed.

This is my code for setting up the perspective matrix.

```cpp
GLfloat
    VFOV = GLfloat(tan(radians(verticalFieldOfView / GLfloat(2.0)))),
    aspectRatio = GLfloat(width) / GLfloat(height);
Matrix4<GLfloat>::identity();
Matrix4<GLfloat>::elements[0][0] = +1.0f / (VFOV * aspectRatio);
Matrix4<GLfloat>::elements[1][1] = +1.0f / VFOV;
Matrix4<GLfloat>::elements[2][2] = (-Zfar - Znear) / (Znear - Zfar);

Matrix4<GLfloat>::elements[2][3] = +(2.0f * Zfar * Znear) / (Znear - Zfar);
Matrix4<GLfloat>::elements[3][2] = +1.0f;

Matrix4<GLfloat>::elements[3][3] = +GLfloat(0.0);

```

The image above has been captured with a FOV=30°.

Translation of the camera is achieved (inefficiently but simply) via the product with the translation matrix (identity with the fourth column having the column vector set to $-position$ of the camera).

I am not sure whether such distortion can be mitigated by the model, hence I don't know whether I am looking for a bug or I am fighting against a limitation of the camera model.

At this point, I have three questions:

1. Is the distortion I am perceiving due to the perspective?
2. If it is, is it to be expected (can not be prevented via such a simple model)?
3. Which model could account for it and correct it?

All help is appreciated.

**Tags:** opengl, projections, perspective

> **Comments:**
> **username_1**: Perspective matrices do distort near the edges depending on the FOV, I suggest trying different values for the vertical FOV to see the different distortion amounts.  
> **username_0**: @username_1 Thank you for the suggestion, I am giving it a shot. I just checked the presence of the vanishing point of my lines and there is exactly one so the distortion is really due to the FOV.  

---

## 2 answers

### Answer by username_2 on 2024-08-29. Score: 1

It's possible that your quaternion code and/or your use of the `lookAt()` method might have mistakes. However, the image that you included looks fine to me, and your perspective projection matrix checks out: When applied to a vector $(x,y,z,1)^T$ and followed by the perspective divide (which happens on the GPU automatically) it maps the view frustum onto the cube $[-1,1]^3$ in normalised device coordinates (NDCs). Moreover, the $z$ coordinate is mapped to an affine function of $1/z$, which means that by $z$-buffering, the GPU will solve the occlusion problem automatically, per fragment, by interpolating $1/z$ between the vertices of each triangle. There are settings in OpenGL and/or extensions to OpenGL, which choose between competing conventions for the bounds of that NDC cube (I think the difference is in whether $z$ is between $-1$ and $1$ or between $0$ and $1$, and I think that DirectX and OpenGL tend to differ on this, with the DirectX choice being arguably the more sensible one for some reason (floating-point precision and $z$-fighting ?) but I don't remember), so you might want to check that your own settings assume the $[-1, 1]^3$ convention.

This might sound silly and/or obvious, but, if you close one eye and position the other eye where the virtual camera is, relative to the graphics window on your monitor (meaning perpendicularly opposite the exact centre of your window, and at such a distance that the height of the window really does subtend an angle `verticalFieldOfView` at your eye) then the "perspective distorsion" should no longer seem like a distortion, because (apart from accommodation) this is pretty much how your eye/brain sees the world ! This is assuming that `width` and `height` really are in the same ratio as are the actual width and height of the window on your monitor. From this position, if you move your head either towards or away from the monitor, then the perspective will seem increasingly "distorted". I do this to check my own code.

**EDIT:** By "this is pretty much how your eye/brain sees the world" I mean that, if one were to look through a window from inside a building, with one eye closed, keeping the head perfectly still, and draw or paint on the glass of the window exactly what the open eye saw, as if tracing it, then the resulting image on the glass would coincide exactly with what your perspective matrix would produce, given an accurate 3d model of the outside world, with the view frustum positioned and oriented so as to represent the positions of your eye and of the pane of glass. It is in this sense that I claim the perspective projection is "not distorted".

Note that distinct vertical lines need not be parallel on screen after perspective projection, even though some engineering or artistic projections would have them parallel. Again, the perspective projection is the one that best models what one sees in real life - skyscrapers are the commonly given example of vertical lines seeming to converge.

**EDIT:** In the following image is my verification that your matrix is correct. In the small diagrams you can see how the image is projected through a point (your virtual eye) onto a plane (the monitor screen), which imitates the way that a pinhole camera works:

[![Perspective projection](https://i.sstatic.net/8Msh2t5T.jpg)](https://i.sstatic.net/8Msh2t5T.jpg)

> **Comments:**
> **username_0**: Hello, thank you for the recap and for telling me the trick about closing one eye, I am new to this kind of thing. I eventually decided my implementation was ok, I reached this conclusion some days ago after comparing the image I posted with analogous perspectives rendered by professional software. I decided that if a professional rendering engine can accept these slight distortions, so can I.  
> **username_2**: You are welcome, and I do apologise if I was somewhat telling you things you already knew. I am glad that you have resolved your issue ! I think that we still have a slight difference of opinion in that I believe your image, and those of the professional rendering engine, are *not* distorted. If you make a pinhole camera, as I used to do as a child, then you should find the images it produces align exactly with the images your code generates, given a geometrically correct model of the scene. If I am right, then it is good news for you ! But engineers, e.g., may *prefer* orthogonal projections.  
> **username_2**: BTW I like to measure the graphics window on my monitor with a ruler, and also the distance between my face and the screen, and to set the parameters of my projection matrix accordingly. I have found that this produces images that are particularly convincing. One is used to looking at perspective projections made without obeying these strictures (e.g. looking at a photograph in a magazine from an arbitrary angle), and one is used to appreciating the perspective projection in spite of this. But I have found that getting it right produces a particularly compelling image. Next - depth of field !  
> **username_2**: PS I added a diagram to my answer, to show what I mean about the perspective projection modeling the behaviour of a pinhole camera.  
> **username_0**: My engine has support for orthogonal projections and they provide convincing results as well. Now I think I get it, there is no distortion: I am just biased by binocular vision.  
> **username_2**: You make an interesting point - it will always look wrong to at least one eye ! Unless we use stereoscopic displays. I sometimes use red-cyan anaglyph, and sometimes convergent or divergent stereo pairs. Maybe for my birthday I'll buy myself a VR headset and a powerful PC to run it ! XD  

---

### Answer by username_3 on 2024-12-03. Score: 0

The perspective looks fine. Parallel lines should all cross in one point and they all do. The crossing points of the red lines in the attached picture are your horizon, this could be a little bit lower than it is now (ideally only slightly above the vertical middle of the screen), so maybe you should translate your scene and/or change the look at position of the camera to achieve this. [![attached picture](https://i.sstatic.net/Itdbm1Wk.png)](https://i.sstatic.net/Itdbm1Wk.png)


---

