⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lflare.htm

📁 关于windows游戏编程的一些文章还有相关图形
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<HTML>
<HEAD>
	<TITLE>The Art of Modeling Lens Flares, by Michael Tanczos</TITLE>
</HEAD>

<BODY bgcolor="#FFFFFF">

<center>
<table border="0" cellspacing="0" width="90%">
<tr><td>

<font face="arial">

<center><h2><font color="#BBBBBB">The Art of Modeling Lens Flares</font></h2></center>
<br>
Version: 1.0<br>
Date: February 20, 1999<br>
Copyright (C) 1999 by Michael Tanczos<br><br>

<font size="+1"><u>Introduction</u></font><br><br>

A few authors recently have discussed methods of alpha blending. For those of you who are clueless as to what alpha blending
is, I'd suggest reading some of the other alpha blending tutorials on gamedev.net for a more extensive overview. This will be a
tough article to work through, and will require a lot of effort on your part to learn everything involved with creating beautiful
flares, but the results will be well worth the effort.<br><br><br>

<font size="+1"><u>Alpha Blending</u></font><br><br>

The basic break-down of the effect is to split up two colors, source1 and source2, into their
RGB components. You then take percentages of each color component (usually on a 0..255 scale), and add them up to create
a destination color component :<br><br>

Figure 1.<br>
<center>
<table border="0" cellspacing="0" cellpadding="10" bgcolor="#EEEEEE">
<tr><td>
<font face="courier" size="-1">
<br>
Dest_r = ((source1_r * alpha) + (source2_r * (255-alpha))/255<br>
Dest_g = ((source1_g * alpha) + (source2_g * (255-alpha))/255<br>
Dest_b = ((source1_b * alpha) + (source2_b * (255-alpha))/255<br>
<br>
</font>
</td></tr>
</table>
</center>

<br>
When done correctly, you can overlay one semi-translucent image over another image.
The next section will assume that you already have at least attempted to perform alpha blending.  
<br><br><br>

<font size="+1"><u>Alpha Blending Speed-ups</u></font><br><br>

Now if one were to attempt to perform fast alpha blending, you may find that the
equations in Figure 1 are not too efficient.  Some common speed-ups involve storing
the inverse alpha value into a new variable so that it doesn't have to be recalculated
each time,  ie :<br><br><br>

Figure 2.<br>
<center>
<table border="0" cellspacing="0" cellpadding="10" bgcolor="#EEEEEE">
<tr><td>
<font face="courier" size="-1">
<br>
int inverse_alpha = 255 - alpha;<br><br>

Dest_r = ((source1_r * alpha) + (source2_r * inverse_alpha))/255<br>
Dest_g = ((source1_g * alpha) + (source2_g * inverse_alpha))/255<br>
Dest_b = ((source1_b * alpha) + (source2_b * inverse_alpha))/255<br>
<br>
</font>
</td></tr>
</table>
</center>
<br><br>

Well, this gets rid of at least two subtractions. Still not good enough.. we may
not even find a fast enough implementation of alpha blending in this article, but
we definitely can beat Figure 1.  On to new optimizations..<br><br>

Examining Figure 2, we can clearly see that the biggest drawbacks in speed lie in
the fact that 6 multiplications and 3 divides are performed.  But one thing that
really jumps out is the value 255.  We won't assume that the compiler optimizes
this code in any form and replace the three divides by bit shift operations.
<br><br><br>

Figure 3.<br>
<center>
<table border="0" cellspacing="0" cellpadding="10" bgcolor="#EEEEEE">
<tr><td>
<font face="courier" size="-1">
<br>
int inverse_alpha = 255 - alpha;<br><br>

Dest_r = ((source1_r * alpha) + (source2_r * inverse_alpha)) >> 8 <br>
Dest_g = ((source1_g * alpha) + (source2_g * inverse_alpha)) >> 8<br>
Dest_b = ((source1_b * alpha) + (source2_b * inverse_alpha)) >> 8<br>
<br>
</font>
</td></tr>
</table>
</center>
<br><br>

Ahh, so we've reduced those divides into simple instructions which will execute
quite fast.  But those 6 muls still jump straight out at us.<br><br>

Here is where things get interesting. We can eliminate at least three
multiplications and one subtract instruction by storing our bitmap differently.
The rest of these optimizations will apply only to those who don't need to
constantly modify their alpha values.<br><br>

Lets check out some sample data:<br><br><br>

Figure 3.<br>
<center>
<img src="alphamap.jpg" width=533 height=273 border=0 alt="Alpha Data">
</center>
<br><br>


The color data is simply a composite of the red, green, and blue channels.  You can see 
what those channels would look like in the lower left corner of Figure 4.  I've added the 
coloring so it is easier to distinguish between the three channels, but normally they 
appear in grayscale format.  The alpha data represents the level of translucency that the 
corresponding pixel in the color data should maintain when blitted onto another color 
surface.
<br><br>
Okay, so here is what we can do.  We can use the same amount of space as before with 
minimal-to-no loss in quality.  Simply pre-divide each pixel in the color data by it's 
corresponding alpha component FIRST.  
<br><br>
Figure 5 illustrates how this can be done.
<br><br>

Figure 5.<br>
<center>
<table border="0" cellspacing="0" cellpadding="10" bgcolor="#EEEEEE">
<tr><td>
<font face="courier" size="-1">
<br>
/*<br><br>

In mathematics, you learn something known as an distributive property of real numbers.  We can illustrate that property as :<br><br>

(A + B) C = AC + BC<br><br>

Where A, B, and C are real numbers.<br><br>

Now lets see what that looks like in code by expanding the source 
below :<br><br>

*/<br><br>

int inverse_alpha = 255 - alpha;<br><br>

Dest_r = (source1_r * alpha)/255 + (source2_r * inverse_alpha)/255<br>
Dest_g = (source1_g * alpha)/255 + (source2_g * inverse_alpha)/255<br>
Dest_b = (source1_b * alpha)/255 + (source2_b * inverse_alpha)/255<br>
<br>
</font>
</td></tr>
</table>
</center>
<br><br>


As you can see, Figure 5 is virtually identical to Figure 1.  We simply store the values 
<b>(source1_r * alpha)/255</b>, <b>(source1_g * alpha) / 255</b>, and <b>(source2_b * alpha) / 255</b> in 
our original bitmap format.<br><br>

Also, our original bitmap format will include some sort of alpha channel.  As you can see 
in the previous code samples, we are only using it in the line : <br><br>

<b>     int inverse_alpha = 255 - alpha;</b><br><br>

Well, we can simply replace every value in the alpha map by the inverse alpha.  Thereby 
eliminating the need to calculate the value for the inverse alpha.  <br><br><br>


The equation then gets reduced to :<br><br><br>

Figure 6.<br>
<center>
<table border="0" cellspacing="0" cellpadding="10" bgcolor="#EEEEEE">
<tr><td>
<font face="courier" size="-1">
<br>
// Remember that alpha now contains the inverse value (255-alpha)<br><br>

Dest_r = source1_r + (source2_r * alpha) >> 8 <br>
Dest_g = source1_g + (source2_g * alpha) >> 8 <br>
Dest_b = source1_b + (source2_b * alpha) >> 8 <br>
<br>
</font>
</td></tr>
</table>
</center>
<br><br>

Are we done yet?  For all intensive purposes, yes.  I have additional methods of
optimization that I haven't tested yet, so I'd prefer not to introduce them at this
point in time. Don't forget that you may additionally examine the assembly output
of your alpha blending routine, and optimize it by hand.
<br><br><br>

<font size="+1"><u>Lens Flare Translucency</u></font><br><br>

Well, I just explained to you everything you'll need to know about alpha blending.  Now 
put that aside, because for lens flares we will utilize additive blending.  Blending in this 
manner is what causes flares to appear purely white over bright surfaces.  
<br><br>
Additive blending is done in unoptimized form as follows :
<br><br><br>

Figure 7.<br>
<center>
<table border="0" cellspacing="0" cellpadding="10" bgcolor="#EEEEEE" width="400">
<tr><td>
<font face="courier" size="-1">
<br>
Dest_r = source1_r + source2_r <br>
Dest_g = source1_g + source2_g<br>
Dest_b = source1_b + source2_b<br><br>

if (Dest_r > 255) Dest_r = 255;<br>
if (Dest_g > 255) Dest_g = 255;<br>
if (Dest_b > 255) Dest_b = 255;<br>
<br>
</font>
</td></tr>
</table>
</center>
<br><br><br>


There is an assumption made in the above equation that may cause problems if you try to 
implement this directly.<br><br>

We assume that Dest_r, Dest_g, and Dest_b are capable of handling numbers greater than 
255.  One solution could be to leave those values as short 16-bit integers.  Though, there 
may be a better brute-force solution which will allow us to use 8-bit integers and get rid 
of those nasty "if" statements.<br><br>

Create a (<b>256+256</b>) byte look-up table as follows : <br><br><br>

Figure 8.<br>
<center>
<table border="0" cellspacing="0" cellpadding="10" bgcolor="#EEEEEE" width="400">
<tr><td>
<font face="courier" size="-1">

<br>
unsigned char alut [512];<br><br>

for (int i = 0; i &lt; 512; i++)<br>
{<br>
  &nbsp;&nbsp;alut [i] = i;<br>
  &nbsp;&nbsp;if (i &gt; 255) alut [i] = 255;<br>
}<br>
<br>

</font>
</td></tr>
</table>
</center>
<br><br><br>


Here is how the table looks :<br><br>
<b>
alut [0] = 0;<br>
alut [1] = 1;<br>
alut [2] = 2;<br>
...<br>
alut [255] = 255;<br>
alut [256] = 255;<br>
...<br>
alut [511] = 255;<br>
</b><br><br>

Our additive blending equation then is rewritten as follows :<br><br><br>

Figure 9.<br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -