Tutorial: visible (laser) light beams with povray

rendering result

In order to dive into the world of povray, I chose the above experimental setup which is actually used for measuring the Raman shift. Google quickly came up with a reference source. However, the source is neither documented, nor explained. Hence, I'm trying to give a short introduction for newbies like me.

The Concept

First of all, you should get the central idea: we simulate the visible laser beam by scattering within an otherwise invisible medium. Actually, this scattering is the reason, why you can see sufficient intense laser light or sunlight passing through the window panes into a dark room. Unfortunately, this is a computational demanding task, so you should use some decent hardware for rendering. The picture above took some 25 minutes to render.

The Medium

As mentioned before, the medium has to scatter the laser light but should be unnoticable otherwise. In particular, it has to be transparent. Let's have a look at how it's done:

// the declare statement is necessary for later reference
#declare transparent_with_media = material{
// stores information about the appearance
	texture {
		pigment { 
// rgbt defined the transmission depending on the color component in the RGB specification
// Hence, rgbt<1, 1, 0> would block blue light. Here, the medium is transparent for
// all color components equally.
			rgbt 1 
		}
// This block controls the reaction of the material on exterior light--both for the
// light sources you defined and the ambient light. In fact, these settings make the 
// medium hide from any ambient light. However, this is not enough to diminish stray
// light scattering from your light sources. We will come back to this point later on.
// see http://www.povray.org/documentation/view/3.6.2/79/#l34
		finish {
			ambient 0
			diffuse 0
		}
	}
// In general, povray only deals with shapes, not with filled objects. As we need the
// scattering to be ubiquitous, we have to define the inner material and both its 
// properties and reaction to incoming light.
	interior{
		media {
// The interesting part ;)
			scattering {
// There are a few scattering types, which differ in the angular dependency of the
// scattering intensity. In our case, the laser beam has the same scattering intensity 
// in most directions. (Don't ever try to check for angular dependency of the 
// intensity with your eyes!) Therefore, we will use isotropic scattering.
// see http://www.povray.org/documentation/view/3.6.1/420/
				1, 
// As this is virtual reality, you can define the light of the scattered light.
// This line implies no change of the incident light at all.
				rgb <0.1, 0.1, 0.1>
// If you want to model a dusty room, you should raise the value of the extinction
// parameter. Hopefully, your optical table is clean enough to justify this rather 
// low value. This parameter describes how fast the intensity of the ray decreases 
// within the medium. You may identify this value with the extinction coefficient
// in the Lambert-Beer law.
				extinction 0.000001
			}
// Raytracing in general is computational expensive. And calculating scattered light
// is even more expensive. Hence, povray uses spatial samples. You can think of 
// these samples as some kind of calculation density. If you increase the number,
// you will get better results at higher costs. The first value denotes the minimum
// you allow povray to use, whereas the second one represents the maximum.
// If you observe intensity oscillations in your resulting image, increase this value.
			samples 20,50
		}
	}
}

Let there be light!

Now we have a transparent nothing right in the void of \mathbb{R}^3. All you need is -- light.

// Again, this is virtual reality. Hence, we can restrict light sources to illuminate
// only certain objects and we can make any medium to refrain from scattering certain
// light. If you put objects into one light group together with light sources then, by 
// default, the light sources will only affect these specific objects.
light_group {
// Create laser light
	light_source {
// Position
		<19, 5, 40>
// Color and intensity multiplicator
		color Green*3
// Usually, a laser has a gaussian beam profile. This type of povray light source
// has the same property. "parallel" would be an alternative--without the gaussian
// beam profile.
		cylinder
// direction of your laser
		point_at <-1, 5, 40>
// Size and properties of the gaussian beam profile
		radius 5
		falloff 5
		tightness 5
// Without this block, you would only get an illumination of the medium until the
// beam has reached the first mirror, as the default is no reflection. Did I 
// mention the high computational costs of raytracing?
		photons {
			reflection on
		}
	}
// You may have wondered, why the medium had no position. Well, we only defined
// its basic properties and apppearance. Here, we define several boxes and merge
// them into one object (the medium). You should make these boxes as small as 
// possible. (Remember the argument concerning the samples parameter above?)
// Do not define overlapping boxes--you will get strange results.
	merge {
// Edge points of the boxes
		box{<0,0,30>,<20,10,50>}
		box{<0,0,-50>,<10,10,30>}
		box{<10,0,-50>,<80,10,30>}
// As I mentioned above, povray works on shapes not on filled objects. However,
// it knows a way to work with filled objects. This line activates this process.
		hollow
// This is the reference of the material mentioned before.
		material {
			transparent_with_media 
		}
// Hollow objects tend to be rather difficult for photons to cross. Hence, we
// have to override povray's default behaviour.
      		photons {
			pass_through
		}
// This line has no effect on the result, as we have defined the material to
// be transparent. This is just a hint to povray which speeds up the raytracing.
		no_shadow
	}
// Besides the laser, we will need some more light sources. But we do not want
// to have scattering from these light sources in our material. This line
// tells povray to disable illumination of any object in this light_group 
// from any light source despite the one in this light_group.
	global_lights off
}

Objects and Objectives of Two Kinds

Of course, we need some mirrors target and lenses. And some more enlightenment by light sources.

// more light
light_source { 
// position
	<80, 50, 40> 
// do I need to explain this line? ;)
	color White 
// The scenery is more realistic, if we allow for reflections from the mirrors,
// as there will be a plane added to the setup.
	photons {
		reflection on
	}
// Just to make sure that we don't get the wrong scattering from the medium.
	media_interaction off
}
// The last light source, I promise!
light_source {
// position
	<50, 50, 0> 
// color and intensity as factor
	color .2*White
// As this light source is only for ambient light, we should suppress
// shadows--otherwise each mirror would have another shadow.
	shadowless
// We don't want this light source to give scattered light, either.
	media_interaction off
}
// notation for combining several expressions
object{
// povray primitive--does exactly what you assume
	box {
// first coordinate
		<0,0,0>, 
// second coordinate (keep in mind that all edges are parallel to either
// the x, y or z axis)
		<1, 10, 10>
// Objects are initialized in the origin of the internal coordinate system.
// As rotations are around the axes, so it's easier to add the translation 
// after the rotation
		rotate <0, 45, 0>
		translate <0, 0, 37>
	}
// add reflective texture
	texture {
		Silver_Metal
	} 
// The texture is only a part of the solution. We need to tell povray that this
// surface reflects incident light
	finish { 
		reflection {1} 
// On the other hand, you can see stray light in the mirror...
		ambient .2 
		diffuse .2 
// For completeness sake, this line ensures that the outgoing light of the mirror
// has at most the intensity of the incident light. Strictly speaking, this should
// only be necessary in case you allow the mirror objects to transmit a fraction of 
// the incident light. This is not the case in this setup.
		conserve_energy
	}
	photons{
// If you omit this line, you won't get any reflections, as povray tries to minimize
// computational effort and, therefore, only does the calculations for reflections
// when this flag is set.
		target
// well...
		reflection on
// If you expose a glass to direct sunlight, you can observe beautiful patterns of 
// bright lines on the table. They are due to the same reason that is causing the
// typical bright lines on the bottom of a swimming pool. These patterns are called
// caustics. povray can deal with them and although they are computational expensive,
// it does so by default. As this object is a mirror, you won't see them that good.
// Hence, we should turn them off...
		collect off
	}
}    
// The following objects are mirrors just like the one before, so I won't repeat myself.
object{
	box {
		<0,0,0>, 
		<1, 10, 10>
		rotate <0, 125, 0>
		translate <0, 0, -30>
	}
	texture {
		Silver_Metal
	} 
	finish { 
		reflection {1} 
		ambient .2 
		diffuse .2 
		conserve_energy
	}
	photons{
		target
		reflection on
		collect off
	}
}  
object{
	box {
		<0,0,0>, 
		<1, 10, 10>
		rotate <0, -10, 0>
		translate <80, 0, -10>
	}
	texture {
		Silver_Metal
	} 
	finish { 
		reflection {1} 
		ambient .2 
		diffuse .2 
		conserve_energy
	}
	photons{
		target
		reflection on
		collect off
	}
}
// our target -- you already know all keywords
box {
	<0,0,0>, 
	<1, 10, 10>
	rotate <0, 0, 0>
	translate <25, 0, -10>
	pigment { Black }
}

// the lens
// see http://www.f-lohmueller.de/pov_tut/x_sam/sam_410d.htm for an detailed explanation
#declare R = 15;
#declare Over= 1.8;
intersection{
	sphere{
		<0,0,0>,
		R
		translate <0,0,-R+Over>
	}
	sphere{
		<0,0,0>,
		R
		translate <0,0, R-Over>
	}
	texture{ 
		T_Glass3 
	}
	interior{ 
		I_Glass
	}
	rotate <0,90,0>
	translate < 40,5,-5>
	photons{
		target
		reflection on
		refraction on
	}
}

// the optical table
plane { 
// position
	<0, 1, 0>, 
	-2
	pigment {
		White
	}
}
// the laser box
object {
// there is a convenient method to produce boxes with round edges
	Round_Box(<0,0,0>, <30, 10, 20>, 1, 1)
	translate <20, 0, 30>
	texture {
		pigment { 
			MandarinOrange 
		}
	}
}

Header

In order to complete the file, we have to import some definitions and define the camera position. Now, the example is complete. If you copy everything into one file (this last section should be the first one), you will get a valid input file for povray. Have fun!

// for White, MandarinOrange, ...
#include "colors.inc"
// remember the lens?
#include "glass.inc"
// remember the mirrors?
#include "textures.inc"
// the rounded box...
#include "shapes.inc"

global_settings { 
// add some global light without any light source
	ambient_light rgb<1, 1, 1> 
// performance settings.
	photons {
// defines the density of the rays in raytracing.
		spacing 0.2
// Sometimes povray is wrong with the assumptions whether it may or
// may not stop the calculations. This flag turns this behavior off.
		autostop 1
// See the computation density above
		media 60
// If a photon hits a mirror (or anything reflective, transmissive, etc.), it
// gets deflected. However, for some cases (as glass), this may require adding
// some more photons to the computation. In order to keep the computational needs
// low, you should give a hint, how deep this nesting should be. In general, this
// number should be as low as possible. In this setup, you can simply count the 
// steps. The lens has to be counted twice.
		max_trace_level 6
	}
}
// From which position do we look at the setup?
camera {
	location <50, 100, -100>
// where to look at
	look_at <35, 0, 5>
// Opening angle of the camera. In this case used in order to use most of the
// rendered image space.
	angle 40
}

You may also like...

9 Responses

  1. Alina says:

    Thank you, this is a great tutorial! I just start using the Pov-Ray and your example is very useful and clear. I try to repeat it, but the first mirror doesn't reflect the light. I can'tunderstand, why I get different output, because I didn't change the code! Can it be because I use AutoRender?
    Thank You,
    With best regards,
    Alina

  2. Guido says:

    Hi Alina,
    AutoRender (the PovRay render queue, I presume) should not have any effect on this. What version of PovRay are you using? Perhaps some of the default values have changed since I did this. In particular, check the reflection properties of the light source (for the green laser here) and target as well as reflection properties of the mirrors.
    Best,
    Guido

  3. David says:

    Thank you for this introduction as to how one can get a visible beam. I, however, had a hard time making it work. It happened to me the same that happened to Alina, and the beam won't be refracted by any kind of refractive medium. It just makes the beam disappear when it traverses through and reappears again, unaffected. What could be the reason behind it?
    Thanks in advance.
    David

  4. Oliver says:

    It seems to have something to do with the light_group. If I remove just that command (and the brackets) everything works. The result looks slightly different (the reflections seem a little bit off), but I guess, this has other reasons.
    As an alternative, you can try putting the mirrors into the light_group

  5. Michael says:

    Thanks Guido for this really beautiful scenery and the comments. I encountered the same problems as stated by the previous users (apparently the image has some slightly different camera and/or light source Settings, so the "error" is less visible). Anayway, after playing around for a while (I am a total newbie in Povray), the problem lies in the ínitial beam path (bevor it hits the first object, i.e. the first mirror). There is a simple yet not sofisticated solution to that:
    (1) One just has to reverse the laser light direction (replace the following subsection)...:
    ...
    light_source {
    // Position

    // Color and intensity multiplicator
    color Green*3
    // Usually, a laser has a gaussian beam profile. This type of povray light source
    // has the same property. "parallel" would be an alternative--without the gaussian
    // beam profile.
    cylinder
    // direction of your laser
    point_at
    ...

    (2) and add a really thin mirror just in front of the laser box (just append the following object)...:
    object{
    box {
    ,

    rotate
    translate
    }
    texture {
    Silver_Metal
    }
    finish {
    reflection {1}
    ambient 0
    diffuse 0
    conserve_energy
    }
    photons{
    target
    reflection on
    collect off
    }
    } ...
    (3) increase the "max_trace_level" to 7

    One small issue remains: In the current scenery, the laser light source can be seen as a purple "artefact"... I leave that Problem to the pro's

    /Michael

  6. Michael says:

    Sorry, somethinf went missing: here are the laser source position and direction:
    Position

    point_at

  7. Michael says:

    One last try::

    19.998, 5, 40
    point_at 20, 5, 40

  8. Søren Roesgaard says:

    Hi.
    I cannot get the solution from Michael to work.

    Could you please try to render render it again with povray 3.7?
    or maybe upload you .pov file?

  9. Bram Mooij says:

    Thanks Guido for the introduction and the extensive comments. My experience was similar to that of Oliver. The light group doesn't work properly, Removing the light group (don't forget to get rid of the "global_lights off" in there. And everything works in POV-ray 3.7.

Leave a Reply

Your email address will not be published.