I am writing a very simple rendering engine. I have already made a few tests, but somehow the images it creates look wrong. Objects that are further away from the camera look larger than objects closer to the camera. I have constructed this example:
pos = [-10, 0, 0] # Camera position
target = [1, 0, 0] # Camera looks at this point
up = [0, 0, 1] # z direction is "up"
fov_y = 25 * degree # field of view in y direction (camera y axis)
aspect_ratio = 1
near = 0.01 # Near clipping plane distance
far = 5000 # Far clipping plane distance
I added two lines to the scene, a red one from [1, 0, 0]
to [1, 0, 1]
and a black one from [4, 0, 0]
to [4, 0, 1]
. The black one is clearly further away from the camera, but appears larger:
From the above description, at first I have constructed the view matrix
V = [[0, -1, 0, 0],
[0, 0, 1, 0],
[1, 0, 0, -10],
[0, 0, 0, 1]]
which seems to be correct. The perspective matrix I calculated is
P = [[4.5107, 0, 0, 0],
[0, 4.5107, 0, 0],
[0, 0, -1.000004, -0.02],
[0, 0, -1, 0]]
I'm assuming the problem is somewhere here. The full transformation matrix is (using numpy):
T = numpy.dot(P, V)
and the transformed points:
p_transformed = numpy.dot(p_untransformed, T.T) # Transpose on the right hand side
For example, [1, 0, 1]
becomes [0, 4.5107, 8.98, 9]
and [4, 0, 1]
becomes [0, 4.5107, 5.98, 6]
and since the last step is to divide the first three components by the last one, this results in the second line being larger than the first one.
Is there a mistake somewhere? If so, where is it?
Edit: Formulae
Here are the formulae I used:
where
d = normalized(target - pos) # direction vector of the camera
r = normalized(cross(d, up)) # x unit vector in camera space
u = normalized(cross(r, d)) # y unit vector in camera space
Furthermore, the formula for P is
(Source)
where
n, f # position of near an far clipping plane
t = n * tan(0.5 * radians(fov_y))
b = -t
r = t * aspect_ratio
l = -r