Clip matrix for 3D Perspective Projection

mclaassen picture mclaassen · Sep 30, 2011 · Viewed 8.1k times · Source

I am trying to create a simple 3D graphics engine and have found and used the equations I found here: http://en.wikipedia.org/wiki/3D_projection#cite_note-0. (I have calculations for Dx, Dy, Dz and Bx, By)

I works, but when I rotate the camera enough lines start flying all over the place and eventually you see the polygons that went off screen start to come back on the opposite side of the screen (you can go here: http://mobile.sheridanc.on.ca/~claassen/3d.html and use the W, A, S and D keys to rotate the camera to see what I'm talking about)

I read this discussion: How to convert a 3D point into 2D perspective projection? where he talked about using a clip matrix but Im still a little confused as to how exactly to use one. Also I'm not sure if I am using 'homogeneous coordinates' as described in the discussion.

Answer

Acorn picture Acorn · Nov 24, 2013

After multiplying by the perspective projection matrix (aka clip matrix) you end up with a homogenious 4-vector [x,y,z,w]. This is called npc (normalized projection coordinates), and also called clip coordinates. To get the 2D coordinates on the screen you typically use something like

xscreen = (x/w) * screen_width
yscreen = (y/w) * screen_width

For points in front of the camera this gives you what you want. But points behind the camera will have w<0 and you will get values that map to valid screen coordinates even though the point is behind the camera. To avoid this you need to clip. Any vertex that has a w<0 needs to be clipped.

A quick thing to try is to just not draw any line if either vertex has w<0. This should fix the strange polygons that show up in your scene. But it will also remove some lines that should be visible.

TO completely fix the problem you need to clip all the lines which have one vertex in front of the camera and one vertex behind the camera. Clipping means cutting the line in half and throwing away the half that is behind the camera. The line is "clipped" by a plane that goes through the camera and is parallel to the display screen. The problem is to find the point on the line that corresponds to this plane (i.e. where the line intersects the plane). This will occur at the point on the line where w==0. You can find this point, but then when you try to find the screen coordinates

xscreen = (x/w) * screen_width
yscreen = (y/w) * screen_width

you end up dividing by 0 (w==0). This is the reason for the "near clipping plane". The near clipping plane is also parallel to the display screen but is in front of the camera (between the camera and the scene). The distance between the camera and the near clipping plane is the "near" parameter of the projection matrix:

[    near/width   ][        0        ][         0              ][        0       ]
[        0        ][    near/height  ][         0              ][        0       ]
[        0        ][        0        ][(far+near)/(far-near)   ][        1       ]
[        0        ][        0        ][-(2*near*far)/(far-near)][        0       ]

To clip to the near plane you have to find the point on the line that intersects the near clipping plane. This is the point where w == near. So if you have a line with vertices v1,v2 where

v1 = [x1, y1, z1, w1]
v2 = [x2, y2, z2, w2]

you need to check if each vertex is in front of or behind the near clip plane. V1 is in front if w1 >= near and behind if w1 < near. If v1 and v2 are both in front then draw the line. If v1 and v2 are both behind then don't draw the line. If v1 is in front and v2 is behind then you need to find vc where the line intersects the near clip plane:

n = (w1 - near) / (w1 - w2)
xc = (n * x1) + ((1-n) * x2)
yc = (n * y1) + ((1-n) * y2)
zc = (n * z1) + ((1-n) * z2)
wc = near
vc = [xc, yc, zc, wc]

Now draw the line between v1 and vc.