Clip matrix for 3D Perspective Projection
I am trying to create a simple 3D graphic开发者_运维问答s 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.
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.
This might be a misunderstanding of the terminology. The clip matrix is more appropriately known as a projection matrix. In OpenGL at least, the projection matrix transforms 4D homogeneous coordinates in view coordinate space (VCS) to clipping coordinate space (CCS). Projection from the CCS to normalized device coodinate space (NDCS) requires the perspective division, i.e., dividing each component by the W component. Clipping is correctly done before this step. So, a 'clipping matrix' doesn't remove the need to clip the geometry prior to projection. I hope I've understood you, and this doesn't sound condescending.
That said, I think you've obviously got the projection matrix right - it works. I suspect that the vertices passing behind the eye have negative W, which means they should be clipped; but I also suspect they have negative Z, so the division is yielding a positive Z value. If you really want to clip the geometry, rather than discard whole triangles, do a search for 'homogeneous clipping'. If you're not really working in 4D homogeneous space, you might start by looking at 'Sutherland-Hodgman' 3D clipping.
精彩评论