2.2. Expressions

2.2.1. Language directives Set directive

Chris Huff

The #set keyword modifies the most recently created version of a variable. So, if a variable has been created previously with either #declare or #local, its value can be changed with the #set directive.

Example 2.2. Using the #set directive

#declare MyCounter = 0:
#set MyCounter = MyCounter + 1;

One advantage is that it makes it more visually clear where variables are 'created', and where they are only 'changed'.

Another advantage is that if you try to change a variable that doesn't yet exist, it produces an error. This could happen if you make a typing mistake, like this:

#declare MyCounter = 0;
#while (MyCounter < 10)
  #declare MyCountr = MyCounter+1;

This would normally cause an infinite loop, and may take a while to track down, especially in complex scenes and with typos that "look right" at a glance. If #set was used, it would cause an error ("#set cannot assign to uninitialized identifier MyCountr.") at that line, pointing you directly at the problem.

2.2.2. Built-in tokens Additional tokens in function syntax

Włodzimierz ABX Skiba

POV-Ray™ 3.5 in its official release does not accept all built-in constants and variables to be used in functions. Following tokens are recognized additionally in VM since MegaPOV 1.0: clock_delta, clock_on, false, final_clock, final_frame, frame_number, initial_clock, initial_frame, image_height, image_width, no, off, on, true, version, yes . All mentioned tokens return the same values as in the whole SDL parser. frame_step key-word

Włodzimierz ABX Skiba

As other animation options, also Frame_Step has its own equivalent in SDL. You can use the frame_step key-word to get the value which was passed to Frame_Step (see Section 2.1.1, “Frame_Step”). Default value is 1.

2.2.3. Functions Time and date functions

Yvo Smellenbergh

With the keyword date, time and/or a date can be used in your images. This might be useful in a macro to place a time stamp in your images, along with your name. The keyword date works like other string functions, except that you have to supply a format string.

Example 2.3. date function usage

Suppose it's Saturday 1 January. The following script:

#declare TheString=date("%a %B")

will return the string: Sat January

The most flexible implementation was chosen (which is probably not the easiest ...) because not all countries write dates in the same way. Just think of the difference between the USA and most parts of Europe. These are the possible specifiers for the format string: Please note that these should be equal for all platforms but if you don't get the expected result, contact the person who compiled your version to find out if there are differences.

Table 2.1. The following time formatting strings are available:

a Abbreviated weekday name.
AFull weekday name.
bAbbreviated month name.
BFull month name.
cThe strftime() format equaling the format string of "%x %X".
dDay of the month as a decimal number.
HThe hour (24-hour clock) as a decimal number from 00 to 23.
IThe hour (12-hour clock) as a decimal number from 01 to 12
jThe day of the year as a decimal number from 001 to 366
mThe month as a decimal number from 01 to 12.
MThe minute as a decimal number from 00 to 59.
p"AM" or "PM".
SThe seconds as a decimal number from 00 to 59.
UThe week number of the year as a decimal number from 00 to 52. Sunday is considered the first day of the week.
wThe weekday as a decimal number from 0 to 6. Sunday is (0) zero.
WThe week of the year as a decimal number from 00 to 51. Monday is the first day of the week.
xThe date representation of the current locale.
XThe time representation of the current locale.
yThe last two digits of the year as a decimal number.
YThe century as a decimal number.
zThe time zone name or nothing if it is unknown.
%  The percent sign is displayed.


To use the '%' character in the result, use it twice: date("%%")

Refer to date.pov for an example scene. Please note that you might have to write the result in a file if you want to abort the rendering and continue later on. Otherwise you could get a different result because time goes on :-) Timer function

Yvo Smellenbergh

The keyword start_chrono sets an internal variable and returns the current internal clock counter of your computer. The return value is not important. However, you must assign this return value from start_chrono otherwise you get an error. Use it like this:

#declare Stopwatch = start_chrono;

or use it like this:

#if (start_chrono)

but not:

start_chrono //parsing stops with a fatal error

The keyword current_chrono returns the time in full seconds (no fractions of seconds) between start_chrono and current_chrono. The start value is not changed. A second current_chrono will still return the seconds between start_chrono and the second current_chrono.

If you don't call start_chrono somewhere before you call current_chrono, you will get the seconds elapsed since the beginning of the current render (parsing).

Example 2.4. Using the timer function

//reset the chrono and return the internal clock counter
#declare ParseStart = start_chrono; 

... syntax to be parsed

//read the seconds elapsed since chrono_start
#declare ParseEnd = current_chrono;
#debug concat("\nParsing took ",str((ParseEnd, 1, 0)," seconds\n")

Refer to chrono.pov for a demo scene. Filename with frame number

Włodzimierz ABX Skiba

Some animators want to use filenames of previous, already rendered frames to average them to mimic motion_blur in one turn. But the concatenation of filename with frame number is not a trivial thing and can be platform dependant. MegaPOV allows you to get n-th filename of current animation. For stills it always returns filename without numbers.

Syntax is:

#declare File_Name=output_filename(Frame_Number)

Example 2.5. Averaging frames with output_filename function

You can force every 10th frame to be averaged content of previous nine frames, this way:

  #declare Averaged_Frames=pigment{
    #local Counter=1;
      [1 image_map{output_filename(frame_number-Counter)}]
      #set Counter=Counter+1;
  // placing of pigment in output area
  // conventional scene
#end Sizes of images

Włodzimierz ABX Skiba

You probably already know that the image_width and image_height keywords return the sizes of a rendered image. But there are cases when you would like to change the content of a scene depending on the sizes of the images used for maps. For this purpose the image_width and image_height keywords are extended with an optional parameter which is the identifier of an item using an image.

Syntax is:

#declare Identifier=image_width [ (ITEM_WITH_IMAGE) ];
#declare Identifier=image_height [ (ITEM_WITH_IMAGE) ];


Włodzimierz ABX Skiba

The usage of the dimension_size is extended since MegaPOV 1.1 with a measurement of floats, vectors and colors. If you want to write a universal script which works differently depending on the number of components in an identifier, you can use the dimension_size to get 1,2,3,4 or 5 as number of the components in the given identifier.

Syntax is:

#declare Identifier=dimension_size ( FLOAT | VECTOR | COLOR ); Type checking

Włodzimierz ABX Skiba

MegaPOV 1.1 allows the verification of the type (and in some cases subtypes) of identifiers. It is possible thanks to the is function which tests the internal type of an identifier.

Syntax is:

#declare Identifier=is ( IDENTIFIER , TYPE | SUBTYPE );

TYPE: array | camera | color | 
      color_map | density | density_map | 
      finish | float | fog | 
      function | interior | light_source | 
      material | media | normal | 
      normal_map | object | pigment | 
      pigment_map | rainbow | sky_sphere | 
      slope_map | spline | string | 
      texture | texture_map | transform | 


SPLINE_TYPE: akima_spline | basic_x_spline | 
             cubic_spline | extended_x_spline | 
             general_x_spline | linear_spline | 
             natural_spline | quadratic_spline | 
             sor_spline | tcb_spline 

OBJECT_TYPE: bicubic_patch | blob | box | 
             cone | cubic | cylinder | 
             disc | height_field | intersection | 
             isosurface | julia_fractal | lathe | 
             merge | mesh | parametric | 
             plane | poly | polygon | 
             prism | quadric | quartic | 
             smooth_triangle | sor | sphere | 
             sphere_sweep | superellipsoid | text | 
             torus | triangle | union

CAMERA_TYPE: cylinder | fisheye | omnimax | 
             orthographic | panoramic | perspective | 
             spherical | ultra_wide_angle | user_defined


Internally mesh2 is stored as mesh. Similar difference is stored as intersection.

An example using the is keyword can be found in the mp_types.inc include file (see Section 3.3, “The 'mp_types.inc' include file”).

2.2.4. Internal functions

MegaPOV delivers new pre-defined functions. These new internal functions can be accessed through the mp_functions.inc include file, so it should be included in your scene to make use of them. f_triangle

Włodzimierz ABX Skiba

f_triangle function has 10 parameters:

FLOAT f_triangle(FLOAT V1x, FLOAT V1y, FLOAT V1z, FLOAT V2x, FLOAT V2y, FLOAT V2z, FLOAT V3x, FLOAT V3y, FLOAT V3z, FLOAT Thickness);

The parameters V1x, V1y, V1z describe the coordinates of the first vertex in the triangle.

The parameters V2x, V2y, V2z describe the coordinates of the second vertex in the triangle.

The parameters V3x, V3y, V3z describe the coordinates of the third vertex in the triangle.

The parameter Thickness describes how thick the triangle is.


In order to achieve the fastest calculation, try to pass the parameters so that the side V1-V2 represents the longest side and V1-V3 represents the shortest side.

2.2.5. Polynomial solver in parser

Włodzimierz ABX Skiba

The polynomial solver is accessible from scripts via the float functions n_roots and nth_root with the following syntax:

INT n_roots(FLOAT an, ..., FLOAT a0, BOOL sturm_flag, FLOAT epsilon);

FLOAT nth_root(FLOAT nth, FLOAT an, ..., FLOAT a0, BOOL sturm_flag, FLOAT epsilon);

n_roots returns the number of roots derived from the polynomial given by the parameters an, ..., a0 and calculated under the conditions specified by the parameters sturm_flag and epsilon.

nth_root returns the value of the nth root of a given polynomial.

The sturm flag turns on a different algorithm of calculation. Its usage influences the number of returned roots. Epsilon (positive) value means that the roots below Epsilon value are ignored. Epsilon=0 means that none of the roots are ignored.


You don't have to call n_roots before nth_root, but if you do call nth_root with the wrong root number then it causes an error and breaks parsing. It is better to call n_roots first to verify the number of available roots.

Example 2.6. Polynomial solver usage

Imagine that we have x3+6*x2-x-6 and that we are interested in its roots for further calculations. So if we declare:

#declare N=n_roots(1, 6, -1, -6, off, 0);

then N has value 3 because the mentioned equation has 3 roots. If we are interested in what roots it has, we can use the following calls:

#declare R0=nth_root(0, 1, 6, -1, -6, off, 0);
#declare R1=nth_root(1, 1, 6, -1, -6, off, 0);
#declare R2=nth_root(2, 1, 6, -1, -6, off, 0);

And it returns R0=-6, R1=1 and R2=-1. So finally we know that x3+6*x2-x-6=(x+6)*(x-1)*(x+1) .

2.2.6. Splines spline follows sor

Włodzimierz ABX Skiba

Splines in POV-Ray™ can be used to create objects through rotation, translation or by being a border of a surface. Usually it is hard to match those surfaces with calculations developed in SDL because they are mostly hard-coded within the source core code of POV-Ray™. The spline feature introduced in POV-Ray™ 3.5 makes such operations much easier but some spline types are still missing. sor_spline is introduced to access the surface of the sor object in SDL.

To use the data from the sor object in a sor_spline, the order of coordinates has to be changed. The old y coordinate is now the clock value in the spline. The advantage is that one sor_spline can hold data from five old sor-s. That's because every spline can operate up to five dimensions along the clock value.

Example 2.7. Conversion from the sor object definition to the sor_spline type in spline


  <0.000000, -1.000000>
  <0.118143,  0.000000>
  <0.620253,  0.540084>
  <0.210970,  0.827004>
  <0.194093,  0.962025>
  <0.286920,  1.000000>
  <0.468354,  1.033755>
} akima spline

Włodzimierz ABX Skiba

An akima_spline is a spline that goes smoothly (pleasingly for some) through all points. ACM Press abstracts original work of Hiroshi Akima:


This method is devised in such a way that the resultant curve will pass through the given points and will appear smooth and natural. It is based on a piecewise function composed of a set of polynomials, each of degree three, at most, and applicable to successive intervals of the given points. In this method, the slope of the curve is determined at each given point locally, and each polynomial representing a portion of the curve between a pair of given points is determined by the coordinates of and the slopes at the points. Comparison indicates that the curve obtained by this new method is closer to a manually drawn curve than those drawn by other mathematical methods.

--The Guide to Computing Literature. 

Syntax is:

spline {
  time_Val_1, <Vector_1> [,]
  time_Val_2, <Vector_2> [,]
  time_Val_n, <Vector_n>
} tcb spline

Włodzimierz ABX Skiba

This spline is also known as Kochanek-Bartels spline.

Syntax is:

spline {
  tcb_spline [TCB_PARAMETERS]
  time_Val_1 [TCB_PARAMETERS], <Vector_1> [TCB_PARAMETERS][,]
  time_Val_2 [TCB_PARAMETERS], <Vector_2> [TCB_PARAMETERS][,]
  time_Val_n [TCB_PARAMETERS], <Vector_n> [TCB_PARAMETERS]

  [tension FLOAT] [continuity FLOAT] [bias FLOAT]

The tension, continuity and bias are fully optional. Depending on the place where they appear, they control the spline in different ways:

  • Placed right after the tcb_spline keyword, they set the default values for all ends of the spline segments. This placement is ignored in case of copying spline without adding new controls because previous defaults were already propagated to each side of control points.
  • Placed between the time_value and the corresponding vector, the tcb parameters determine the properties of the spline segment ending in the vector that follows these parameters.
  • For tcb parameters following a vector, the properties of the spline segment beginning after this vector are set.

What is controlled by these parameters?

  • tension controls how sharply the curve bends.
  • continuity controls how rapid speed and direction change.
  • bias controls the direction of the curve as it passes through the control point.

A tcb_spline needs additional control points before and after the spline. This is required to control the first and last segment of the spline. x splines

A very nice property of x splines is that they can go through a control point as well as just approximate it. basic x spline

Włodzimierz ABX Skiba

Syntax is:

spline {
  basic_x_spline [freedom_degree FLOAT]
  time_Val_1, <Vector_1> [,]
  time_Val_2, <Vector_2> [,]
  time_Val_n, <Vector_n>

A basic_x_spline needs additional control points before and after the spline. This is required to control the first and last segment of the spline. extended x spline

Włodzimierz ABX Skiba

The extended_x_spline offers the possibility to mix smooth curves and sharp edges in an unrestricted way in one spline.

Syntax is:

spline {
  extended_x_spline [freedom_degree FLOAT]
  time_Val_1, <Vector_1> [freedom_degree FLOAT ][,]
  time_Val_2, <Vector_2> [freedom_degree FLOAT ][,]
  time_Val_n, <Vector_n> [freedom_degree FLOAT ]
} general x spline

Włodzimierz ABX Skiba

Syntax is:

spline {
  general_x_spline [freedom_degree FLOAT]
  time_Val_1, <Vector_1> [freedom_degree FLOAT ][,]
  time_Val_2, <Vector_2> [freedom_degree FLOAT ][,]
  time_Val_n, <Vector_n> [freedom_degree FLOAT ]
} Spline accessed like array

Włodzimierz ABX Skiba

Since MegaPOV 1.0 it is possible to read values stored in a spline with a notation similar to an array. Previously once the spline was declared, it was only possible to evaluate it for a specified argument. Now two new usages are possible: you can get the number of entries and read the exact values placed in splines.


  #declare Spline_Value = MySpline(Val);
  #declare Spline_Value = MySpline(Val, SPLINE_TYPE);

  #declare Number_Of_Entries = dimension_size( MySpline );

  #declare Float_Time_Parameter = MySpline[ Counter ][ 0 ];
  #declare Vector_Value_Of_Entry = MySpline[ Counter ][ 1 ];

2.2.7. Transforms The normal modifier for transforms

Christoph Hormann

This patch adds a new option to the transform syntax that modifies the transform to be suited for transforming normal vectors.

When a mesh is transformed by the transformation matrix M the normals need to be transformed with the transpose of the inverse of M. This is handled automatically by this patch.

Syntax is:

transform {
  normal on|off

The default value is off so you get a standard transform.