Let’s call the intrinsic camera matrix K.
If you would sample an opengl texture at coordinate (0,0), it samples the corner of the texture. The mapping of K to (0,0) however usually samples the center of the corner pixel.
So you have to adjust K to
| K11 0 K13+0.5 |
| 0 K22 K23+0.5 |
| 0 0 1 |
If you now sample where K originaly mapped to (0,0), it will sample from (0.5,0.5) which is the center of the corner pixel.
Now we map into the canonical viewvolume of opengl, with ranges [-1,1]x[-1,1].
| 2*K11/width 0 2*(K13+0.5)/width -1 |
| 0 2*K22/height 2*(K23+0.5)/height-1 |
| 0 0 1 |
This maps [0,width]x[0,height] to [-1,1]x[-1,1]
Next, we convert the 3x3 matrix to a 4x4 matrix accepted by opengl.
| 2*K11/width 0 2*(K13+0.5)/width -1 0 |
| 0 2*K22/height 2*(K23+0.5)/height-1 0 |
| X X X X |
| 0 0 1 0 |
Note that the third row of the original matrix is placed in the fourth row. This is because we want do do the perspective divide on the Z-component and not the homogeneous component, which is in most cases always equal to 1.
All you need to do now, is fill in the X values according to your near and far plane.