📄 engine07.shtml
字号:
*/</font>
.
.
.
cPatch <font color="navy">*</font>pSrc<font color="navy">, *</font>pDest<font color="navy">, *</font>pNext<font color="navy">;</font>
<font color="blue">double</font> FF<font color="navy">,</font> deltaRad<font color="navy">;</font>
<font color="blue">while</font><font color="navy">( (</font> pSrc <font color="navy">=</font> FindBrightestPatch<font color="navy">() ) !=</font> NULL <font color="navy">) {</font>
<font color="blue">for</font><font color="navy">(</font> pDest <font color="navy">=</font> pPatchList<font color="navy">;</font> pDest<font color="navy">;</font> pDest <font color="navy">=</font> pNext <font color="navy">) {</font>
pNext <font color="navy">=</font> pDest<font color="navy">-></font>d_pNext<font color="navy">;</font>
FF <font color="navy">=</font> FormFactor<font color="navy">(</font> pSrc<font color="navy">,</font> pDest <font color="navy">);</font>
<font color="blue">if</font><font color="navy">( !</font>FF <font color="navy">)</font> <font color="blue">continue</font><font color="navy">;</font>
deltaRad <font color="navy">=</font> pSrc<font color="navy">-></font>d_deltaRad <font color="navy">*</font> pDest<font color="navy">-></font>d_reflect
<font color="navy">*</font> FF <font color="navy">*</font> H <font color="navy">*</font> pSrc<font color="navy">-></font>d_area <font color="navy">/</font> pDest<font color="navy">-></font>d_area<font color="navy">;</font>
pDest<font color="navy">-></font>d_deltaRad <font color="navy">+=</font> deltaRad<font color="navy">;</font>
pDest<font color="navy">-></font>d_rad <font color="navy">+=</font> deltaRad<font color="navy">;</font>
<font color="navy">}</font>
<font color="navy">}</font>
.
.
.
<font color="green">
/* There's an extra multiply and divide that could
* also be removed but I left it in because
* src.area/dest.area is a ratio, it's easier to
* understand what's going on.
*/</font>
<font color="blue">double</font> FormFactor<font color="navy">(</font> cPatch <font color="navy">*</font>pSrc<font color="navy">,</font> cPatch <font color="navy">*</font>pDest <font color="navy">) {</font>
<font color="blue">double</font> H<font color="navy">,</font> angle1<font color="navy">,</font> angle2<font color="navy">,</font> dist<font color="navy">,</font> factor<font color="navy">;</font>
cVector3 vec<font color="navy">;</font>
H <font color="navy">=</font> LineOfSight<font color="navy">(</font> pSrc<font color="navy">,</font> pDest <font color="navy">);</font>
<font color="blue">if</font><font color="navy">( !</font>H <font color="navy">)</font> <font color="blue">return</font> <font color="red">0.0</font><font color="navy">;</font>
vec <font color="navy">=</font> pDest<font color="navy">-></font>d_center <font color="navy">-</font> pSrc<font color="navy">-></font>d_center<font color="navy">;</font>
dist <font color="navy">=</font> vec<font color="navy">.</font>Length<font color="navy">()</font><font color="navy">;</font>
vec <font color="navy">/=</font> dist<font color="navy">;</font>
angle1 <font color="navy">=</font> vec <font color="navy">|</font> pSrc<font color="navy">-></font>d_pPoly<font color="navy">-></font>GetNormal<font color="navy">()</font><font color="navy">;</font>
angle2 <font color="navy">=</font> <font color="navy">-(</font> vec <font color="navy">|</font> pDest<font color="navy">-></font>d_pPoly<font color="navy">-></font>GetNormal<font color="navy">() )</font><font color="navy">;</font>
factor <font color="navy">=</font> angle1 <font color="navy">*</font> angle2 <font color="navy">*</font> pDest<font color="navy">-></font>d_area <font color="navy">*</font> H<font color="navy">;</font>
factor <font color="navy">/=</font> PI <font color="navy">*</font> dist <font color="navy">*</font> dist<font color="navy">;</font>
<font color="blue">return</font> factor<font color="navy">;</font>
<font color="navy">}</font>
</pre>
<font face="arial" size="-1">
Often when rendering large models it's a good idea to see the work in progress so that you can stop if it
isn't going quite as planned. Rendering patches to the screen shouldn't prove to be a big challenge for
you battle hardened 3D veterans but there will be little problem: at the start of the program the light
level for most polygons will be zero! The solution is to compensate by adding the <i>global ambient</i>
term to each patch as it is being rendered. Note that the global ambient term is <b>ONLY</b> for rendering
while calculating because it will approach zero as the calculation nears completion. The global ambient
term is calculated thusly:<br>
</font>
<pre>
<font color="green">/* Ambient term calculation. Reflective term can be
* used later to speed up ambient term updates
* and prevent infinite looping.
*/</font>
cPatch *</font>pPatch<font color="navy">, *</font>pNext<font color="navy">;</font>
<font color="blue">double</font> ambient<font color="navy">,</font> reflect<font color="navy">,</font> area<font color="navy">;</font>
ambient <font color="navy">=</font> <font color="red">0.0</font><font color="navy">;</font>
reflect <font color="navy">=</font> <font color="red">0.0</font><font color="navy">;</font>
area <font color="navy">=</font> <font color="red">0.0</font><font color="navy">;</font>
<font color="blue">for</font><font color="navy">(</font> pPatch <font color="navy">=</font> pPatchList<font color="navy">;</font> pPatch<font color="navy">;</font> pPatch <font color="navy">=</font> pPatch <font color="navy">) {</font>
pNext <font color="navy">=</font> pPatch<font color="navy">-></font>d_pNext<font color="navy">;</font>
ambient <font color="navy">+=</font> pPatch<font color="navy">-></font>d_deltaRad <font color="navy">*</font> pPatch<font color="navy">-></font>d_area<font color="navy">;</font>
reflect <font color="navy">+=</font> pPatch<font color="navy">-></font>d_reflect <font color="navy">*</font> pPatch<font color="navy">-></font>d_area<font color="navy">;</font>
area <font color="navy">+=</font> pPatch<font color="navy">-></font>d_area<font color="navy">;</font>
<font color="navy">}</font>
reflect <font color="navy">/=</font> area<font color="navy">;</font>
<font color="green">// <= 0 - almost all walls black
// >= 1 - all walls white, infinite loop.</font>
<font color="blue">if</font><font color="navy">(</font> reflect <font color="navy"><=</font> <font color="red">0.0</font> <font color="navy">||</font> reflect <font color="navy">>=</font> <font color="red">1.0</font> <font color="navy">)</font> return<font color="navy">;</font>
reflect <font color="navy">=</font> <font color="red">1.0</font> <font color="navy">/ (</font> <font color="red">1.0</font> <font color="navy">-</font> reflect <font color="navy">);</font>
ambient <font color="navy">*=</font> reflect <font color="navy">/</font> area<font color="navy">;</font>
</pre>
<font face="arial" size="-1">
Now that you know everything you need for your first radiosity processor, let's take a look at some ways to speed
things up and avoid pitfalls.<br>
<br>
<hr>
<b>Patches: Triangles or Rectangles?</b><br>
<br>
There are two basic options for splitting polygons into patches: triangles and rectangles. I tried
triangles first because<br>
<ul>
<li>Their area is easy to calculate.
<li>Their corners are (relatively) easy to calculate.
<li>The triangle patches stay exactly within the boundaries of the region of the light map of the polygon
they're associated to. Go ahead, say it six times fast, I dare you. P:
<li>When <i>subdividing</i> a patch into smaller pieces I could use the middle of each edge as the points
for the new vertexes, giving me four new patches exactly 1/4 the size. The added advantage here was that
if the original patch was very tall and very narrow (not good) then each of the sub patches would be 1/2
the size and 1/2 the width, bringing them gradually closer to right angled (better).
</ul>
They were great for a brief time but I quickly realized why they weren't used in games like quake and
half-life: <i>They look like crap</i>. So I switched to square patches and discovered many advantages.
<ul>
<li>Square patches are even easier to subdivide.
<li>They don't require information on where the corners are, just the width and height so they save time
and ram. Schwinnng! <i>Party on Wayne. Party on Garth.</i>
<li>Converting square patches back into light maps is a lot simpler - you don't have to rasterize triangles
or worry about floating point imprecision.
<li>Squares are much better area to approximate over than irregular triangles, so results would be more
accurate.
<li>They don't look like crap.
</ul>
<hr>
<b>Pitfalls</b><br>
<br>
Radiosity really had me stumped at first and I kept screwing with just about every piece of code I could
until I stumbled upon the solution and, of course, it wasn't where I expected at all. So here are a few
of the setbacks I encountered and what to do about them:<br>
<br>
<ul>
<li><b>I have no idea what the hell is going on...</b> Try starting with a simpler model. The first
radiosity images were of a cube with a lit ceiling (think of the cheap halogen light panels at school).
Always remember to start simple. After all, you did and look! You're almost nearly perfect! (:
<li><b>Everything is way too dark, except the light source!</b> This could be one of two problems:
<ol>
<li>Your patch reflect value is way too low. I find a value of around 0.55 to 0.75 in the models I've
tested so far.
<li>Your patches are too big. The smaller the patches, the more accurate the image. A good way to gauge
the amount of inaccuracy is to sum the total light that actually reaches the destination patches and
compare that to the amount of light that left the source patch. You'll see that the number starts
frighteningly large and drops in a k/n<sup>2</sup> fashion if your patches are too big.
</ol>
<li><b>Things are so SLOOOW!</b> The greater the detail, the slower the calculation. Et la vie, elle pu
de temps en temps. Squeeze every possible ounce out of your optimizations as you possibly can.
<li><b>There's a tiny patch in front of a big patch and the big patch is completely black!</b> (or)
<li><b>There's a tiny patch in front of a big patch, why doesn't the tiny patch cast a shadow?</b> Your
line of sight test isn't catching this situation correctly. Or perhaps it is, but not returning the
correct fraction. It's this visibility problem that keeps scientists employed.
</ul>
<hr>
<b>Faster, faster! OH, YES! YES!</b> *ahem*<br>
<br>
How to go faster can be summed into three categories.<br>
<br>
<b>Adaptive Subdivision</b> is a really neat trick. Instead of cutting your initial polygons into teeny
tiny itsy bitsy eeny weeny (yellow polka dot bikini...) patches try starting with somewhat larger patches.
When you're sending light to the patch, check to see if the radiosity gradient is too high across the
surface (if the change in light is too high). If it is, split
the patch into smaller pieces.<br>
<br>
<center><img src="0708.jpg" width="428" height="128" border="0" alt="Adaptive subdivision"></center>
<br>
<b>Elements</b> are another good idea for your calculator. Each element contains a certain number of adjacent
patches. Only <b>send</b> from the elements but <b>catch</b> the light with the patches, which then report
the change in delta radiosity to their element. I made one element for every four patches, thus saving myself
1/4 the work. Granted, it will widen the margin of error but by so little that it shouldn't matter. Also be
careful that when you design your elements that they won't cause problems with adaptive subdivision, I had
trouble getting them to play nice together.<br>
<br>
<b>Hemicubes</b> offer a distinct speed improvement and are by far the most touted, though why this is I don't
really know, they seem way too prone to error for my taste. I'll write more about them after I get a chance
to try them.<br>
<br>
<hr>
<br>
Wasn't that fun? I didn't think so either. I finished my first radiosity calculator in nine days
without eating, sleeping or taking care of personal hygiene 'cause I had a deadline to meet. Can you tell
it's 0400 where I live?<br>
<br>
...Since we've been talking about reflective surfaces, it seems only appropriate that we delve into mirrors
next!
<br>
<br>
<a href="#top">Back to the top</a>
<hr>
<b>PREV: <a href="Engine06.shtml">Possible Visible Set</a></b><br>
<b>NEXT: <!--a href="Engine08.shtml"-->Mirrors</a></b><br>
<br></font>
</td></tr></table>
</td>
</tr>
</TABLE>
<HR ALIGN="CENTER" SIZE="1" WIDTH="700" NOSHADE>
<FONT FACE="arial" SIZE="-2">All photos copyright of their respective owners. All other content of this website is © 1997-1999 Dan Royer.<BR>
Designed for IE 5.0+, 800x600x16 or greater. Some pages use style sheets.<br>
<A HREF="http://members.home.com/droyer/index.html"
TITLE="Dan's Homepage">http://members.home.com/droyer/index.html</A><br>
</FONT>
</CENTER>
<BR>
<BR>
</BODY>
</HTML>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -