If I clip vertices to the near plane, how do I determine which vertices should actually be drawn

Let's assume a triangle which crosses the near clipping plane:

The triangle is defined counter-clockwise by 3 vertices (v1,v2,v3).

The vertices v1,v2 are on the positive side of the clipping plane and v3 is outside.

All you have to do is to process each edge:

1. edge (v1,v2)

Both vertices are inside, there's no need to clip.

Just keep the first vertex (v1).

Don't care about the second vertex, it get's processed with the next edge.

2. edge (v2,v3)

One of the vertices is inside, the other one is outside (doesn't matter which one), it needs to be clipped.

The first vertex (v2) is inside, keep it again.

Create a new vertex "n1" (*).

3. edge (v3,v1)

Again needs clipping.

Don't keep the first vertex (v3) because it's outside.

Create a new vertex "n2".

You now have a properly clipped quad (v1,v2,n1,n2).

If your rasterizer processes triangles only, split the quad into two triangles (v1,v2,n1), (v1,n1,n2).

(*)

The new vertices lie on an edge between two vertices v1 and v2.

Any point "n" between the two vertices can be described as

n= v1 + t * (v2-v1) with t= 0..1

In case of z-clipping you want your new vertex at n.z= nearClip:

nearClip = v1.z + t * (v2.z - v1.z)

=> t= (nearClip-v1.z) / (v2.z - v1.z)

You mentioned a bit operation. My guess is you're testing all 3 vertices are behind the eye and then skip that triangle completely if true?

Yes, that would remove all triangles behind the near clipping plane.

It is more efficient to remove all triangles that are outside of view-frustum, though.

The frustum is build from six planes. For each vertex create a bit-set which tells whether the vertex is beyond any of the planes, eg:

`TOP = 1 `

BOTTOM = 2

LEFT = 4

RIGHT = 8

FRONT = 16

BACK = 32

v1.clip = TOP | BOTTOM | RIGHT;

v2.clip = BOTTOM;

v3.clip = BOTTOM | LEFT;

To test whether a polygon is out of the frustum just "and" the clip-flags of its' vertices.

It's invisible if any of the bits remains, eg:

v1.clip & v2.clip & v3.clip = BOTTOM

-> the triangle is outside

Since your on-screen-coordinates are all -1..+1 you just have to check whether x/z and y/z are in range which turns out very easy:

x < -z: LEFT

x > z: RIGHT

y < -z: TOP

y > z: BOTTOM

And it's actually faster to transform all vertices and perform the cliptest in clip-space than trying to cull early with arbitrary planes to save some vertex-transformations.