Jump to content
  • Advertisement
Sign in to follow this  
Gage64

Questions about Charles Bloom's software rendering article

This topic is 3900 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm trying to create a software renderer using the architecture described in Charles Bloom's article, and I have some questions. 1) He projects the vertices to the screen while transforming them, and before any clipping is done, but what if the vertex's Z-coordinate is zero? I only thought about this after implementing it, and I never got any errors or visual glitches. I stepped through it with the debugger, and when z = 0, the clip-space coordinates were something like 1.INF, but I never got a divide by zero error. Is this the way it should work or can it fail on another computer or when using a different compiler (I use VC++ 2005 Express)? Also, if it does work this way, I guess I have nothing to worry about because those vertices are not visible on the screen (after viewport mapping the coordinates are still 1.INF)? 2) If I am doing the rasterization myself, are there any different speed tradeoffs I need to consider? 3) Somewhat unrelated so I won't go into details - he bases a lot of his decisions on how a modern CPU works (being cache friendly, avoiding pipeline stalls, using predictable branches, etc.). Can you recommend a resource (preferably a website) that explains these concepts and how they affect performance? This is the first time I'm writing a software renderer, but I still want it to be reasonably efficient. Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement
Look at the aritcles about the Pixomatic software rasterizer optimization by
Michael Abrash. Interesting reading.

http://www.ddj.com/architect/184405765

Petr

Share this post


Link to post
Share on other sites
In the article you linked to, the author says he (only) clips to near Z plane before projecting to screen space. This makes sense, as otherwise you just get garbage at negative Z values even if you don't crash when dividing by zero. The rest of the clips are done in screen space to make sure you don't output off the screen.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fingers_
In the article you linked to, the author says he (only) clips to near Z plane before projecting to screen space.


I don't know where you saw this, but if you look at the pseudo-code he provides, you'll see that the vertices are projected long before any clipping takes place.

Quote:
This makes sense, as otherwise you just get garbage at negative Z values even if you don't crash when dividing by zero.


Exactly why I asked, but as I stated above, division by zero can still occur because clipping is done after projection.

The funny thing is that before I added near-Z clipping, my program crashed every time an object went behind the camera, and I attributed these crashes to the division by zero. After I added clipping, the crashes disappeared but the division by zero still happens sometimes, so I don't know why there were crashes in the first place.

Share this post


Link to post
Share on other sites
Actually, looking at it again we're both right. Here's the paragraph I was talking about, about a third the way down:

"I clip against the near Z in View Space, and then clip against the other
planes in Screen Space. I produce new PVs where the edges intersect a
clip plane. These new PVs are filled out by interpolating
ViewSpacePosition (but not normal! it's not needed any more), color,
uv's, and specular. The reason I clip against the sides of the view in
Screen Space (instead of View Space) is to absolutely gaurantee that the
verts are inside the frame buffer rectangle. If you clip in view space
and then project, floating imprecision may push the verts slightly
outside of view, which can cause memory trashes."

I assume what he does is this: if the triangle requires near Z clipping, you create the new vertices in view space and transform them into screen space after the near Z clip, but before the screen space (top/bottom/left/right) clips. This way the screen space clip only deals with vertices with Z >= near Z, therefore they have finite screen space coordinates. The divided-by-zero values are never used for anything (that's when it'd crash). This is really clever.

The IEEE floating point standard has standard behavior for division by zero which will always result in the +/- infinite values. This will of course still crash if you feed the result to something that expects a finite number (like a screen space clipping algorithm).

[Edited by - Fingers_ on January 15, 2008 1:52:14 AM]

Share this post


Link to post
Share on other sites
The clipping is included in the pseudo code (the last part). Also, if you read carefully you'll see that he says he does near-Z clipping before doing screen-space clipping, but the projection is done before doing any clipping at all.

In my code, I also re-project the vertices that result after clipping (because the clipping process can create new vertices), but other vertices are projected before clipping and they can also have Z values that are zero or negative.

Quote:
I assume what he does is this: if the triangle requires near Z clipping, you create the new vertices in view space and transform them into screen space after the near Z clip, but before the screen space (top/bottom/left/right) clips. This way the screen space clip only deals with vertices whose Z is always >= near Z.


Now that you mention this, this might be the reason that the crashes disappeared, but I don't understand why it's important. Why can't screen-clipping deal with vertices with a Z that's less or equal to zero?

Thanks for you help so far.

Share this post


Link to post
Share on other sites
The projection of the original vertices is done before any clipping, but when you do the near Z clipping, any vertices with Z < nearZ are rejected.

For example, if you look at a triangle that starts with one vertex Z == 0 and two vertices Z > nearZ, the nearZ clipping operation produces two triangles with all positive (view space) Z values. The two new vertices are projected, screen space coordinates are finite because their Z > 0. The two remaining original vertices were already projected and known to have finite screen space coordinates. No infinities will slip through to the screen space clip routine.

The reason why the screen space clipping can't work with the divisions by zero is that you can't really do much if any arithmetic with infinities. Like if you have a vertex with infinite X coordinate, you can't interpolate a new vertex between that and a vertex with a finite X (Infinity + N == Infinity, and all that) to place it at the edge of the screen.

Share this post


Link to post
Share on other sites
I'll try to explain my "worries" a little bit better.

First, all vertices are projected. Some will have a Z value of zero, so for some of them the screen space position will be infinity. At the same time, clip flags are computed for each vertex using the following code (which appears in the article):


PV.ClipFlags = 0;
if ( VB_CF & FRONT_PLANE )
PV.ClipFlags |= ( PV.ViewSpacePosition.Z <= Near_Z ) ? FRONT_PLANE : 0;
if ( VB_CF & LEFT_PLANE )
PV.ClipFlags |= ( PV.ScreenSpacePosition.X <= 0 ) ? LEFT_PLANE : 0;
//etc...



But this code does a comparison between two values, and one of them might be infinity. Is such a comparison defined? And if it works here, why can't the screen space clipper do the same (note that by screen space clipping I mean clipping that takes place during rasterization)? Also note that this code is executed before any clipping takes place.

Share this post


Link to post
Share on other sites
I'm not certain about what the FP standard says about comparison to infinities, but since they're mathematically valid (ie. any finite number is greater than -inf and less than +inf) it'll probably be fine. In this case it's largely irrelevant as long as it doesn't "crash"; if the vertex is clipped by the near Z plane then the other clip flags of that vertex will never be looked at by the screen space clipping code. Even if the comparison generated garbage in the clip flags it would have no effect on the final result.

In general, what'll ultimately cause the system to crash in a division by zero situation depends on the exact code and may be quite a bit later than the division itself. This makes it hard to debug and is why people generally avoid divisions by zero completely.

In the software rendering example I suspect that the clipper would choke on the infinity but that's just a hunch based on that being the first place in the code that'll use the screen space coordinates. It might well not crash until e.g. the actual triangle rasterizer tries to draw an infinitely long horizontal line, or whatever comes out when you convert an infinity to an integer! If you're curious enough you can always disable the nearZ clip and run in a debugger to see how far down the pipeline the infinity will travel before something breaks.

[Edited by - Fingers_ on January 15, 2008 2:13:07 PM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!