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

📄 m_fire.htm

📁 一个很漂亮的火焰源代码
💻 HTM
字号:
<html>
<body>

<body bgcolor=#999999 text=#000000 link="#0000ff" vlink="#000099" background="paper.jpg">
<title> Fire </title>
                                                                                        
<center><h1> Fire </h1></center>
<p><tr><td colspan=2><hr></td></tr><p>

<a href="../graphics/flowfire.zip"><img src="m_fire1.gif" align=left></a>
<dd>I wasn't really sure weather to put this one under Graphics or Models. In the end, I chose
Models because I felt like it. Fire is an extremely hard thing to simulate accurately on a
computer because it is a huge monster 3D fluid dynamic system. To produce an accurate simulation
would require this much (arms stretched wide) computing power, and would certainally not be
possible in real time. Moreover, I haven't the foggiest idea how to do it. It is for these
reasons that I am not going to describe a super accurate model.

<dd>Most of you will have seen the 2D fire effect that was shown off in many demos, and is still
lingering around. I am going to describe and explain this system first, then explain how this
can be taken furthur to create a more pleasing flame.<p>

<dd>You can download the fire I wrote on the left. My apologies to owners of slower computers.
Although it's been optimised a bit (to about twice the speed), it's not yet really fast. It
should run fine on a pentium. It requires <A HREF="../dos4gw.zip">DOS/4GW</a>.<br clear>

<a href="firesrc.zip"><b>source</b></a>
<p>

<dd>Please note that, being a PC programmer, I tend to make this kind of thing in VGA 320x200
screen mode with 256 colours. So I tend to use the words pixel and byte interchangably.<p>

<p><tr><td colspan=2><hr></td></tr><p>

<dd>The idea behind the origional fire effect was simple. The bottom of the screen was constantly
seeded with 'hot' pixels. On each time step, the image was smoothed, darkened and scrolled up
one pixel. These three simple operations, combined with the speckled pixels at the bottom, and
an orangey palette, creates what undoubtedly looks like a flame. Some implementations looked
very good, others just looked like a characterless fire effect. With a little thought, the
fire can be made quite complex, producing those nice toungs of flame you get in real fires. On
this page, I will show you how to make fire with uneven cooling, and convection effects. Because
the fire is a realtime effect, I will be including source code here in (slightly) Pentium
optimised assembler, but not without explaining the process in English and pseudo-code first.

<p><tr><td colspan=2><hr></td></tr><p>

There are several parts to a fire effect. All these are done in an offscreen buffer, which is
then copied over to the screen. The buffer typically consists of an array of bytes. 

<ul>
        <li>The heat source<br>
        <dd>Each frame a few pixels of maximum brightness are placed randomly at the bottom few
        lines of the screen.
        <li>Heat spread<br>
        <dd>Then the image is smoothed. This makes the fire spread as it ages and gives the
        fire body.
        <li>Cooling<br>
        <dd>The flames are then cooled a little by subtracting a small amount from each pixel.
        <li>Convection<br>
        <dd>The image is scrolled up by one pixel. This makes the flames rise.
</ul>


<font size=+1>1. The Heat Source</font>
<dd>The flames can be made to start anywhere on the screen by simply sprinkling a few pixels.
Most implementations had the flame source at the bottom of the screen. You can make the flames
stronger or weaker by plotting lighter or darker pixels respectively. You can make the flames
smoother or more flickery by plotting more or less pixels respectively.<p>

<font size=+1>2. Heat Spread</font>
<dd>The next step is to smooth the image. There are a few ways to do this depending on exactly
how you want the image to smooth. I tried to be really crafty about it, working things out really
mathematically, but in the end, the effect was rubbish. The simplest ways are the best. You can
smooth the image by making each pixel equal to the average of it's four neighbours.<br>

<pre>
                pixel(x,y) = (pixel(x,y-1) + pixel(x,y+1) + pixel(x-1,y) + pixel(x+1,y))
                             -----------------------------------------------------------
                                                        4
</pre>

Simple and fast. I will explain other smoothing techniques later which allow you to make the
convection proportional to the temperature of the pixel.<p>

<font size=+1>3. Cooling</font>
<dd>The cooling is simple and involves subtracting a small amount from every pixel. The exact
amount depends on how quickly you want the fire to cool. Watch out for wrap around. Make sure
the value of the pixel does not go below zero.<p>

<font size=+1>4. Convection</font>
<dd>The basic convection model just scrolls the image up by a pixel or two.<p>

<p><tr><td colspan=2><hr></td></tr><p>

<dd>So that's the basic idea behind the flame effect. Those of you who are even remotely alert
will have noticed that the algorithm described above could be made significantly faster by
combining the smoothing and convection into one. You are indeed correct. Any programmer worth
their salt should see that, so that is where I am going to leave it. What I want to explain is
how to make the fire look really good. (And incidently in this next method the smoothing and
convection are indeed both done at once).

<p><tr><td colspan=2><hr></td></tr><p>
<font size=+2>Uneven Cooling</font>
<dd>The problem with the method above is that the fire tends to look rather boring. The flames
rise linearly, and the whole system cools at exactly the same rate. Any unevenness in the fire
depends on plotting random pixels. 
<dd>One way to give your fire those nice tounges of flame, without relying on careful pixel sprinkling
is to make the flames cool unevenly. Since these flames are to be done in realtime, your best
bet is to create a cooling map.<p>

<h4>Cooling Map</h4>
<img src="coolmap.jpg" align=left>
<dd>Create an array of bytes the same size as the screen, and cover it with some smooth pattern.
A good way to create the pattern is to sprinkle a few thousand pixels of various intensities
onto the screen, then apply several smoothing passes to it (about 20 is good). This map should
be quite dark, intensities ranging from 0 to about 10. 
<dd>Now, rather than subtracting the same small amount from every pixel, values from the cooling
map can be used instead. so:

<pre>
        pixel(x,y) = pixel(x,y) - coolingmap(x,y)
</pre>
<br clear>
<dd>Dark areas on the map will produce bigger flames, and light areas cool the flames quickly.
The best results can be achieved by scrolling the cooling map upwards at the same speed as
the convection. Obviously, if you were to actually program this, you would not physically
scroll the cooling map every frame, but access it by some vertical offset.<p>

<dd>The cooling map actually defines the shape of the flames. You needn't restrict yourself to
a randomly generated map. You can add simple shapes, (pentagrams, skulls, acid house smilies)
to the map. and see them created in flame. The shapes should have low pixel values, and be
surrounded by higher value pixels.<p>

<p><tr><td colspan=2><hr></td></tr><p>

Right, so now we've got that out of the way, it's time for some pseudocode.<p>

<pre>

INTEGER: xsize
INTEGER: ysize
INTEGER: c
INTEGER: n1
INTEGER: n2
INTEGER: n3
INTEGER: n4
INTEGER: p
ARRAY_OF_BYTES: buffer1(xsize*ysize)
ARRAY_OF_BYTES: buffer2(xsize*ysize)
ARRAY_OF_BYTES: CoolingMap(xsize*ysize)

loop forever

  loop y  from 1 to (ysize-2)                   ;Loop through all pixels on the screen, except
    loop x  from 1 to (xsize-2)                 ;the ones at the very edge.

      n1 = read pixel from buffer1(x+1, y)      ;Read the 4 neighbouring pixels
      n2 = read pixel from buffer1(x-1, y)
      n3 = read pixel from buffer1(x, y+1)
      n4 = read pixel from buffer1(x, y-1)

      c  = read pixel from CoolingMap(x, y)     ;Read a pixel from the cooling map

      p = ((n1+n2+n3+n4) / 4)                   ;The average of the 4 neighbours
      p = p-c                                   ;minus c

      if p<0 then p=0                           ;Don't let the fire cool below zero

      write pixel of value p to buffer2(x,y-1)  ;write this pixel to the other buffer
                                                ;notice that it is one pixel higher.

    end x loop
  end yloop

  copy buffer2 to the screen                    ;Display the next frame
  copy buffer2 to buffer1                       ;Update buffer1
  scroll CoolingMap up one pixel

end of loop
</pre>

<p>
<hr>
<font size=+2>The finishing touch</font>
<dd>There is still something missing, life. The flames rise up from their source at a constant
speed. It's as if the fire was burning in space. There's no air. Look at a real fire and you
will see it swirling and flickering. We can add this to our fire.
<dd>All that's needed is some kind of constantly changing flow of air. As is happens, you will
find an article on just this in the graphics section. It is called <a href="../graphics/x_warp.htm">Warp
Feedback</a>.
<p>
<hr>

<font size=+2>More Effects</font>
<dd>Careful placing of the seed pixels can make a fire effect look really good. Rather than
just sprinkling then randomly at the bottom of the screen, try doing other things.<p>

<font size=+1>Sparks</font>
<dd>You can have a few pixels rising up out of the fire, creating little glowing dots like
sparks. In turn, these can pop, giving off a couple more sparks. With time they can dim.<p>

<font size=+1>Fire Balls</font>
<dd>Try throwing the pixels around in a clump. They will move around the screen, leaving a flaming
trail. Make them explode when they hit something. The effect can be quite impressive. 
<dd>On a smaller scale, the fire can even be used as a flame thrower effect for a game. Throw
pixels out of the gun, creating a stunning BBQ weapon.


</body>
</html>

⌨️ 快捷键说明

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