📄 zbuffering.htm
字号:
<!--Header-->
<HTML>
<HEAD>
<TITLE>GPMega - Advanced Section - Z-Buffering</TITLE>
<META NAME="DESCRIPTION" CONTENT="Tom Hammersley, A great 3D coder explains the intricasies of Z-Buffering (including implementation details) in this article.">
</HEAD>
<BODY BGCOLOR=#000000 TEXT=#FFFFFF LINK=#00FF00 VLINK=#00FF00 ALINK=#0000FF>
<!--End Header-->
<!--Advertiser-->
<CENTER>
<TABLE>
<TR>
<TD>
<A HREF="http://www.ugo.com/">
<IMG SRC="/GPMega/ugologo120.gif" BORDER=0 WIDTH=120 HEIGHT=60></A>
</TD>
<TD>
<IMG SRC="/GPMega/sponsored.gif" WIDTH=468 HEIGHT=10><br><br>
<SCRIPT LANGUAGE= "JavaScript">
<!--
var now = new Date();
var random_num = now.getSeconds();
document.write("<A HREF='http://www.ugo.net/RealMedia/ads/click_nx.cgi/www.perplexed.com/GPMega/advanced/zbuffering.htm/" + random_num + "/@Top'>");
document.write("<IMG SRC='http://www.ugo.net/RealMedia/ads/adstream_nx.cgi/www.perplexed.com/GPMega/advanced/zbuffering.htm/" + random_num + "/@Top' BORDER='0' WIDTH='468' HEIGHT='60'></A>");
//-->
</SCRIPT>
</TD>
</TR>
</TABLE>
</CENTER>
<!--End Advertiser-->
<!--Splitter-->
<BR>
<!--End Splitter-->
<!--Body-->
<FONT SIZE=2 FACE=Helvetica>
<STRONG>
<!--Top Navigation-->
<A NAME="top"></A>
<CENTER>
<TABLE WIDTH=75%>
<TR VALIGN=MIDDLE>
<TD ALIGN=LEFT>
<IMG SRC="gradsplit2.jpg" WIDTH=100% HEIGHT=1><BR><BR>
<A HREF="http://www.perplexed.com/GPMega/"><IMG SRC="logo.jpg" BORDER=0 ALT="Home" WIDTH=80 HEIGHT=47 ALIGN=CENTER></A>
<FONT COLOR=#666666 FACE=HELVETICA SIZE=-1><I>
This Article Is Taken From <A HREF="http://www.perplexed.com/GPMega/">The Game Programming MegaSite</A>, A Definitive Resource For Game Developers!
</I></FONT><BR>
<IMG SRC="gradsplit2.jpg" WIDTH=100% HEIGHT=1>
</TD>
</TR>
</TABLE>
</CENTER>
<BR><!--End Top Navigation-->
<!--Title-->
<H3 ALIGN=CENTER><font color="#FFE800">Z</font><font color="#FFD100">-</font><font color="#FFBA00">B</font><font color="#FFA300">u</font><font color="#FF8C00">f</font><font color="#FF7500">f</font><font color="#FF5E00">e</font><font color="#FF4700">r</font><font color="#FF3000">i</font><font color="#FF1900">n</font><font color="#FF0200">g</font><BR><FONT SIZE=-2>By: Tom Hammersley</FONT></H3>
<!--End Title-->
<H3><FONT COLOR=YELLOW><I>Introduction</I></FONT></H3>
<P>ZBuffering is a very handy graphics algorithm. Invented by Catmull in '79, it allows us to paint objects to the screen
without sorting, without performing intersection calculations where objects interpenetrate, to paint in whatever order
we like, and to paint any kind of object we like. But there is one big problem with it: unless in hardware, its slow and
inefficient. But you might as well add it to your engine, its very useful. A ZBuffer type system is also used in Radiosity,
if you are calculating form-factors in the hemicube algorithm.
<H3><FONT COLOR=YELLOW><I>How It Works</I></FONT></H3>
<P>The basic idea behind zbuffer is very simple: If the pixel we are currently painting is the closest yet painted, write it. If not, don't
write it. To identify if the pixel is the nearest, we need a memory buffer - the Z buffer. Here we store the Z of each pixel painted
so far. Pseudo-code for a naive implementation of this would be:
<CENTER><P><TABLE WIDTH=65% CELLPADDING=0 CELLSPACING=0>
<TR><TD>
<TABLE><TR><TD>
<PRE><FONT COLOR=#FF0000 FACE=Courier SIZE=2>
Clear Z-Buffer to a certain value
For every polygon
For every scanline of that polygon
For every pixel
If this is nearest pixel {
Write Pixel
Write Z into zbuffer
}
End
End
End
</FONT></PRE>
</TD></TR></TABLE>
</TD></TR>
</TABLE></CENTER>
<P>If you are wondering where to get your Z from, then its simply a case of linear interpolation. There are lots of documents
available to cover that, so I won't go into that right now. Simply take the Z values at the vertices, and interpolate across the
edges. Then, take the Z value at either edge, and interpolate that, getting you a Z value for each pixel.
<P>Note that we needn't be using solely polygons. The implementation could equally be:
<CENTER><P><TABLE WIDTH=65% CELLPADDING=0 CELLSPACING=0>
<TR><TD>
<TABLE><TR><TD>
<PRE><FONT COLOR=#FF0000 FACE=Courier SIZE=2>
Clear Z-Buffer to a certain value
For every primitive
For every scanline of that primitive
For every pixel
If this is nearest pixel {
Write Pixel
Write Z into zbuffer
}
End
End
End
</FONT></PRE>
</TD></TR></TABLE>
</TD></TR>
</TABLE></CENTER>
<P>So we could build a graphics engine that handles things such as real spheres, torii etc. Such engines are very versatile.
<P>However, there are four main problems with the z-buffer:
<OL>
<LI>Clearing the zbuffer
<LI>Re-writing pixels that have already been written (overdraw)
<LI>Z-compression with distant objects
<LI>Jumping at every pixel!
</OL>
<H3><FONT COLOR=YELLOW><I>Improvements</I></FONT></H3>
<P>There are a number of improvements we can make to the z-buffer algorithm. The first is to use 1/z values. Such values are
linear in screen space, are always in the range -1 to +1, and do not suffer from z-compression. Clearing the zbuffer simply
becomes a case of memset(zbuffer, 0, zbuffersize), because 0 in floating point is 00000000h. We must however invert our
condition, from:
<CENTER><P><TABLE WIDTH=65% CELLPADDING=0 CELLSPACING=0>
<TR><TD>
<TABLE><TR><TD>
<PRE><FONT COLOR=#FF0000 FACE=Courier SIZE=2>
If CurrentZ <= ZBuffer[y][x]
To:
If CurrentZ >= ZBuffer[y][x]
</FONT></PRE>
</TD></TR></TABLE>
</TD></TR>
</TABLE></CENTER>
<p>An advantage of using 1/z is that operations can be done in parallel with the FPU. So for example while you are stepping
through your Z in the FPU, you can be calculating the next address, decrementing your counters etc in the IPU.
<P>The penalty of clearing the Z-buffer can be improved with dirty rectangles. The idea behind this is that you just clear the part of
your screen (and Z-buffer) that you have written to. However, this is not much use if you're doing full screen animation.
Alternatively, you can try adding some value to your Z every frame. Eg if you are using a 32-bit integer zbuffer, try adding on a
value greater than the far clipping limit; for example 65536. Apparently, using this technique, you can avoid clearing the frame
buffer. I think pseudo code would go something like:
<CENTER><P><TABLE WIDTH=65% CELLPADDING=0 CELLSPACING=0>
<TR><TD>
<TABLE><TR><TD>
<PRE><FONT COLOR=#FF0000 FACE=Courier SIZE=2>
// Init Stuff...
zadd = 0
ClearZBuffer()
for(;;) { // Render loop
Project, Transform, Light Polygons etc...
Clear Screen
Add "zadd" to every Z value to be interpolated
Render to zbuffer
Add 65536 to zadd
if zadd overflows {
ClearZBuffer
zadd = 0
}
}
</FONT></PRE>
</TD></TR></TABLE>
</TD></TR>
</TABLE></CENTER>
<P>Using this method, you can avoid clearing your buffer for literally hours, if you select the correct value. For those of you (like
me) who use a floating point 1/z representation, I think this may still work; but I'm not sure if you have to do 1 / (z + zadd) or
(1 / z) + zadd. Here I would expect a zadd increment of 1 should work well.</P>
<!--Bottom Navigation-->
<A NAME="bottom"></A>
<!--End Bottom Navigation-->
</STRONG>
</FONT>
<!--End Body-->
<!--Bottom-->
<BR>
<IMG SRC="gradbar.jpg">
<BR>
<FONT SIZE=2 COLOR=#8B8B8B FACE=Helvetica>
<I><font color="#FBFBFB">T</font><font color="#F7F7F7">h</font><font color="#F3F3F3">e</font><font color="#EFEFEF"> </font><font color="#EBEBEB">G</font><font color="#E7E7E7">a</font><font color="#E3E3E3">m</font><font color="#DFDFDF">e</font><font color="#DBDBDB"> </font><font color="#D7D7D7">P</font><font color="#D3D3D3">r</font><font color="#CFCFCF">o</font><font color="#CBCBCB">g</font><font color="#C7C7C7">r</font><font color="#C3C3C3">a</font><font color="#BFBFBF">m</font><font color="#BBBBBB">m</font><font color="#B7B7B7">i</font><font color="#B3B3B3">n</font><font color="#AFAFAF">g</font><font color="#ABABAB"> </font><font color="#A7A7A7">M</font><font color="#A3A3A3">e</font><font color="#9F9F9F">g</font><font color="#9B9B9B">a</font><font color="#979797">S</font><font color="#939393">i</font><font color="#8F8F8F">t</font><font color="#8B8B8B">e</font> -
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -