@smochi I do, yes. Overdraw is very expensive and large triangles (i.e: those that get close to the camera) result in overflows and other nasties.
Top-level
@smochi I do, yes. Overdraw is very expensive and large triangles (i.e: those that get close to the camera) result in overflows and other nasties. 8 comments
@smochi I'm familiar with the general approach, it's more an issue of micro-optimising. I'm on a very resource-constrained platform, so every little trick helps. I'm mostly interested in ways to cut down on unnecessary interpolation steps (i.e: because another plane will clip the interpolated section anyway) @jsbarretto Are you using a Z buffer? It won't avoid geometry processing, but will at least eliminate overdraw of occluded surfaces. @smochi Sadly not! Not enough fast memory for a z buffer (nor grunt for computing per-pixel z). A coverage buffer + presorting is the best I've got. @smochi All being done, thankfully. My target platform is the Gameboy Advance: everything is being rasterised in software using fixed point ( the GBA has no GPU nor support for floating point). If you're curious: https://youtu.be/RDrjsrKmeOs I do think I'm rapidly getting into diminishing returns at this point. I'm down to optimising things down to the instruction level (and below) in many of the inner loops. Over the past few days I rewrote the clipper & it now seems to no longer be the bottleneck. @jsbarretto Heh, that's pretty cool! Reminds me of PSX graphics, particularly FF9. They also had very limited precision, which led to slight distortion when objects were being rotated. @smochi I've actually improved a lot of that distortion recently as a result of revising the clipping code, but I've not yet posted an update. |
@jsbarretto I'm sure there's plenty material on the topic, but from what I recall of fixed-function pipelines, clipping is usually done in NDC space, which means it happens after the view frustum transformation. The advantage is that clipping is much easier, because you only have to compare coordinates to [-1,1].
You'll still have to process all edges of all triangles, though:
1. Loop over all triangles
2. Test which vertices of the triangle are outside or inside the NDC cube.
3. If all are outside, cull the triangle. Skip to next.
4. If all are inside, no culling/clipping is needed. Skip to next.
5. If one is inside, calculate the intersection of the clipped edges with the NDC cube. This is easy, because you can fix one coordinate to the clip plane (x, y or z = -1 or 1) and calculate the others with the help of to the line equation (r = a + t • (b - a)). Generate two new vertices with the calculated coordinates and replace the triangle with a new one created from the new vertices. Skip to the next.
6. If two are inside, calculate the intersection vertices as in step 5, but replace the triangle with 2 new ones forming a trapezoid. Skip to the next.
You could keep track of the unused vertices and remove them at the end, but that will require additional processing time. They'll be ignored by the rasterizer if they're not used in any triangle, but if memory usage or bandwidth is a concern, you might still have to do that.
@jsbarretto I'm sure there's plenty material on the topic, but from what I recall of fixed-function pipelines, clipping is usually done in NDC space, which means it happens after the view frustum transformation. The advantage is that clipping is much easier, because you only have to compare coordinates to [-1,1].