POVRAY CSG modelling

Written by Paul Bourke
February 1998


The following image and accompanying geometry file csg.pov illustrate the basics of the CSG (Constructive Solid Geometry) operations supported by POVRAY. The operations are performed on an intersecting circle and cylinder. Note that while the union and merge appear to give the same result, in the later the interior structure does not exist. This can be demonstrated by doing the rendering using a transparent material.




Bump Maps in PovRay

Written by Paul Bourke
April 2001


Bump maps are a way of creating the appearance of surface detail without needing to create additional geometric detail. This is achieved by purturbing the normals at each point on the surface. Since the normal is used to determine how light interacts with the surface the appearance of the surface is affected. The effect is very powerful, in some of the examples below it is hard to imagine that the surface hasn't been geometrically modified.
The following illustrate some of the procedural bump maps provided by PovRay. Not all the bump maps are shown but the more interesting ones are. This gives a quick visual index when looking for a particular effect. Note that some bump maps create artifacts on the curved surface used below, this is because they are designed for planar surfaces.

agate
#declare thenormal = normal {
   agate
   agate_turb 0.5
   scale 1
}
bozo previously known as spotted
#declare thenormal = normal {
   bozo
   scale 0.1
}
brick
#declare thenormal = normal {
   brick
   brick_size 1
   mortar 0.02
   scale 1
}
bumps
#declare thenormal = normal {
   bumps
   scale 0.2
}
checker
#declare thenormal = normal {
   checker 0.75
   scale 0.6
}
crackle
#declare thenormal = normal {
   crackle 1
   scale 0.5
}
dents
#declare thenormal = normal {
   dents 1
   scale 0.4
}
gradient
#declare thenormal = normal {
   gradient z,1
   scale 0.5
   rotate <0,45,0>
}
granite
#declare thenormal = normal {
   granite
   scale 1
}
hexagon
#declare thenormal = normal {
   hexagon 1
   scale 0.1
}
leopard
#declare thenormal = normal {
   leopard 1
   scale 0.1
}
mandel
#declare thenormal = normal {
   mandel 200,0.5
   scale 2
   rotate <0,90,0>
   rotate <0,0,15>
}
marble
#declare thenormal = normal {
   marble 1
   scale 0.2
   rotate <0,45,0>
}
quilted
#declare thenormal = normal {
   quilted 1
   control0 0.5
   control1 0.5
   scale 0.75
}
radial
#declare thenormal = normal {
   radial 1
   frequency 200
   rotate <70,0,0>
   rotate <0,45,0>
}
ripples
global_settings { number_of_waves 10 }
#declare thenormal = normal {
   ripples 1
   frequency 10
   phase 0
   translate <-0.5,-0.5,-0.5>
   scale 1
   rotate <0,0,45>
}
spiral1
#declare thenormal = normal {
   spiral1 2,1
   scale 1
   rotate <45,0,0>
}
spiral2
#declare thenormal = normal {
   spiral2 1,1
   scale 1
   rotate <45,0,0>
}
waves
global_settings { number_of_waves 10 }
#declare thenormal = normal {
   waves 1
   frequency 10
   phase 0
   translate <-0.5,-0.5,-0.5>
   scale 1
   rotate <0,0,45>
}
wood
#declare thenormal = normal {
   wood 1
   scale 0.1
}
wrinkles
#declare thenormal = normal {
   wrinkles 1
   scale 0.6
}
Scene file: bump.pov
#declare VP = <15,0,0>;
#declare VD = <-1,0.5,0>;
#declare VU = <0,1,0>;

camera {
   location VP
   up y
   right -4*x/3
   angle 60
   sky VU
   look_at VP+VD
}

global_settings {
   ambient_light
   rgb <1,1,1>
}

background {
   color rgb <0,0,0>
}

light_source {
   VP + 10*VU
   color rgb <1,1,1>
}

#declare thefinish = finish {
   ambient 0.5
   diffuse 0.7
   specular 0.4
   roughness 0.001
   phong 1
}

sphere {
   <0,0,0>, 10
   pigment {
      color rgb <250/255.0,100/255.0,100/255.0>
   }
   finish { thefinish }
   normal { thenormal }
}
ini file: bump.ini
Input_File_Name=bump.pov
Output_File_Name=bump.tga
Output_File_Type=T
Buffer_Output=off
Width=800
Height=600
Antialias=on
Antialias_Threshold=0.01

Statistic_Console=off
Warning_Console=off
Debug_Console=off
Display=on




Media (PovRay 3.5)

Written by Paul Bourke
August 2002


Introduction

The use of media within PovRay to achieve a particular effect can be challenging. The process is generally one of repeated trial and error where the result of a parameter change mostly hard to predict. The following attempts to illustrate a range of effects, hopefully as a starting point for the readers own exploration.


Scene files
test.ini -- test.pov

The test scene consists of a unit sphere resting on a ground surface, this sphere will contain the media. There are two white lights, one directly above the sphere and the other closer to the centre of the sphere. In order to observe the effect of the media on objects, cylinders are placed behind the media and spheres are placed through the centre of the media sphere.


Media sphere

The media in these examples is bound within a sphere. The density is varied radially using the "spherical" pattern modifier which returns 1 in the centre and 0 at a radius greater than 1. The sphere below has all the media attributes (scattering, emission, and absorption) set to zero, effectively so the media has no effect. The resulting rendering is on the right.

sphere {
   <0,0,0>, 1
   hollow
   texture {
      pigment {
         rgbt <1,1,1,1>
      }
      finish {
         ambient 0
         diffuse 0
      }
   }
   interior {
      media {
         intervals 30
         ratio 0.9
         samples 2,4
         confidence 0.9
         variance 1.0/128.0
         method 1
         absorption <0.0,0.0,0.0>
         emission <0,0,0>
         scattering {
            1, <0,0,0>
            extinction 0
         }
         density {
            spherical
            turbulence 0
            density_map {
               [0.0 color rgb 0 ]
               [1.0 color rgb 1 ]
            }
         }
      }
   }
   translate <0,0,1>
}

Scattering, absorption, emission

Three renderings on the right illustrate setting non-zero absorption, emission, and scattering. In each case there is no colour variation, so white light is scattered, white light is emitted, or white light is absorbed. Note that in the absorbing case the light passing through the media sphere from the light above ends up being reddish. A word of warning, scattering media can be very CPU expensive.


Multiple density

Multiple densities result in the densities being multiplied together (compared to multiple media where the densities are added together). In this example the goal was to have a slow transition from high to 0 density but to have turbulent variation within the media, this can be achieved with the following density description.

         density {
            spherical
            density_map {
               [0.0 color 0 ]
               [1.0 color 1 ]
            }
         }
         density {
            bozo
            scale 0.2
            density_map {
               [ 0.0 color 0.1 ]
               [ 1.0 color 1 ]
            }
         }

This can be animated by using a function of the clock variable with phase and turbulence.

         density {
            bozo
            scale 0.2
            turbulence 1
            phase clock
            density_map {
               [ 0.0 color 0.1 ]
               [ 1.0 color 1 ]
            }
         }

Colour variation

Colour variation can be added throughout the media by adding a colour map. Because there are two density sections the effects are multiplied together, the result modulated by the amount of scattering, emission, and absorption. The following colour map creates a green central region (spherical = 1) and red rim (spherical approaching 0).

         density {
            spherical
            density_map {
               [ 0.0 color 0 ]
               [ 1.0 color 1 ]
            }
         }
         density {
            spherical
            color_map {
               [ 0.0 color <1,0,0> ]
               [ 1.0 color <0,1,0> ]
            }
         }
 
0 absorption, 0 scattering, 0 emission


1 absorption, 0 scattering, 0 emission


0 absorption, 0 scattering, 0.5 emission


0 absorption, 0.25 scattering, 0 emission


blue absorption, 0 scattering, 0 emission


Multiple media, emission only and bozo pattern


Colour map, green to red spherical ramp, emission only




POVRAY quality settings

Written by Paul Bourke
June 1999, updated for version 3.6 Oct 2006


The following illustrates renderings from POVRAY using the different quality settings. The scene being rendered for this example is quality.pov. The quality setting in POVRAY is set by using +Qn on the command line or Quality=n in a ".ini" file. All the rendering below were done with antialiasing on (otherwise default antialiasing settings) and rendered at 400x400, the relative times are multiples of the quality=1 raytracing time.

Quality=1

Quick colours and ambient light

Time unit = 1

Quality=3

Calculate specific diffuse and ambient light

Time unit = 1.6

Quality=5

Include shadows and extended lights

Time unit = 2.4

Quality=7

Include texture patterns

Time unit = 3.0

Quality=9

Calculate reflected, refracted, and transmitted light

Time unit = 7.2




Texture billboarding in PovRay

Written by Paul Bourke
May 2002


Billboarding is a well established technique that maps a texture onto a planar surface that stays perpendicular to the camera. It is commonly used in interactive OpenGL style applications where textures are a much more efficient means of representing detail than creating actual geometry. The classic example is to represent pine trees (relatively radially symmetric), the texture image of the tree always faces the camera giving the impression of a 3D form.

The example that will be used here is the creation of a galaxy that rotates slowly and stays facing a camera that moves along a flight path. For each section and image below a PovRay file is provided which illustrates the step and can be used to create the image. path.

PovRay default texture coordinates (default.pov)

The texture will be mapped onto a disc, used because the galaxy images were mostly circular, a polygon could just as easily have been used. The default PovRay texture lies on the x-y plane at z=0 as shown below.

Changing the orientation (orientate.pov)

The first step is to consider how to transform the texture so that it faces the camera. The camera model used here is as follows, where normally the camera position (VP), camera view direction (VD), and up vector (VU) are set by the flight path description.

camera {
   location VP
   up y
   right -4*x/3
   angle 60
   sky VU
   look_at VP + VD
}

The view direction, up vector, and right vector need to be kept mutually perpendicular, to be more precise, orthonormal. The PovRay transform statement is used to orientate the texture coordinate system so it is perpendicular to the camera view direction.

Changing the position (position.pov)

In the aove the disc and texture are still centered on the origin so they now need to be translated to the correct position. This could be done in the transform above (see last row of zeros) but a separate translate has been used here.

Changing the orientation (final.pov)

Finally, the rotation is done, one only has the ensure that it's done at the right stage, namely while the galaxy was still centered at the origin.




Fog (PovRay 3.5)

Written by Paul Bourke
August 2002


Scene files
fog.ini -- fog.pov

The scene on the right was created in order to test the effect of various fog types and variable.


Constant fog

The simplest type of fog (type 1) is uniform in all directions, the rate at which the fog colour alters the colour of objects is proportional to the exp(-d/d0) function where d0 is the argument in the "distance" variable. So, if the object is d0 away the colour contribution for that pixel will be 0.63 of the fog colour plus 0.37 of the object colour. An object twice d0 away the colour will be 0.86 of the fog colour and 0.14 of the object colour.

fog {
   /* Range for exp(-1) colour contribution */
   distance 6 
   color rgb <1,0.6,0>
   fog_type 1
}

Transmittance and Filter

The transmittance and filter of the fog colour is used to set the minimum translucency and the degree of filtering of light passing through the fog. So a transmittance of 0 and filter of 0 (eg: color rgbft <1,0.6,0,0,0>) would give the same result as "color rgb <1,0.6,0>". Increasing the filtering means the light sources become increasingly coloured by the fog, this in turn will affect the colour of objects illuminated by the light. Increasing the transmittance sets an upper limit on the degree to which the fog blocks distant objects. An example of the right show the result with a 50% filtering.

fog {
   distance 6 
   color rgbft <1,0.6,0,0.5,0> 
   fog_type 1
}

and a 50% transmittance.

fog {
   distance 6
   color rgbft <1,0.6,0,0,0.5>
   fog_type 1
}

Ground Fog

PovRay has a second type of fog (type 2) called "ground fog", this has a vertical density dependence. Control of the vertical dependence is made with two variables, the first (fog_offset) sets a height below which the fog has a constant density, the second variable (fog_alt) controls the rate of density falloff above that height. A small value of "fog_alt" compared to "fog_offset" results in a sharp transition. The exact equation for heights above the fog_offset is

(1 + (height - fog_offset) / fog_alt)-2

So at a height of fog_alt above the fog_offset the fog density is 1/4 of what it is at (or below) fog_offset. At twice fog_alt above fog_offset the density is 1/9th.

fog {
   distance 6
   color rgbft <1,0.6,0,0,0>
   fog_type 2
   up <0,0,1>
   fog_offset 0.5 /* Constant below this */
   fog_alt 0.5 /* Decay rate */
}

Turbulence

The turbulence variable is used the same as when applied to patterns, the argument dictates the degree of turbulence. An additional variable "turb_depth" determines where along the ray the turbulence is calculated. 0 indicates at the camera, 1 is at the first object the traced ray strikes. The other parameters for turbulence such as octaves, lambda, and omega can be specified to control the turbulence function.

fog {
   distance 6
   color rgbft <1,0.6,0,0,0>
   fog_type 2
   up <0,0,1>
   fog_offset 0.5
   fog_alt 0.5
   turbulence 2
   turb_depth 0.9
}

Multiple fog

Multiple fogs may be specified, the effect is additive. Here is a sharp yellow layer under a brownish top layer.

fog {
   distance 6
   color rgbft <1,0.6,0,0,0>
   fog_type 2
   up <0,0,1>
   fog_offset 0.5
   fog_alt 0.5
}
fog {
   distance 6
   color rgbft <0.8,0.3,0.3,0,0>
   fog_type 2
   up <0,0,1>
   fog_offset 0.3
   fog_alt 0.1
}

Night vision

Limited night vision can be simulated with black fog.

fog {
   distance 6
   color rgbft <0,0,0,0,0.3>
   fog_type 1
}
 
No fog


Constant fog with no transmittance or filtering.


Constant fog with 50% filtering


Constant fog with 50% transmittance


Ground fog


Turbulence


Multiple layers


Limited night vision




PovRay lens types

The Beneventum Stadium

Written by Paul Bourke

AutoCAD Model courtesy of Stephanie Phan, Andrew Hutson, Frank Sears from the Melbourne University School of Architecture

Photos of "the real thing"


The lens types available in version 3 of PovRay are illustrated here along with the camera specifications for each one. The way (and order) in which PovRay treats the various camera attributes isn't always obvious, the section of the manual dealing with the camera settings should be read carefully.

A model of the Roman beneventum stadium has been used to ilustrate the various lens types. The geometry for the model was imported into MicroStation and converted into a PovRay scene through the WRL export, this creates the cleanest and most convenient geometry output of all the formats provided by AutoCAD and MicroStation.

The plans and elevations of this model are given on the right. A rendering using a standard perspective proection (aperture=60) is shown below.

Front view
Top view
 
Left view

Perspective

The camera aperture for the following is 90, 120, and 150. The model used by PovRay is that of a straightforward pinhole camera, that is, there are no lens effects. The "angle" argument is the prefered method of specifying the camera aperture, in earlier version of PovRay the relative length of the "direction" and "right" vector determined the camera aperture.

#declare VP = <0,12000,30000>;
#declare VD = <1,0,1>;
#declare APERTURE = 120;

camera {
   perspective
   location VP
   up y
   right -4*x/3
   angle APERTURE
   sky <0,1,0>
   look_at VP+VD
}

The same camera position and view direction (VP and VD) will be used for the remainder of the renderings unless otherwise specified. Note the negative value for the right vector, this changes the coordinate system from a left to a right hand one (this is what the modelling software used). The 4/3 scale factor for the right vector creates the correct aspect ratio for an image size of 800x600 as specified in the ini file.

Width=800
Height=600



Fisheye

A fisheye lens implements a standard spherical projection, the "angle" may range from 0 to 360 degrees. At 180 degrees half the visible space is visible, at 360 degrees the whole visual space is visible (note that in this case a point behind the viewer is stretched around the perimenter of the projection circle). The fisheye lens examples here correspond to camera apertures of 180, 270, and 360.

camera {
   fisheye
   location VP
   up y
   right -x
   angle APERTURE
   sky <0,1,0>
   look_at VP+VD
}

This projection is normally created with a 1:1 aspect ratio so that the projection results in a circular image.




Ultra wide angle

This projection type is related to the fisheye projection except the resulting image is mapped onto a rectanglar area instead of a circular one. The examples here are for 180 and 270 degrees.

camera {
   ultra_wide_angle
   location VP
   up y
   right -x
   angle APERTURE
   sky <0,1,0>
   look_at VP+VD
}


Omnimax

This is a special purpose projection for omnimax theatres. The angle is fixed at 180 degrees. Normally omnimax images/movies are filmed with a matching lens system to the intended projection system, the projection system "undoes" the fisheye like distortion introduced with the matching camera.

camera {
   omnimax
   location VP
   up y
   right -x
   angle 180 /* Not used */
   sky <0,1,0>
   look_at VP+VD
}

Comparing this projection with the 180 degree fisheye, the top half appears the same but the bottom half has been elliptically clipped.


Panoramic

This is also known as a cylindrical equirectangular projection.

camera {
   panoramic
   location VP
   up y
   right -2*x
   angle APERTURE
   sky <0,1,0>
   look_at VP+VD
}
Cylindrical

For this projection the scene is mapped onto a cylindrical band, PovRay allows the band to run vertically as well as horizontally. PovRay also supports two modes, one where the view point remains in the same place and another where the view point moves around the cylinder.

camera {
   cylinder 2
   location VP
   up y
   right -2*x
   angle 180
   sky <0,1,0>
   look_at VP+VD
}

Cuberender

This is a mapping external to PovRay, further details can be found here.

camera {
   perspective
   location VP
   up y
   right -x
   angle 90
#switch (clock)
   #case (1)
      sky <0,1,0>
      look_at VP +x
   #break
   #case (2)
      sky <0,1,0>
      look_at VP -z
   #break
   #case (3)
      sky <0,1,0>
      look_at VP -x
   #break
   #case (4)
      sky <0,1,0>
      look_at VP +z
   #break
   #case (5)
      sky <1,0,0>
      look_at VP +y
   #break
   #case (6)
      sky <1,0,0>
      look_at VP -y
   #break
#end
}




Making QuickTime Navigable objects using PovRay

Written by Paul Bourke
April 2000


QuickTime VR navigable objects are one of the original features (along with panoramics) Apple built into QuickTime after simple movie playing. They allow exploration of an object by moving a virtual camera around the object, generally on the surface of a sphere. Internally they are just a linear QuickTime movie but with some extra information to indicate which frame sets form the lines of longitude and latitude.

The three steps in creating a QT navigable object are as follows:

The rest of this document will describe how to perform the first step above using PovRays animation support based upon the clock variable, namely, creating all the images required and in the correct order. In polar coordinates (R,Theta,Phi), sometimes called spherical coordinates, given a fixed radius (R) all the points lie on a sphere. The two angles (Theta,Phi) determine the lines of longitude (0 to 360) and latitude (90 to -90) respectively.

These lines of latitude and longitude can be "unwrapped" from the sphere and represented as a grid.

QuickTime VR object movies allow any rectangular part of this grid to be used. In most cases the entire grid is used in which case panning right past theta=360 will wrap to theta=0 for any line of latitude. Note that the line along the top and bottom edge of the grid map to a single point at the north and south pole. Whichever part of the grid is used one will need to give the longitude and latitude bounds to the software that performs step 3 above.

In the following example using PovRay the object to be explored is assumed to be located at the origin, if this isn't the case it can readily be translated there or the PovRay code below modified to create the views about some other position. In the first section given below, the parameters that determine the grid resolution and range are specified. In the example here the resulting navigation will be in 5 degree steps left/right (longitude) and 10 degree steps up/down (latitude).

/*
   The ini file should have NLONGITUDE * (NLATITUDE + 1) frames
   And a clock variable that goes across the same range
   for example for NLONGITUDE = 72 and NLATITUDE = 18
      Initial_Frame = 0
      Final_Frame   = 1367
      Initial_Clock = 0
      Final_Clock   = 1367
   Fill in the next 7 parameters
*/
#declare NLONGITUDE   = 72;
#declare NLATITUDE    = 18;
#declare LONGITUDEMIN = 0;
#declare LONGITUDEMAX = 360;
#declare LATITUDEMIN  = -90;
#declare LATITUDEMAX  = 90;
#declare CAMERARADIUS = 100;

Next we compute the polar coordinates (theta,phi) with a constant camera range given by CAMERARADIUS above. From these the camera position (VP), view direction (VD), and up vector (VU) are derived.

/* Calculate polar coordinates theta and phi */
#declare DLONGITUDE = LONGITUDEMAX - LONGITUDEMIN;
#declare DLATITUDE  = LATITUDEMAX - LATITUDEMIN;
#declare THETA = LONGITUDEMIN + DLONGITUDE * mod(int(clock),NLONGITUDE) / NLONGITUDE;
#declare THETA = radians(THETA);
#declare PHI   = LATITUDEMAX - DLATITUDE * int(clock/NLONGITUDE) / NLATITUDE;
#if (PHI > 89.999)
   #declare PHI = 89.999;
#end
#if (PHI < -89.99)
   #declare PHI = -89.999;
#end
#declare PHI = radians(PHI);
#debug concat("\n****** Clock: ",str(clock,5,1),"\n")
#debug concat("       Theta: ",str(degrees(THETA),5,1),"\n")
#debug concat("       Phi:   ",str(degrees(PHI),5,1),"\n")

/* Calculate the camera position */
#declare VP = CAMERARADIUS * <cos(PHI) * cos(THETA),cos(PHI) * sin(THETA),sin(PHI)>;
#declare VD = -VP;
#declare VU = <0,0,1>;
#declare RIGHT = vcross(VD,VU);
#declare VU = vnormalize(vcross(RIGHT,VD));

In the above the tweeking of PHI at 90 and -90 (the poles) is a nasty solution to the problem of creating the correct up vector (VU) at the poles, there are more elegant ways but this seems to work OK. This method works in combination with the cross product to calculate a right vector and then the correct up vector that is at right angles to the view direction.

These camera variables (position, view direction and up vector) are finally combined into a camera definition which may look something like the following.

camera {
   location VP
   up y
   right x
   angle 60
   sky VU
   look_at <0,0,0>
}

An unfortunate reality of these navigable object movies is their size. For D1 degree steps in longitude and D2 latitude, the total number of frames for a full sphere is given by ((180+D2)/D2)*(360/D1). So for the example above D1 = 5 and D2 = 10 degrees so there are 1368 frames. For a smoother sequence where there 2 degree steps in both directions there would be 16380 frames! For this reason I haven't included an actual QuickTime VR object example movie.

Screen shot examples of various QT VR tools