PART 1 - Media basics

One of the greatest features of POVRay 3.1+ is that it can create volumetric effects using media. The media is mostly used to fill the interior of some primitive objects, which are containers for the media. There are three basic types of media. The first type is scattering which calculates how light beams collide with particles in a volumetric texture. This can be used to simulate visible light sources, dusty space in rooms, atmosphere etc. If you want to use media for that, you can expect very long rendering time ... it is very slow, but it can be very useful in some situations. The second type of media effect is emission which is used when you want to make some volumetric effects that are self-illuminated. This light is not real light (like point, spot or area) and for that reason it doesn't illuminate surrounding objects. The third type is absorption which is used to filter the light passing through it. I will explain how you can use these last two types of media effects. For now there will be no tutorial on scattering, but I’ll try to fill this space with another nice tutorial in the future.

Ok, let’s start with a simple example.

Scene

For this first tutorial on media’s emission feature we will create one simple scene.

It contains camera at <0,0,-4> coordinate pointing in z direction, and one sphere at <0,0,0> with a radius of 1. Type this code:

camera {
   location <0,0,-4>
   look_at  <0,0,0>
}

sphere {
   <0,0,0>,1
}

As you can see, there is no light. Why? Because if you use the emission feature of media you don’t need light sources. If you try to render this scene, you will get a black screen, because there are no light sources.

Transparency, hollow & illumination

The next step, before filling the interior with media, is to make the object, which is in this case a sphere, transparent and hollow, and to make it not illuminated with light sources in case you want to use them. Since it will be easier to declare the material before the objects and assign the material to the sphere lately, we will do so.

Let’s start by making the object hollow. Add the line containing hollow word to the sphere, so that POV knows that there will be something inside that sphere (media), and that it shows that media:

sphere {
   <0,0,0>,1
   hollow
}

Now we will declare a material before sphere, which will be applied to the sphere. We will also connect that material to the sphere so that POV knows that the sphere is made out of that material.

Let’s call our material "EMaterial".

#declare EMaterial =
material {
   texture {
   }
}

sphere {
   <0,0,0>,1
   material { EMaterial }
   hollow
}

Ok, now when the renderer knows which material to use for the sphere, we must declare that sphere transparent and not illuminated by light sources.

To make the sphere transparent we will add the pigment keyword in the texture description:

#declare EMaterial =
material {
   texture {
      pigment { color rgb 0 transmit 1 }
   }
}

In case you don’t know, "pigment" is used to describe appearance of the colors on the sphere. "color rgb 0" means that we are using black colored sphere, but since we have "transmit 1" we are also telling to the renderer that the sphere is totally transparent (100%).

Now we will add the finish keyword and let’s turn off the diffuse reflection (diffuse 0) and ambient illumination (ambient 0):

#declare EMaterial =
material {
   texture {
      pigment { color rgb 0 transmit 1 }
      finish { ambient 0 diffuse 0 }
   }
}

Our material and sphere are now prepared to receive some media inside.

Interior and Media

Before we start filling the sphere with media, I want to tell you a few facts which can be very useful.

First, when you build you own scenes make sure that your object which contains media is placed inside hollow objects, otherwise the media will not be visible. It is not enough to make only the sphere that contains the media hollow, you must also make hollow the object which contains the object with the media. For example if you create the sky with one giant sphere and inside that sphere you put another object which contains media, you must also make your giant sphere (sky) hollow.

Second, it is very difficult to achieve desiered effects using media, so you will probably spend a lot of time before getting the desired result. It will be very useful to know how to code the textures in POV, especially how to use patterns, pigment maps, turbulence, black holes etc.

Let’s start with our first media description. We will insert the interior and media keywords is our material description:

#declare EMaterial =
material {
   texture {
      pigment { color rgb 0 transmit 1 }
      finish { ambient 0 diffuse 0 }
   }
   interior {
      media {
      }
   }
}

Remember that the interior description can have as many media descriptions as you want. The interior from POV 3.1 is also used for describing the index of refraction of objects, which we will not use in this scene.

Now we will create our first scene. We will use a simple emission with the yellow color:

#declare EMaterial =
material {
   texture {
      pigment { color rgb 0 transmit 1 }
      finish { ambient 0 diffuse 0 }
   }
   interior {
      media {
         emission <1,1,0>
      }
   }
}

Don’t forget to use the camera and the sphere from the beginning!

Now render the scene. ( Render > Edit Settings/Render > 320x240 resolution is enough > click Render )

As you can see we have a nice sphere filled with yellow media in the middle of our screens.

Density and patterns

Now, we come to the part of this tutorial where you will need some knowledge of using patterns (wrinkles, granite, agate etc.)

To use a pattern in media we have to use density and density_map. As you probably assumed, the density and density map are used to control the density in the media. After calling the density keyword you must type which pattern will be used to control the density of the media. For the first try we will use the wrinkles pattern, first without density_map and later with it.

#declare EMaterial =
material {
   texture {
      pigment { color rgb 0 transmit 1 }
      finish { ambient 0 diffuse 0 }
   }
   interior {
      media {
         emission <1,1,0>
         density {
            wrinkles
         }
      }
   }
}



On the left side you can see the media in the sphere using the wrinkles pattern. On the right side you can see the wrinkles pattern applied to a simple plane, and below these two pictures is the gradient used in the wrinkles pattern, which is in this case the default gradient, but we will change that later.

By using the wrinkles pattern in the density function you can easily create effects like smoke. But since that is not our goal in this tutorial, we will leave that for some other time.

Now we will learn how to use the density_map function. When using the density_map function you can decide which parts of patterns will be used to create the area with more or less density.

First, we will create the same density as above, but with density_map included. Why do we get the same result? Because this type of  gradient is default for wrinkles pattern.

media {
   emission <1,1,0>
   density {
      wrinkles
      density_map {
         [ 0 color rgb 0 ]
         [ 1 color rgb 1 ]
      }
   }
}

"[ 0 color rgb 0 ]" - this means that at the position in which we have the lowest intensity (black color) in the standard wrinkles pattern we want the density to be minimal (0)

"[ 1 color rgb 1 ]" - this means that at the position in which we have the highest intensity (white color) in the standard wrinkles pattern we want the density to be maximal (1)

If you want to achieve an invert effect you must change the density to this:

media {
   emission <1,1,0>
   density {
      wrinkles
      density_map {
         [ 0 color rgb 1 ]
         [ 1 color rgb 0 ]
      }
   }
}

This means that:

"[ 0 color rgb 1 ]" - this means that at the position in which we have the lowest intensity (black color) in the standard wrinkles pattern we want the density to be at maximal (1)

"[ 1 color rgb 0 ]" - this means that at the position in which we have the highest intensity (white color) in the standard wrinkles pattern we want the density to be at minimal (0)

If you render it you will get something like this:

Let’s continue playing with the density mapping. Now we will create a density map in which we have constant low density  from the region in the wrinkles pattern that has the intensity (colors)  from 0% (black) to 50% (gray or rgb 0.5), and high density from 50% of gray to 100% (white color or rgb 1). Our gradient line will look like this:

media {
   emission <1,1,0>
   density {
      wrinkles
      density_map {
         [ 0.5 color rgb 0 ]
         [ 0.5 color rgb 1 ]
      }
   }
}

Intervals and samples (increasing quality of media)

As you can see, there is a high contrast between the areas with high density and the areas with low density. But if you look closer to the picture on the left side (media), you will see that it has some noise. The reason for that noise in media is POV using a small amount of intervals when media occurs. There are two ways to achieve better quality of the media. One is increasing intervals (the default value is 10) and the other is to tell POV to calculate more samples between intervals (default value is 1,1). I most cases I’m increasing intervals because it is faster than using more samples. We will see how these two keywords work in the next two examples.

First we will increase the intervals and we will see what will happen with the media. We will also zoom one part of the media so that we have a closer look on what is happening.

...emission <1,1,0>
intervals 10
density {...
...emission <1,1,0>
intervals 20
density {...
...emission <1,1,0>
intervals 30
density {...
...emission <1,1,0>
intervals 40
density {...

Now you can see how to achieve better quality of the media by increasing intervals. It is obvious that if you are using the default value of intervals (10)  you will get very noisy and low quality pictures, as shown in first picture. The second picture looks much better than the first one because we are using two times more intervals, but it also has some noise. The third and fourth pictures are looking very nice because of more intervals. In most cases you will get nice media when using intervals between 30 and 50 intervals.

We will also try to increase the quality of the picture by increasing samples. Samples are calculated inside every interval, and are defined by two values. The first value specifies the minimum samples taken per interval and the second one the maximum. Let’s render some pictures. Intervals will be switched to the default value (10).

...emission <1,1,0>
   intervals 10
   samples 1,1
   density {...
...emission <1,1,0>
   intervals 10
   samples 2,2
   density {...
...emission <1,1,0>
   intervals 10
   samples 3,3
   density {...
...emission <1,1,0>
   intervals 10
   samples 4,4
   density {...

The last picture, with samples set to 4,4 takes about 1 minute to render. The picture in which we are using "intervals 40" needs the same amount of time to render and the quality of these two pictures is incomparable. This means that in the other parts of this tutorial we will increase intervals to get better quality of our images and media. But, be free to experiment with these two values.

Changing the color of the media using density and pigment_map

Now we will try to change the color in the media using density_map and color change. In the beginning of this tutorial we used the yellow color by setting emission to rgb <1,1,0>. If  you want to use a constant color of media, you only need to declare the color after the emission keyword, but if you wish to map some other colors to patterns used in your media, the only way to do this is to define these colors in density. For this reason we will change the emission color to white. We will also change the pattern to granite, just to show you how other patterns behave with media.

Now change your code to this and render picture:

media {
   emission 0.5
   intervals 30
   density {
      granite
      density_map {
         [ 0 color rgb <1,1,0> ]
         [ 1 color rgb <1,0,0> ]
      }
   }
}

The colors are set in a way in which at the area in the pattern where we have the minimum value, color of media is yellow and at the area in the pattern in which we have the maximum intensity, media color is red. Everything between is the linear interpolation of these two colors. Our media, pattern and gradient will look like this:

Media

Pattern used in media

Gradient used in pattern

Just go and play with patterns and colors in media for some time so that you get the feeling on how to use this features.

PART 2 - Advanced media effects - Creating a space explosion using media

1. THE EXPLOSION RING

We are going to learn some advanced techniques used in the process of constructing appropriate media. This part of tutorial will explain how to use media to create explosions in space. For this, it would be that you already know how to use patterns, and how to map patterns inside other patterns. But I will try to go step by step so that less experienced users can also follow this tutorial.

Let’s start with our scene of space explosion. This is how the scene will look at the end of this tutorial:


The first thing we have to do every time we start building media, is to create containers for the media. In this scene we have two containers. One is for the center of the explosion and the other is for the explosion wave (ring). For the ring we will use a box, and a sphere for the center. The camera and light are also defined. Light is not important here so you can delete it if you want. This is the code for the starting scene:

camera {
   location <0,10,0>
   look_at 0
}

light_source {
   <5,10,-5>
   color rgb 1
}

box {
   <-4.5,-0.2,-4.5> <4.5,0.2,4.5>
   texture { pigment { color rgb 1 } }
   hollow
}

sphere {
   <0,1,0>,3
   texture {
     pigment { color rgb <1,1,1> }
   }
   hollow
}

The next thing we have to do is to make objects 100% transparent and to set the ambient light to 0%. This is all done in the texture statement for both objects:

box {
   <-4.5,-0.2,-4.5> <4.5,0.2,4.5>
   texture {
      pigment { color rgb 1 transmit 1 }
      finish { ambient 0 }
   }
   hollow
}

sphere {
   <0,1,0>,3
   texture {
      pigment { color rgb 1 transmit 1 }
      finish { ambient 0 }
   }
   hollow
}

If you render the scene you will see that it is totally black.  That is because there is no ambient light and transparency is set to 100%. This means that it is time to fill our objects with media. We will first create the media for the box (ring) and then for the center. You already know how to add media to an object so I will not explain that process.

For the ring we will use the spherical pattern because it is the most appropriate solution for this case. The pattern is also scaled 4 times so that its border is 4 units from center. Intervals will be set to 10 (default) for normal quality, and for the final rendering (best quality) we can use intervals from 30-40. Emission is for now set to 1. Let’s see the code and render the first picture:

box {
   <-4.5,-0.2,-4.5> <4.5,0.2,4.5>
   texture {
      pigment { color rgb 1 transmit 1 }
      finish { ambient 0 }
   }
   interior {
      media {
         emission 1
         intervals 10
         density {
            spherical
            scale 4.0
         }
      }
   }
   hollow
}

As you can see the media in the picture is very dark. We can brighten media by increasing emission. Increase emission to 3. The other solution for increasing brightness will be to scale the box object in Y direction, but let’s leave the object as it is and stick to the emission.

media {
   emission 3
   intervals 10
      density {
         spherical
         scale 4.0
   }
}

Now the media looks nice and it is time to code the density map for the ring. Before you start adding entries to the density map, you must know that the location 0.00 in the entry is at the border of the spherical pattern and when you map color on 1.00, it is in the center of the sphere pattern.

At the border of the spherical pattern (0.00) we must have the density of 0% because this last color goes to infinity. At the position near the border (0.10) we will use a density of 100% (white color), and after that at 0.25 units from the border we will again use a density of 0% that spreads to the center (1.00) of the spherical pattern. Because of this, we have a ring made out of media. Type the text below and render the scene to see the effect. I recommend to you that you play a little with these entries in denisty_map to get the feeling of how it works.

density {
   spherical
   density_map {
      [ 0.00 color rgb 0 ]
      [ 0.10 color rgb 1 ]
      [ 0.25 color rgb 0 ]
      [ 1.00 color rgb 0 ]
   }
   scale 4.0
}

To control the thickness of the ring, you must add a new entry to the denisty map, just after the second entry:

density {
   spherical
   density_map {
      [ 0.00 color rgb 0 ]
      [ 0.10 color rgb 1 ]  // outer border of ring
      [ 0.15 color rgb 1 ]  // inner border of ring
      [ 0.25 color rgb 0 ]
      [ 1.00 color rgb 0 ]
   }
   scale 4.0
}

Now you can decrease or increase the thickness of ring by changing the position values of the denisty_map. For example, if you want a thicker ring you will change the code to something like this:

density {
   spherical
   density_map {
      [ 0.00 color rgb 0 ]
      [ 0.10 color rgb 1 ]  // outer border of ring
      [ 0.40 color rgb 1 ]  // inner border of ring
      [ 0.50 color rgb 0 ]
      [ 1.00 color rgb 0 ]
   }
   scale 4.0
}

This was the easy part of the tutorial, and now it’s time to get deeper into the density_map and to map some new patterns inside the spherical pattern. Let’s just start from the border. At the border we can use the granite pattern. To get better contrast, in the granite pattern we will use a gradient from 0.3 to 0.7 with the same color, but the second color will be multiplied by 0.5. The granite pattern is also scaled by 0.05. Scaling is used to get more chaos-noise in explosion. This will not be visible when working with small resolution images, but at resolutions from 800x600 and further this is very noticeable.

density {
   spherical
   density_map {
      [ 0.00 color rgb 0 ]
      [ 0.10
         granite
         color_map {
            [ 0.3 color rgb <0.4,0.25,0.1>     ]
            [ 0.7 color rgb <0.4,0.25,0.1>*0.5 ]
         }
         scale 0.05
      ]
      [ 0.40 color rgb 1 ]
      [ 0.50 color rgb 0 ]
      [ 1.00 color rgb 0 ]
   }
   scale 4.0
}

After the granite pattern at the border we can again use the granite pattern, but with a different set of colors. The color position in the pattern is set to 0.15. But first erase the entries at position 0.40 and 0.50. Change the last entry (1.00) to 0.75 and leave the black color. After you do that, you can continue adding this code:

...
[ 0.15
   granite
   color_map {
      [ 0.3 color rgb <1,0.8,0.45>     ]
      [ 0.7 color rgb <1,0.8,0.45>*0.5 ]
   }
   scale 0.05
]
[ 0.75 color rgb 0 ] // last entry - position changed from 1.00 to 0.75
...

If you render this picture you will get something like this:

Just continue adding more layers to the ring. After the position 0.15 add this entry at 0.25. As you can see we are again using the granite pattern with a different set of colors. If you want, you can also try to experiment with wrinkles or bump patterns. Brighter colors are used in this entry because this is the must powerful point of the wave.

...
[ 0.25
   granite
   color_map {
      [ 0.3 color rgb <1,1,0.7>     ]
      [ 0.7 color rgb <1,1,0.7>*0.7 ]
   }
   scale 0.05
]
[ 0.75 color rgb 0 ]
...

After this we must create stripes pointing to the center of the explosion to simulate the expansion of the ring.  This can be done using a granite pattern with a black hole. Since one black hole is not enough, we will use several black holes, but to make things more simple and flexible we will write a macro that does this. If you don’t know what a black hole is,  please consult POV’s documentation for an explanation.

"warptexture" is the name of our macro, and input parameters are:

For example, if you have a plane with the granite pattern and you want to use 5 black holes at position <0,0,0> with the radius of 4, falloff of 2, strength of 1 you will call this macro like this:

plane {
   y,0
   texture {
      pigment {
         granite
         warptexture (5,2,1,<0,0,0>,4) // <--- call for macro to use black holes
      }
      finish { ambient 1 diffuse 0 }
   }
}

Below you can see three examples of how this macro works. In the first example ‘times’ is set to 1. That means that there is only one black hole applied to the pattern. In the second, ‘times’ is set to 5 and in the third example to 10. You can see that in the third example, when using 10 black holes at the same position, we can get stripes pointing to the center, which we can use for our explosion.

...

warptexture (1,2,1,<0,0,0>,4)

...

...

warptexture (5,2,1,<0,0,0>,4)

...

...

warptexture (10,2,1,<0,0,0>,4)

...

This is the code four our macro:

#macro warptexture(times,fal,strn,pos,rad)
   #local wcounter = 0; // set counter to 0
   #local maxc = times; // number of black holes
   #while (wcounter<maxc)
   warp {
      black_hole pos,rad
      falloff fal
      strength strn
      turbulence 0.4 // some turbulence for the black hole
   }
   #local wcounter = wcounter +1;
   #end
#end

The macro we wrote will be used in the layers below. At position 0.30 and 0.45 the granite pattern is again used. After scaling the granite pattern, we are telling to our macro to get stripes pointing to the center of the explosion. Since at the 0.75 position we have an entry with black color, stripes are fading when approaching position of 0.75 where the black color occurs.  The "warptexture" macro is called using these parameters: "times" is set to 4, but you are free to experiment with higher or lower values; "falloff" is set to 1, same is for "strength"; position is at <0,0,0> and the radius is 3. The radius must be set to a value bigger than the distance from the center of explosion to the world’s position of the entry where the stripes are starting to appear. The distance from the center to the border of the ring is 4, and the position of the entry where the stripes start to appear is 0.30. By using these parameters you can calculate how far is this entry in world’s space: (1-0.30)*4 = 2.8. This means that at the position 2.8 from the center of explosion stripes start to appear. It is recommended for the radius of the black hole to be bigger than this value. Because of that we are setting the radius to 3.

...
[ 0.30
   granite
   density_map {
      [ 0 color rgb <0.4,0.25,0.1>*0.9 ]
      [ 1 color rgb <0.4,0.25,0.1>*1.9 ]
   }
   scale 2
   warptexture(4,1,1,<0,0,0>,3)
]
[ 0.45
   granite
   density_map {
      [ 0 color rgb <0.2,0.05,0.0>*0.5 ]
      [ 1 color rgb <0.2,0.05,0.0>*1.4 ]
   }
   warptexture(4,1,1,<0,0,0>,3)
   scale 2
]
[ 0.75 color rgb 0 ]
...

The rendered picture will look like this:

This is the final ring. By changing the position of the camera we can get a better perspective. Just change the position and point of view to this:

camera {
   location <0,4,-5>
   look_at <0,-1,0>
}

...and increase intervals to something from 30-50 to achieve better quality of media. I’m using intervals set to 40 for pictures below.

    

2. THE CENTER OF THE EXPLOSION

It’s time to make the last step to the final scene. The center of explosion can be made using techniques similar to those we used while creating the ring. This part is simpler than the ring part, but it also requires some experience from the user. Do you remember the spherical and granite patterns we used before. Guess what, they are waiting to be used again.

The first thing you can do is comment out the code for the ring or decrease intervals to a value equal to 10 or lower so you can make faster previews while working on the center of the explosion. For now we will comment out the ring and later we will turn it on so that the center can have an appropriate scale comparing to the wave. Now move your cursor to that empty sphere standing alone without a soul, waiting for true love to come and fill her heart from border to center. And guess who will do that. :-)

Let’s change position of the camera so we can get closer view of the explosion center:

camera {
   //location <0,4,-5>
   //look_at <0,-1,0>
   location <0,3,0>
   look_at <0,0,0>
}
...

Also, add some simple media to our sphere with density using the spherical pattern:

...
sphere {
   <0,1,0>,3
   texture {
      pigment { color rgb 1 transmit 1 }
      finish { ambient 0 }
   }
   interior {
      media {
         emission 1
         intervals 10
         density {
            spherical
         }
      }
   }
   hollow
}
...

This doesn’t look like an explosion. It looks more like a bad stroke with a brush in Photoshop and a noise effect applied. :-) Ok, let’s add some colors to our media to make it look like a decent explosion. As you can see from the code below, we are using four entries to fill the spherical pattern with color. At position 0.00 we are using the black color again, a brown-red color is used at positions 0.20 and 0.40, but at the 0.40 position this color is brighter and at 0.70 we are using a color somwhere between yellow and white to create the core of explosion. Code:

density {
   spherical
   density_map {
      [ 0.00 color rgb 0 ]
      [ 0.20 color rgb <0.6,0.3,0.15> ]
      [ 0.40 color rgb <0.7,0.5,0.3>  ]
      [ 0.70 color rgb <1.0,1.0,0.8>  ]
   }
}

And the rendered picture:

To create more chaos and noise in the explosion we will use a granite pattern and the macro for black holes. The technique for the stripes is the same as the one used in the ring. Let’s change entries at positions 0.20 and 0.40 to this:

...
[ 0.20
   granite
   color_map {
      [ 0 color rgb <0.6,0.3,0.15> ]
      [ 1 color rgb <0.6,0.3,0.15>*0.2 ]
   }
   warptexture(4,1,1,<0,0,0>,1)
]
[ 0.40
   granite
   color_map {
      [ 0 color rgb <0.7,0.5,0.3> ]
      [ 1 color rgb <0.7,0.5,0.3>*0.3 ]
   }
   warptexture(4,1,1,<0,0,0>,1)
]
...

Now change the position of camera again to this:

camera {
   location <0,4,-5>
   look_at <0,-1,0>
}
...

Turn the ring on and render the scene again. As you can see on the picture below, our explosion center is a bit small. This means that we have to scale the center. We will also use the same media again but with a different scale to make the effect look better.

Ok now scale the media, and add some turbulence. We will scale this media in x and z direction by 2.4 and in y direction 0.7. Just add these lines after density_map:

...
scale <2.4,0.7,2.4>
turbulence 0.05
octaves 6
lambda 3
omega 0.8
...

This looks very nice.

A very nice thing about interior is that you can have more than one media inside it. This is what we will use in this case to make the effect more complex. Select the media we created, and then after the first media make another copy. Then, in the second media change scale from:

scale <2.4,0.7,2.4>

... to this:

scale <0.7,2.3,0.7>

As you can see, the only difference between the first and the second media is that the second one is more scaled in y direction.

Our explosion is now finished. Let’s render a small picture and then we will change the position of the camera for a more dramatic situation:

Try experimenting with different positions. The camera I used in the final picture is this:

camera {
   location <0,2,-5>
   look_at <0,0,-1>
   rotate z*30
}

Don’t forget to change the intervals for every media to some value around 40 to get a high quality media. Also be free to experiment with different patterns, scales, colors, and don’t forget to add stars to the picture. I assume that you will use a giant sphere to simulate the stars. Just remember that this sphere must be declared as hollow.

Thank you for your patience, and don’t be very critical because this is my first tutorial. If you have any suggestions and comments feel free to email me.


Toni Bratincevic
E-Mal: tbratinc@foi.hr