Windows Table of Contents

POV-Ray for Windows version 3.7
Home POV-Ray for Windows POV-Ray Tutorial POV-Ray Reference
Introduction
What is POV-Ray for Windows?
... And What Is It Not?
Who Can Use POV-Ray for Windows?
System Requirements
System Specific Features
What's new in POV-Ray for Windows
SYS File Type
System Specific Charset
Spelling
Reporting Bugs
Trademarks
Real-Time Raytracing
Clockless Animation
Video Capture
Options
Video Source
Getting Started
The Demo
Starting a Render Job
Dragging and Dropping Files
File Associations
Tutorials
Understanding File Types
POV Files
INI Files
INI File Sections
Using the Internal Editor
The Editor Feature Set
Turning the Internal Editor On or Off
Preventing File Restore
Switching between Editor windows
Keyword Expansion and CodeList
A Quick Example
How Keyword Expansion Works
CodeList
Using CodeList
Summary
Configuring the Internal Editor
Important Editor Notes
Default Key Mappings
Setting Key Mappings
Reserved Keys
Using the Mouse
Hints for Match Brace
The Language Setting
The Font Setting
I/O Restrictions
High-Level Configuration
Overall Options
No Restrictions
Restrict Write but Allow Read
Restrict Read/Write
Restrictions Affect all Core File I/O
Additional Options
Permit Read/Write in Current Directory
Disable Starting other Programs
Low-Level Configuration
Overall Concept
Implicitly Permitted Locations
Adding or Changing Allowed Directories
For Those Who use an Image Output Directory
Command-Line Options
POV-Ray Documents Directory
Special Command-Line Options
The Benchmark Command-line Option
Non-Standard Installations
Background
The /INSTALL and /QINSTALL switches
Publishing via Group Policy
System Admins / Lab Techs
Adding New Resolutions
Windows
The Main Window
The Toolbar
Preset Rendering Options
Toolbar Command Line
The Status Bar
The Tab Control
The Message Window
The Editor Window
The Render Window
Menus
File Menu
New File
Open File
Close
Close All
Print
Exit
MRU List
Older Files sub-menu
Edit Menu
Copy Pane
Clear Messages
Undo
Redo
Cut
Copy
Paste
Delete
Select All
Selection sub-menu
Indent
Indent To Previous
Undent
Uppercase
Lowercase
Convert Spaces To Tabs
Convert Tabs To Spaces
Search Menu
Find dialog
Match Whole Word Only
Match Case
Wildcard Search
Replace
Find Next
Match Brace
Text Menu
Show White Space
Set Repeat Count
Tab Size
Indent sub-menu
Auto-Indent Style sub-menu
None
Language Scope
Copy From Previous Line
Bookmarks sub-menu
Clear All
First
Last
Next
Previous
Toggle
Editor Menu
Auto-Load Error File
Auto-Show Parse Messages
Auto-Save Delay
Create Backups
Allow Undo After Manual Save
Click Beyond EOL
Constrain Caret To Text
Overlay Keyword Expansion On Tab Key
Show Message Window
Editor Preferences dialog
Record Macro/Play Macro
Auto-Reload sub-menu
Scroll Bars sub-menu
Color Scheme sub-menu
Editor Preferences
Color/Font
Item
Color
Background
Font
Language/Tabs
Auto Indentation Style
Tabs
Language
Keyboard
Misc
Smooth Scrolling
Show Left Margin
Line Tooltips on Scroll
Allow Drag and Drop
Allow Column Selection
Confine Caret to Text
Color Syntax Highlighting
Show Horizontal/Vertical Scrollbar
Allow Horizontal/Vertical Splitting
Line Numbering
Max Undoable Actions
Insert Menu
Physical Layout
Sorting the Insert Menu
Adding a Separator
Using the Insert Menu
Render Menu
Edit Settings/Render dialog
Select File and Render dialog
Start Rendering (Go!)/Stop Rendering
Run Demo
Run Benchmark
File Queue dialog
Clear Queue
Render Priority sub-menu
Duty Cycle sub-menu
Thread Count dialog
Prevent Sleep
Sound Settings dialog
On Completion sub-menu
Do Nothing
Display Message
Exit POV-Ray for Windows
File List
Options Menu
Keep Single Instance
Show Toolbar
Place in System Tray
Script I/O Restrictions
Drag'N'Drop Destination sub-menu
Update Checks sub-menu
Periodically Check for Updates
Include System Information
Check for Update Now
Other Settings sub-menu
Video Source sub-menu
Use Editor
Show Tips of the Day
Show Tooltips
Preserve Messages
Save Settings on Exit
Hide New User Help
Show Next Tip
Re-Render Insert Menu Bitmaps
Message Window sub-menu
Select Plain Background
Text Font
Text Color
Background Color
Tiling Options
Render Window sub-menu
Force 8 Bit Display
Preserve Contents During Animation
Re-Display
Autoclose
Close
Keep Above Main
Get Focus on Creation
Hide When Main Minimized
Editor Window sub-menu
Tools Menu
PVTOOLS.INI Syntax
Reload Tool Menu
Edit PVTOOLS.INI
Example PVTOOLS.INI
Window Menu
Context Menus
The Message Window context menu
Minimize to System Tray
Show Tip
The Render Window context menu
The Editor Window context menu
Show or Hide Messages
Context Help
Open Filename
Copy ... to Command-Line
Bug Reports
Bugs and GUI Extensions
Crash Upload Utility
Bug Reporting via Email
Bug Reporting via our Bug Tracking System
Speed Considerations
Render Priority
Render Window
Memory
Scene Features
Render Quality


Windows Section 1

1.1 Introduction

This section provides information on how to use the Microsoft Windows™ version of the Persistence of Vision Raytracer™ (also known as POVWIN).

Before we start, we'll have a brief discussion of just what this program is, and what it does.

1.1.1 What is POV-Ray for Windows?

POV-Ray™ is short for the Persistence of Vision Raytracer™, a tool for producing high-quality computer graphics. POV-Ray is Free Software (as per the definition of the Free Software Foundation) as its source code is licensed under the »Affero General Public License (AGPL).

POV-Ray for Windows (also known as POVWIN) is POV-Ray, ported to the Microsoft Windows™ operating system. It contains all the features of POV-Ray itself, plus some others specific to Windows. The additional features do not affect the core rendering code; they all relate to making the program easier to use under Windows.

An extensive discussion of the POV-Ray 3 Scene Description Language can be found elsewhere in this help file. For a quick demonstration of POV-Ray for Windows, start up the program by selecting 'Run Demo' from the Render menu.

1.1.2 ... And What Is It Not?

POV-Ray for Windows is not a modeler. It will not let you design scenes graphically on-screen. The POV-Ray project does have a freeware 3D modeler for Windows called 'Moray'. Moray is currently under re-development to make it compatible with modern versions of Windows. There are also several other shareware and freeware programs available for this purpose.

With POV-Ray itself, to write or modify POV-Ray scenes you just edit the actual text file containing the commands. New users might be surprised to learn that, although this sounds primitive, it is in fact one of the things that gives POV-Ray so much power and flexibility. There are many other rendering programs that give you a point-and-click interface, but when it comes down to absolute control of your scene, it's hard to beat a text-based scene description language (even though it's harder for some to learn).

1.1.3 Who Can Use POV-Ray for Windows?

Almost anyone can use POV-Ray for Windows. If you have never seen a ray tracing program before, you can have great fun just rendering the sample scenes and animations installed together with POV-Ray for Windows. Once you have studied some scene files and spent a little bit of time reading this documentation, you can start putting basic scene files together.

Remember, though, that you do need to invest some time getting to know the program. For instance, you do not have to worry about most of the POV-Ray settings at first, but some of them are important. Ignore them and POV-Ray may not do what you expect. The default settings have been selected so as to be satisfactory in the large majority of cases, but sometimes they will not give you what you want. Don't give up. The solution is bound to be a simple one, as long as you take the time to read the documentation. Investing a little bit of time getting to know the program will pay off - guaranteed!

As for experienced POV-Ray users, you will find POV-Ray for Windows makes life much easier. Working under Windows means you can edit one scene while rendering another and modifying the INI file of a third. This feature, combined with the File Queue option lets you speed up the scene generation cycle considerably while leaving you the option of doing some 'serious' work at the same time.

1.1.4 System Requirements

POV-Ray for Windows requires Windows XP or later, and has been tested on versions up to and including Windows 7 (32 and 64-bit). We recommend having at least 100mb or so of free disk space (for temporary file storage during renders) and at least 1GB of available memory (though less is OK if you are not doing complicated scenes).

1.1.5 System Specific Features

1.1.5.1 What's new in POV-Ray for Windows

This section covers version 3.7 changes and new features that apply to POV-Ray for Windows. See the section Changes and New Features Summary for information about non-platform specific changes.

  1. An experimental Real-Time Raytracing feature was added.
  2. Added 'alternate render file' feature to povwin IDE. Look here for more details.
  3. New Render Window behavior.
  4. The Render Priority menu supports a new option.
  5. Added extensions .MCR and .MAC to the list of files povwin considers include files (i.e. which are filtered as such in the various file dialogs and assigned the POV file type for the editor syntax highlighting).
  6. Added .INI file type to povwin editor syntax highlighting.
  7. Added window menu to povwin IDE. Entries are MRU-sorted.
  8. Added these POVWIN features:
    • file modified indicator to filename shown in POVWIN main window caption.
    • notification for when auto-reload results in files being auto-saved.
  9. Added ability to close edit tab in windows version by middle-clicking on it. (NB this means on the tab itself, not the contents of the tab). Also, Ctrl-W now defaults to closing the current editor file.
  10. Added /EDITDLLPATH command-line parameter, which overrides the default edit DLL locations for the windows version.
  11. Added a crash upload utility.
  12. Added ability to specify thread count from Windows version render menu (unsaved setting).
  13. Windows console version now sends stream output to stderr by default.
  14. Added Control-A support in windows version commandline input box (select all).
  15. Changed windows version render window keypress code to hand focus to main window for any key, not just escape.
  16. Expanded number of available insert menu ID's to about 9000.
  17. Added support for loading of PNG and JPG files as insert menu hints. (search order PNG, JPG then BMP)
  18. Windows editor tab/indent settings are no longer per-file+global default; changing one affects all files.
  19. Added display of filename when hovering over an editor tab.
  20. Added a right-click menu to editor tabs allowing the following:
    • opening of folder in explorer.
    • copy of filename to clipboard.
    • save the file.
    • close it, close all but it.
    • move the tab left and move the tab right.
  21. Additionally the previous new entries have also been added to the window menu.
  22. Added a new file ~ini\user-keywords.txt that allows users to add their own keywords for syntax highlighting and auto-completion in the editor.
  23. Added new option to prevent the system from sleeping whilst a render is in progress (by default this is selected).
  24. Added the /BENCHMARK command-line parameter to automatically run the standard benchmark, write the result to a file, and exit.

1.1.5.2 SYS File Type

The SYS file type has been deprecated, and the cross-platform output file type is now PNG, or type n. See the section Output File Type for more information.

1.1.5.3 System Specific Charset

The section titled Charset refers to a system specific charset. There is no system specific charset support specially implemented within POV-Ray for Windows.

1.1.6 Spelling

Some US Residents have commented on the spelling of some words such as colour, initialisation, and minimised (they expect color, initialization, or minimized). POV-Ray is an international effort and as such our spelling sometimes conforms to British, European, or Australian, rather than American, English. You'll find examples of this both in this document and in POV-Ray itself (for example, POV accepts both 'color' and 'colour' as valid keywords).

1.1.7 Reporting Bugs

There is a section in this help file for bug reports. Make sure that you read it before sending us a complaint/bug report !

1.1.8 Trademarks

The terms 'POV-Ray', 'Persistence of Vision Ray Tracer' and 'POVWIN' are trademarks of Persistence of Vision Raytracer Pty. Ltd. All other trademarks are acknowledged as being the property of their respective owners.

1.1.9 Real-Time Raytracing

The version 3.7 release of POV-Ray contains a provisional implementation of a real-time raytracing feature. In addition to this, there are two related features that also are provided for testing purposes: clockless animation and video capture.

The real-time raytracing feature is activated via the Real_Time_Raytracing INI option or the +rtr command-line option. Internally, this causes POV to turn off file output and render the selected scene multiple times. Once all threads in the render have completed a single frame, the frame is sent to the frontend for display as a single message, and the threads then start rendering the same frame again, optionally changing the camera first, if clockless animation is enabled.

It is important to note that while the display preview window is only updated once per frame, the backend still uses render blocks as has been the case since the first beta of 3.7. This is important to remember since the size of the render block can affect the frame rate in a real-time render. Setting it too small can reduce performance. However setting it too large can cause idle CPU's (assuming you have an SMP system), since all threads have to wait until the last block is completed before starting on a new frame. This could impact performance if the last block(s) to be rendered (lower-right) are quite slow, and a large block size is being used.

When used with clockless animation and video capture, the RTR feature can lend itself to some interesting renders, provided a sufficiently powerful computer is used (two cores is recommended; four cores is of course better). However if you are willing to confine yourself to simple scenes and/or use low resolution (e.g. 160x120), it is still possible to use it on single CPU computers.

Note: Currently, it is not possible to save the rendered RTR output to disk. We will provide this as an option if we keep RTR in POV-Ray. Also, the current implementation does not provide any means of synchronising the camera selection with time; that is, if the frame rate changes (as it will tend to do if camera motion reveals or hides items that can slow down the render), the relative rate of camera motion will also change. If RTR turns out to be popular enough, we might investigate the possibility of the camera selection being keyed by elapsed time rather than frame count. This would allow a more consistent rate of motion at the expense of possibly having 'jerky' output if the render slows down.

1.1.9.1 Clockless Animation

Clockless Animation is a very specific form of POV-Ray's animation feature set which allows a series of images to be rendered without re-parsing the scene file. Traditionally the clock variable is used to control animation scene content. For this to work as expected, it is necessary to re-parse the scene file. As the aim of clockless animation is to avoid such re-parsing, the clock is not able to be used in its normal manner; it is from this fact that the feature name derives. Note also that, in addition to not re-parsing the scene file, neither is the scene re-bounded. This implies that no finite objects may move between frames of the render. Clockless Animation enforces this by not providing any means to do so.

As things stand, a clockless animation CA scene has exactly one thing that may change from frame to frame: the camera. Each frame of a CA has an associated camera, which is declared in the SDL in the normal manner. In fact, SDL has not been changed at all to permit this feature to work. Provided that CA has been activated by using either the Clockless_Animation INI entry, or the +kla command-line option, POV's parser switches from complaining when an additional camera definition is encountered to instead storing a list of all cameras declared.

Put simply, each camera definition in the SDL represents exactly one frame of the animation, in the order that they are parsed. The number of frames thus is the number of cameras, and the normal first and last frame INI parameters are ignored. (The subset start and end still work as expected, though they do not apply during real-time raytracing).

Currently, the use of clockless animation is limited to the real-time-raytracing feature. However it is intended to expand its scope to normal rendering as well.

1.1.9.2 Video Capture

Note: Video Capture under Windows is currently disabled due to stability issues. Since this is a windows only feature, this means that no current official POV-Ray release has video capture. However the infrastructure is still in place and the below documentation will remain as it will eventually be re-enabled.

Video capture is an experimental feature that will certainly change prior to it being considered stable (if indeed it is kept at all). Currently it is only implemented on the Windows platform. Video Capture (vidcap) allows a video source (e.g. webcam) to be fed into a rendering just as if it were a still image. Currently, this is done by overloading the 'sys' filetype in image maps (this will change in the future once a dedicated keyword is added for it).

Here is a simplistic example of an image map that will obtain an image from a video capture device:

pigment { image_map {sys ":vidcap:" map_type 0} }

and a more complex one:

pigment {
  image_map {
    sys ":vidcap:width=640:height=480:double-buffer=0:skip-initial=0:gamma=1.0" map_type 0
    }
  }

The requirements are that the image type is sys and that the image filename starts with the text :vidcap:. The text following the :vidcap: (if any) is considered to be additional options which are then provided to the platform-specific video capture support code.

1.1.9.3 Options

At this point of time the following options are supported:

width=nnn
height=nnn
double-buffer=yes|true|1|no|false|0
skip-initial=nnn
gamma=fff

If omitted, defaults are:

width and height - the default for the video capture device.
double-buffer    - turned on
skip-initial     - 0 frames (i.e. turned off)
gamma            - 1.0

It is possible to specify just the width or height, in which case the code will default to using the first supported resolution with that size in that dimension (it won't care what the other dimension is). Specifying -1 as a width or height is also a way of saying it is a don't-care. If the requested size is not available, the render will fail.

skip-initial is the number of frames to skip before returning from the video device initialization. This is needed on some webcams that need a number of frames to perform their setup (such as auto exposure and auto white-balance). This matters mostly if the vidcap input is being used for something other than real-time rendering.

double-buffer is a means of telling the video capture system to store the incoming video data in a separate buffer, which is then copied to the main buffer at the end of each rendered frame. Typically this is what you would want. However it has a time penalty on SMP systems due to the use of a mutex and thus is by default turned off. This means that it is possible to see 'tearing' and similar artifacts in RTR.

gamma allows an input device to have a specific gamma correction applied to the delivered pixels prior to their being applied to the image map. Generally this is best left at 1.0.

1.1.9.4 Video Source

The video source for this windows only feature is chosen via a new sub-menu.


Windows Section 2

1.2 Getting Started

This section will help new users get started with POV-Ray for Windows.

1.2.1 The Demo

If you have never seen POV-Ray at work before, start by running the demo (select Render/Run Demo), then click on Start Rendering. You will see POV-Ray for Windows start up a Render Window and generate a sample scene block by block. By default, these blocks are 32x32 pixels in size. Notice that if you close the Render Window, the rendering job is not interrupted. If you have POV-Ray set up to save the image as a file (this is the default setting), that file will be produced whether or not you display the image on screen as you render. To stop rendering, select Render/Stop Rendering (or use the keyboard short-cut ALT-G).

Even if you minimize the rendering window, POV-Ray for Windows will display the progress of the rendering job by showing the percentage completed. If you close the render window and want it back, click the right mouse button over the main POV-Ray window, and select the appropriate menu item, or just click the toolbar button labelled 'Show'.

1.2.2 Starting a Render Job

Starting POV-Ray rendering any scene file is as simple as selecting the file through the menu (Render/Select File and Render) or dragging and dropping it from Windows Explorer. This will work with either a POV file or an INI file (as long as it has an associated POV file). See Understanding File Types. The scene is rendered with the current POV-Ray 3 options (see Command-Line Options). Note that you can tell POV-Ray for Windows to open a file in the editor instead of rendering it if you drag and drop it into the program (this is in fact the default setting now). See the Options Menu for more information.

N.B. One of the most common errors new users make is turning off the display option. The Display option (+d) is ON by default. If you turn this OFF in the INI file or on the command line, POV-Ray will not display the file as you render, no matter how many times you press the Show Render Window button. However this does not mean the rendered file is not written to disk.

Please also note that POV-Ray for Windows will write the output file to a .PNG by default. There is no way to 'save the render window' after rendering is completed. If you turned file output off before starting the render, and change your mind, you will have to start the rendering all over again. We recommend that you just leave file output on all the time.

1.2.3 Dragging and Dropping Files

Dragging and dropping (a.k.a. Drag'N'Drop) from Windows Explorer (a.k.a. 'My Computer') has the advantage that you can select more than one file at a time. You can drag and drop up to 512 POV and/or INI files. POV-Ray for Windows will start processing the first file in the queue and add the rest to the queue. See File Queue dialog in the Render Menu for more details.

Note: If the dropped files destination is set to Editor (the default), the files will be opened in the internal editor instead. In that case, there is a limit of 32 files that may be opened at any one time.

1.2.4 File Associations

When POVWIN is installed using the official installer, a file association is established between .POV files and POVWIN. This means that if you double-click on a file with the .POV extension it will be opened in POVWIN's editor. In addition, right-clicking on a .POV file to open the standard Windows context menu will show two dedicated menu entries: 'Open' and 'Render with POV-Ray'. 'Open' is the same as double-clicking (internally it calls POVWIN with the '/EDIT' option). Choosing 'Render with POV-Ray' will cause the selected file to be rendered by POVWIN (note that it is not opened in the editor - having a file open in the editor is not a requirement for rendering it).

Newer versions of Windows allow users to associate other file types with programs of their choice; e.g. as a 'default program'. As a general rule, if this is done for POVWIN and the file is double-clicked, POVWIN will open it in the editor rather than render it (which would otherwise be the default, for compatibility with versions of POV-Ray for other platforms). If you want to associate a file extension with POVWIN in order to render it rather than edit it, you'll need to change the association to pass the /RENDER command-line option Documenting how to change windows to include this is beyond the scope of this tutorial.

1.2.5 Tutorials

There is a comprehensive beginner's tutorial included in this help file. It relates to the use of POV-Ray in general (i.e. on all platforms, not only Windows), so we recommend that you read the rest of section 1 first before attempting to go any further, as section 1 tells you how to use the interface of POV-Ray for Windows itself. The more ambitious may like to check out the advanced tutorial section.

1.2.6 Understanding File Types

This section points out the various types of text files that POV-Ray for Windows works with.

1.2.6.1 POV Files

POV-Ray for Windows works with two types of plain text files. The first is the standard POV-Ray scene description file (also known as 'SDL', for Scene Description Language). Although you may give files of this type any legitimate extension, it is more convenient for you if you name them using the .POV extension. In this Help file, scene description files are referred to as POV files.

The second type, the initialization file, normally have .INI extensions and are referred to in this help file as INI files.

1.2.6.2 INI Files

An INI file is a text file containing settings that instruct POV-Ray how to render a scene. These settings are different from what is in the POV file, which contains instructions to POV-Ray about what is in a scene.

You can store a default set of options in the file called POVRAY.INI in the INI folder under the POV-Ray documents folder. Unless you chose to install the user-specific files elsewhere when you installed, this will be (for example) 'POV-Ray\v3.7\ini\povray.ini' within your 'My Documents' folder. There is a command in the Tools menu that allows you to open this directly (regardless of where you installed).

You can also pass any other INI file to POV-Ray for Windows by selecting it (through Render/Select File and Render) or by dragging it from the Windows File Manager and dropping it onto the POV-Ray window.

One of the options you can set in any INI file is the name of an input file. If you now instruct POVRAY to render the INI file, it will use the above option to determine what POV file to read to generate the actual image. Any other options provided in the INI file will also be applied to the image; hence this way you can customize POV-Ray settings for any individual scene file without having to type them in each time.

For instance, if you have a file called SCENE.POV, you can create a file SCENE.INI to contain settings specific for SCENE.POV. If you include the option 'Input_File_Name=scene.pov' in SCENE.INI, and then ask POV-Ray to render SCENE.INI, POV-Ray will process SCENE.POV with the options specified in SCENE.INI.

Remember, though, that any options set at the POV-Ray for Windows command line when you process an INI file override any corresponding options in the INI file (see Command-line Options and Render Menu). Also, any options you do not set in the INI file will be inherited from any previously-processed INI files (e.g. POVRAY.INI).

You can instruct POV-Ray to generate an INI file containing all the options active at the time of rendering. This way, you can pass a POV file and its associated INI file on to another person and be confident that they will be able to generate the scene exactly the same way you did. See the section titled Using INI Files for more information about INI files.

1.2.6.2.1 INI File Sections

Sections are not files in themselves; they are portions of INI files. Sections are a means of grouping multiple sets of POV-Ray options together in a single INI file, by introducing them with a section label. Consider the following INI file, taken from the POV-Ray 3 documentation:

; RES.INI
; This sample INI file is used to set resolution.

+W120 +H100 ; This section has no label.
; Select it with "RES"

[Low]
+W80 +H60 ; This section has a label.
; Select it with "RES[Low]"

[Med]
+W320 +H200 ; This section has a label.
; Select it with "RES[Med]"

[High]
+W640 +H480 ; Labels are not case sensitive.
; "RES[high]" works

[Really High]
+W800 +H600 ; Labels may contain blanks

If you select this INI file, the default resolution setting will be 120 x 100. As soon as you select the [High] section, however, the resolution becomes 640 x 480. See Edit Settings/Render in the Render Menu for instructions on selecting sections. The 'quick resolution' listbox in POVWIN is an example of this type of file. For more information on POV-Ray options and INI files consult the section on POV-Ray Options.

1.2.7 Using the Internal Editor

The POV-Ray internal editor is an advanced programmer's editor, offering syntax highlighting for POV files (as well as C, Java, and a number of other languages), several indent styles, block indent/undent, column selections, OLE drag and drop, amongst other things. Most of the key mappings are configurable, as are the colors and a number of other options.

It consists of two parts - a custom control, and the 'wrapper' code that encapsulates it. It's important that you remember this, as it will explain some of the behavior that it exhibits (for example, not being able to reassign all keystrokes, just most of them). It is not essential for POVWIN's operation to have the editor present - it is quite possible for it to run without it. However, under normal circumstances, the editor is present.

As of version 3.7 there been a few notable changes to the POVWIN IDE.

  1. There is now a Window menu, which is located where the GUIEXT menu used to be (the latter has moved to within the Options menu). The MRU (most-recently-used) arrangement of this window menu makes it trivial to toggle between files without taking your eyes off the text or using the mouse. The most recently view window (i.e. the current one) will always be entry 1 in the list. The second most recently viewed (i.e. the last window viewed before switching to the current one) will always be entry 2 in the list, and so forth. Given that entries 1 through 10 in the list are given the menu mnemonics 1 through 0 respectively, all you need to do to toggle between the current and previous files is hit Alt-W then 2. To go to the third oldest, Alt-W then 3, and so forth. Note that the MRU list is not saved on exit.
  2. An 'alternate render file' feature was added. This is intended to make things easier when editing macro or include files. While it is possible to use SDL to detect whether a macro/include file is being rendered directly and to pull in supporting code, that approach is not very flexible. The alternate render file feature allows a render to be started on an include file, and instead of the include file being rendered directly (as would have happened previously), the source file that most recently included that file in a render will be rendered instead. For this feature to work, you need to have rendered a file which includes the target file during the current editing session (the association between include files and source files is not persisted when POVWIN exits). Additionally you need to have requested to render a source file which does not have the .POV or .INI extension. When you request the render, a message box will appear asking you what to do. You can choose to render the alternate file this time only, to render the alternate file each time you render this one, or to render this one each time (i.e. disable the alternate file option). In all cases, the choice you give only persists for the current editing session; it is not restored when you re-launch POVWIN. this is by design.

    Note: The term 'source file' means either a .POV, .INI, .MAC or .MCR file.

  3. It is now possible for users to provide their own custom keywords for the SDL keyword completion list and syntax highlighting. These keywords are read from the file 'ini\user-keywords.txt' (located in the POVWIN documents folder) when POVWIN starts up. A tool menu entry provides a shortcut to open this for you.

1.2.7.1 The Editor Feature Set

Here are just a few of the features offered by the editor, as implemented in POVWIN:

Color Syntax Highlighting.
Language-specific keywords, comments, and strings are colored differently to set them apart from plain text.
Keyword Completion.
Language-specific keywords can be automatically expanded or cycled through by pressing the TAB key while the caret is at the end of a partial keyword. Users can add their own keywords by editing a custom definition file.
CodeList.
A pop-up list of keywords will appear if you press Ctrl + Space anywhere in the editor window. If the edit caret is over a partial keyword, the list will be scrolled appropriately.
User Choice Regarding End-Of-Line Behavior.
Some users prefer the ability to place the edit caret beyond the end of line, while other users dislike this behavior. You can choose either.
Customizable Keyboard Mappings.
Keystrokes can be added and removed to emulate popular keyboard mappings. Over 120 individual commands are able to be assigned to the keyboard.
Keystroke Macros.
Users can record a series of keystrokes and assign a keystroke to play back the keystrokes repeatedly. Up to 10 macros may be recorded. These are preserved across editing sessions.
Drag and Drop Text Manipulation.
Highlighted text can be dragged and dropped between any window supporting OLE text Drag and Drop. Text may be copied or moved.
Column Selection and Manipulation.
Columns of text can be selected with the mouse and then manipulated. Empty columns (columns with a width of zero characters) can be selected, causing subsequent typing and deletion to occur over multiple lines at the same time.
Multiple Split Views.
Users can create up to four separate views of the same edit buffer. Each view can be scrolled independently.
Unlimited Undo/Redo.
All edit actions are fully undoable and redoable. A limit can be set on the number of edit actions that may be undone.
Auto Indentation.
Once a language is chosen, as the user enters code, CodeMax will automatically indent lines to following the scoping rules of the language.
Optional Auto-Save.
If turned on, changed files are saved periodically.
Optional Auto-Reload of Changed Files.
The editor will optionally automatically reload an editor file that was changed by an external program while POVWIN didn't have the focus. It can also prompt you as to whether or not you want it reloaded (which is the default behavior).
Brace Matching
Pressing the Ctrl + ] key while the edit caret is on a ’[’, ’(’ or ’{’ will cause the caret to jump to the matching ’]’, ’)’ or ’}’, and vice-versa.
Block Indent/Undent
Pressing the TAB or Shift + Tab keys will indent or unindent a selected block of text.
Tabify/Untabify
You can convert text that was formatted with hard TAB characters into space-expanded form, and vice-versa.
Customizable Colors.
All editor colors (including the background) are customizable. POVWIN also provides two ’quick set’ defaults - white text on a black background and black text on a white background.
Smart Case Preservation in Replace Operations.
During search and replace, you can optionally have the replaced text retain its original case.
Enhanced MRU (Most Recently Used files) List
POVWIN's MRU list not only recalls the filenames of recently opened files, it also remembers the the line, column, and language settings.
Keyword Expansion and CodeList
This feature allows fast insertion of standard POV-Ray keywords either by typing a partial match and hitting TAB, or by using Ctrl + Space to bring up a complete list.
Editor Tab Right-Click Menu
In addition to the usual ’Copy filename to clipboard’ and ’Open containing folder’, there are also menu entries to save the file, close it, close all but it, move the tab left and move the tab right. In addition these new entries have also been added to the window menu. There is no default key combination for moving tabs left or right as the most obvious bindings are already in use. Users can assign whatever they like to it in the editor preferences dialog.

1.2.7.2 Turning the Internal Editor On or Off

Select the Options|Other Settings|Use Editor menu item. If this is off, POV-Ray for Windows will not attempt to load the editor DLL at startup, and the editors will not be available.

1.2.7.3 Preventing File Restore

By default, POV-Ray for Windows will attempt to re-load the files you had open in the editor when you last exited the program. If this causes a problem (e.g. maybe one of the files is very large and you don't want it re-loaded), you can add the '/NR' (or '/NORESTORE') option to the POV-Ray for Windows command line. In this case POVWIN will flush the list of files you had opened.

1.2.7.4 Switching between Editor windows

You can use the Alt+LeftArrow and Alt+RightArrow keys to cycle amongst the editor windows and the message window. Some users are more comfortable with Ctrl-Tab, so this is available as well.

1.2.7.5 Keyword Expansion and CodeList

This facility is designed to speed up the authoring of POV-Ray scene files by allowing you to quickly insert any of the standard or user-defined keywords by typing part of the word and pressing TAB (provided you have the 'Overlay Keyword Expansion On Tab Key' option in the Editor Menu turned on).

If this option is enabled, the tab key serves two functions: it firstly will function to invoke keyword expansion, and secondly, if it appears that keyword expansion is not desired at the current edit position, it functions as a normal tab key (inserting tabs or spaces as defined by your configuration of the editor).

1.2.7.5.1 A Quick Example

Before getting into the explanation below, we suggest you try it for yourself. Firstly, make sure that 'Overlay Keyword Expansion On Tab Key' is turned on (this is the default so unless you have turned it off it will already be on).

Now, open a .POV file in an editor if you don't already have one open, and position the edit cursor ('caret') on a blank line and type the letters 'am', then press TAB. The word 'ambient' should now appear where you had 'am'. Now press it again and you will see the word 'ambient' become 'ambient_light'. Now press SHIFT+TAB (shift and tab together) and you will see that it goes back to 'ambient', and, if pressed again, back to plain 'am'.

1.2.7.5.2 How Keyword Expansion Works

When you press TAB, the editor firstly looks at the characters to the left and right of the current edit caret position. If there is blank space to the left of the caret, or there is no blank space to the right of the caret then keyword expansion does not occur and the TAB key will function normally. Note that for the purposes of this test, the start of the line is not considered blank space, but the end of the line is.

To pass the above test, therefore, the caret must be at the end of a word containing at least one character, followed by a space, tab, or the end of the line. The editor will then get this word from the line and compare it (with case-sensitivity) against the list of known POV-Ray scene file keywords that it holds internally.

If the above comparison yields a perfect match (that is, the word on the left of the caret is exactly the same as a keyword), then keyword expansion does not occur and the tab key functions normally.

If the above test fails (that is, the word is not a perfect match), then a test is made for a partial match. If the word on the left of the caret does not even partially match any word in the keyword list, then expansion does not occur and the tab key functions normally.

If the above test passes, the word on the left of the caret must be a partial keyword (for example, 'pigm' is considered a partial keyword since the editor knows that 'pigment' is a keyword). Given this fact, the editor extracts the list of all keywords that match the partial keyword (in the above example, 'pigment', 'pigment_map', and 'pigment_pattern' all contain the prefix 'pigm' and as such would be included in the list).

The editor stores this list in memory and then completes the partial keyword with the first one (alphabetically) from the list it stored (in the above example, this would be 'pigment'). Once this has occurred, the editor is in 'keyword expansion' mode. The editor remains in this mode until you move the edit position or otherwise make any change to the text other than via TAB and SHIFT-TAB expansion.

Pressing TAB again will cause the next keyword in the stored list of possible matches to appear, replacing the first one, and so forth. If you reach the end of the list, pressing TAB will cause the caption bar of POV-Ray for Windows to flash. This is a visual indication that there are no more keywords in the forward direction.

Pressing SHIFT+TAB causes the previous keyword to appear, and if you are at the first keyword in the list, it will cause the original text you typed to be restored. If you are at the original word and press SHIFT+TAB, the caption bar will flash to indicate that you cannot go back any further.

While all this sounds complex in theory, it is in practice very straightforward and natural to use, and once you get used to it you probably won't want to go back to the old way of doing things.

The advantage of keyword expansion becomes clear if you look at the following example: suppose you wanted to enter the 'smooth_color_triangle' keyword. You could of course type the entire keyword in (a total of twenty-one keystrokes). Or, using keyword expansion, you could enter it using only four keystrokes by typing 'sm' then TAB and TAB again. The first tab expands it to 'smooth' and the second tab expands it all the way to 'smooth_color_triangle'.

Hint: If you use keyword expansion and accidentally expand to a word you don't want, if you haven't yet exited keyword expansion mode, the best way to get back is to use SHIFT+TAB to go backwards. It is very easy to just hit the normal 'Undo' key out of habit. While this will work, it won't always restore the caret position. Using SHIFT+TAB also moves the edit caret back to its starting position as well as restoring the starting word.

1.2.7.5.3 CodeList

The CodeList feature is, like Keyword Expansion, designed to make editing POV-Ray scene files more convenient. It is by default assigned to the keystroke CTRL+SPACE (you can change this from the Keyboard Configuration property page).

Unlike keyword expansion (which allows you to cycle through a list of keywords, one at a time), CodeList allows you to see many of them at once, and select one with the cursor keys or mouse.

CodeList keyword expansion
1.2.7.5.4 Using CodeList

When you press CTRL+SPACE, the editor will extract the word under or immediately to the left of the edit caret (note that this differs from keyword expansion, which requires that the caret be at the end of a word). If this word is blank (that is, the caret was on blank space), or if the word does not even partially match any keyword, an alphabetically-sorted list of all POV-Ray scene file keywords is displayed slightly to the right of and below the edit position. If the extracted word was blank, the list will be positioned at the first entry, otherwise it will be positioned at the keyword that is closest (alphabetically) to the extracted word.

If, however, the extracted word perfectly matches a keyword, and is not part of any other keyword in the list, then the list box does not appear. Instead, the keyword that it matched is inserted into the line and the edit caret is moved to the end of that keyword.

If the above match does not occur, then the alphabetically-sorted list of keywords is displayed, and the list is positioned such that the keyword that the extracted word most closely matches is highlighted and is as close as possible to the center of the displayed portion of the list.

If you look at the above image, you will see an example of this situation. The partial keyword (just above and to the left of the top left-hand corner of the list box) is 'phon', and the list has been positioned to the closest keyword, which is 'phong'.

Once the list is displayed, you can cause the highlighted entry to be inserted into the line by just pressing ENTER, SPACE, TAB, or CTRL+SPACE again, or by double-clicking on a list entry. Pressing the ESCAPE key will remove the listbox without altering the line you are editing. You can navigate the listbox by using the up, down, page-up and page-down keys on your keyboard, by the mouse, or by typing (see below). If you cause text to be inserted by any of the above methods other than SPACE, the edit caret will be positioned immediately at the end of the inserted word. If, however, you press SPACE, the word will be inserted followed by a space, and the new edit position will be after the space.

While the list is displayed, even though the up and down arrow keys map to the listbox, the normal character keys still map to the editor. If you continue to type, the letters will be typed into the line at the editor caret position, and, additionally, the list box will automatically scroll so that the highlighted line is always the keyword that has the closest match to what you have typed in.

1.2.7.5.5 Summary

Just like keyword expansion, the codelist feature can seem complicated when explained in words. However, once you get used to it, it will become quite natural to use.

1.2.7.6 Configuring the Internal Editor

The built-in editor is extensively customizable. It utilizes syntax highlighting and understands .POV, .INC, .MAC, and .MCR files as being in POV syntax. You can change the color settings used from the properties dialog (Alt + Enter). It also has built-in syntax highlighting for C, C++, Java, Basic, Pascal, SQL, HTML and XML. Users can also add their own keywords for syntax highlighting and auto-completion in the editor. See the file ini\user-keywords.txt located in the user's POV-Ray documents folder (or use the tool menu shortcut to open it).

1.2.7.6.1 Important Editor Notes

One important thing to note right away is that the editor properties dialog only allows you to set things that are implemented within the editor (remember, the editor is two components - a DLL called 'povcmax32.dll' (or similar), and another DLL which loads and 'wraps' it into POV-Ray for Windows). There are some other options implemented within the editor wrapper code in POV-Ray for Windows which are able to be accessed via the Editor menu (only visible when an editor is selected). For example, the keybinding for saving a file (Ctrl-S) is not listed in the editor properties since this function is handled by the wrapper code. You can't change this assignment.

Some people have asked why the don't ask again option in the render save dialog is not persistent across sessions. This is by design and is not likely to change.

The edit window context menu has an option for 'show/hide message window'. This window - when displayed at the bottom of an editor window - is sizable. A quick way to close the message window is just to hit ESCAPE, or drag the divider down to within a few pixels of the bottom border - when you release the mouse, the message window will vanish.

You can also tell POVWIN not to display the message window automatically when starting a render. You do this from the Editor menu, by turning off 'Auto-Show Parse Messages'. This is most useful with the Error File option.

POVWIN will optionally automatically load a file in which a parse error has occurred into the editor (or select it if it's already loaded) and place the cursor on the line and column of the offending code. This is able to be turned on or off using the 'Auto-Load Error File' option in the Editor menu. Also, if this option is on, and the message window was displayed automatically (see above), it will be closed automatically rather than being left open. The text describing the error will be displayed in the status bar at the bottom of the window. Note that, occasionally, if the error occurs inside a macro, the displayed line/column for the error will be wrong (though this is uncommon).

1.2.7.6.2 Default Key Mappings

Listed below is the complete set of default keystrokes and the CodeMax command that each keystroke maps to. Note that many depend on caret position. If two sets of keystrokes are listed, either may be used (e.g. 'Copy' is defined as 'Ctrl + C or Ctrl + Insert', which means that you may use either 'Ctrl + C' or 'Ctrl + Insert' to perform a copy; whichever suits you. There is no difference between one or the other).

Note that if more than one key sequence is assigned to a command, and the command is one of those listed in the menus (not all commands are listed in the menus), the key sequence shown as the shortcut key in the menu is generally the shortest one (in terms of its printed representation).

You can change any of the below-mentioned key assignments if the defaults don't suit you. Additionally, the below table does not list the more than 50 commands for which there is no default key assignment. Use Alt + Enter on an editor screen, or select 'Codemax Properties' from the Editor menu to assign these.

BookmarkNext | F2 | Move to next bookmark
BookmarkPrev | Shift + F2 | Move to previous bookmark
BookmarkToggle | Ctrl + F2 | Place a bookmark
CharLeft | Left Arrow | Move caret left
CharLeftExtend | Shift + Left Arrow | Move caret left and highlight
CharRight | Right Arrow | Move caret right
CharRightExtend | Shift + Right Arrow | Move caret right and highlight
CodeList | Ctrl + Space | Show keywords (reference or insertion into file)
Copy | Ctrl + C or Ctrl + Insert | Copy selection to clipboard
Cut | Ctrl + X or Shift + Delete | Remove selection to clipboard
CutSelection | Ctrl + Alt + W | Remove selection (same as Cut)
Delete | Delete | Delete one character right (can Undo)
DeleteBack | Backspace or Shift + Backspace | Remove one character left (can Undo)
DocumentEnd | Ctrl + End | Move to end of file
DocumentEndExtend | Ctrl + Shift + End | Move to end of file and highlight
DocumentStart | Ctrl + Home | Move to start of file
DocumentStartExtend | Ctrl + Shift + Home | Move to start of file and highlight
Find | Alt + F3 or Ctrl + F | Find, or search
FindNext | F3 | Find next (specified)
FindNextWord | Ctrl + F3 | Find next (selected)
FindPrev | Shift + F3 | Find previous (specified)
FindPrevWord | Ctrl + Shift + F3 | Find previous (selected)
FindReplace | Ctrl + Alt + F3 or Ctrl + H | Find/Replace dialog
GoToLine | Ctrl + G | Move to a line number dialog
GoToMatchBrace | Ctrl + ] | Match brace }, bracket ], or parenthesis )
Home | Home | Move to start of line text (or line)
HomeExtend | Shift + Home | Move to start of line and highlight
IndentSelection | Tab | Indentation (number of spaces set in properties)
LineCut | Ctrl + Y | Remove current line
LineDown | Down Arrow | Move to next line
LineDownExtend | Shift + Down Arrow | Move to next line and highlight
LineEnd | End | Move to end of line text (or line)
LineEndExtend | Shift + End | Move to end of line and highlight
LineOpenAbove | Ctrl + Shift + N | Make new line above current line
LineUp | Up Arrow | Move to previous line
LineUpExtend | Shift + Up Arrow | Move to previous line and highlight
LowerCaseSelection | Ctrl + U | Change highlighted text to lower case
PageDown | Page Dn | Move down a page
PageDownExtend | Shift + Page Dn | Move down a page and highlight
PageUp | Page Up | Move up a page
PageUpExtend | Shift + Page Up | Move up a page and highlight
Paste | Ctrl + V or Shift + Insert | Place clipboard contents into file
Properties | Alt + Enter | CodeMax properties dialog
RecordMacro | Ctrl + Shift + R | Record/stop a macro
Redo | Ctrl + Y | Redoes last undone action (i.e. undo an undo)
SelectAll | Ctrl + A | Highlight entire file
SelectLine | Ctrl + Alt + F8 | Highlight the current line
SelectSwapAnchor | Ctrl + Shift + X | Switch place of caret with start of highlighting
SentenceCut | Ctrl + Alt + K | Remove a continuous line to clipboard
SentenceLeft | Ctrl + Alt + Left Arrow | Move to start of continuous line
SentenceRight | Ctrl + Alt + Right Arrow | Move to end of continuous line
SetRepeatCount | Ctrl + R | Number of times to do next command
TabifySelection | Ctrl + Shift + T | Change highlighted spaces to tabs
ToggleOvertype | Insert | Toggle between inserting and overwriting
ToggleWhitespaceDisplay | Ctrl + Alt + T | Show or hide spaces
Undo | Ctrl + Z or Alt + Backspace | Undo last change
UnindentSelection | Shift + Tab | Remove indentation of selected line
UntabifySelection | Ctrl + Shift + Space | Change highlighted tabs to spaces
UpperCaseSelection | Ctrl + Shift + U | Change highlighted text to upper case
WindowScrollDown | Ctrl + Up Arrow | Scroll file down, leaving caret
WindowScrollLeft | Ctrl + Page Up | Scroll file left, leaving caret
WindowScrollRight | Ctrl + Page Dn | Scroll file right, leaving caret
WindowScrollUp | Ctrl + Down Arrow | Scroll file up, leaving caret
WordDeleteToEnd | Ctrl + Delete | Delete a word from caret to end
WordDeleteToStart | Ctrl + Backspace | Delete a word from caret to start
WordLeft | Ctrl + Left Arrow | Move to start of current word
WordLeftExtend | Ctrl + Shift + Left Arrow | Move to start of current word and highlight
WordRight | Ctrl + Right Arrow | Move to end of current word
WordRightExtend | Ctrl + Shift + Right Arrow | Move to end of current word and highlight
1.2.7.6.3 Setting Key Mappings

Most of the keystrokes used by the editor are re-assignable - even those listed in the menus. (Some users have assumed that commands with shortcuts listed in the menus aren't assignable, but this isn't the case - if you change the assignment, the new shortcut shows up in the menu).

Each editor command can have up to two different keyboard actions assigned to it, and each keyboard action may have either one or two keystrokes. Most users will use only one keystroke, but those who are still familiar and comfortable with the old 'Wordstar' key assignments (e.g. Ctrl-Q, F for Find) will be pleased to discover that these are still available to them, should they want to take the time to assign them.

If you assign more than one key sequence to a command, and the command is one of those listed in the menus (not all commands are listed in the menus), the one that is listed in the menu as the shortcut key is generally the shortest one (in terms of its printed representation).

You can access the keystroke assignments via the CodeMax properties dialog. By default, this is mapped to Alt+Enter when an editor is displayed. Alternatively, you can get at it from the Editor menu (only visible when an editor is selected) or the editor right-mouse-button context menu.

1.2.7.6.4 Reserved Keys

Not all commands are assignable ! In general, only the commands that are directly implemented in the CodeMax editor DLL are able to be set. These commands are ones that relate to operations on individual edit buffers. They do not include such things as file operations (load, save, print, etc). These operations are implemented in the POVWIN editor wrapper code and are not managed or able to be changed by CodeMax. Therefore, it should be clear that you can neither change the key bindings for operations such as file save, nor use the POVWIN- assigned keystroke (e.g. Ctrl-S in the case of save) for any other purpose.

1.2.7.6.5 Using the Mouse

The editor supports the following mouse actions:

Left click over text | Changes the caret position
Right click over open file | Displays the pop-up menu
Left Button down over selection, hold and drag | Moves text
Ctrl + Left Button down over selection, hold and drag | Copies text
Left click over left margin | Selects line
Left click over left margin, hold and drag up or down | Selects multiple lines
Alt + Left Button down, hold and drag | Select columns of text
Left double click over text | Select word under cursor
Spin IntelliMouse (compatible) mouse wheel | Scroll the window vertically
Single click mouse wheel | Select the word under the cursor
Double click mouse wheel | Select the line under the cursor
Click and drag splitter bar | Split the window into multiple views or adjust the current splitter position
Double click splitter bar | Split the window in half into multiple views or unsplit the window if already split
1.2.7.6.6 Hints for Match Brace

Several European users have commented that the default key assignment for 'Match Brace' (Ctrl-]) is not usable on their keyboards. Please note that you can change this to whatever you please. Another thing to remember about the match brace command is that it only works if it is executed when the edit caret is on a brace character ('{', '}', '(', ')', '[', ']'). The caret will then jump to the matching character (e.g. if it's on a '(', it will jump to the matching ')').

1.2.7.7 The Language Setting

The language setting is a good example of a setting that applies to the current file only. This setting determines what sort of syntax highlighting is applied to the file. For example, a POV or INC file would probably have a language setting of 'POV-Ray'. A Java file (should you choose to use POVWIN to edit one) would have a language setting of 'Java'.

This setting is initially (when you first open a file, or create a new one) set according to the file extension. .POV, .INC, .MCR and .MAC files are considered POV syntax. A new file (one with the name 'Untitled') has no language.

Once the file is first loaded, you are free to change the language to whatever you like. This change affects only the current file and no other file ! The change you have made will be remembered by POV-Ray. Any file that is still in the MRU list (or the 'Older File' list - see the File Menu section for more details) has its language setting stored along with a number of other file-specific attributes.

Note that if you open a file manually (using Drag-Drop or the file browse dialog, for example), the old settings are discarded, even if the file was in the MRU list. This is by design.

1.2.7.8 The Font Setting

The Font setting is a good example of a global setting - it affects all open files. Once you change the font used in the editor, all open files get the new font, as well as any new files opened after that point.

1.2.8 I/O Restrictions

I/O Restrictions are a feature introduced in POV-Ray v3.5. The purpose of this feature is to attempt to at least partially protect a machine running POV-Ray from having files read or written outside of a given set of directories.

The need for this is related to the fact that the POV-Ray scene language has, over the years, become something more akin to a scripting language combined with a scene-description model. It is now possible to write obsfucated POV-Ray code, and to open, create, read and write arbitrary files anywhere on the target system's hard disk (subject to operating system permission).

The basic idea of I/O Restrictions is to attempt to protect the user from a script that may have been downloaded from an untrusted source, and which may attempt to create or modify files that it should not.

The I/O Restriction facility hooks the file open and creation functions in the core POV-Ray renderer code, and allows the Windows version to allow or deny any particular file operation. Please note that this only affects file I/O from the core POV-Ray code; that is, the code that implements the parser and renderer. It does not affect which files the Windows interface can read and write. That is to say, it does not prevent you loading a file into an editor, or saving a file from the editor, or any other feature implemented on the Windows interface that is not part of the core POV-Ray feature set. (The 'core feature set' is those features of POV-Ray that are available on all operating systems and computer platforms for which a version of POV is available).

We do not guarantee that the I/O Restriction facility will actually stop anything from happening. There is always the chance that, like almost all software, it could have a bug in it that causes it to malfunction. Therefore, the onus is on the person who chooses to load an INI or scene file into POV-Ray to ensure that it does not do anything that it should not do. I/O Restrictions are just a sometimes-helpful backup for manual checks.

Please read this section in full so that you understand the caveats and conditions of the facility (such as the fact that some directories are allowed by default).

1.2.8.1 High-Level Configuration

Now to the details: how to configure the I/O Restrictions (or get them out of your hair if you want them turned off). Under the Options menu there is a sub-menu called Script I/O Restrictions.

Script I/O Restrictions sub-menu

This provides you with high-level control of the restriction subsystem. The top section of the menu provides you with three options (detailed below). You can only choose one of the three. The bottom section provides you with two additional options, either of which can be on or off.

1.2.8.2 Overall Options

1.2.8.3 No Restrictions

If this option is chosen, POV scripts can read/write everything (subject to operating system permission). The I/O Restriction system is turned off.

1.2.8.4 Restrict Write but Allow Read

If this option is chosen. POV scripts can read anything, but file creation and file write is only allowed in the implicit and user-specified directories (see Low-Level Configuration for more information on how to specify which directories).

Another way to put it is that I/O Restrictions are turned off for reading files, but not for writing them.

1.2.8.5 Restrict Read/Write

Both read and write by POV scripts is restricted to implicit and user-specified directories. Note that this is the default setting for a clean installation of POV-Ray for Windows.

1.2.8.6 Restrictions Affect all Core File I/O

Note that the above settings do not just affect scripted file I/O; they also affect things like include files, output files, and input .POV files. Basically any file-related input or output by the rendering engine. You should take careful note of this statement if you are in the habit of writing your output files to anywhere other than the same directory as the scene file is in (see below).

1.2.8.7 Additional Options

In addition to the above, there are two other options:

1.2.8.8 Permit Read/Write in Current Directory

If turned on, the current directory (but not any below it) is automatically added to the allowed list of read/write locations. Since POVWIN sets the current directory to that which contains the source file (.pov or .ini) at the start of a render, this automatically enables the location containing a scene for read/write. For most people, this is a useful feature, so it is on by default for a clean install.

Please note that having this option unchecked does not prevent read in the current directory if you have turned off read restrictions (as documented above), and nor will it prevent writing if you have turned off I/O Restrictions altogether. Also, turning it on will not allow read/write in subdirectories of the current directory - just that dir alone.

1.2.8.9 Disable Starting other Programs

If this option is selected (the default), shell-outs will not be permitted. 'Shell Outs' are a facility where an INI file can specify that a particular program be run either before or after a frame is rendered as well as at other points in the parse/render process. If you want these, you have to explicitly allow them by unchecking this option.

1.2.8.10 Low-Level Configuration

This section tells you how to manually specify explicit directories for read/write access, if the standard settings aren't suitable. First we need to cover what is and isn't protected by default.

1.2.8.11 Overall Concept

The overall concept of the I/O Restrictions, when enabled, is that everything should be denied unless it is explicitly allowed (with one or two exceptions). So unless you add a directory to the 'allowed' list, unless it is one of the implicitly allowed locations then the directory in question is not permitted to be accessed.

1.2.8.12 Implicitly Permitted Locations

The exceptions to the 'deny everything' rule (referred to above as 'implicit' locations) are as follows:

  1. The document installation directory of POV-Ray for Windows (as given by the registry or otherwise determined at run-time) is permitted to be used for read (but not write). This includes all of its subdirectories (except as below). Note that you can alter this setting if you like.
  2. Write is permitted to the 'Insert Menu' sub-directory within the POV-Ray documents install directory. This is to enable the 'Re-render Insert Menu Bitmaps' feature to function without needing to modify the restrictions.
  3. Read is permitted from the Windows 'Fonts' directory. This is to allow TTF files to be read, as POV-Ray's portable rendering engine has its own TTF parser. (The Fonts directory is also added to the include path automatically).

1.2.8.13 Adding or Changing Allowed Directories

Note: The INI subdirectory contained within the document install directory is permanently write-protected (unless the I/O Restriction system is turned off). Even if you grant permission to write this dir from he below INI file, writes will not succeed. This is to prevent the INI file that contains the I/O Restriction configuration from being modified by a script to grant itself more access next time POVWIN is run.

To add or change allowed directories, you'll need to modify the file <installdir>\ini\pvengine.ini, where <installdir> is where the POV-Ray for Windows user-editable files where installed. An easy way to get at this file is to select it from the tools menu (by default, it is the second item).

Within PVENGINE.INI you may see two sections like the following ... (note that the actual contents of the installed version are slightly different from this example).

[Permitted Input Paths]
1=%INSTALLDIR%

[Permitted Output Paths]
1=%INSTALLDIR%

If they are not present, it means that POVWIN is using the defaults, in which case you may add them. For example, %INSTALLDIR% is implicitly allowed for input and does not need to be added to the INI file (though there is no harm in doing so).

%INSTALLDIR% resolves to the location that the POVWIN user-editable files were installed. It would be legal to say something like -

%INSTALLDIR%\scenes

for example, to refer to (say) C:\Users\Joe\Documents\POV-Ray\3.7\Scenes.

Relative paths are legal as well, and will be resolved only once at load time (but relative to the current directory, not the documents folder). For example, a relative path like the following ...

[Permitted Output Paths]
1=..\output

would be resolved with relation to the current directory at the time POV-Ray for Windows was started, so if you started pvengine.exe from the directory c:\myscenes\newscene, then the above path would be resolved as c:\myscenes\output. Please note that the actual location of the POV-Ray executable file is not relevent here - it is the current directory that matters (which is not necessarily that of the program installation). You only need to care about this if you want to use relative paths in the restrictions setup: 99% of users don't, so if it doesn't make sense, don't worry :-)

A directory placed in the permitted input paths section only allows read. One placed in the output paths section permits both read and write; write permission is inferred to mean read permission. This means you don't need to duplicate entries (the above example shows such a duplication - it is not harmful, just unnecessary). You can have up to 64 entries (numbered 0..63) in each section.

An entry in the permitted paths sections gives permission not only for that directory, but all the ones below it (note that this is different from the 'permit read/write in current directory' option mentioned earlier, which only applies to that one directory alone, and not those below it).

A reminder that, as mentioned above, if write protection is turned on at all, the <installdir>\INI directory is always write-protected, and nothing in the above permission sections should be able to allow it. This is to prevent a script from modifying pvengine.ini to remove or alter the I/O Restrictions for the next time that POVWIN runs.

1.2.8.14 For Those Who use an Image Output Directory

Some users have POV-Ray set up such that all images are written into the same output directory. To make this work with I/O Restrictions active, and assuming the output directory isn't in the POV-Ray for Windows document folder, you will need to add that directory to the permitted output list.

For example, if your image output directory is c:\images\, you could have something like this in the INI file -

[Permitted Input Paths]
1=%INSTALLDIR%

[Permitted Output Paths]
1=%INSTALLDIR%
2=c:\images

If you want to grant access to an entire drive (e.g. d:\), just add it like this -

[Permitted Input Paths]
1=%INSTALLDIR%

[Permitted Output Paths]
1=%INSTALLDIR%
2=c:\images
3=d:\


Windows Section 3

1.3 Command-Line Options

Options are what previous versions of POV-Ray used to refer to as command-line options. The term is no longer accurate for POV-Ray since version 3.5, because the command line is only one way of passing options to the program. There are now four ways you can pass an option to POV-Ray:

  1. You can store them in the INI\POVRAY.INI file located within the POV-Ray documents directory. This is the master INI file. Whenever you start a render, this file is read before any other INI file. If you want to make changes to the way POV-Ray works by default, you should make them in this file. The Tools menu contains an entry to edit this master POVRAY.INI.
  2. You can store them in an POVRAY.INI file in the directory containing the file being rendered. POV-Ray looks for a POVRAY.INI file in this location whenever it starts rendering after it has read the master POVRAY.INI file. Options in this INI file will thus override options specified in the master POVRAY.INI.
  3. You can store them in an INI file created for a particular scene (this is a standard POV-Ray feature not specific to Windows).
  4. You can enter them on the command line (see Command Line Dialog or the Toolbar Command Line). Any command-line option override any options specified elsewhere (i.e. they have the highest priority). POV-Ray for Windows interprets the command line from left to right, so that any option (or INI file) on the command line overrides a corresponding option (or another INI file) to its left on the command line.

1.3.1 POV-Ray Documents Directory

The 'POV-Ray Documents Directory' is the file folder on your computer that the user-editable files for POVWIN are stored. The default for this has changed in version 3.7. In prior versions, this was called the 'Home Directory' and was the same location that the POV-Ray program itself was installed in. Due to changes required to support Windows Vista and later, POVWIN now installs in two folders: the first, holding the program and any support files that are not user-specific (such as the help), is placed wherever you specified it be placed during install (by default this will be in Program Files).

The location of the POV-Ray Documents directory containing user-editable files (include and INI files, sample scenes, insert menu, etc) now defaults to <Your Documents Folder>\POV-Ray\v3.7 (for version 3.7). You may specify a different location upon install if you wish.

Note: System admins/lab techs should check the /INSTALL command-line option for means of customizing the above.

1.3.2 Special Command-Line Options

POV-Ray for Windows supports several special command-line options not recognized by other versions.

Note: Do not confuse the term 'command-line options' in this section with the toolbar command-line. The command-line we are referring to here is the one used to start the POV-Ray for Windows program file. The following special command-line options cannot be used on the toolbar command-line or in the command-line dialog.

  • The /DEMO command tells POV-Ray to run its demonstration render. All other options on the command-line are ignored.
  • The /EXIT command tells POV-Ray to perform the render given by the other command-line options, combined with previously-set options such as internal command-line settings, INI file, source file, and so forth, and then to exit. By default, if this switch is not present, POV-Ray for Windows will remain running after the render is complete. This switch only applies to renders started by other options on the command-line. It will not affect renders started manually from within POV-Ray for Windows itself.
  • The /NR command (same as /NORESTORE) tells POV-Ray for Windows to not attempt to restore any previous edit sessions (i.e. files that were open in the editor). This is handy when you had a large number of files open and you don't want them taking up time loading.
  • The /RENDER command tells POV-Ray for Windows to render the file following. Only one command is permitted on the command-line. Wildcards are not permitted.
  • The /EDIT command causes POV-Ray to load the following file into an editor. You can have multiple commands on the command-line, with one file per command. The filenames may not contain wildcards.
  • The /EDITDLLPATH normally would not be needed, unless the DLL isn't in the expected location and isn't stored with the EXE. It excepts a PATHNAME as an argument.
  • The /INSTALL and /QINSTALL options are to ease non-standard installations of POV-Ray. See below for more information.
  • The /THREADS option allows you to specify how many threads are used during renders (this value can also be set via a menu option but is - by design - not persisted).
  • The /DEBUG option turns on a number of debugging features related to POVWIN specifically (i.e. not related to rendering or the core code). During startup some additional information is written to the message pane. Further, the same information is written to the Windows debug facility via OutputDebugString. Finally, the file c:\temp\povdebug.txt will be created (provided that the c:\temp directory already exists) and the debug output sent there as well. If the file already exists, it is deleted prior to re-creation. The file is opened and closed each time it is appended to during the session.
  • The /BENCHMARK option runs the standard POV-Ray benchmark. See below for more details.

Note: When supplying a filename with spaces in it, you will need to enclose the filename itself within quotes.

1.3.3 The Benchmark Command-line Option

The /BENCHMARK command-line option causes POVWIN to begin rendering the standard POV-Ray benchmark as soon as it is launched, then exit. Normally no dialogs should be presented - the intention is to allow for the benchmark to be rendered without user interaction. The results of the benchmark are automatically placed into the clipboard at the end of the run, and additionally saved to a file in the POV-Ray documents directory (this is the same location that the include file and sample scene folders are placed upon installation - by default this is c:\users\<username>\Documents\POV-Ray\v3.7). The file name is in the format benchmark-YYYYMMDD.HHMMSS.txt, where the timestamp represents the time the render completed. An example of the file content is below.

CPU time used: kernel 0.87 seconds, user 2049.90 seconds, total 2050.77 seconds.
Elapsed time 274.16 seconds, CPU vs elapsed time ratio 7.48.
Render averaged 956.16 PPS (127.83 PPS CPU time) over 262144 pixels using 8 thread(s).

Render of benchmark version 2.01 completed at Saturday, September 21, 2013 06:34:15 UTC.
----------------------------------------------------------------------------
cpuarchitecture=9
numberofcpus=8
processortype=8664
processorlevel=21
processorrevision=258
cpufrequency=3612
cpufeatureset=540753406
cpuname=AMD FX(tm)-8150 Eight-Core Processor
cpuidentifier=AMD64 Family 21 Model 1 Stepping 2
cpuvendoridentifier=AuthenticAMD
osversion=6.1
osbuild=7600
csdversion=
physicalmemory=12843241472
povversion=3.7.0
compilerversion=.msvc10
platformversion=win32

Most of the contained information is self-explanatory. To interpret the values shown for fields such as cpuarchitecture, please consult the Microsoft documentation for the GetNativeSystemInfo() Win32 API call.

1.3.4 Non-Standard Installations

The /INSTALL and /QINSTALL command-line switches should not normally be needed. They exist to make it easier for POV-Ray to be set up in a lab environment or otherwise used without having to perform a full installation. See below for detailed information.

1.3.4.1 Background

POVWIN does not require the normal registry entries (HKCU\Software\POV-Ray) to be present in order to function. It can, if need be, infer the information it needs at run-time, provided a standard layout is used. If this works for you, it may not be necessary to install anything. The only support binaries needed by the program are expected to be in the bin directory along with the executable; these are the editor DLL's, the crashdump utility (optional), and dbghelp.dll (also optional, and only needed for crashdumps). There is no dependance on dynamic run-time libraries outside of the standard ones shipped with Windows.

The two distinct locations POVWIN needs to know of are the location of the non-user-specific files (DLL's, help files, etc), and the location of the user-specific files. The normal layout is to have the EXE's and DLL's in a bin directory, help files in help, sound files in sound, and background bitmap tiles (not used by default) in tiles. All of these directories should be contained in the same parent directory or the root of a drive or network mapping. This location (referred to as the 'Home' directory in previous versions of POVWIN) is used by POVWIN to work out where to find e.g. the help file if F1 is pressed. The second location is the place where the user-editable files are expected to be found. This covers the include files, sample scenes, and the INI folder used to read and store settings that aren't obtained from the registry.

If the home directory is not specified in the registry, POVWIN will attempt to work it out by looking at the path from which it was loaded, then taking the parent of that and looking for the help directory within that. So for example if POVWIN was loaded from m:\foo\bar\bin\pvengine32.exe, it would look for m:\foo\bar\help. If this is not found it will look for sounds and then finally tiles. If any of these succeed it will infer that this parent directory is the home and store that for the session along with a value in the registry that lets POVWIN check if it has changed (the Home registry key is not set however). The first time this infer succeeds, a message is displayed in a dialog saying so. The next time POVWIN starts it will do the infer again and if the location has not changed it won't display this message.

If the POVWIN documents directory is not stored in the registry, POVWIN will - each time it is run - look for its presence in the default location, which is \POV-Ray\v3.7 for the case of POV-Ray v3.7. If that directory does not exist, it will be automatically created along with the INI directory beneath it. No error message is issued if this create fails, however, nor will it prevent POVWIN from working (provided any needed source/include files can be located elsewhere).

If you want to persist the inferred location, or want to provide custom locations for the above without the need to run an installer on each workstation, you may use the /INSTALL or /QINSTALL command-line switches as documented below.

1.3.4.2 The /INSTALL and /QINSTALL switches

/INSTALL and /QINSTALL operate identically except that if you use /QINSTALL, any actions taken are performed quietly and any questions that would normally be asked are defaulted.

The syntax is /INSTALL [home dir] [user dir], where home dir is the location of the directory containing the bin, help etc folders as described above, and user dir is that of the POV-Ray user documents folder. The paths, if supplied, must be quoted if they contain spaces. If called without parameters, POVWIN attempts to infer the first path as normal and if successful writes this location to HKCU and (if permissions permit) to HKLM. When run normally POVWIN will first look in HKCU then HKLM for the home directory, so this can be used to set a machine-wide value.

If called with one parameter, the action is the same as for no parameters, except that no infer is done: the supplied path is just written to the registry.

If called with two parameters, the action is as above, and the second parameter is taken to be the location of the user files directory. This is checked for validity; if it does not exist a dialog will ask if you wish to use it anyway (unless you specified quiet, in which case the answer defaults to 'yes'). This value is then written to the registry under HKCU; there is no HKLM equivalent at this point.

For most cases, the zero or one parameter version would be sufficient, as POVWIN is quite happy to use the default location for the user documents and will not issue any messages if it doesn't exist.

1.3.4.3 Publishing via Group Policy

If you wish to push the settings out via GP, there's only one or two values you need to supply. The main one is the location of the home dir containing the binaries etc. This is HKCU\Software\POV-Ray\v3.7\Windows\Home, which is a REG_SZ containing the path. Alternately you may place this into the same location within HKLM on each workstation; either is sufficient (with HKCU being checked first).

The second value is that of the user files directory: HKCU\Software\POV-Ray\v3.7\Windows\DocPath, also a REG_SZ. There is no HKLM equivalent of this.

In either case, if the version of POV-Ray changes, the registry key will change accordingly, but only for X.X releases; e.g. 3.8 would use HKCU\Software\POV-Ray\v3.8\..., but 3.71 would still use HKCU\Software\POV-Ray\v3.7\.... This allows multiple versions of POV-Ray to be used on the same system.

1.3.4.4 System Admins / Lab Techs

If you need to do custom installation of POVWIN, please see Non-Standard Installations. If you want to use our standard installer, please note it is built with NSIS and is thus not available as an MSI. [We did experiment with MSI's - for about two years our betas were MSI-based - but after some bad experience with InstallShield decided to go with an open-source installer.]

Please note also that any official Windows binaries distributed by the POV-Ray developers will be signed. This includes the setup executable itself and all DLL's and EXE's contained within it. The key as of the time of writing (February 2013) is issued by DigiCert to Persistence of Vision Raytracer Pty Ltd and has a thumbprint of 32 61 e6 2e 2e e8 2a fa 71 2f a2 0e 89 b6 5b a0 68 35 20 e4.

Note: The POV-Ray developers would like to extend thanks to »DigiCert for providing us with the above code-signing key and also our site SSL certificates.

1.3.5 Adding New Resolutions

The 'Preset Rendering Options' drop-down combobox on the toolbar provides a quick way of choosing previously specified sets of rendering options. The contents of this combobox can be modified. Here's how to do it.

All the resolution and rendering options that are available in the combobox mentioned above, are in fact loaded from an INI file. The INI file is called QUICKRES.INI by default, and is located in the INI folder within the POV-Ray documents folder referred to above. This file is known as the 'secondary INI file' (or 'resolution INI file') because it is loaded after the main POVRAY.INI (see INI Files for more information). You can also change the current secondary INI file selection from the Render Settings dialog.

An easy way to edit the secondary INI file is to select 'Edit Resolution INI File' from the Tools menu. Each section (delimited by '[' and ']') in this file will, once POV-Ray for Windows is restarted, be loaded into the resolution combobox for you to choose. Of course, you are not limited to resolutions; the sections can contain any valid POV-Ray INI file options, such as output file type, anti-aliasing, radiosity settings, etc.

To add a new resolution, just add a new section and re-start POV-Ray. Here's an example of what you could add to insert the new resolution 1600 x 1200 with AA 0.3. The entry will appear on the resolution list with the name 'Big and Slow' -

[Big and Slow]
Width=1600
Height=1200
Antialias=On
Antialias_Threshold=0.3

The name of the section between the square brackets ('Big and Slow') is what you see in the resolution list.

One more thing - you don't need to add a new resolution to the INI file if you don't want to. You can still, as always, specify an arbitrary resolution on the command-line via the Render Settings Dialog mentioned above or via the toolbar command-line.

Note: One occasional mistake made by users of previous versions of POV-Ray for Windows was to assume that the list of resolutions available in the above toolbar combobox was fixed and unable to be changed (some even thought that POV-Ray could not render any resolutions other than those listed in the combobox ... despite the documentation saying otherwise). This is a good illustration of the need to read documentation.


Windows Section 4

1.4 Windows

This section gives you a short run-down on the three main window elements that you will need to deal with - the Main Window, the Message Window, and the Render Window.

1.4.1 The Main Window

POV-Ray for Windows main window

1.4.2 The Toolbar

The toolbar contains a number of buttons and two controls. The buttons are labelled and should be self-explanatory. The purpose of the two controls, which are the pre-set rendering options combobox and the toolbar command-line, are discussed below.

1.4.2.1 Preset Rendering Options

 | This listbox contains a list of pre-set rendering options that you can choose just by clicking on one of them. By default, the list contains resolution and anti-aliasing related options, however, any POV-Ray option can be specified in the INI file that the list in the listbox is built from. It is easy to add your own entries to this list; see the section titled Adding New Resolutions for instructions.
Preset rendering options listbox |

Note: Options entered on the POV-Ray command-line (via the toolbar, the command-line dialog, or the pvengine.exe command-line) will override any options specified by the above listbox.

1.4.2.2 Toolbar Command Line

The toolbar command-line is a shortcut to the command-line that is found in the Command Line Dialog. In past versions of POV-Ray for Windows, the key combination Alt+C would bring up the command-line dialog; now it will instead shift focus to the toolbar command-line. The command-line dialog is still accessible via the Render Menu, as before. |
 | Toolbar command line edit box

Once the toolbar command-line has focus, you may return focus to the editor or message window by pressing ESCAPE. Pressing ENTER will start a render. Any valid generic POV-Ray command-line switch can be used in this command-line, including INI options. See the Options Reference for a full list.

Hint: The Editor Context Menu has a handy shortcut for copying commonly-used command-lines from your scene files into the command-line field.

1.4.3 The Status Bar

At the bottom of the main window is a status bar. The left part of the status bar contains an information and help field. After that comes the current line and column of the editor caret, followed by a panel that shows 'INS' for editor insert mode, and 'OVR' for overwrite mode. Next to this you will find a Pixel-Per-Second indicator and a clock showing time elapsed (in days-hours-minutes-seconds) since the beginning of the last render job. This clock stops when the job completes. Note that on extremely slow renders, the PPS indicator may change to showing PPM (pixels per minute), or PPH (pixels per hour). Note also that the clock shows only elapsed time - not CPU time. As Windows is a multi-tasking operating system the two are not the same (though if you are running no other applications they will be fairly close).

1.4.4 The Tab Control

Displayed within the main window is a tabbed control. Using this you may select either the Message window or an Editor window (if a file is open) to be displayed within the main window. You may also switch tabs by using the 'Alt+Left Arrow', 'Alt+Right Arrow', 'Ctrl+Tab' or 'Shift+Ctrl+Tab' keyboard shortcuts.

Hovering your mouse over an editor tab will cause the name of the file to be shown in a hint. Right-clicking on it will pop up a menu providing the option to copy the full filename to the clipboard, open the folder containing the file in Windows Explorer, close the file, close all files other than the tab's file, move the tab left and move the tab right. Middle-clicking on it will close the tab. Note that you can also assign keyboard shortcuts to these actions.

Note that POV-Ray for Windows does not support MDI (the Multiple Document Interface). This is by design. You can only display one window at a time (with the exception that you can see a portion of the Message window from an editor window when rendering, and that the editor itself can split the edit pane into several views).

1.4.5 The Message Window

The message window displays text output from the POV-Ray raytracing engine. You'll find such things as render setting info, parse/render statistics, and parse warnings/errors displayed here. It has its own Context Menu.

You can change the background of the message window, along with its font and font color, from the Options|Message Window menu. The Edit menu allows you to copy the currently visible message pane to the clipboard as text (it is not possible to select portions of the text), and to erase the messages.

By default, each time you run a render, the message pane is cleared. If you wish new messages to be appended to the end of the existing messages you can turn on 'Preserve Messages' in the options menu.

1.4.6 The Editor Window

The editor window

An Editor Window shows a file which has been opened for editing. It has its own Context Menu. There will be one editor window for each open file (maximum 32). The particular editor window being shown depends on the tab control that contains it.

There are an extensive set of options available for customizing the appearance and function of the editor window. See the sections on Using the Internal Editor, Configuring the Internal Editor, the Editor Menu, the Text Menu, and the Editor Preferences Dialog.

1.4.7 The Render Window

 | The Render Window pops up whenever you render a scene with the POV-Ray 3 display option (+d) set. The Render Window shows the scene as it is being rendered. The window is updated in blocks (default 32x32 pixels) as each render thread sends through its most recent result. It has its own Context Menu. If you close the Render Window you can re-display it by selecting Re-display from the Render Window submenu in the Options Menu, or by pressing the 'Show' button on the toolbar.
The render window |

Warning: Just because you can see the image in the Render Window does not mean it is being saved to disk, or that it can be saved to disk. In many cases the data stored for display purposes is different than the data stored in an output file. If you don't have Output_To_File switched ON (this is the default, unless you have turned it off) then you will not get an output file and once the render is finished it is too late. If you want an output file you must select it before you start rendering.

We realize that this is different from many Windows programs, but the resources needed to store a full version of a rendered image in memory (especially if it's large) could often be best used elsewhere. The Render Window is only meant to be a preview of the final image. It is there for convenience.

Don't forget that if you choose (via an INI file) to have images written to a default directory, then that is where they will be unless you override this behavior. If you didn't select this option then the file will be written to the directory containing the scene file. Specifying an output file name that consists of only a path, such as c:\images\, will cause the output file to be written to that directory. POV-Ray determines if the filename is a path by looking at the last character and making sure that it is a '\'. The directory must already exist.

Note: To disable the Render Window, you must specify the -d option on the command-line, or Display=Off on the command-line or in one of the INI files processed. Simply closing the render window after it is created does not free up the memory used by it.

If you are running a high-resolution render, and have a high-color or true-color display, you can save RAM by turning the render window off. The amount of RAM used by the render window can be calculated as render width * render height * 3 bytes (if using 24 bits per pixel for your video display) or x 4 if using 32bpp. Most modern PC's will use either 24 or 32bpp. For example, a render of a 1024x768 pixel image on a 24bpp system will require about 2.4 megabytes of image buffer (even if you hide or minimize the render window). The only way to avoid this is to turn the render window off before the render starts.

If you have a high or true color display, selecting the 'Options|Render Window|Force 8-bit Display' option will cause only one-third of the memory to be allocated for the render bitmap, since the data will be stored (and displayed) as 8-bit pixels instead of true-color (24-bit). Needless to say, this has absolutely no effect on the output file.

See also Speed Considerations.


Windows Section 5

1.5 Menus

1.5.1 File Menu

 | The File Menu contains commands that, in general, relate to loading and saving files. Note: In the interest of brevity, we will not explain obvious file menu entries. We assume that all readers will understand Save, Save As, etc., as these are basic Windows knowledge issues.
The File Menu |

1.5.1.1 New File

This creates a new file in a new window in the internal editor. The language type will be set to 'none', so unless you change this from the editor properties, syntax highlighting will not occur until you do a Save As.

1.5.1.2 Open File

This creates a new window in the internal editor and opens the specified file in it. POV-Ray will attempt to set the language type according to the extension. .POV, .INC, .MAC and .MCR files are assumed to be POV-Ray files and will have POV syntax highlighting. If you use a different file extension for POV source code, you can set the language type manually after you open it.

Note that POVWIN will not let you load more than one copy of the same file. If you attempt to load an already-loaded file, that file will be selected as the current file in the editor, but nothing else will happen.

1.5.1.3 Close

This closes the file open in the currently-selected internal editor.

1.5.1.4 Close All

This closes all files currently open in the internal editor.

1.5.1.5 Print

Provides a dialog that allows selection of printing options for the currently selected editor file (does not work with the message window). You can even choose two-up printing (that is, printing two pages on a single sheet of paper by splitting it down the middle). Note that the printing will not reflect any colored syntax highlighting in the editor; printing is always done in monochrome.

1.5.1.6 Exit

This option lets you exit POV-Ray for Windows. If you have Save Settings on Exit selected, your current POV-Ray for Windows settings will be saved for your next session.

If you shut down your computer without exiting POV-Ray for Windows first, POV-Ray will load itself again next time you log in as the same user. Note that we do not recommend shutting down your computer without saving any edited files first - while the editor will attempt to do the right thing with unsaved files during a shutdown, to a great extent it is at the mercy of the operating system.

1.5.1.7 MRU List

The MRU (most recently used) file list holds up to nine (9) files. The Older Files menu (see above) holds up to 32 additional files. After a file scrolls off the bottom of the MRU list it goes into the top of the Older Files menu.

When you select a file from the MRU list, if it is already open in the editor, it is selected and moved to the top of the MRU list. Otherwise, it is opened and moved to the top of the list. The MRU list remembers several things about files, including the last line, column, and top line number, plus the language and indent settings. The comments in this paragraph also apply to the Older Files menu.

1.5.1.8 Older Files sub-menu

After files have scrolled off the bottom of the MRU (Most Recently Used) list that appears at the bottom of the File Menu, they will appear in the Older Files menu. The MRU list holds up to nine (9) files, the Older Files menu holds up to 32 additional files. If there are no files in the Older Files menu (such as when POV-Ray is initially installed), it will be disabled.

1.5.2 Edit Menu

 | The Edit Menu contains commands relating to altering, cutting, copying, and pasting text. Note that there are actually two edit menus, though you only ever see one at a time. These are the edit menu that is displayed when the message window is selected, and the edit menu that is displayed when any of the editor windows are selected. The contents are different since the windows have different functions.
The Edit Menu |

Note: The Message Window shortcut keys for Cut, Copy, etc. have been changed to the newer Ctrl-C, Ctrl-V style. The old shortcuts (Ctrl-Ins etc.) will still work, however, even though they're not shown in the menu.

The shortcut keys assigned when the Editor Windows are selected are set according to your preferences. See the Configuring the Internal Editor section for more information as to how to do this.

1.5.2.1 Copy Pane

This command lets you copy all the text currently displayed in the POV-Ray window to the clipboard. From there you can paste it into any text file for modification with a text editor or word processor. This can be particularly useful for bug reporting. Note: This command only appears if the currently selected window is the Messages window.

1.5.2.2 Clear Messages

Clears all messages in the Message Window. This command only appears if the currently selected window is the Messages window.

1.5.2.3 Undo

This command, and the remaining ones, only appear if the current window is an editor window.

The Undo command 'undoes' (reverses or remedies) the last change made to the text. Consecutive Undo operations can be used to revert to earlier and earlier text. The editor keeps seperate Undo and Redo histories for each open file.

1.5.2.4 Redo

Redoes the last change undone with Undo. Can only be used immediately following an Undo operation; editing the text will erase the Redo history. Consecutive Redo operations are possible if consecutive Undo operations were performed. The editor keeps seperate Undo and Redo histories for each open file.

1.5.2.5 Cut

Deletes the selected text and places it on the clipboard.

1.5.2.6 Copy

Places the selected text on the clipboard.

1.5.2.7 Paste

Inserts text from the clipboard, overwriting any selected text. If no text is selected, the pasted text is inserted at the current caret position, even if the editor is in overwrite mode.

1.5.2.8 Delete

Deletes the selected text.

1.5.2.9 Select All

Selects all text in the current window.

1.5.2.10 Selection sub-menu

The Selection sub-menu contains commands which relate to operations on blocks of selected text. If there is no text selected in the editor, all of these commands will be disabled.

The Selection sub-menu

See Using the Mouse for a description of the various ways you can select text (including full line blocks, stream blocks, and column blocks).

1.5.2.10.1 Indent

Inserts a tab (or spaces, depending on your tab settings) at the beginning of the selection on each line. You must have multiple lines and/or a newline selected, or the selected text will be replaced by a tab instead.

1.5.2.10.2 Indent To Previous

Moves the caret to the position of the next text on the previous line.

1.5.2.10.3 Undent

Removes one level of indent from the beginning of the selected lines.

1.5.2.10.4 Uppercase

Converts all alphabetical characters in the selected text to uppercase.

1.5.2.10.5 Lowercase

Converts all alphabetical characters in the selected text to lowercase.

1.5.2.10.6 Convert Spaces To Tabs

Converts sequences of space characters to tabs. (Note: The tab size can be set under the Text menu.)

1.5.2.10.7 Convert Tabs To Spaces

Converts tabs to sequences of space characters. (Note: The editor does this automatically by default. This behavior can be turned off in the Language/Tabs section of the Editor Preferences.)

1.5.3 Search Menu

 | The Search Menu, which is only displayed when an edit pane is active, contains commands related to searching for and replacing text.
The Search Menu |

1.5.3.1 Find dialog

 | Searches the file for the first occurrence of a specific string of text and highlights/selects it.
The Find Dialog |
1.5.3.1.1 Match Whole Word Only

If this option is checked, partial matches will not occur (for example, the search string 'Persist' will not find the word 'Persistence', whereas normally it would).

1.5.3.1.2 Match Case

If this option is checked, then the case of the search string and the searched-for text will be the same.

1.5.3.1.3 Wildcard Search

The search string allows the following wildcard characters if the "Wildcard Search" option is checked -

? | Matches any single character
+ | Matches one or more of the previous character or item (which may be a wildcard or group), up to a maximum of the end of the line. For example, ?+ will match from the next character to the end of the line, and [0-9.]+ will match any number, with or without a decimal point.
* | This operator works like '+' above, but matches zero or more rather than one or more. Put another way, it makes the previous character or item optional.
[] | Characters enclosed in square brackets will be treated as an inclusive set. Character ranges may be specified with a '-' (e.g. [a-c] would match the characters 'a', 'b', or 'c').
| | Subexpressions may be ORed together with the | pipe symbol.
() | A wildcard expression may be enclosed within parentheses and will be treated as a unit.
 | Sequences such as \t, etc. will be substituted for an equivalent single character. To represent a literal backslash, use two (e.g. \\).

Be Aware: The wildcard search facility does have some bugs in it and may not always match correctly (e.g. [0-9A-Za-z] will match all alphanumerics, but [A-Za-z0-9] does not match numbers, even though it should).

1.5.3.2 Replace

 | Searches the file for any occurrences of a specific string of text and replaces them with a different string. Users of other programmer's editors should note that there is no means of back-referencing wildcard groups from the search expression during a replace operation.
The Replace Dialog |

1.5.3.3 Find Next

Finds the next occurrence of the string specified in the last Find operation.

1.5.3.4 Match Brace

Finds and highlights/selects the other brace for the block of code enclosed by the brace at the caret. For example, if you had the edit caret on a '{' character, it would be moved to the matching '}', taking into account the nesting of any '{}' blocks between them. Note that this also works in reverse.

1.5.4 Text Menu

 | The Text Menu contains options and operations that act on text which is displayed in the editor. It is only displayed when an editor pane is chosen.
The Text Menu |

1.5.4.1 Show White Space

Indicate where white space is using a dot. Note that this does not affect the file itself, just how it is shown on the screen.

1.5.4.2 Set Repeat Count

Most editor commands can be automatically repeated a specified number of times. By setting the repeat count, you cause the next editor command you issue to be repeated that number of times (this includes caret positioning using the keyboard).

1.5.4.3 Tab Size

The Tab size setting only applies to the current file and any subsequently opened files. Changing the tab spacing for one file does not automatically change it for all the other files that are already open. The tab setting you choose is stored with the MRU list, so if you re-open a file from the MRU, the old setting comes back (for that file only).

Note that the new value you apply to the tab setting becomes the default for any file opened or created after that point (apart from those in the MRU list). So if you change the tab setting to, say, 3, the setting for the current file changes, but not that of any other open file. Any new file that you create or load from that point, however, will be created with a default tab spacing of 3.

1.5.4.4 Indent sub-menu

See the Selection sub-menu.

1.5.4.4.1 Auto-Indent Style sub-menu
1.5.4.4.2 None

No indentation occurs. The next line begins at column 1.

1.5.4.4.3 Language Scope

Language-specific scoping is used to determine the correct indentation level for the next line. This setting causes the editor to parse the buffer contents, looking backward for scope keywords until the start of the current scope is encountered. Once found, the indentation is copied to the next line. If no language is set, the editor acts as if 'Copy From Previous Line' was chosen.

1.5.4.4.4 Copy From Previous Line

Indentation is copied from the previous line.

1.5.4.5 Bookmarks sub-menu

Bookmarks provide a means to quickly get to a previously-marked position in a file. Any bookmarks you define are lost when POVWIN exits.

1.5.4.5.1 Clear All

Delete all bookmarks.

1.5.4.5.2 First

Jump to the first bookmark.

1.5.4.5.3 Last

Jump to the last bookmark.

1.5.4.5.4 Next

Jump to the next bookmark.

1.5.4.5.5 Previous

Jump to the previous bookmark.

1.5.4.5.6 Toggle

Toggle a bookmark on or off at the current line.

1.5.5 Editor Menu

The Editor Menu contains commands that relate to the configuration and use of the editor. It is only displayed when an editor pane is selected.

The Editor Menu

1.5.5.1 Auto-Load Error File

If this option is checked, POVWIN will automatically load a file, in which a parse error has occurred, into the editor (or select it if it's already loaded), then place the cursor on the line and column of the offending code.

Note that if this option is on, and the message window was displayed automatically (see 'Auto-Show Parse Messages' below), it will be closed automatically rather than being left open. The text describing the error will be displayed in the status bar at the bottom of the window. Note that, occasionally, if the error occurs inside a macro, the displayed line/column for the error will be wrong.

1.5.5.2 Auto-Show Parse Messages

If this option is selected, when you start a render, a small version of the message window will be opened at the bottom of the edit window. You can resize this window vertically using the mouse. To close it, just hit ESCAPE.

Note that unless you have 'Auto-Load Error File' selected, the message window will remain visible upon a parse error (so that you can see it without switching windows). If the render completes successfully, the message window will close.

1.5.5.3 Auto-Save Delay

The delay, in minutes, between automatic saves of your work. If you set this to 0, no automatic saves will be made.

Be Aware: If Auto-Reload is set to either 'Ask' or 'Always', switching focus to another application will cause all of your files to be automatically saved.

1.5.5.4 Create Backups

If this option is checked, the editor will create a backup file named the same as the original but with '.bak' appended to it the first time the file is saved in each edit session. Note that it is not created with each save, but only the first!

Also note that appending the '.bak' extension is meant literally - unlike editors that hail from the old 8.3 filename era, which would remove the old extension and replace it with .bak (e.g. 'foo.pov' would become 'foo.bak'), we literally append '.bak', such that 'foo.pov' becomes 'foo.pov.bak', thus avoiding the problem that having two files named 'foo.pov' and 'foo.inc' in the same directory would have caused.

1.5.5.5 Allow Undo After Manual Save

Unless this option is checked, manually saving a file clears the undo buffer. In this case, you will not be able to undo changes made before you saved a file.

1.5.5.6 Click Beyond EOL

This option, which is on by default, allows the editor caret to be positioned beyond the end of the line if you choose to left-click there with the mouse. This is the behavior that most users seem to want. However, a number of users have requested that the 'old' behavior (from the previous POVWIN editor, which did not allow the caret beyond the end of a line) be preserved. Note that this option is only available if 'Constrain Caret to Text' (see below) is not checked.

1.5.5.7 Constrain Caret To Text

This option forces the edit caret to always remain within existing text (except when extending the end of the file). As with the 'Click Beyond EOL' option above, this is the behaviour that some users prefer and was the default in the POVWIN 3.0 editor. Note that selecting this option causes the 'Click Beyond EOL' menu entry to be disabled.

If 'Click Beyond EOL' is turned off, and you left-click beyond the end of a line, the editor caret will snap to the location after the last character on the line. You can still manually (using the cursor keys) move the caret right past the end of the line, or down onto a new line (and thus be past the end of that line, if it were shorter).

If 'Constrain Caret to Text' is turned on, it has the same effect as turning 'Click Beyond EOL' on, with the additional restriction that using the cursor keys will not move the caret into virtual space. For example, moving the caret right at the end of a line will cause it to wrap to the start of the next line instead of moving right into virtual space.

1.5.5.8 Overlay Keyword Expansion On Tab Key

See the Keyword Expansion section.

1.5.5.9 Show Message Window

Manually cause the small message window to be displayed (or hidden if it is showing, in which case this menu entry will read 'Hide Message Window' instead of 'Show Message Window'). Note that you can also use the Escape key to hide the message window.

See Auto-Show Parse Messages for more information.

1.5.5.10 Editor Preferences dialog

See the Editor Preferences sub-section.

1.5.5.11 Record Macro/Play Macro

A keystroke macro (not to be confused with POV-Ray scene file macros) is a collection of editing actions (which may include cursor movement, text editing, search, replace, and so forth) which may be assigned to a shortcut key and stored for re-use. POV-Ray for Windows stores macros in the registry, so they will still be available next time you run the program. You can have up to ten keystroke macros recorded at any one time.

Once you activate the 'Record Macro' command, a small dialog box will appear that allows you to stop the recording, and then assign a key to the macro before it is saved. If you do not assign a key, the macro will still be playable via the 'Play Macro' menu.

1.5.5.12 Auto-Reload sub-menu

The Auto-Reload facility (which by default is set to 'Ask') causes the editor to check the time and date of all files that are currently open when it receives focus from another application. For example, suppose you were using a program that automatically generates POV scene files (these are quite common) and had the output file open in POVWIN. If you switched to that application, told it to regenerate the output file, then switched back to POVWIN, the editor would detect that the file had been changed (assuming Auto-Reload is enabled).

The three settings available for Auto-Reload are 'Never', 'Ask', and 'Always'.

  • 'Never' means never check - changes to a file made externally to POVWIN will not be detected and you risk overwriting the changes if you save the copy open in the editor.
  • 'Ask' means that, if changes to a file are detected, POVWIN will ask you if you want it reloaded. If you reply 'Yes' and you have unsaved changes, they will be lost. Your undo buffer will also be cleared.
  • 'Always' means that, if POVWIN detects that a file has changed, it will always reload it without asking you! If you have unsaved changes, they will be automatically discarded. Your undo buffer is also cleared.

Be Aware: If Auto-Reload is set to either 'Ask' or 'Always', switching focus to another application will cause all of your files to be automatically saved.

Warning: The auto-reload feature is not intended as a substitute for common sense. We do not guarantee that it will work. It is not always possible to determine if a file has changed (for example, the time stamp may not be updated by the other application) and apart from that, it takes time to save a file. If the other application is still in the process of saving the file when you switch back to POVWIN, it's possible that the change won't be picked up. Likewise if POVWIN is still saving the file when the other application is selected; for example, if it is an editor with a similar feature, it may not pick up the change.

Nevertheless, Auto-Reload is a useful feature under most circumstances.

1.5.5.13 Scroll Bars sub-menu

Select whether the edit window has horizontal scrollbars, vertical scrollbars, or both.

Note that if you turn off a scrollbar, you lose the ability to split the window in that direction (since the window splitter for each direction is on the scrollbar).

1.5.5.14 Color Scheme sub-menu

The colors used by POVWIN's editor are able to be customized by you on a case-by-case basis. However, for convenience, there are two built-in color schemes accessible from the Editor menu. These are 'Black on White' (the default) and 'White on Black'.

Black on White is the traditional Windows style of presentation, with black text being drawn on a white background.

White on Black is the other way around - a black background with white text. Many users who became accustomed to using text editors under DOS will be comfortable with this.

Note that choosing one of these options will overwrite any changes you had made to your color scheme ! Once you have chosen a new scheme, you may customize it from that point (or simply choose 'Custom' to be taken to the Color/Font dialog).

1.5.5.15 Editor Preferences

The following sections cover the available Editor Preferences.

1.5.5.15.1 Color/Font

This property page allows setting of various editor parameters relating to the color of the syntax highlighting, page background, and font. Changes made on this page affect all editor windows immediately and are stored in the registry for recall the next time POVWIN is run.

The Color/Font tab
1.5.5.15.1.1 Item

This list box allows you to select which item you want to set the color for. An 'item' is any individually-controllable color within the editor. For example, plain text, bookmarks, the left border, comments, and so on are all individually controllable.

See also Color Scheme sub-menu.

1.5.5.15.1.2 Color

This sets the foreground color of the item selected in the 'Item' listbox.

1.5.5.15.1.3 Background

This sets the background color of the item selected in the 'Item' listbox. If it is set to 'default', then the background color will be the same as the window background.

1.5.5.15.1.4 Font

This allows you to set the font face, size, and style that is used for displaying the text within the editor windows.

1.5.5.15.2 Language/Tabs

This property page allows you to manually specify the language that the current file uses. The editor normally will set this for you, but if you are editing a supported language in a file with an unrecognized extension, you may want to manually specify it.

You can also set the auto-indentation style in use and the tab settings.

The Language/Tabs tab
1.5.5.15.2.1 Auto Indentation Style

This allows you to select the auto-indentation style for the currently selected file. This style will then become the default for all newly-loaded files, but will not change the auto-indentation style for any already-loaded files. Note that the auto-indentation style selected for a file is saved in the registry, and is retained with the file in the MRU (most-recently-used) file list held in the File Menu.

1.5.5.15.2.2 Tabs

You can select the number of columns tabs expand to here. Additionally, if 'Convert tabs to spaces while typing' is checked, pressing the TAB key will not insert a hard tab but will instead insert the apppropriate number of spaces.

We strongly recommend that you use the 'Convert tabs to spaces while typing' option if you intend to use the tab key in a file that you will distribute to other users. This is because different people have different preferences for tab indentation settings, and if a person receives a file from you with hard tabs embedded in it, and has a different setting for tab expansion, your code may not align properly. This can make it hard to read.

Changing the tab expansion setting affects the current file, and also becomes the default for any newly-loaded files. It does not affect the tab expansion settings for already-loaded files.

1.5.5.15.2.3 Language

You can choose the file language here. This setting controls syntax highlighting and the indentation rules (if you have 'Follow Language Scoping' set for the Auto-indentation style).

The editor supports syntax highlighting for the following file types: POV-Ray, C/C++, Basic, Java, Pascal, SQL, HTML, and XML.

1.5.5.15.3 Keyboard

This property page allows you to set the key sequence assigned to all built-in editor commands.

The Keyboard configuration tab

Not all commands are assignable ! In general, only the commands that are directly implemented in the CodeMax editor DLL are able to be set. These commands are ones that relate to operations on individual edit buffers. They do not include such things as file operations (load, save, print, etc). These operations are implemented in the POVWIN editor wrapper code and are not managed or able to be changed by CodeMax. Therefore, it should be clear that you can neither change the key bindings for operations such as file save, nor use the POVWIN- assigned keystroke (e.g. Ctrl-S in the case of save) for any other purpose.

See the Default Key Mappings section for a list of all the default assignments of editor commands to keystrokes. Note that each command may have two different key sequences assigned to it, and that each key sequence may have up to two keystrokes (e.g. the old 'Wordstar'-style commands).

To assign a key to a command, choose the command you want in the listbox on the left, and then click in the box titled 'New Key Assignment' and press the key(s) you want to use, then press 'Assign' to set it.

Hint: It's very easy to just press 'OK' after typing in a new key assignment, without pressing 'Assign' first! If you do this, the new keystroke will not be assigned.

1.5.5.15.4 Misc

With the exception of 'Line Numbers', all the options on this property page affect all editors. All take effect immediately.

The Miscellaneous Settings tab
1.5.5.15.4.1 Smooth Scrolling

If checked, scrolling of the editor window will be 'smooth' rather than jerky. Some people prefer this, though it is slower than the traditional scrolling.

1.5.5.15.4.2 Show Left Margin

If checked, the left margin will be visible. The left margin is a useful area that can contain things such as line numbers and bookmark markers. It can also be colored differently from the main text. You can highlight an entire line by clicking in the left margin next to it, and highlight a range of lines by clicking and dragging in the margin.

See The Editor Window for an example of the appearance of the left margin.

1.5.5.15.4.3 Line Tooltips on Scroll

If checked, and you scroll the edit window by dragging the scroll-bar thumb, a line tooltip will show the approximate line number you have scrolled to.

1.5.5.15.4.4 Allow Drag and Drop

If checked, OLE drag and drop text editing is enabled. This allows you to highlight blocks of text and drag them to another position within the editor window, or even to another editor program that supports the same feature (e.g. the standard Windows 'wordpad' editor, Microsoft Word, and many others). Of course, you can also drag text from those applications and drop it into the editor window.

Mouse Action | Result
L-Button down over selection, and drag | Moves text
Ctrl + L-Button down over selection, and drag | Copies text
1.5.5.15.4.5 Allow Column Selection

If checked, columns of text can be selected with the mouse and then manipulated. Empty columns (columns with a width of zero characters) can be selected, causing subsequent typing and deletion to occur over multiple lines at the same time.

See Using the Mouse for a description of how to select columnar blocks.

1.5.5.15.4.6 Confine Caret to Text

This is the same as the Constrain Caret To Text option in the Editor Menu. Please refer to that documentation.

1.5.5.15.4.7 Color Syntax Highlighting

If checked, color syntax highlighting will be used according to the Language setting. You can control the colors used from the Color/Font.

See The Editor Window for an example of the appearance of syntax highlighting.

1.5.5.15.4.8 Show Horizontal/Vertical Scrollbar

These two options select whether the edit window has horizontal scrollbars, vertical scrollbars, or both.

Note that if you turn off a scrollbar, you lose the ability to split the window in that direction (since the window splitter for each direction is on the scrollbar). In this case, the appropriate 'Allow Splitting' option (see below) will be dimmed and unavailable.

1.5.5.15.4.9 Allow Horizontal/Vertical Splitting

These two options select whether or not you can split a window by dragging on the horizontal or vertical splitters (see The Editor Window for an example of what the splitters look like).

Using this method you can split the window into up to four different sections. Each section will still show the same file, but the sections can show different parts of the file. Editing in one section causes the changes to be immediately visible in any other sections that are showing the same part of the file.

1.5.5.15.4.10 Line Numbering

This allows you to turn on line numbering, which may be in decimal, hex, octal or binary (!). Note that this setting does not influence whether or not line numbers are included in printouts you make of the file; if you want printed line numbers, you can select that option in the print dialog.

Note that, unlike the other settings on this property page, the Line Numbers setting only applies to the current editor file. Additionally, it is not preserved across invocations of the editor; once you exit, the setting is forgotten.

1.5.5.15.4.11 Max Undoable Actions

Allows you to set a limit on the number of edit actions that will be stored in the 'undo' buffer. Actions older than this limit will be discarded. Unless you are critically low on memory (or don't like having hundreds of undo's available), we recommend that you leave this on the default setting of 'infinite'.

1.5.6 Insert Menu

The Insert menu

The Insert menu allows you to insert header sections, object definitions, etc. into a file you are editing with the internal editor, with only a few clicks of your mouse. It is only visible if you have selected an editor window.

This menu is built dynamically from the directory called 'Insert Menu', which is in the POV-Ray for Windows installation directory. The way it works is similar to the Windows 95/NT Start Menu. You can even edit it at run-time, and POVWIN will automatically pick up the fact that it's been changed and re-load it.

It has the additional special feature that menu entries may optionally have an image file associated with them, which is displayed when that entry is highlighted. A set of these image files is shipped with POV-Ray for Windows as standard; you can re-render these at a higher resolution if you like - see Re-Render Insert Menu Bitmaps in the Other Settings sub-menu menu.

1.5.6.1 Physical Layout

Each sub-menu in the Insert Menu is a directory (also called a 'folder' these days). To create a new sub-menu, just create a new directory. The submenu will have the same name as the directory.

The actual items that you can insert in your scene files are simply text files. POVWIN recognizes them by the extension .TXT. Any .TXT file in the Insert Menu directory tree will appear in the Insert Menu. The name shown in the Insert Menu will be the filename of the .TXT file, minus the .TXT extension. If you select this file from the Insert Menu, the contents of the corresponding text file will be inserted into your scene file at the current cursor location.

1.5.6.2 Sorting the Insert Menu

It is possible to order the insert menu entries any way you like, both for folders and for the files (or sub-folders) within them. Normally, the entries are added to the menu in alphabetical order, with all folders being added before files. However, you can influence the ordering of each group (folders and files) by prepending a 'NN - ' to a folder or file, where 'NN' is any letter or digit (note however that this does not permit you to place a file before a folder).

For example, suppose you wanted to move the folder called 'Transformations' (which creates the menu entry called 'Transformations' in the above sample image) so that it appears between the 'Expressions' and 'Headers' items in the menu. You could achieve this by re-naming the folder from 'Transformations' to, say, 'F0 - Transformations' (the choice of 'F0' in this example is arbitrary - you could use anything that will alphabetically sort between 'Expressions' and 'Headers').

When the editor code builds the insert menu (which happens each time you change it), any file or folder that starts with a prefix of 'NN - ' (note the trailing space) will be sorted using the prefix, but displayed without the prefix.

1.5.6.3 Adding a Separator

Creating a special file called '-.txt' (a hyphen followed by .txt) usually prefixed by a 'NN - ' (e.g. '30 - -.txt'), will cause a menu separator to be drawn instead of inserting a new item into the menu. The contents of the file are ignored.

To create a separator between sub-menus, do the same thing as above, but create a folder instead of a file and leave off the '.txt' extension.

1.5.6.4 Using the Insert Menu

Each Insert Menu text file can have an associated BMP, JPG or PNG file that provides a preview of the item that the text file can generate. In the previous example image, the item provides the no_reflection keyword, so the preview image shows a rendered example of this in use. The easiest way to understand how it all fits together is to inspect the Insert Menu directory that ships with POV-Ray for Windows. The first item in the Insert Menu will allow you to do that by opening an Explorer window located at that point on your disk.

See also Re-Render Insert Menu Bitmaps in the Other Settings sub-menu menu.

1.5.7 Render Menu

 | The Render Menu contains options that relate to starting, stopping, and controlling the rendering process (i.e. the generation of images).
The Render Menu |

1.5.7.1 Edit Settings/Render dialog

This command lets you select an INI and/or a POV file and make any last-minute command-line changes to the POV-Ray options before rendering.

In the 'Ini file' box, you can select an INI file by typing in the filename. You can also browse your directory structure for it. POV-Ray for Windows remembers the last directory from which an INI file was actually selected. If you select an INI file that has sections (see Sections in Understanding File Types), the Section box shows the first section label. Clicking on the down arrow brings up a menu of other sections in the INI file for you to choose from.

The Render Settings dialog

In the 'Source file' box, you can select a POV file by typing in the filename. You can also browse your directory structure for it. Once again, the directory that shows up is the last directory from which a POV file was actually selected.

If you currently have an editor window selected, you will not be able to change these entries as they will be set to the name of the file you are editing (even if its extension is not .POV). If you want to use these fields you need to choose the Message window first.

The commands are processed from top to bottom. Any options in the INI file you select override the default POVRAY.INI file as well as any POVRAY.INI file in the directory where the scene file resides. A selected POV file overrides any 'Input_File_Name=' option in the selected INI file. Finally, any command-line options override corresponding options in any INI file. The command line is processed from left to right; if an option is repeated on the command line, the one last processed applies.

If you want to change the command-line settings but do not want to start rendering the currently loaded POV file, press 'Set but don't Render'.

The command line is versatile. If you have a POV file and a number of options loaded, you can override the scene to be rendered by typing the name of another POV file on the command line. Conversely, you can type in one or more options (or the name of an INI file), forcing POV-Ray for Windows to render the currently loaded POV scene with the new options. If you type the name of an INI file which specifies a new POV file with the 'Input_File_Name=' option, the current scene file as well as the current options are overridden. See also Understanding File Types.

1.5.7.2 Select File and Render dialog

This is the way to select a file from disk for immediate rendering. If the file is a POV file, it is rendered with the current options. If it is an INI file with no POV input file specified, the options will apply to the currently loaded POV file, only to be overridden by command-line settings. If the INI file specifies a POV input file, that POV scene is rendered with the options set in the INI file. See also Understanding File Types.

1.5.7.3 Start Rendering (Go!)/Stop Rendering

This is a toggle. If you are not currently rendering, the command Start Rendering instructs POV-Ray for Windows to start rendering the currently loaded POV file with the current settings. While POV-Ray for Windows is rendering, the command reads Stop Rendering and will interrupt the current rendering job.

1.5.7.4 Run Demo

The easiest way to see what POV-Ray for Windows is capable of is selecting this command, which renders a sample POV-Ray file to screen. To interrupt rendering, select Render/Stop Rendering or double-click on the drawer icon in the top left-hand corner of the rendering window. See also Getting Started.

1.5.7.5 Run Benchmark

This command instructs POV-Ray for Windows to run the standard POV-Ray benchmark file, using a given set of options. In version 3.7 the built-in benchmark mode has been further modified to run without accessing any other distribution files, so now benchmarking can now be done with just the compiled executable.

Note: The file itself and the options used are built into the program and may not be changed (this includes the resolution). Any options specified on the command-line will be ignored.

Be aware that during the render, there is no image display, and furthermore, no output file is produced. The only purpose of the benchmark command is to determine how long it takes to render the standard file with the specific options used.

Immediately before POV-Ray for Windows starts writing the render information to the message display, it will output a line telling you what version of the official benchmark is being used.

Note: If you choose to quote your benchmark results publicly, it is essential that you include the benchmark version and the exact version of POV-Ray that you ran it on. Changes to the benchmark file itself, and optimizations to POV-Ray, may make comparisions between different versions of the benchmark or different versions of POV-Ray meaningless, especially if it is CPU performance that you are testing.

The actual benchmark file used is built-in to the program; it is not dependent on the benchmark.pov file which is included in the ~\scenes\advanced directory. However, if you want to run the benchmark manually, or on another platform, you may use that file (just make sure it is the same version). The file also contains the recommended command-line parameters to be used with the render.

After the benchmark completes a dialog box will be displayed showing the average PPS (pixels per second) that the render took. Larger numbers are better (indicative of a faster and/or more efficient CPU). We recommend using this number when quoting results. The results are also copied to the clipboard.

1.5.7.6 File Queue dialog

 | Selecting this command lets you look at the queue of files ready to be processed. You can add a file to the bottom of the queue or delete a file (you have to select it first by clicking on it). Once you have made your changes to the file queue, press OK to confirm the changes or Cancel to leave the queue as it was before you called up the screen. You can select multiple files in the file browse dialog box by using Control or Shift when clicking on them.
The File Queue dialog |

The File Queue dialog box has two check-boxes in addition to the normal controls (like add/remove file etc.)

The first, Reload on Startup, when selected, causes the contents of the file queue to be stored to disk each time it is accessed. When POV-Ray is started up with this option active, and the file queue had entries in it, they are loaded off disk and back into the queue. If Auto Render was also selected, POV-Ray would then start rendering them.

The second, Auto Render, instructs POV-Ray for Windows to render whatever is in the file queue (see File Queue below). When you switch Auto Render off, any files dropped onto the POV-Ray window are added to the queue but not rendered. In other words, while Auto Render is turned off, the file queue is inactive. However, any file selected with the Render/Start Rendering command will still be processed. Once you switch Auto Render back on again, if there are files in the queue, they will begin to be processed.

Note: Due to the way that some versions of Windows returns multiple file selections to us, if you use Ctrl or Shift to select more than two files in the Add to Queue file browse box, and then click on OK, the first and last entries will be transposed. (We can't swap them back to their original position since we can't tell if the transposition has happened in the first place).

1.5.7.7 Clear Queue

If you want to clear the entire queue in one go, this is the way to do it. The command shows you how many entries you will be throwing away.

1.5.7.8 Render Priority sub-menu

The available render priority settings are 'Low', 'Normal, 'High' and 'Background'. Changing this setting can allow POV-Ray to get more (or less) of the CPU during renders; the higher the priority, the more CPU time should be allocated to POV-Ray. The Background setting is only available on Windows Vista or later, and causes the render to be run at a very low priority.

Some users have expressed surprise that changing render priority does not always seem to significantly affect rendering times. This will be the case if the computer in question is not doing anything else at the time. All the render priority setting does is tell Windows to change the priority it assigns to POV-Ray when it is sharing the CPU time out amongst processes. This generally only matters when you are running another CPU-intensive process on the computer; i.e. one that would compete with POV-Ray for a share of CPU time. It is then that changing this setting will make a noticeable difference. If the computer isn't doing much (other than running POV-Ray), then the render is already getting more or less all of the CPU time.

See also Speed Considerations.

1.5.7.9 Duty Cycle sub-menu

The Duty Cycle setting is provided only for unusual cases of heat accumulation. It is not intended to be used in other circumstances (as it offers little benefit other than as described below). Unless you are using a laptop in a restricted environment (or perhaps in orbit), this sub-menu will be of little interest to you.

Some computers - particularly laptops or notebooks - cool their CPU's by convection. No CPU fan is used. This can make this type of device prone to overheating in certain circumstances (for example, where circulation of air is restricted, such as in a confined space, or where hot air does not, by its nature, rise, such as in zero-gravity).

POV-Ray makes extensive use of a processor's Floating Point Unit (FPU), a portion of the CPU that is not normally prone to high activity over long periods. Such use can potentially cause the CPU to generate more heat. Additionally, high CPU activity can cause the unit's normal heat-reducing facilities (such as lower-power CPU modes) to be inactive.

The Duty Cycle setting is used to tell POV-Ray to only use a certain percentage of the CPU's available time, even if nothing else is competing for the CPU. For example, a duty cycle of 10% would cause POV-Ray, during a render, to sleep for 90% of the available time, and only render during 10% of it.

During rendering, if the duty cycle is not set to 100% (the default), POV-Ray will update the status bar at the bottom of the window if it is in sleep mode. This update will show how many seconds remain until rendering starts again (which is based around a ten-second cycle). For example, a duty cycle of 70% would see POV-Ray render for seven seconds, then sleep for three.

Note: While it may seem far-fetched to include a feature in POV-Ray that seems primarily to be of use in zero-gravity, it in fact is for this exact reason it is here. On 25 April 2002, African entrepreneur Mark Shuttleworth was blasted into space in a Russian Soyuz capsule. Accompanying Mark on this launch was a copy of POV-Ray for Windows v3.5 beta 15, and a special scene written for the purpose by two of the word's best POV-Ray artists. Whilst on the International Space Station, Mark rendered a 6000x8000 pixel version of that scene. This scene is now available as a poster; »see our website for more information.

1.5.7.10 Thread Count dialog

Selecting this entry displays a dialog allowing you to set the number of threads used for rendering. The default value varies according to system, but in general should be equal to the number of cores available to POVWIN (or double that if hyperthreading is available). Changing this value will only affect new renders and does not persist (i.e. it is not saved upon exit). This is by design. If you wish to set a permanent value please modify POVRAY.INI or set it on the command-line.

1.5.7.11 Prevent Sleep

This option, which is enabled by default, instructs POVWIN to request that Windows not go into low-power or sleep mode whilst a render is in progress. During renders if this option is set POVWIN will notify Windows once every 10 seconds that it needs use of the system; unless Windows is instructed (via power management settings) to ignore this advice it will not put the system into low-power mode. Note that this does not affect the screensaver or display power management, which will work as normal.

1.5.7.12 Sound Settings dialog

 | In the sound setting dialogue you can enable POV-Ray to signal the finishing of a render, a parse error and a render error or cancellation of a render. For each of the three signals a specific sound (WAV file) can be set.
The Sound Settings dialog |

1.5.7.13 On Completion sub-menu

The On Completion submenu allows you to specify what POV-Ray will do when it completes a rendering (or series of renderings, in the case of animations).

1.5.7.13.1 Do Nothing

No special actions are taken.

1.5.7.13.2 Display Message

This will cause POV-Ray for Windows to display a message window indicating that it has finished.

1.5.7.13.3 Exit POV-Ray for Windows

POV-Ray for Windows will exit after the render has completed.

1.5.8 Options Menu

 | This menu contains settings that change the operation of POV-Ray for Windows as a whole.
The Options Menu |

1.5.8.1 Keep Single Instance

This option prevents more than one instance of POV-Ray for Windows from running at a time. If you attempt to launch a new one, the currently running one is activated instead. This is handy if you are using File Manager or Explorer to launch POV files by double-clicking. (Explorer users can get even more control by using the right mouse button menu.)

1.5.8.2 Show Toolbar

This option will alternately show or hide the toolbar, and can be used if you want more room for the editor.

1.5.8.3 Place in System Tray

Places POVWIN in the system tray on the taskbar. Double-click to restore POVWIN. You can also right-click to get a context menu.

1.5.8.4 Script I/O Restrictions

See the I/O Restrictions topic.

1.5.8.5 Drag'N'Drop Destination sub-menu

This sub-menu allows you to select the destination for the files that are dropped onto the POV-Ray window from Windows Explorer or similar file managers. See Dragging and Dropping Files for full information.

1.5.8.6 Update Checks sub-menu

 | This sub-menu contains settings related to checking for updated versions of POV-Ray for Windows.
Update Checks sub-menu |
1.5.8.6.1 Periodically Check for Updates

The 'Periodically Check for Updates' feature - which is turned on by default - instructs POV-Ray for Windows to periodically ask our web server if there is a newer version of POV-Ray available than the one you are using.

Note: All POV-Ray does is check for a new version; it does not download it. We would never download files onto your computer without your permission.

If POV-Ray discovers that there is a new version available, it will display a page in your default web browser that looks something like the one depicted below -

A sample updated version available page

POV-Ray attempts to be both intelligent and polite about the way that it does these checks. It will not perform one unless Windows tells it that the internet is already connected. In this way, it does not cause an annoying dialer dialog to pop up while you are working. Additionally, POV-Ray does not run the checks out of a scheduler or via any third-party program - you have to be actually running POV-Ray for Windows for anything to happen. It also won't run a check the first time it is started after installation, in order to give you time to turn off the update check option if that's what you want to do.

If it successfully contacts our web server and receives a 'yes' or 'no' answer as to whether an upgrade is available, it will not attempt again for several days. If, however, it failed in its attempt to contact the server, it will try again in no less than 24 hours. POV-Ray will never contact our server more than once per day.

Note: POV-Ray uses the Microsoft WinINet functionality to perform the above connection; this means that whatever settings have been configured in the 'Internet' applet of your control panel (e.g. your proxy server) will be applied to the request.

1.5.8.6.2 Include System Information

This option - which is turned on by default - instructs POV-Ray for Windows to include some information that is valuable to the developers when it sends the above update request.

Note: We would never intentionally send any information that personally identifies you or that could violate your privacy. All we are interested in is system information that will help us better cater our userbase when we create new versions of POV-Ray. Of particular importance to us is knowing common memory, CPU, and screen configurations employed by our users.

Here is an actual sample of the information that is sent, exactly as it appears on the wire (taken as of v3.5 release candidate 5). The data sent in the current version may vary from this, but is fundamentally the same concept.

TestVersion=3.5.beta.RC5.msvc.win32
CurrentVersion=3.5.beta.RC5.msvc.win32
CPUArchitecture=0x0000
NumberOfCPUs=0x0001
ProcessorType=0x024a
ProcessorLevel=0x0006
ProcessorRevision=0x0404
OSVersion=5.0
OSBuild=0x00000893
CSDVersion=Service Pack 2
BitsPerPixel=32
HorzRes=1600
VertRes=1200
NumberOfMonitors=1
HasMouseWheel=1
CPUFrequency=1396
FeatureSet=0x00004fff
CPUName=AMD Athlon(tm) Processor
CPUIdentifier=x86 Family 6 Model 4 Stepping 4
VendorIdentifier=AuthenticAMD
PhysicalMemory=1073201152
DefaultLanguage=English (Australia)

This tells us that the machine running POV-Ray was a single-CPU box equipped with an AMD Athlon CPU running at 1396mhz (1.4ghz), and had 1,073,201,152 bytes (1 gigabyte) of RAM. It is running version 3.5.beta.RC5.msvc.win32 of POV-Ray for Windows on version 5.0 of Microsoft Windows (this is Windows 2000), which had been patched up to service pack 2. It had a single monitor, set for a resolution of 1600x1200 pixels with 32 bits per pixel. Its mouse had a mouse wheel. The user's default language selection was English.

Information like this - while seeming rather mundane - is important to us because it tells us the sort of hardware that people are using POV-Ray on.

1.5.8.6.3 Check for Update Now

This command instructs POV-Ray to check for an updated version immediately. If an update is available the normal update message is shown (as described above). Otherwise a message will be shown indicating the outcome (e.g. no update available, failed to contact server, etc).

1.5.8.7 Other Settings sub-menu

 | This sub-menu contains a number of less-commonly-used options so as to reduce clutter in the main options menu.
The Other Settings sub-menu |
1.5.8.7.1 Video Source sub-menu

This sub-menu is designed to allow for selection of a video source for the experimental video image mapping feature. It is currently disabled pending a re-implementation of the capture code.

1.5.8.7.2 Use Editor

Turns the use of the internal editor on or off.

1.5.8.7.3 Show Tips of the Day

This command lets you decide whether you want POV-Ray for Windows to display the tip of the day on startup. By default, POV-Ray for Windows displays a new tip every time the program is started more than 24 hours after the previous tip was shown. Selecting Show Tips of the Day has the same effect as selecting the 'Show tip tomorrow' box in the tip screen.

1.5.8.7.4 Show Tooltips

Turns Tooltips on or off. A Tooltip is a little yellow window that will pop up over a toolbar button if you keep the cursor there for long enough. The tip window tells you what the button does.

1.5.8.7.5 Preserve Messages

Whenever you perform a render, POV-Ray for Windows generates a number of messages (active POV-Ray settings, rendering statistics etc.) in the POV-Ray window. If you select Preserve Messages, POV-Ray for Windows retains all messages generated during the current session. If you deselect this option, all existing messages are deleted every time you perform a new render. See also Clear Messages in the Edit Menu.

1.5.8.7.6 Save Settings on Exit

If you select this option, any settings you have selected during your current POV-Ray for Windows session will be stored for the next one. These include the position and size of the Main Window as well the position of the Render Window.

1.5.8.7.7 Hide New User Help

Selecting this option will cause the 'Help On This Menu' entries to be removed from all menus. We recommend you do this once you're an experienced user.

1.5.8.7.8 Show Next Tip

If you do not want to see the tip of the day pop up automatically on startup every day, you can still see a tip whenever you feel like it. If you select Show Next Tip, POV-Ray for Windows displays a single tip but keeps the 'Show tip tomorrow' box unchecked.

1.5.8.7.9 Re-Render Insert Menu Bitmaps

The preview bitmaps distributed with the POV-Ray for Windows insert menu are of a fairly small size in order to keep the size of the distributed setup file down. However, it is easy to re-render them all at a larger size (though it may take a while on a slower computer).

Just select the 'Re-Render Insert Menu Bitmaps' option and leave POV-Ray for Windows running. Eventually all the bitmaps will be replaced with larger ones.

1.5.8.7.10 Message Window sub-menu
 | This sub-menu allows you to set certain properties of the message window.
The Message Window sub-menu |
1.5.8.7.11 Select Plain Background

If you have chose a background image for the message window and want to change back to a plain color, you can select this command. The background takes on the currently defined background color (see Background Color below).

1.5.8.7.12 Text Font

Use this command to determine the font POV-Ray for Windows uses to display messages and statistics. In addition to the type of (non-proportional) font, you can set font size and appearance. POV-Ray for Windows remembers the font setting between sessions.

Note: If you select italic text, this setting will not be preserved across invocations of POV-Ray.

1.5.8.7.13 Text Color

This command lets you determine which text color best fits the background you have selected for the message window.

1.5.8.7.14 Background Color

This command lets you select the color of the plain background for the Main Window. Note that this command has no effect while you have tiled the background with a bitmap. The color only becomes visible when you select Plain Background (see above).

1.5.8.7.15 Tiling Options

You can change the tiled bitmap POV-Ray for Windows displays in its message window. Choosing Tiling Options brings up a sub-menu where you can select one of several built-in bitmaps. You can also browse your disk for other bitmaps you might prefer. POV-Ray for Windows pre-installs a number of them in the TILES subdirectory of your POV-Ray for Windows home directory. The bitmaps should have no more than 256 colors. If the BMP file you select is smaller than the Main Window, it will be tiled. If it is larger, POV-Ray for Windows fits it into the top-left corner of the Main Window and displays as much of it as the Main Window allows.

Note that because of the POV-Ray for Windows generalized palette, if you are running in 256-color mode, external bitmaps may not tile 100% perfectly, and the colors may be slightly altered. If you are running in 16-color mode, tiled backgrounds are not available at all. In practice, choosing tileable bitmaps other than the standard Marble one, using a 256-color display, will often not yield attractive results.

1.5.8.7.16 Render Window sub-menu
 | This sub-menu allows you to set certain properties of the render preview window.
The Render Window sub-menu |
1.5.8.7.17 Force 8 Bit Display

POV-Ray for Windows is capable of displaying a rendering scene in 24-bit color (Truecolor). This takes up more RAM than 8-bit mode: 3 bytes for every pixel in the rendered scene. If you do not have enough RAM to spare, you should select this option. It forces POV-Ray for Windows to display the scene in 8-bit color (1 byte per pixel) and to use color dithering to represent the rendered image on the screen. If you are already using a 256-color video mode it does not make any difference since the image is already stored as one byte per pixel. Note that this does not change the way that the rendered image is stored on disk. If you are writing an output file, the file will still be 24-bit color!

In 15 or 16 bit color modes, the image is stored in memory as 24-bit but only displayed as 15 or 16 bit. No dithering is (currently) performed in these modes.

1.5.8.7.18 Preserve Contents During Animation

If this option is enabled (the default) and you are rendering an animation, the contents of the render window (which shows the previous frame of the animation) are not erased prior to a new frame being started. This makes it easier to see subtle changes in the image output (such as a small object moving from frame to frame, while the rest of the image stays static).

Note that the render window contents are always erased prior to the first frame, regardless of the setting of this option.

1.5.8.7.19 Re-Display

If the Render Window is closed (see Close below), you can re-display it by selecting this command. If the window is not closed in the first place (or has never been displayed), you cannot re-display it, and so the Re-display command is grayed.

Note that this command is also available on the toolbar.

1.5.8.7.20 Autoclose

This causes the Render window to close automatically when rendering is complete. This is particularly useful if you're doing quick test renders at low resolution.

1.5.8.7.21 Close

This command closes the Render Window. This does not interfere with any rendering activity. Indeed, it speeds up rendering (see also Speed Considerations). To re-display the Render Window, select Re-display, use the right-mouse button speed menu on the message window, or simply click the 'Show' toolbar button.

Note that this command is also available on the toolbar.

1.5.8.7.22 Keep Above Main

If you make the POV-Ray for Windows Main Window active with Keep Above Main deselected, the rendering window may still be obscured by the main or any other window. Selecting Keep Above Main ensures that the rendering window pops up from under other windows whenever you make POV-Ray for Windows active. Note that if this option is set, you cannot hide the render window behind the main window (this can be a problem if you are rendering at the same time you are editing; hence the ability to set both modes via this option).

Note: If you enable this option, the 'Get Focus on Creation' and 'Hide When Main Minimized' options detailed below will be grayed out.

1.5.8.7.23 Get Focus on Creation

This command causes the POV-Ray window to get focus (pop to the foreground and become active) whenever a new file is processed. If POV-Ray for Windows is processing a file queue or animation, the POV-Ray Main Window gets focus every time a new file is initialized from the top of the queue, or a new pass over the animation source file is performed. This only applies, of course, if you are using the render window.

If you want to do other work on your Windows machine while POV-Ray is rendering, but you have the render window displayed, you will probably want to have this option off since otherwise the window will keep on popping up over whatever you are doing, each time a new image is rendered.

Hint: A handy shortcut to remember is that hitting the Escape key when the render window gets focus will return focus to the main window. This is particularly useful after a quick test render.

Note: If the 'Keep Above Main' option documented above is enabled, this option will be grayed out. This is because 'Keep Above Main' implies 'Get Focus On Creation'. If you don't want the render window to get focus on creation, you will need to turn 'Keep Above Main' off.

1.5.8.7.24 Hide When Main Minimized

If you have 'Keep Above Main' turned off, the main POV-Ray window and the Render Window are no longer linked. You now have the option of continuing to show the Render Window whenever the Main Window is minimized. If you select this option, the Render Window disappears as soon as you minimize the Main Window.

Note: If the 'Keep Above Main' option documented above is enabled, this option will be grayed out. This is because 'Keep Above Main' implies 'Hide When Main Minimized'. If you don't want the render window to be hidden when the main window is minimized, you will need to turn 'Keep Above Main' off.

1.5.8.7.25 Editor Window sub-menu

This sub-menu is identical to the main Editor Menu. It is included in the Options Menu for consistency.

1.5.9 Tools Menu

 | The Tools Menu provides you with a simple means of customizing POV-Ray for Windows. You can develop your own commands (up to 32) to show up under this menu. Since the menu is determined by the file PVTOOLS.INI, editing and reloading this INI file changes the Tools Menu.
The Tools Menu |

1.5.9.1 PVTOOLS.INI Syntax

The syntax of entries in PVTOOLS.INI is as follows:

[Menu]
ItemN=Description

[Command]
ItemN=command_string

[Help]
ItemN=help_line

Where N is a number between 0 and 31, and entries in the [Help] section are optional.

Item0 ... Item31

are the item numbers that define the order in which entries appear in the Tools Menu.

[Menu]

Entries in the [Menu] section are what actually appears in the Tools Menu. The '&' character tells Windows where to put the underline in the menu entry. The underlined letter becomes the abbreviation for the command. For example the letter 'C' in '&Click Me' would become 'Click Me' when displayed in the Tools Menu, and you could access the command by pressing Alt+T and then 'C'. (Alt+T activates the Tools Menu).
You should make sure that all Tools Menu entries have different abbreviations if you intend to access them this way. Of course, you don't have to supply any abbreviation if you don't want to.

Note: By default newer versions of Windows will not display the underline beneath the abbreviation until you press ALT. This means if you use the mouse to open the menu you won't see the underlines.

[Command]

This is the command that POV-Ray will execute for that entry. This can be a Windows EXE, a batch file, or anything else that may be executed by the Win32 ShellExecute() API call. The command consists of the actual command name followed by any parameters you want to supply to the program.
There are two special commands, '$S' and '$E'. $S means 'use the shell association for the filename that follows it', and '$E' means 'open the following file in the internal POVWIN editor'. Let's look at an example -

Item4=$S %1

Since %1 refers to the output file (see below) this means that Item 4 of the tools menu expands to a command to Windows to open the last output file with whatever program is associated with it. For example, if the last output file was 'c:\images\torus4.png' then the above command example would use whatever program is associated with PNG files (i.e. the program that Windows runs if you double-clicked on the TORUS4.PNG file in Windows Explorer) to open it.

Note: If using the $S or $E special commands, do not quote the parameters with '"', even if they will have spaces in them. Both of these commands may only be supplied a single parameter, which is taken to be the entire line following the command.

POV-Ray for Windows has a number of pre-defined parameters that you can substitute into the command line before the program is run. These are defined by a percent sign ('%') followed by a letter or number. For example, '%i' means substitute the POV-Ray for Windows INI file directory in the place of the '%i'.

Let's look at the command:

notepad.exe %ipvtools.txt

If you had installed POV-Ray for Windows into the directory 'c:\povwin3', then our standard INI file directory would be 'c:\povwin3\ini\'. When POV-Ray ran the above command, the '%i' would be replaced with 'c:\povwin3\ini\'. Note that the trailing '\' is provided by POV-Ray. This means that:

notepad.exe %ipvtools.txt

would become:

notepad.exe c:\povwin3\ini\pvtools.txt

Here are all of the predefined substitutions:

%0 | The contents of the 'SourceFile' entry of the 'LastRender' section in PVENGINE.INI. This will be the input file provided to POV-Ray for the most recent render. This information is extracted from the rendering engine itself, rather than any input dialog or command-line. It is the file which, after all processing of the command line and INI files was complete, was finally assigned as the input file.
%1 | The contents of the 'OutputFile' entry of the 'LastRender' section in PVENGINE.INI. This will be the output file from the last render, if any. This entry could be blank.
%2 The contents of the 'SceneFile' entry of the 'LastRender' section in PVENGINE.INI. This will be the scene file name for the last render, without the .POV extension. You can use this by appending a new extension to it. For example,
tga2gif %d\%1 %2.gif
could expand to:
tga2gif c:\scenes\myscene.tga myscene.gif
assuming the input file was myscene.pov and the current directory at that time was c:\scenes.
%4 | The contents of the 'IniOutputFile' entry of the 'LastRender' section in PVENGINE.INI. If you had instructed POV-Ray to write an INI file from the last render, this would contain its name.
%D | The contents of the 'CurrentDirectory' entry of the 'LastRender' section in PVENGINE.INI. This is the current working directory that was set on your machine when POV-Ray began rendering the last file, and is what the other output file entries are probably relative to. You may need to provide '%d' with some of these other entries to get the full path.
%H | The POV-Ray for Windows install directory, as specified in the registry or inferred at run- time, e.g. 'c:\Program Files\POV-Ray for Windows v3.7\'. Note the trailing backslash is supplied.
%P | The POV-Ray for Windows user documents directory, as specified in the registry or inferred at run- time, e.g. 'c:\Users\Joe\Documents\POV-Ray\v3.7\'. Note the trailing backslash is supplied. This is the directory where the sample scenes, include files, and INI files are stored.
%I | The POV-Ray for Windows INI directory. e.g. 'c:\Users\Joe\Documents\POV-Ray\v3.7\ini\'.
%N | The preset INI filename, as used in the render options dialog.
%R | The last render file (with full path) as supplied to POV-Ray from the render or choose file dialog. This is not necessarily the same thing as %S or %0.
%S | The source file name as provided to POV-Ray on the last render of the current session. This is not necessarily the same thing as the %0 or %R directive. For example, %R will never provide the path to a file that was rendered via the File Queue without the use of the Command dialog. %S will, however, include any such file.
%T | The full path to PVTOOLS.INI. This is the file which holds the Tools Menu commands.
%% A literal percent character ('%').

If any of the above seems confusing, there's an easy way to find out what's going on. If you place the statement DEBUG=1 in the General section of PVTOOLS.INI, POV-Ray for Windows will print out the string for each command both before and after it is expanded, instead of running the command that you select in the tool menu. That way you can see exactly what POV-Ray substitutes. The printout will be visible in the messages window.

For example:

[General]
Debug=1

will turn on debugging. while

[General]
Debug=0

or omitting the statement entirely turns it off.

[Help]

You can have a help line appear in the status bar at the bottom of the window. You don't have to supply this entry if you don't want to.

Example:

[Help]
Item1=Edit master POVRAY.INI in installation directory

This command makes the string 'Edit master POVRAY.INI in installation directory' appear on the status bar when the mouse is over the 1st item in the Tools menu.

1.5.9.2 Reload Tool Menu

If you want your changes to take immediate effect after you have edited PVTOOLS.INI using a text editor, you have to select the Tools Menu command Reload Tool Menu to instruct POV-Ray for Windows to re-read the INI file and activate the new settings.

1.5.9.3 Edit PVTOOLS.INI

This standard Tools Menu command lets you modify PVTOOLS.INI using the Notepad editor. The command is part of PVTOOLS.INI itself, which means you may delete it entirely if you don't want it. It is present by default in the standard distribution of POV-Ray for Windows.

1.5.9.4 Example PVTOOLS.INI

[Menu]
Item0=Edit &master POVRAY.INI
Item1=Edit PVEN&GINE.INI
Item2=Edit &last rendered file
Item3=Edit last &scene file
Item4=&View last rendered file
Item5=Edit resolution &INI file
Item6=Edit &user-defined syntax file
Item7=&Browse sample scenes folder
Item8=Edit &this menu

[Command]
# NOTE! If using the $E or $E, DO NOT quote the parameters with '"'.
# If you are calling a program directly, you will probably need to quote the
# parameter; e.g. notepad.exe "%r"
Item0=$e %pini\povray.ini
Item1=$e %pini\pvengine.ini
Item2=$e %r
Item3=$e %0
Item4=$s %1
Item5=$e %n
Item6=$e %I\user-keywords.txt
Item7=$s %pscenes\
Item8=$e %t

[Help]
Item0=Edit master POVRAY.INI in installation directory
Item1=Edit PVENGINE.INI in installation directory
Item2=Edit the last file that POV-Ray was rendering
Item3=Edit the last scene file that you selected
Item4=View the output of the last render (assumes file output was on)
Item5=Edit secondary INI file as specified in Command-line dialog
Item6=Edit the user-defined syntax highlighting file
Item7=Open the folder containing the sample scenes installed with POV-Ray
Item8=Edit PVTOOLS.INI to alter this menu

[General]
Debug=0

1.5.10 Window Menu

The Window menu contains a number of commands related to editor tab management (in the context of this section, a 'window' refers to a tab in the editor) and additionally a list of tabs showing the name of their contents. At a minimum (if no files are open) this list will contain one entry: the Message tab.

The MRU (most-recently-used) arrangement of the tab list in this menu makes it trivial to toggle between files without taking your eyes off the text or using the mouse. The most recently viewed tab (i.e. the current one) will always be entry 1 in the list. The second most recently viewed (i.e. the last tab viewed before switching to the current one) will always be entry 2 in the list, and so forth. Given that entries 1 through 10 in the list are given the menu mnemonics 1 through 0 respectively, all you need to do to toggle between the current and previous files is hit Alt-W then 2. To go to the third oldest, Alt-W then 3, and so forth. Note that the MRU list is not saved on exit.

1.5.11 Context Menus

Most POV-Ray windows have shortcut (also known as 'context') menus. You access them by right-clicking over the window in question (e.g. the message, edit, or render window). The menu that appears will have the most commonly-used commands (as available in the main menus) that apply to that particular type of window.

1.5.11.1 The Message Window context menu

 | When the mouse right button is pressed over the Message window, a pop-up menu containing these commands are displayed:
The Message Window context menu |

All of these commands and sub-menus except 'Minimize to System Tray' and 'Show Tip' are documented elsewhere; the following list links to that documentation.

  • Edit Settings/Render dialog
  • Select File and Render dialog
  • Start Rendering
  • File Queue dialog
  • Clear Queue
  • Clear Messages
  • Re-Display Render Window
  • Render Priority

1.5.11.2 Minimize to System Tray

This command (which is also available as a toolbar button) will hide POV-Ray for Windows and place a small icon in the system tray (the system tray usually contains a clock and is often at the right hand side of the task bar at the bottom of the screen).

You can use the right-mouse button on this icon to get a context menu. Double-clicking on it restores POVWIN from the tray.

1.5.11.3 Show Tip

If you select Show Tip, POV-Ray for Windows displays a single tip (see Show Tips of the Day).

1.5.11.4 The Render Window context menu

The Render Window context menu

See the Render Window sub-menu for documentation on the commands in this menu.

1.5.11.5 The Editor Window context menu

The Editor Window context menu

The actual content of the line shown as 'Open "filename"' will vary according to what was on the line under the cursor when the right mouse button was clicked. All of the commands except 'Show Messages', 'Context Help', and 'Open "filename"' are documented elsewhere; the following list links to that documentation.

  • Cut
  • Copy
  • Paste
  • Undo
  • Redo
  • Bookmark sub-menu
  • File
  • Search
  • Selection sub-menu
  • Close Current File
  • Properties

1.5.11.6 Show or Hide Messages

Manually cause the small message window to be displayed (or hidden if it is showing, in which case this menu entry will read 'Hide Message Window' instead of 'Show Message Window'). Note that you can also use the Escape key to hide the message window.

See Auto-Show Parse Messages for more information.

1.5.11.7 Context Help

This command (which can also be activated with the F1 key) will cause the editor to look for the closest word to the edit caret and attempt to look it up in the help file. If more than one match is found, you will be given a choice as to which one. If no match is found, the help file will open with the index at the closest match it could find.

1.5.11.8 Open Filename

Whenever you open the context menu, the editor first looks underneath the edit caret to see if there is a line that looks like a POV-Ray scene file '#include' directive. If one is found, the name of the specified file is placed into the menu in place of "filename". If one is not found, then it may show Copy ... to Command-Line (see below).

If you then select this command, the editor will attempt to find and open the file in a new edit window. The standard include paths (as defined in PVENGINE.INI) will be searched if the file is not found relative to the current directory.

1.5.11.9 Copy ... to Command-Line

If, when the editor searches for an include file name on the current line (see above), it does not find one, it will then look for something that looks like a 'command line'. By 'command line' we mean a line that could be used in the toolbar command-line field as options. The editor uses several simple rules to decide if something is likely to be a command-line:

Firstly, the line must contain a '//' somewhere. Then, either -

  1. The first non-whitespace character after the '//' is either a '+' or a '-', and the next character after that is alphabetical, or
  2. The first non-whitespace after the '//' contains 'Cmd:' (case-insensitive).

If the line fits this description then the text after the '//' (with the 'Cmd:' removed if it were present) is considered the command-line (minus leading and trailing whitespace). There is one slight variation to the detection rules, though: if the line also contains a quoted string that looks like it could be a filename and you right-click before the end of that string, the context menu will present the 'Open File in Editor' option instead of the 'Copy Command' option. To get the 'Copy Command' option, simply make sure you right-click somewhere to the right of the filename.

The "Copy to command-line" feature

In this case the menu will have a command to copy the found command to the toolbar command-line, such as the one shown on the left. If this command is chosen, the text in the toolbar command-line will be replaced with the text extracted from the line, and focus will be changed to the toolbar command-line field.

The purpose of this facility is to allow users to keep a set of commonly-used command-line options at the top of the scene file, and use this facility to quickly copy one of them to the command-line for a render.

Example command-lines which could be embedded into a scene file -

// +w480 +h200 +a0.1
// +w960 +h400 +a0.1

The following would also be legal (and equivalent to the above example) -

// Cmd: Width=480 Height=200 Antialias_Threshold=0.1 AntiAlias=On
// Cmd: Width=960 Height=400 Antialias_Threshold=0.1 AntiAlias=On

See also Toolbar Command Line.


Windows Section 6

1.6 Bug Reports

Before submitting any bug reports to our forums, make sure that the bug is not already listed on our »bug tracker. Please remember that the POV-Ray users who provide assistance on our forums are volunteers who give their time for free so you can enjoy this program for no charge. Keep this in mind when wording your message.

Make sure that the subject of your report isn't already covered in this document. We also strongly recommend that you check out the online version of the »POV-Ray Questions and Tips before submitting a report.

1.6.1 Bugs and GUI Extensions

If you have installed any GUI Extensions (or used any software that may have installed them), make sure you see if the problem exists with the extensions disabled and unloaded.

To do this, go to the GUI Extensions sub-menu of the Options menu, and deselect 'Use Extensions'. Then exit and restart POV-Ray for Windows. The GUI Extensions menu should then state 'No Extensions Loaded' (it may already do this if you've got none installed). Then attempt to duplicate the problem again.

1.6.2 Crash Upload Utility

In order to assist the team in tracking down crashes, Structured Exception Handling and mini-dump generation capabilities have been added. After an unhandled exception POVWIN will now offer the option of creating a mini-dump (brief or full) for submission either manually or via the crash upload utility which is installed with the program. If you want to draw immediate attention to a crash it is strongly recommended that you also post a comment in the povray.bugreports or »povray.windows forum and provide the crash report ID supplied by the upload utility.

1.6.4 Bug Reporting via our Bug Tracking System

Bug reports may be lodged about POVWIN by using the »bug tracking system. The bugtracker is monitored regularly by the POV-Ray development team and they will address any properly-lodged bug reports in the most timely manner possible.

You may like to remember, however, that no matter where you end up getting assistance from, users who show that they have looked in the documentation and read the »POV-Ray Questions and Tips first, will be much more likely to receive the response they want than someone who obviously has not done their homework. It's also important to check that the bug hasn't already been reported - if it has, and is still open, don't add a new report - if you have relevant information not already in the existing report, consider adding a comment.

Any messages or reports sent to us may be re-posted in our forums, bug tracker, or our web site if we consider it appropriate to do so. We will in such cases of course remove any obvious identifying or personal information first.

You should not expect any reply to bug reports. If you wish to follow the progress of a bug, it's best to use the bug tracker (be sure to configure your account to receive notifications of replies to your bug). You can also request to be emailed when there are replies to an existing bug report.

The minimum information to include in your bug report is

  1. The version number of POV-Ray for Windows. You can see this by selecting About from the Help Menu.
  2. Your operating system. We need to know what version of Windows you are running.
  3. Your computer ; what processor and how much memory.
  4. A complete description of the problem and what led up to it. It will make it a lot easier to track a bug down if you can include a scene file that will cause the problem. If the file is large, try removing parts until you have the minimum scene file that will cause the problem.


Windows Section 7

1.7 Speed Considerations

The following tips can help you increase the speed at which your images render. Most of the time, the increase will be marginal, but in a very long render (some users have renders that take several days) even a small increase can save a noticable amount of time.

1.7.1 Render Priority

Raising the render priority may speed up your render, at the cost of reducing system response times and slower execution of other programs.

See Render Priority in the Render Menu for information on how to do this and whether or not to expect it to make any noticeable difference.

1.7.2 Render Window

Closing the render window will also speed up things. If your render is writing a lot of text to the message window, either hiding it (select an editor window for example), or better still, minimizing POV-Ray for Windows, will help somewhat. Note that the effect that these actions have is generally directly related to the time it takes to render the file, and the resolution of the render. They have less effect on long renders, and more effect on very fast renders.

1.7.3 Memory

In general, the more memory you have (up to a point) the faster things will run, although this is not a direct effect. (The less time Windows spends swapping things out to disk, the more time is available for your render)

1.7.4 Scene Features

Anti-aliasing, fog, media, area lights, photons, isosurface--all of these will cause your scene to require more time for completion. See the POV-Ray documentation for more details.

1.7.5 Render Quality

Consider using a lower quality setting if you're just testing your scene, and do not care about the quality of the output.


Tutorial Table of Contents

Introduction
Program Description
What is Ray-Tracing?
What is POV-Ray?
Features
Changes and New Features Summary
Trademarks
The Early History of POV-Ray
The Original Creation Message
The Name
A Historic 'Version History'
How Do I Begin?
Notation and Basic Assumptions
Getting Started
Our First Image
Understanding POV-Ray's Coordinate System
Adding Standard Include Files
Adding a Camera
Describing an Object
Adding Texture to an Object
Defining a Light Source
Basic Shapes
Box Object
Cone Object
Cylinder Object
Plane Object
Torus Object
CSG Objects
What is CSG?
CSG Union
CSG Intersection
CSG Difference
CSG Merge
CSG Pitfalls
Co-incident Surfaces
The Light Source
The Pointlight Source
The Spotlight Source
The Cylindrical Light Source
The Area Light Source
The Ambient Light Source
Light Source Specials
Using Shadowless Lights
Assigning an Object to a Light Source
Using Light Fading
Simple Texture Options
Surface Finishes
Adding Bumpiness
Creating Color Patterns
Pre-defined Textures
Using the Camera
Using Focal Blur
POV-Ray Coordinate System
Transformations
Translate
Scale
Rotate
Matrix
Transformation Order
Inverse Transform
Transform Identifiers
Transforming Textures and Objects
Setting POV-Ray Options
Command Line Switches
Using INI Files
Using the POVINI Environment Variable
Advanced Features
Spline Based Shapes
Lathe Object
Understanding The Concept of Splines
Surface of Revolution Object
Prism Object
Teaching An Old Spline New Tricks
Smooth Transitions
Multiple Sub-Shapes
Conic Sweeps And The Tapering Effect
Sphere Sweep Object
Bicubic Patch Object
Text Object
Polygon Based Shapes
Mesh Object
Mesh2 Object
Smooth triangles and mesh2
UV mapping and mesh2
A separate texture per triangle
Polygon Object
Other Shapes
Blob Object
Component Types and Other New Features
Complex Blob Constructs and Negative Strength
Height Field Object
Isosurface Object
Simple functions
Several surfaces
Non-linear functions
Specifying functions
Internal functions
Combining isosurface functions
Noise and pigment functions
Conditional directives and loops
Transformations on functions
Improving Isosurface Speed
Poly Object
Creating the polynomial function
Writing the polynomial vector
Polynomial made easy
Superquadric Ellipsoid Object
Gamma Handling
Setting Up Your Display
Setting Up POV-Ray
Gamma in Output Images
Setting Up Your Scene
Gamma in Literal Colors
Gamma in Input Images
Gamma in Legacy Scenes
Advanced Texture Options
Pigments
Using Color List Pigments
Using Pigment and Patterns
Using Pattern Modifiers
Using Transparent Pigments and Layered Textures
Using Pigment Maps
Normals
Using Basic Normal Modifiers
Blending Normals
Slope Map Tutorial
Slopes, what are they?
Syntax of a slope map
Examples of slope maps
Finishes
Using Ambient
Using Emission
Using Surface Highlights
Using Reflection, Metallic and Metallic
Using Iridescence
Working With Pigment Maps
Working With Normal Maps
Working With Texture Maps
Working With List Textures
What About Tiles?
Average Function
Working With Layered Textures
Declaring Layered Textures
Another Layered Textures Example
When All Else Fails: Material Maps
Limitations Of Special Textures
Using Atmospheric Effects
The Background
The Sky Sphere
Creating a Sky with a Color Gradient
Adding the Sun
Adding Some Clouds
The Fog
A Constant Fog
Setting a Minimum Translucency
Creating a Filtering Fog
Adding Some Turbulence to the Fog
Using Ground Fog
Using Multiple Layers of Fog
Fog and Hollow Objects
The Rainbow
Starting With a Simple Rainbow
Increasing the Rainbow's Translucency
Using a Rainbow Arc
Simple Media Tutorial
Types of media
Some media concepts
Simple media examples
Emitting media
Absorbing media
Scattering media
Multiple medias inside the same object
Media and transformations
A more advanced example of scattering media
Media and photons
Radiosity
Introduction
Radiosity with conventional lighting
Radiosity without conventional lighting
Normals and Radiosity
Performance considerations
Making Animations
The Clock Variable: Key To It All
Clock Dependant Variables And Multi-Stage Animations
The Phase Keyword
Do Not Use Jitter Or Crand
INI File Settings
While-loop tutorial
What a while-loop is and what it is not
How does a single while-loop work?
How do I make a while-loop?
What is a condition and how do I make one?
What about loop types other than simple for-loops?
What about nested loops?
Mixed-type nested loops
Other things to note
SDL tutorial: A raytracer
Introduction
The idea and the code
Short introduction to raytracing
Global settings
Scene definition
Initializing the raytracer
Ray-sphere intersection
Inner workings of a macro
The ray-sphere intersection macro
The Trace macro
Calculating the closest intersection
If the ray doesn't hit anything
Initializing color calculations
Going through the light sources
Shadow test
Diffuse lighting
Specular lighting
Reflection Calculation
Calculating the image
Creating the colored mesh
The structure of the mesh
Creating the mesh
Creating the vertex points
Creating the textures
Creating the triangles
The Camera-setup
Questions and Tips
Appendices
Contacting the Authors
POV-Ray License
Contact Information
Support Library Licenses
OpenEXR
Citing POV-Ray in Academic Publications
Contributors to POV-Ray
Thanks
What to do if you don't have POV-Ray
Which Version of POV-Ray should you use?
Microsoft Windows
Apple Macintosh
Linux/Unix
All Versions
Where to Find POV-Ray Files
World Wide Website www.povray.org
Suggested Reading


Tutorial Section 1

2.1 Introduction

This document provides a tutorial for the Persistence of Vision Ray-Tracer™ (POV-Ray). The documentation applies to all platforms to which this version of POV-Ray is ported. The platform-specific documentation is available for each platform separately.

The tutorial is divided into five main parts:

  1. This introduction which explains what POV-Ray is and what ray-tracing is. It gives a brief overview of how to create ray-traced images.
  2. A Beginning Tutorial which explains step by step how to use the different features of POV-Ray.
  3. An Advanced Tutorial which contains more advanced tutorial topics.
  4. POV-Ray questions and tips gives answers to many frequently-asked questions about POV-Ray.
  5. In the Appendices you will find some tips and hints, where to get the latest version and versions for other platforms, the POV-Ray licence, information on compiling custom versions of POV-Ray, suggested reading, contact addresses and legal information.

The current release of POV-Ray runs on 32 and 64-bit versions of Microsoft Windows from XP through Windows 8, Mac OS X, Linux/UNIX, and numerous other platforms (when compiled from source).

If you do not yet have POV-Ray installed or are not sure you have the official version or the latest version, see appendix What to do if you don't have POV-Ray.

This book covers only the generic parts of the program which are common to each version.

Note: Each version has platform-specific documentation not included in this section.

We recommend you finish reading this introductory section then read the platform-specific information before reading the rest of the tutorial. The platform-specific docs will show you how to render a sample scene and will give you detailed descriptions of the platform-specific features.

The Windows version documentation is available on the POV-Ray program's Help menu or by pressing the F1 key while in the program.

The Unix / Linux version documentation can be found at the same place as the platform independent part. Usually that is /usr/local/share/povray-3.?

2.1.1 Program Description

The Persistence of Vision Ray-Tracer creates three-dimensional, photo-realistic images using a rendering technique called ray-tracing. It reads in a text file containing information describing the objects and lighting in a scene and generates an image of that scene from the view point of a camera also described in the text file. Ray-tracing is not a fast process by any means, but it produces very high quality images with realistic reflections, shading, perspective and other effects.

2.1.2 What is Ray-Tracing?

Ray-tracing is a rendering technique that calculates an image of a scene by simulating the way rays of light travel in the real world. However it does this simulation backwards; in the real world, rays of light are emitted from a light source and then strike objects. Some of the light rays then bounce off the objects and enter our eyes (or perhaps a camera). However, most of the rays never reach anything that 'observes' them; they either leave the area of interest or are absorbed by objects within it.

Because the vast majority of rays never reach an observer, it would take a very long time for software to trace even a simple image if the rays were cast as they were in the real world (because almost all of the calculations would end up going to waste). For the purposes of drawing a representation of a scene as viewed from an imaginary camera, we are generally only interested in rays that reach that camera's lens.

A 'scene' is the virtual world which you wish to take a 'picture' of with our simulated camera. There can be (and usually are) objects in the scene that do not appear in the final image, just as objects outside the field of view of a real camera do not directly appear in the final image. (They can still cast shadows or be seen as reflections, though).

Accordingly, ray-tracing programs like POV-Ray start with their simulated camera and trace rays backwards out into the scene. The user specifies the location of the camera and the type of lens it is using, the light sources that illuminate the scene, the objects within it, as well as the surface texture properties of objects, their interiors (if transparent) and any atmospheric media such as fog, haze, or fire.

For every pixel in the final image one or more viewing rays are shot from the camera into the scene to see if it intersects with any of the objects in the scene. These "viewing rays" originate from the viewer (represented by the camera), and pass through the viewing window (representing the pixels of the final image).

Every time an object is hit, the color of the surface at that point is calculated. For this purpose rays are sent from that point to each light source to determine the amount of light coming from that source. These "shadow rays" are tested to tell whether the surface point lies in shadow or not. If the surface is reflective or transparent new rays are set up and traced in order to determine the contribution of the reflected and refracted light to the final surface color.

Special features like inter-diffuse reflection (radiosity), atmospheric effects and area lights make it necessary to shoot a lot of additional rays into the scene for every pixel.

2.1.3 What is POV-Ray?

POV-Ray™ is short for the Persistence of Vision Raytracer™, a tool for producing high-quality computer graphics. POV-Ray is Free Software (as per the definition of the Free Software Foundation) as its source code is licensed under the »Affero General Public License (AGPL).

POV-Ray was developed from DKBTrace 2.12 (written by David K. Buck and Aaron A. Collins) by a bunch of people (called the POV-Team™) in their spare time. The headquarters of the POV-Team is on the »internet (see Where to Find POV-Ray Files for more details).

The POV-Ray package includes detailed instructions on using the ray-tracer and creating scenes. Many stunning scenes are included with POV-Ray so you can start creating images immediately when you get the package. These scenes can also be modified so you do not have to start from scratch.

In addition to the pre-defined scenes, a library of pre-defined shapes and materials is provided. You can include these shapes and materials in your own scenes by just including the library file name at the top of your scene file, and by using the shape or material name in your scene.

2.1.4 Features

Here are some highlights of POV-Ray's features:

  • Easy to use scene description language.
  • Large library of stunning example scene files.
  • Standard include files that pre-define many shapes, colors and textures.
  • Very high quality output image files (up to 48-bit color).
  • Create landscapes using smoothed height fields.
  • Many camera types, including perspective, orthographic, fisheye, etc.
  • Spotlights, cylindrical lights and area lights for sophisticated lighting.
  • Photons for realistic, reflected and refracted, caustics. Photons also interact with media.
  • Phong and specular highlighting for more realistic-looking surfaces.
  • Inter-diffuse reflection (radiosity) for more realistic lighting.
  • Atmospheric effects like atmosphere, ground-fog and rainbow.
  • Particle media to model effects like clouds, dust, fire and steam.
  • Several image file output formats including BMP, PNG, JPG and OpenEXR.
  • Basic shape primitives such as:
    • spheres
    • boxes
    • quadrics
    • cylinders
    • cones
    • triangle
    • planes
  • Advanced shape primitives such as:
    • tori (donuts)
    • bezier patches
    • height fields (mountains)
    • blobs
    • quartics
    • smooth triangles
    • text
    • superquadrics
    • surface of revolution
    • prisms
    • polygons
    • lathes
    • fractals
    • isosurfaces
    • parametric
  • Shapes can easily be combined to create new complex shapes using Constructive Solid Geometry.
  • POV-Ray supports unions, merges, intersections and differences.
  • Objects are assigned materials called textures and interior properties such as index of refraction and particle media.
  • Built-in color and normal patterns:
    • Agate
    • Bozo
    • Bumps
    • Checker
    • Crackle
    • Dents
    • Functions
    • Granite
    • Gradient
    • Hexagon
    • Image
    • Leopard
    • Mandel
    • Marble
    • Onion
    • Quilted
    • Ripples
    • Spotted
    • Spiral
    • Radial
    • Waves
    • Wood
    • Wrinkles
  • Users can create their own textures or use the pre-defined ones included with the distribution.
  • Combine textures using layering of semi-transparent textures or tiles of textures or material map files.
  • Display preview of image while rendering (on supported platforms).
  • Halt and save a render part way through, and continue rendering the halted partial render later.

2.1.4.1 Changes and New Features Summary

This section covers version 3.7 Changes and New Features that apply no matter what platform you are using. Changes and information pertaining to your particular installation are covered in the platform specific documentation that's included with the distribution.

The categorized list below outlines the additions, changes and improvements along with links (when appropriate) to their relevant passages in the Reference Section.

Look Here First

These items definitely deserve your attention, because some of them represent key changes or enhancements to the way POV-Ray operates or behaves.

  1. POV-Ray now supports Symmetric MultiProcessing.
  2. The addition of the mesh_camera permits simulation of arbitrary lenses and makes texture baking possible.
  3. An experimental gamma handling feature has been added, some of the highlights are:
    1. a different role for assumed_gamma
    2. changes in the global_settings section
    3. the srgb keyword and its kin can be used to specify gamma pre-corrected colors
    4. an Antialias_Gamma feature has been added
    5. lastly you can also change the input file gamma for individual input files
  4. Make sure to review the Images and Image Related category below for important changes and additions.
  5. Redistribute the workload to render threads by specifying a render block size.
  6. Binary Space Partitioning or BSP tree bounding is now available.
  7. A resource control option for output image caching has been added.
  8. An overall review of the entire radiosity section is probably a good idea; some of the highlights are:
    1. a revised radiosity tutorial
    2. the new maximum_reuse parameter
    3. adaptive pretrace mode added to the nearest_count parameter
    4. the loading and saving of radiosity data has changed
    5. new command line options can help to further customize radiosity features
  9. The ovus object was added, along with support for uv_mapping
  10. Raised max order of the poly, cubic and quartic objects. Alternate syntax is also available.
  11. Added multiple-thread support to photon shooting code.
  12. New thread-safe random number generator was added.
  13. The buit-in benchmark process now runs without any other distribution files. See the platform specific documentation for details.
  14. The Draw_Vistas, Vista_Buffer and Light_Buffer options have been deprecated. Look here for additional details.

Patterns Pigments and Textures

This category deals with items that are the building blocks of materials and textures and their appearance.

  1. Added diffuse backside illumination capability.
  2. An experimental subsurface scattering feature was added.
  3. Support for area_light diffuse and specular illumination was implemented.
  4. These list patterns, a warp, and a slope pattern extensions were added:
    1. aoi pattern
    2. cubic pattern
    3. cubic warp
    4. pavement pattern
    5. square pattern
    6. tiling pattern
    7. triangular pattern
    8. slope pattern extension
  5. Improvements to iterations and two new exterior types were added. See Fractal Patterns for more details.
  6. The finish block now supports the emission keyword.
  7. A sky_sphere layered pigment related behavior change.
  8. A new Slope Map Tutorial has been added.
  9. Re-enabled the crand finish attribute.

Images and Image Related

Image formats and handling issues are covered in this section.

  1. Get your display gamma correct! See the new gamma handling tutorial.
  2. There have been various changes regarding output file types these are the highlights:
    1. cross platform default output file type is PNG
    2. BOTH input and output support for two High Dynamic Range file types has been added
    3. JPEG default quality and chroma sub-sampling changes
    4. output file type "s" has been deprecated
  3. An output file dithering feature has been added.
  4. The interpolate option now supports bicubic interpolation.
  5. Use of the hf_gray_16 keyword has been deprecated in the global_settings block.
  6. A couple of important changes and additions regarding Alpha Channel usage.
  7. Added "out-of-the-box" transparency support for GIF input files.

Language Basics and Directives

A macro, a few functions and some programming directives completes this summary.

  1. Now you can declare an identifier as deprecated.
  2. Several bitwise functions were added.
  3. A string function datetime() has also been added.
  4. Added a new pre-declared variable input_file_name.
  5. New string relational operators have been added.
  6. Added binary #write capability, see the ARRAYS_WriteDF3 macro for usage.
  7. The #break directive behavior has changed.
  8. An atand function has been added to the math.inc file.
  9. The max_extent function can now return the pixel resolution of an image map.
  10. A new #version directive requirement has been added.
  11. The #if directive now supports an #elseif clause.
  12. A new #for loop directive has been added.
  13. The CPU Utilization Histogram feature has been deprecated.
  14. Added a +GP option. See the section: Directing Text Streams to Files for more information.

2.1.5 Trademarks

The terms 'POV-Ray', 'Persistence of Vision Ray Tracer', and 'POV-Team' are trademarks of Persistence of Vision Raytracer Pty. Ltd. All other trademarks are acknowledged as being the property of their respective owners.

2.1.6 The Early History of POV-Ray

Here's how POV-Ray came to be, as described by David Buck:

Back in 1986 or so, I had an Amiga. A friend who also has an Amiga downloaded the C code for a raytracer for Unix from the Internet and brought it over. I thought it looked interesting and I ported it to the Amiga and wrote the drivers to display it with Amiga graphics. The program only rendered untextured spheres with a planar floor in black and white, but I was still impressed by it. I played with it a bit adding support for color, but I eventually decided that I could do a better job writing a raytracer from scratch, so I scrapped the C program and started my own - DKBTrace had begun.

I decided to start with general quadric surfaces since they could represent spheres, ellipsoids, cylinders, planes, and more. I worked out the ray-quadric intersection calculations and used some calculus to work out the surface normal to a quadric surface at a point. For the program structure, I decided to use an object-oriented style since I had learned Smalltalk at university and it fit nicely. To make modeling more flexible, I added CSG and procedural textures. In the end, I had an interesting little raytracer and I decided to release it as freeware since I was planning to return to university to start my Master's degree and didn't have time to develop a commercial raytracer. Besides, there were already commercial renders for the Amiga that had user interfaces (not just text files) and I felt I couldn't sell it as a commercial product. I called it DKBTrace and released it to local BBS'es and to the Internet.

DKBTrace was an Amiga-only program, but it attracted quite a lot of interest. I released several versions of it adding in new features, better primitives, more texturing options, etc. Eventually I released version 2.01.

Sometime around 1987 or 1988, I was contacted by Aaron Collins. He had found the C code for DKBTrace and ported it to the PC. He also added a Phong lighting model and a few more goodies. I was interested in what he had done, so I contacted him to see if he wanted to help develop a new version of the program. This one would be portable across more platforms (at university I had access to Unix workstations). We eventually came up with version 2.12 which was the last version of DKBTrace ever released (1989).

While Aaron and I were working up to version 2.12, there was a group of people on CompuServe who were very excited about DKBTrace and were creating all sorts of neat scenes for it. They were also expressing frustration that Aaron and I weren't able to add new features into DKBTrace fast enough. They started talking about building a whole new raytracer from scratch that they could control and add the features they wanted. At that time, I was starting to pursue other areas and was starting to drift away from raytracing. So, I posted a message on CompuServe with the following offer: We could form a team to develop a new raytracer using DKBTrace as a base. I had three requirements for this team. The resulting code had to be freeware with the source code freely available, it had to remain portable between different platforms, and it had to have a different name than DKBTrace.

The name DKBTrace was, of course, based on my initials: David Kirk Buck (there's some little known trivia for you). With a package developed by a team of people, it was inappropriate to use my initials. I was also starting to drift away from raytracing (as I mentioned) and I didn't want people thinking that I was the head of the team forever. The name that was proposed was "Persistance Of Vision Raytracer" which was shortened to POV-Ray. It worked in three ways. It was the result of a persistent vision of the developers, it was a reference to the Salvador Dali work which depicted a distorted but realistic world, and the term "persistance of vision" in biology referred to the ability to see an image that was presented briefly - almost an after image.

In 1989, then, DKBTrace 2.12 was officially released and the POV-Ray project had begun. I worked with the team for a few years after that. I was responsible for the Amiga port among other things. Drew Wells was the project leader. Aaron Collins dropped out of the project around that time as well. Other early members included Chris Young, Steve Anger, Tim Wegner, Dan Farmer, Bill Pulver (IBM drivers), and Alexander Enzmann (quartics and cool math stuff). Chris Cason joined shortly after (my apologies if I left anyone out - lots of people were involved). The reference to Robert Skinner in the credits for POV-Ray was because we had a hard time finding a good noise function. In another raytracer, he had a great noise function written by Robert Skinner, so we asked for and received permission to use it in POV-Ray.

There was so much demand for us to release a new version that we created POV-Ray 0.5 and released it. It was basically an enhanced DKBTrace with a similar grammar but many more features. Eventually, we released POV-Ray 1.0 which had the new grammar and lots of new stuff. Drew dropped out later and Chris Young took over as project leader.

It was around that time that I started to drift away from the POV-Ray team. The project had momentum and could continue on without me. I was getting into different areas (physically based modeling and animation) and no longer had the time to continue with POV-Ray. Around the release of version 2.0, I left the project and the POV-Ray team developed it to its current state. Chris Cason is now the project leader.

Even though I'm no longer on the POV-Ray development team, I still like to follow its progress. I haven't built my own scene by hand for years now (although I occasionally use Moray). I still enjoy the one thing that drove me back in the DKBTrace days - I love seeing the works of other people who used my software. Even though I can no longer call POV-Ray "my software", I still enjoy admiring the artwork people create with it. I'm constantly amazed at what people can do. It was always the feedback from user community that drove me.

David Buck,
david [at] simberon.com

august 2001

2.1.6.1 The Original Creation Message

11906 S16/Raytraced Images
   07-Mar-91 18:56:37
Sb: DKB Development
Fm: David Buck 70521,1371
To: All

Greetings all.  This is my first posting to this group, so you'll
have to excuse me if I make any mistakes in this post.

Finally, after several weeks of waiting, I've received my CompuServe
account.  It's nice to see that people are enjoying my raytracer
(DKB, of course). I have noticed, however, that you are less than
satisfied at the support I've been able to provide <grin>.
True, I'm the first to admit that the support is poor.  I have
little time these days to work on graphics - it takes long enough
to answer all the questions I get asked on a daily basis from all
across the world.

My motivation for releasing the raytracer as Freely Distributable
software in the first place was to allow people to have some fun
with a program I'd developed for just that purpose.  I don't
consider it to be a professional package - I know it's nowhere near
that good.  I didn't make it shareware, however, because I knew I
wouldn't have much time for support.  I didn't want the hassles of
maintaining user lists, sending updates and notices, etc.

There has recently been a proposal in this forum that you write
your own raytracer to use instead of DKB.  Perhaps I can make that
prospect a little bit easier.  Suppose we take DKB and use it as a
base for a completely new system (the name "Renderdog" has
been tossed around, but I'm not fond of that one <g>). I would
like to propose the name "Software Taskforce on Animation and
Rendering" or STAR.  I would imagine that there would be
several packages developed such as:

 STAR Light  - the raytracer
 STAR Guider - an animation system
 STAR Maker - a user interface for StarLight

If you decide to do this, I would like to place a few rules on the
packages (or at least those developed from DKB):

  - they will remain freely distributable
  - support and maintenance of this new product will be undertaken
    by the STAR team (including but not limited to myself)
  - the programs will remain as portable as possible

What do you think of this proposal?

David Buck

2.1.6.2 The Name

More on how POV-Ray came to its name.

**************************************************************
from Chris Young, to whom I asked if POV's name was related
to the title of a sci-fi book I had just found on a flea market.
**************************************************************

Varley is one of my favorite authors and I've owned that book
long before POV-Ray existed.  POV-Ray was originally going to be
called Starlight or StarLite or something similar but somebody
else, I don't know who, said we'd get in trademark trouble over
some existing product.  Drew Wells was team leader and he picked
Persistence of Vision based on the properties of the human visual
system. I also felt there was a double meaning in that POV-Ray
was the continuation (or persistance) of David K. Buck's DKB-Trace.
I warned Drew about Varley's book but book titles aren't as messy
as product names.  Note also that Public Broadcasting System has
a documentary series called POV but that stands for Point Of View
which is the filmmaking term for hand-held camera, cinema-verite
style used in many documentaries.

I wanted to take our team name from the Fractint Stone Soup Group
and call us the Crystal Soup Group but I got voted down.

        Chris Young, POV-Team Coordinator

**************************************************************
from unknown source
**************************************************************

After the recent thread on the starting time of POV-Ray I did
a search and found this post to this very news group from
David Buck himself. The message places the birth of the POV-Ray
project to be in May of 1991. A very historic event!

I hope I'm not stepping on toes by re-posting
it  :-)

Harold

Sun, 19 Feb 1995 19:14:44 GMT
(STEERPIKE) says:
>I had always presumed that Persistance of Vision was a pun on
>the name of Salvador Dali's painting "The Persistance of
>Memory". Is this right, and if not, how did POV-Ray come to
> have such a poetic name? :)

The POV-Ray project started in May 1991 when I first proposed the
idea to a group of people on CompuServe.  They liked my DKBTrace
raytracer but didn't like the fact that I was too slow adding new
features to it.  They were going to re-write a raytracer from
scratch, but I suggested that after version 2.12 of DKBTrace, they
could take the code as is and develop it from there into a new
raytracer.  The first name was STAR - an acronym for something or
other.  Then someone in the group came up with "Persistance of
Vision".  We liked it because of its reference to Dali (I
believe the painting was actually called Persistance of Vision - am
I mistaken?).  Moreover, it seemed to symbolize the team who
"Persisted" to achieve their "Vision".  The
third reference was to the phychological effect that seeing an image
flashed on a screen causes you to retain that image in short term
memory.  Thus, your memory was a representation of reality but not
really reality. They all seemed to fit together to make a nice name.
Early on, we were abbreviating the name to PVRay, but we were
concerned about a commercial product called PV-Wave.  We agreed to
change the abbreviation to POV-Ray and standardize on the spelling.

>David Buck

2.1.6.3 A Historic 'Version History'

The version history as it was included in PV-Ray 0.5 BETA. Notice the name changes...

Persistence of Vision Raytracer Version History
-------------------------------------------------

 PV-Ray was originally DKBTrace Ver. 2.12 written by David Buck. He
donated the rights to his source code so the PV-Team could enhance
this raytracer as a group project similar to Fractint. The source
code for PV-Ray will always be freely distributable subject to the
restrictions in the header files. Thanks David, for your generous
gift!

Version 0.02 BETA Release 7/29/91 (as STAR-Light)
----------------------------------
 First version is still basically DKBTrace 2.12 with a few new
 features.

 - Materials mapping added by Drew Wells.(see matmap.dat)
 - ONION & LEOPARD textures added by Scott Taylor.
 - Time to trace display added by Bill Pulver.
 - Grayscale display (+g) for IBM-PC's added by Scott Taylor.
 - Small wood texture bug fixed to create true cylinders.
 - Verbose now displays more info including file being traced.
 - Option +vO added to enable old-style terse verbose.
 - Texture.c broken into smaller modules.
 - PAINTED1, 2, & 3 added for developers.
 - BUMPY1, 2, & 3 added for developers.

PvRay Version 0.5 BETA Release 9/07/91
----------------------------------
 Many more changes this time around, including...

- Many enhancements from Alexander Enzmann
   - Bezier bicubic subpatches
   - Polynomial surfaces
   - New mapping types (sphere, etc.)
   - Sturmian sequences
   - Clipping shapes
   - (have I forgotten anything??)
- Lots of hard work and enhancements by Aaron Collins
- Height fields by Doug Muir
- Bump Mapping by Doug Muir and Drew Wells
- Interpolation by Girish T. Hagan adapted for mapping by Drew Wells
- # and ; are now ignored.
- case_sensitive keywords and commandline option added by Drew Wells
  > case_sensitive_yes -- All words checked for exact case.
                             Keywords must be in upper case.
                             (*Old DKB Style*)
  > case_sensitive_no  -- Case is ignored for all words.
  > case_sensitive_opt -- DEFAULT - All words checked for exact
                             case except keywords. Keywords will be
                             accepted in upper and/or lower case.
  > command line -- /ty = yes, /tn = no, /to = opt
- cnvdat.c to convert old dat files included with pvsrc.
- C++ style commenting - // ignore to end of line.
  and /* ignore between braces */ nesting not allowed.
- New default style verbose trace info (+v1)
- Old-new style verbose (+v0)
- Verbose trace info outputs to stderr so that stats can be
  redirected to file.
- New stats display outputs to stdout for better redirection.
- New lighting routines by David Buck.
- The declared colors Red, Green, and Blue in colors.dat are now
  CRed, CBlue, CGreen.
- The declared quadric Sphere in shapes.dat is now QSphere.
- Textures.dat has been cleaned up and commented.

2.1.7 How Do I Begin?

POV-Ray scenes are described in a special text language called a scene description language. You will type commands into a plain text file and POV-Ray will read it to create the image. The process of running POV-Ray is a little different on each platform or operating system. You should read the platform-specific documentation as suggested earlier in this introduction. It will tell you how to command POV-Ray to turn your text scene description into an image. You should try rendering several sample images before attempting to create your own.

Once you know how to run POV-Ray on your computer and your operating system, you can proceed with the tutorial which follows. The tutorial explains how to describe the scene using the POV-Ray language.

2.1.8 Notation and Basic Assumptions

Throughout the tutorial and reference books, a consistent notation is used to mark keywords of the scene description language, command line switches, INI file keywords and file names.

For example:

Scene description language keywords and command-line switches:

  • sphere, 4.0 * sin(45.0)
  • +W640 +H480

Syntax, optional syntax, multiple syntax, and zero or more syntax items allowed respectively:

  • SYNTAX_ITEM
  • [SYNTAX_ITEM]
  • SYNTAX_ITEM...
  • [SYNTAX_ITEM...]

A float value or expression, and a vector value or expression:

  • Value_1
  • <Value_1>

Choices are represented by a vertical bar between syntax items:

  • ITEM1 | ITEM2 | ITEM3

Certain lists and arrays also require square braces as part of the language rather than the language description:

  • [ ITEM ]

Note: POV-Ray is available as a command-line program on some platforms and as a GUI on others. Some of these platforms use folders to store files while others use directories. Some separate the folders and sub-folders with a slash character (/), back-slash character (\), or others. We have tried to make this documentation as generic as possible but sometimes we have to refer to folders, files, options etc., and rather than try to represent all possible combinations we sometimes simplify the documentation by referring to a hypothetical 'standard installation' of POV-Ray upon a Microsoft Windows computer.

Here are some assumptions to be found in the documentation:

  1. You installed POV-Ray in the default location (on Windows, binaries in c:\Program Files\POV-Ray\v3.7 and include/scene files in My Documents\POV-Ray\v3.7). If we say 'include files are stored in the include directory', we mean the directory called 'include' located immediately within the folder which was used for documents (in the above case, it would be My Documents\POV-Ray\v3.7\include). We assume you can translate that to something like /usr/local/share/povray-3.7/include (for Linux) or whatever is appropriate for your platform, operating system and personal installation.
  2. POV-Ray uses INI files and/or command-line switches (if available) to choose options in all versions, but some platforms (e.g. Windows) also use dialog boxes or menu choices to set options. We will describe options assuming you are using switches or INI files when describing what the options do, as it is consistent across all platforms (all GUI versions of POV-Ray also provide a means of accepting command-line options and reading INI files from within the GUI - generally speaking, the menus and dialogs just provide an easier means of doing the same thing).
  3. You may be reading this documentation using an operating-system specific help program, web browser, physical printout, PDF viewer, or text editor. We assume you know how to get around in which ever medium you are using. If we say "See the chapter on Setting POV-Ray Options" we assume you can click, scroll, browse, flip pages or whatever to get there.


Tutorial Section 2

2.2 Getting Started

The beginning tutorial explains step by step how to use POV-Ray's scene description language to create your own scenes. The use of almost every feature of POV-Ray's language is explained in detail. We will learn basic things like placing cameras and light sources. We will also learn how to create a large variety of objects and how to assign different textures to them. The more sophisticated features like radiosity, interior, media and atmospheric effects will be explained in detail.

2.2.1 Our First Image

We will create the scene file for a simple picture. Since ray-tracers thrive on spheres, that is what we will render first.

2.2.1.1 Understanding POV-Ray's Coordinate System

First, we have to tell POV-Ray where our camera is and where it is looking. To do this, we use 3D coordinates. The usual coordinate system for POV-Ray has the positive y-axis pointing up, the positive x-axis pointing to the right, and the positive z-axis pointing into the screen as follows:

 | This kind of coordinate system is called a left-handed coordinate system. If we use our left hand's fingers we can easily see why it is called left-handed. We just point our thumb in the direction of the positive x-axis (to the right), the index finger in the direction of the positive y-axis (straight up) and the middle finger in the positive z-axis direction (forward). We can only do this with our left hand. If we had used our right hand we would not have been able to point the middle finger in the correct direction. |
The left-handed coordinate system |  | Computer Graphics Aerobics

The left hand can also be used to determine rotation directions. To do this we must perform the famous Computer Graphics Aerobics exercise. We hold up our left hand and point our thumb in the positive direction of the axis of rotation. Our fingers will curl in the positive direction of rotation. Similarly if we point our thumb in the negative direction of the axis our fingers will curl in the negative direction of rotation.

In the above illustration, the left hand is curling around the x-axis. The thumb points in the positive x direction and the fingers curl over in the positive rotation direction.

If we want to use a right-handed system, as some CAD systems and modelers do, the right vector in the camera specification needs to be changed. See the detailed description in Handedness. In a right-handed system we use our right hand for the Aerobics.

There is some controversy over whether POV-Ray's method of doing a right-handed system is really proper. To avoid problems we stick with the left-handed system which is not in dispute.

2.2.1.2 Adding Standard Include Files

Using our personal favorite text editor, we create a file called demo.pov. Some versions of POV-Ray come with their own built-in text editor which may be easier to use. We then type in the following text. The input is case sensitive, so we have to be sure to get capital and lowercase letters correct.

  #include "colors.inc"    // The include files contain
  #include "stones.inc"    // pre-defined scene elements

The first include statement reads in definitions for various useful colors. The second include statement reads in a collection of stone textures. POV-Ray comes with many standard include files. Others of interest are:

  #include "textures.inc"    // pre-defined scene elements
  #include "shapes.inc"
  #include "glass.inc"
  #include "metals.inc"
  #include "woods.inc"

They read pre-defined textures, shapes, glass, metal, and wood textures. It is a good idea to have a look through them to see a few of the many possible shapes and textures available.

We should only include files we really need in our scene. Some of the include files coming with POV-Ray are quite large and we should better save the parsing time and memory if we do not need them. In the following examples we will only use the colors.inc, and stones.inc include files.

We may have as many include files as needed in a scene file. Include files may themselves contain include files, but we are limited to declaring includes nested only ten levels deep.

Filenames specified in the include statements will be searched for in the current directory first. If it fails to find your .Inc files in the current directory, POV-Ray searches any library paths that you have specified. Library paths are options set by the +L command-line switch or Library_Path option. See the chapter Setting POV-Ray Options for more information on library paths.

Because it is more useful to keep include files in a separate directory, standard installations of POV-Ray place these files in the c:\povray3\include directory (replace c:\povray3 with the actual directory that you installed POV-Ray in). If you get an error message saying that POV-Ray cannot open colors.inc or other include files, make sure that you specify the library path properly.

2.2.1.3 Adding a Camera

The camera statement describes where and how the camera sees the scene. It gives x-, y- and z-coordinates to indicate the position of the camera and what part of the scene it is pointing at. We describe the coordinates using a three-part vector. A vector is specified by putting three numeric values between a pair of angle brackets and separating the values with commas. We add the following camera statement to the scene.

  camera {
    location <0, 2, -3>
    look_at  <0, 1,  2>
  }

Briefly, location <0,2,-3> places the camera up two units and back three units from the center of the ray-tracing universe which is at <0,0,0>. By default +z is into the screen and -z is back out of the screen.

Also look_at <0,1,2> rotates the camera to point at the coordinates <0,1,2>. A point 1 unit up from the origin and 2 units away from the origin. This makes it 5 units in front of and 1 unit lower than the camera. The look_at point should be the center of attention of our image.

2.2.1.4 Describing an Object

Now that the camera is set up to record the scene, let's place a yellow sphere into the scene. We add the following to our scene file:

  sphere {
    <0, 1, 2>, 2
    texture {
      pigment { color Yellow }
    }
  }

The first vector specifies the center of the sphere. In this example the x coordinate is zero so it is centered left and right. It is also at y=1 or one unit up from the origin. The z coordinate is 2 which is five units in front of the camera, which is at z=-3. After the center vector is a comma followed by the radius which in this case is two units. Since the radius is half the width of a sphere, the sphere is four units wide.

2.2.1.5 Adding Texture to an Object

After we have defined the location and size of the sphere, we need to describe the appearance of the surface. The texture statement specifies these parameters. Texture blocks describe the color, bumpiness and finish properties of an object. In this example we will specify the color only. This is the minimum we must do. All other texture options except color will use default values.

The color we define is the way we want an object to look if fully illuminated. If we were painting a picture of a sphere we would use dark shades of a color to indicate the shadowed side and bright shades on the illuminated side. However ray-tracing takes care of that for you. We only need to pick the basic color inherent in the object and POV-Ray brightens or darkens it depending on the lighting in the scene. Because we are defining the basic color the object actually has rather than how it looks the parameter is called pigment.

Many types of color patterns are available for use in a pigment statement. The keyword color specifies that the whole object is to be one solid color rather than some pattern of colors. We can use one of the color identifiers previously defined in the standard include file colors.inc.

If no standard color is available for our needs, we may define our own color by using the color keyword followed by red, green and blue keywords specifying the amount of red, green and blue to be mixed. For example a nice shade of pink can be specified by:

  color red 1.0 green 0.8 blue 0.8

Note: The international, rather than American, form "colour" is also acceptable and may be used anywhere that "color" may be used.

The values after each keyword should be in the range from 0.0 to 1.0. Any of the three components not specified will default to 0. A shortcut notation may also be used. The following produces the same shade of pink:

  color rgb <1.0, 0.8, 0.8>

In many cases the color keyword is superfluous, so the shortest way to specify the pink color is:

  rgb <1.0, 0.8, 0.8>

Colors are explained in more detail in section Color Expressions.

2.2.1.6 Defining a Light Source

One more detail is needed for our scene. We need a light source. Until we create one, there is no light in this virtual world. Thus we add the line

  light_source { <2, 4, -3> color White}

to the scene file to get our first complete POV-Ray scene file as shown below.

  #include "colors.inc"
  background { color Cyan }
  camera {
    location <0, 2, -3>
    look_at  <0, 1,  2>
  }
  sphere {
    <0, 1, 2>, 2
    texture {
      pigment { color Yellow }
    }
  }
  light_source { <2, 4, -3> color White}

The vector in the light_source statement specifies the location of the light as two units to our right, four units above the origin and three units back from the origin. The light source is an invisible tiny point that emits light. It has no physical shape, so no texture is needed.

That's it! We close the file and render a small picture of it using whatever methods you used for your particular platform. If you specified a preview display it will appear on your screen. If you specified an output file (the default is file output on), then POV-Ray also created a file.

Note: If you do not have high color or true color display hardware then the preview image may look poor but the full detail is written to the image file regardless of the type of display.

The scene we just traced is not quite state of the art but we will have to start with the basics before we soon get to much more fascinating features and scenes.

2.2.2 Basic Shapes

So far we have just used the sphere shape. There are many other types of shapes that can be rendered by POV-Ray. The following sections will describe how to use some of the more simple objects as a replacement for the sphere used above.

2.2.2.1 Box Object

The box is one of the most common objects used. We try this example in place of the sphere:

  box {
    <-1, 0,   -1>,  // Near lower left corner
    < 1, 0.5,  3>   // Far upper right corner
    texture {
      T_Stone25     // Pre-defined from stones.inc
      scale 4       // Scale by the same amount in all
                    // directions
    }
    rotate y*20     // Equivalent to "rotate <0,20,0>"
  }

In the example we can see that a box is defined by specifying the 3D coordinates of its opposite corners. The first vector is generally the minimum x-, y- and z-coordinates and the 2nd vector should be the maximum x-, y- and z-values however any two opposite corners may be used. Box objects can only be defined parallel to the axes of the world coordinate system. We can later rotate them to any angle.

Note: We can perform simple math on values and vectors. In the rotate parameter we multiplied the vector identifier y by 20. This is the same as <0,1,0>*20 or <0,20,0>.

2.2.2.2 Cone Object

Here is another example showing how to use a cone:

  cone {
    <0, 1, 0>, 0.3    // Center and radius of one end
    <1, 2, 3>, 1.0    // Center and radius of other end
    texture { T_Stone25 scale 4 }
  }

The cone shape is defined by the center and radius of each end. In this example one end is at location <0,1,0> and has a radius of 0.3 while the other end is centered at <1,2,3> with a radius of 1. If we want the cone to come to a sharp point we must use radius=0. The solid end caps are parallel to each other and perpendicular to the cone axis. If we want an open cone with no end caps we have to add the keyword open after the 2nd radius like this:

  cone {
    <0, 1, 0>, 0.3    // Center and radius of one end
    <1, 2, 3>, 1.0    // Center and radius of other end
    open              // Removes end caps
    texture { T_Stone25 scale 4 }
  }

2.2.2.3 Cylinder Object

We may also define a cylinder like this:

  cylinder {
    <0, 1, 0>,     // Center of one end
    <1, 2, 3>,     // Center of other end
    0.5            // Radius
    open           // Remove end caps
    texture { T_Stone25 scale 4 }
  }

2.2.2.4 Plane Object

Let's try out a computer graphics standard The Checkered Floor. We add the following object to the first version of the demo.pov file, the one including the sphere.

  plane { <0, 1, 0>, -1
    pigment {
      checker color Red, color Blue
    }
  }

The object defined here is an infinite plane. The vector <0,1,0> is the surface normal of the plane (i.e. if we were standing on the surface, the normal points straight up). The number afterward is the distance that the plane is displaced along the normal from the origin -- in this case, the floor is placed at y=-1 so that the sphere at y=1, radius=2, is resting on it.

Note: Even though there is no texture statement there is an implied texture here. We might find that continually typing statements that are nested like texture {pigment} can get to be tiresome so POV-Ray let's us leave out the texture statement under many circumstances. In general we only need the texture block surrounding a texture identifier (like the T_Stone25 example above), or when creating layered textures (which are covered later).

This pigment uses the checker color pattern and specifies that the two colors red and blue should be used.

Because the vectors <1,0,0>, <0,1,0> and <0,0,1> are used frequently, POV-Ray has three built-in vector identifiers x, y and z respectively that can be used as a shorthand. Thus the plane could be defined as:

  plane { y, -1
    pigment { ... }
  }

Note: We do not use angle brackets around vector identifiers.

Looking at the floor, we notice that the ball casts a shadow on the floor. Shadows are calculated very accurately by the ray-tracer, which creates precise, sharp shadows. In the real world, penumbral or soft shadows are often seen. Later we will learn how to use extended light sources to soften the shadows.

2.2.2.5 Torus Object

A torus can be thought of as a donut or an inner-tube. It is a shape that is vastly useful in many kinds of CSG so POV-Ray has adopted this 4th order quartic polynomial as a primitive shape. The syntax for a torus is so simple that it makes it a very easy shape to work with once we learn what the two float values mean. Instead of a lecture on the subject, let's create one and do some experiments with it.

We create a file called tordemo.pov and edit it as follows:

  #include "colors.inc"
  camera {
    location <0, .1, -25>
    look_at 0
    angle 30
  }
  background { color Gray50 } // to make the torus easy to see
  light_source { <300, 300, -1000> White }
  torus {
    4, 1              // major and minor radius
    rotate -90*x      // so we can see it from the top
    pigment { Green }
  }

We trace the scene. Well, it is a donut alright. Let's try changing the major and minor radius values and see what happens. We change them as follows:

  torus { 5, .25      // major and minor radius

That looks more like a hula-hoop! Let's try this:

  torus { 3.5, 2.5    // major and minor radius

Whoa! A donut with a serious weight problem!

With such a simple syntax, there is not much else we can do to a torus besides change its texture... or is there? Let's see...

Tori are very useful objects in CSG. Let's try a little experiment. We make a difference of a torus and a box:

  difference {
    torus {
      4, 1
      rotate x*-90  // so we can see it from the top
    }
    box { <-5, -5, -1>, <5, 0, 1> }
    pigment { Green }
  }

Interesting... a half-torus. Now we add another one flipped the other way. Only, let's declare the original half-torus and the necessary transformations so we can use them again:

  #declare Half_Torus = difference {
    torus {
      4, 1
      rotate -90*x  // so we can see it from the top
    }
    box { <-5, -5, -1>, <5, 0, 1> }
    pigment { Green }
  }
  #declare Flip_It_Over = 180*x;
  #declare Torus_Translate = 8;  // twice the major radius

Now we create a union of two Half_Torus objects:

  union {
    object { Half_Torus }
    object { Half_Torus
      rotate Flip_It_Over
      translate Torus_Translate*x
    }
  }

This makes an S-shaped object, but we cannot see the whole thing from our present camera. Let's add a few more links, three in each direction, move the object along the +z-direction and rotate it about the +y-axis so we can see more of it. We also notice that there appears to be a small gap where the half Tori meet. This is due to the fact that we are viewing this scene from directly on the x-z-plane. We will change the camera's y-coordinate from 0 to 0.1 to eliminate this.

  union {
    object { Half_Torus }
    object { Half_Torus
      rotate Flip_It_Over
      translate x*Torus_Translate
    }
    object { Half_Torus
      translate x*Torus_Translate*2
    }
    object { Half_Torus
      rotate Flip_It_Over
      translate x*Torus_Translate*3
    }
    object { Half_Torus
      rotate Flip_It_Over
      translate -x*Torus_Translate
    }
    object { Half_Torus
      translate -x*Torus_Translate*2
    }
    object { Half_Torus
      rotate Flip_It_Over
      translate -x*Torus_Translate*3
    }
    object { Half_Torus
      translate -x*Torus_Translate*4
    }
    rotate y*45
    translate z*20
  }

Rendering this we see a cool, undulating, snake-like something-or-other. Neato. But we want to model something useful, something that we might see in real life. How about a chain?

Thinking about it for a moment, we realize that a single link of a chain can be easily modeled using two half tori and two cylinders. We create a new file. We can use the same camera, background, light source and declared objects and transformations as we used in tordemo.pov:

  #include "colors.inc"
  camera {
    location <0, .1, -25>
    look_at 0
    angle 30
  }
  background { color Gray50 }
  light_source{ <300, 300, -1000> White }
  #declare Half_Torus = difference {
    torus {
      4,1
      sturm
      rotate x*-90  // so we can see it from the top
    }
    box { <-5, -5, -1>, <5, 0, 1> }
    pigment { Green }
  }
  #declare Flip_It_Over = x*180;
  #declare Torus_Translate = 8;

Now, we make a complete torus of two half tori:

  union {
    object { Half_Torus }
    object { Half_Torus rotate Flip_It_Over }
  }

This may seem like a wasteful way to make a complete torus, but we are really going to move each half apart to make room for the cylinders. First, we add the declared cylinder before the union:

  #declare Chain_Segment = cylinder {
    <0, 4, 0>, <0, -4, 0>, 1
    pigment { Green }
  }

We then add two Chain_Segments to the union and translate them so that they line up with the minor radius of the torus on each side:

  union {
    object { Half_Torus }
    object { Half_Torus rotate Flip_It_Over }
    object { Chain_Segment translate  x*Torus_Translate/2 }
    object { Chain_Segment translate -x*Torus_Translate/2 }
  }

Now we translate the two half tori +y and -y so that the clipped ends meet the ends of the cylinders. This distance is equal to half of the previously declared Torus_Translate:

  union {
    object {
      Half_Torus
      translate y*Torus_Translate/2
    }
    object {
      Half_Torus
      rotate Flip_It_Over
      translate -y*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate x*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate -x*Torus_Translate/2
    }
  }

We render this and voila! A single link of a chain. But we are not done yet! Whoever heard of a green chain? We would rather use a nice metallic color instead. First, we remove any pigment blocks in the declared tori and cylinders. Then we add a declaration for a golden texture just before the union that creates the link. Finally, we add the texture to the union and declare it as a single link:

  #declare Half_Torus = difference {
    torus {
      4,1
      sturm
      rotate x*-90  // so we can see it from the top
    }
    box { <-5, -5, -1>, <5, 0, 1> }
  }

  #declare Chain_Segment = cylinder {
    <0, 4, 0>, <0, -4, 0>, 1
  }

  #declare Chain_Gold = texture {
    pigment { BrightGold }
    finish {
      ambient .1
      diffuse .4
      reflection .25
      specular 1
      metallic
    }
  }

  #declare Link = union {
    object {
      Half_Torus
      translate y*Torus_Translate/2
    }
    object {
      Half_Torus
      rotate Flip_It_Over
      translate -y*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate x*Torus_Translate/2
    }
    object {
      Chain_Segment
      translate -x*Torus_Translate/2
    }    texture { Chain_Gold }
  }

Now we make a union of two links. The second one will have to be translated +y so that its inner wall just meets the inner wall of the other link, just like the links of a chain. This distance turns out to be double the previously declared Torus_Translate minus 2 (twice the minor radius). This can be described by the expression:

  Torus_Translate*2-2*y

We declare this expression as follows:

  #declare Link_Translate = Torus_Translate*2-2*y;

In the object block, we will use this declared value so that we can multiply it to create other links. Now, we rotate the second link 90*y so that it is perpendicular to the first, just like links of a chain. Finally, we scale the union by 1/4 so that we can see the whole thing:

  union {
    object { Link }
    object { Link translate y*Link_Translate rotate y*90 }
    scale .25
  }

We render this and we will see a very realistic pair of links. If we want to make an entire chain, we must declare the above union and then create another union of this declared object. We must be sure to remove the scaling from the declared object:

  #declare Link_Pair =
  union {
    object { Link }
    object { Link translate y*Link_Translate rotate y*90 }
  }

Now we declare our chain:

  #declare Chain = union {
    object { Link_Pair}
    object { Link_Pair translate  y*Link_Translate*2 }
    object { Link_Pair translate  y*Link_Translate*4 }
    object { Link_Pair translate  y*Link_Translate*6 }
    object { Link_Pair translate -y*Link_Translate*2 }
    object { Link_Pair translate -y*Link_Translate*4 }
    object { Link_Pair translate -y*Link_Translate*6 }
  }

And finally we create our chain with a couple of transformations to make it easier to see. These include scaling it down by a factor of 1/10, and rotating it so that we can clearly see each link:

  object { Chain scale .1 rotate <0, 45, -45> }

We render this and we should see a very realistic gold chain stretched diagonally across the screen.

The torus object can be used to create chains.

2.2.3 CSG Objects

Constructive Solid Geometry, or CSG, is a powerful tool to combine primitive objects to create more complex objects as shown in the following sections.

2.2.3.1 What is CSG?

CSG stands for Constructive Solid Geometry. POV-Ray allows us to construct complex solids by combining primitive shapes in four different ways. In the union statement, two or more shapes are added together. With the intersection statement, two or more shapes are combined to make a new shape that consists of the area common to both shapes. The difference statement, an initial shape has all subsequent shapes subtracted from it.

And last but not least merge, which is like a union where the surfaces inside the union are removed (useful in transparent CSG objects). We will deal with each of these in detail in the next few sections.

CSG objects can be extremely complex. They can be deeply nested. In other words there can be unions of differences or intersections of merges or differences of intersections or even unions of intersections of differences of merges... ad infinitum. CSG objects are (almost always) finite objects and thus respond to auto-bounding and can be transformed like any other POV primitive shape.

2.2.3.2 CSG Union

Let's try making a simple union. Create a file called csgdemo.pov and edit it as follows:

  #include "colors.inc"
  camera {
    location <0, 1, -10>
    look_at 0
    angle 36
  }
  light_source { <500, 500, -1000> White }
  plane { y, -1.5
    pigment { checker Green White }
  }

Let's add two spheres each translated 0.5 units along the x-axis in each direction. We color one blue and the other red.

  sphere { <0, 0, 0>, 1
    pigment { Blue }
    translate -0.5*x
  }
  sphere { <0, 0, 0>, 1
    pigment { Red }
    translate 0.5*x
  }

We trace this file and note the results. Now we place a union block around the two spheres. This will create a single CSG union out of the two objects.

  union{
    sphere { <0, 0, 0>, 1
      pigment { Blue }
      translate -0.5*x
    }
    sphere { <0, 0, 0>, 1
      pigment { Red }
      translate 0.5*x
    }
  }

We trace the file again. The union will appear no different from what each sphere looked like on its own, but now we can give the entire union a single texture and transform it as a whole. Let's do that now.

  union{
    sphere { <0, 0, 0>, 1
      translate -0.5*x
    }
    sphere { <0, 0, 0>, 1
      translate 0.5*x
    }
    pigment { Red }
    scale <1, .25, 1>
    rotate <30, 0, 45>
  }

We trace the file again. As we can see, the object has changed dramatically. We experiment with different values of scale and rotate and try some different textures.

There are many advantages of assigning only one texture to a CSG object instead of assigning the texture to each individual component. First, it is much easier to use one texture if our CSG object has a lot of components because changing the objects appearance involves changing only one single texture. Second, the file parses faster because the texture has to be parsed only once. This may be a great factor when doing large scenes or animations. Third, using only one texture saves memory because the texture is only stored once and referenced by all components of the CSG object. Assigning the texture to all n components means that it is stored n times.

2.2.3.3 CSG Intersection

Now let's use these same spheres to illustrate the intersection CSG object. We change the word union to intersection and delete the scale and rotate statements:

  intersection {
    sphere { <0, 0, 0>, 1
      translate -0.5*x
    }
    sphere { <0, 0, 0>, 1
      translate 0.5*x
    }
    pigment { Red }
  }

We trace the file and will see a lens-shaped object instead of the two spheres. This is because an intersection consists of the area shared by both shapes, in this case the lens-shaped area where the two spheres overlap. We like this lens-shaped object so we will use it to demonstrate differences.

2.2.3.4 CSG Difference

We rotate the lens-shaped intersection about the y-axis so that the broad side is facing the camera.

  intersection{
    sphere { <0, 0, 0>, 1
      translate -0.5*x
    }
    sphere { <0, 0, 0>, 1
      translate 0.5*x
    }
    pigment { Red }
    rotate 90*y
  }

Let's create a cylinder and stick it right in the middle of the lens.

  cylinder { <0, 0, -1> <0, 0, 1>, .35
    pigment { Blue }
  }

We render the scene to see the position of the cylinder. We will place a difference block around both the lens-shaped intersection and the cylinder like this:

  difference {
    intersection {
      sphere { <0, 0, 0>, 1
        translate -0.5*x
      }
      sphere { <0, 0, 0>, 1
        translate 0.5*x
      }
      pigment { Red }
      rotate 90*y
    }
    cylinder { <0, 0, -1> <0, 0, 1>, .35
      pigment { Blue }
    }
  }

We render the file again and see the lens-shaped intersection with a neat hole in the middle of it where the cylinder was. The cylinder has been subtracted from the intersection. Note that the pigment of the cylinder causes the surface of the hole to be colored blue. If we eliminate this pigment the surface of the hole will be black, as this is the default color if no color is specified.

OK, let's get a little wilder now. Let's declare our perforated lens object to give it a name. Let's also eliminate all textures in the declared object because we will want them to be in the final union instead.

  #declare Lens_With_Hole = difference {
    intersection {
      sphere { <0, 0, 0>, 1
        translate -0.5*x
      }
      sphere { <0, 0, 0>, 1
        translate 0.5*x
      }
      rotate 90*y
    }
    cylinder { <0, 0, -1> <0, 0, 1>, .35 }
  }

Let's use a union to build a complex shape composed of copies of this object.

  union {
    object { Lens_With_Hole translate <-.65, .65, 0> }
    object { Lens_With_Hole translate <.65, .65, 0> }
    object { Lens_With_Hole translate <-.65, -.65, 0> }
    object { Lens_With_Hole translate <.65, -.65, 0> }
    pigment { Red }
  }

We render the scene. An interesting object to be sure. But let's try something more. Let's make it a partially-transparent object by adding some filter to the pigment block.

  union {
    object { Lens_With_Hole translate <-.65, .65, 0> }
    object { Lens_With_Hole translate <.65, .65, 0> }
    object { Lens_With_Hole translate <-.65, -.65, 0> }
    object { Lens_With_Hole translate <.65, -.65, 0> }
    pigment { Red filter .5 }
  }

We render the file again. This looks pretty good... only... we can see parts of each of the lens objects inside the union! This is not good.

2.2.3.5 CSG Merge

This brings us to the fourth kind of CSG object, the merge. Merges are the same as unions, but the geometry of the objects in the CSG that is inside the merge is not traced. This should eliminate the problem with our object. Let's try it.

  merge {
    object { Lens_With_Hole translate <-.65, .65, 0> }
    object { Lens_With_Hole translate <.65, .65, 0> }
    object { Lens_With_Hole translate <-.65, -.65, 0> }
    object { Lens_With_Hole translate <.65, -.65, 0> }
    pigment { Red filter .5 }
  }

Sure enough, it does!

2.2.3.6 CSG Pitfalls

There is a severe pitfall in the CSG code that we have to be aware of.

2.2.3.6.1 Co-incident Surfaces

POV-Ray uses inside/outside tests to determine the points at which a ray intersects a CSG object. A problem arises when the surfaces of two different shapes coincide because there is no way (due to the computer's floating-point accuracy) to tell whether a point on the coincident surface belongs to one shape or the other.

Look at the following example where a cylinder is used to cut a hole in a larger box.

  difference {
    box { -1, 1 pigment { Red } }
    cylinder { -z, z, 0.5 pigment { Green } }
  }

Note: The vectors -1 and 1 in the box definition expand to <-1,-1,-1> and <1,1,1> respectively.

If we trace this object we see red speckles where the hole is supposed to be. This is caused by the coincident surfaces of the cylinder and the box. One time the cylinder's surface is hit first by a viewing ray, resulting in the correct rendering of the hole, and another time the box is hit first, leading to a wrong result where the hole vanishes and red speckles appear. This problem can be avoided by increasing the size of the cylinder to get rid of the coincidence surfaces. This is done by:

  difference {
    box { -1, 1 pigment { Red } }
    cylinder { -1.001*z, 1.001*z, 0.5 pigment { Green } }
  }

In general we have to make the subtracted object a little bit larger in a CSG difference. We just have to look for coincident surfaces and increase the subtracted object appropriately to get rid of those surfaces.

The same problem occurs in CSG intersections and is also avoided by scaling some of the involved objects.

2.2.4 The Light Source

In any ray-traced scene, the light needed to illuminate our objects and their surfaces must come from a light source. There are many kinds of light sources available in POV-Ray and careful use of the correct kind can yield very impressive results. Let's take a moment to explore some of the different kinds of light sources and their various parameters.

2.2.4.1 The Pointlight Source

Pointlights are exactly what the name indicates. A pointlight has no size, is invisible and illuminates everything in the scene equally no matter how far away from the light source it may be (this behavior can be changed). This is the simplest and most basic light source. There are only two important parameters, location and color. Let's design a simple scene and place a pointlight source in it.

We create a new file and name it litedemo.pov. We edit it as follows:

  #include "colors.inc"
  #include "textures.inc"
  camera {
    location  <-4, 3, -9>
    look_at   <0, 0, 0>
    angle 48
  }

We add the following simple objects:

  plane {
    y, -1
    texture {
      pigment {
        checker
        color rgb<0.5, 0, 0>
        color rgb<0, 0.5, 0.5>
      }
      finish {
        diffuse 0.4
        ambient 0.2
        phong 1
        phong_size 100
        reflection 0.25
      }
    }
  }
  torus {
    1.5, 0.5
    texture { Brown_Agate }
    rotate <90, 160, 0>
    translate <-1, 1, 3>
  }
  box {
    <-1, -1, -1>, <1, 1, 1>
    texture { DMFLightOak }
    translate <2, 0, 2.3>
  }
  cone {
    <0,1,0>, 0, <0,0,0>, 1
    texture { PinkAlabaster }
    scale <1, 3, 1>
    translate <-2, -1, -1>
  }
  sphere {
    <0,0,0>,1
    texture { Sapphire_Agate }
    translate <1.5, 0, -2>
  }

Now we add a pointlight:

  light_source {
    <2, 10, -3>
    color White
  }

We render this and see that the objects are clearly visible with sharp shadows. The sides of curved objects nearest the light source are brightest in color with the areas that are facing away from the light source being darkest. We also note that the checkered plane is illuminated evenly all the way to the horizon. This allows us to see the plane, but it is not very realistic.

2.2.4.2 The Spotlight Source

Spotlights are a very useful type of light source. They can be used to add highlights and illuminate features much as a photographer uses spots to do the same thing. To create a spotlight simply add the spotlight keyword to a regular point light. There are a few more parameters with spotlights than with pointlights. These are radius, falloff, falloff and point_at. The radius parameter is the angle of the fully illuminated cone. The falloff parameter is the angle of the umbra cone where the light falls off to darkness. The tightness is a parameter that determines the rate of the light falloff. The point_at parameter is just what it says, the location where the spotlight is pointing to. Let's change the light in our scene as follows:

  light_source {
    <0, 10, -3>
    color White
    spotlight
    radius 15
    falloff 20
    tightness 10
    point_at <0, 0, 0>
  }

We render this and see that only the objects are illuminated. The rest of the plane and the outer portions of the objects are now unlit. There is a broad falloff area but the shadows are still razor sharp. Let's try fiddling with some of these parameters to see what they do. We change the falloff value to 16 (it must always be larger than the radius value) and render again. Now the falloff is very narrow and the objects are either brightly lit or in total darkness. Now we change falloff back to 20 and change the tightness value to 100 (higher is tighter) and render again. The spotlight appears to have gotten much smaller but what has really happened is that the falloff has become so steep that the radius actually appears smaller.

We decide that a tightness value of 10 (the default) and a falloff value of 18 are best for this spotlight and we now want to put a few spots around the scene for effect. Let's place a slightly narrower blue and a red one in addition to the white one we already have:

  light_source {
    <10, 10, -1>
    color Red
    spotlight
    radius 12
    falloff 14
    tightness 10
    point_at <2, 0, 0>
  }
  light_source {
    <-12, 10, -1>
    color Blue
    spotlight
    radius 12
    falloff 14
    tightness 10
    point_at <-2, 0, 0>
  }

Rendering this we see that the scene now has a wonderfully mysterious air to it. The three spotlights all converge on the objects making them blue on one side and red on the other with enough white in the middle to provide a balance.

2.2.4.3 The Cylindrical Light Source

Spotlights are cone shaped, meaning that their effect will change with distance. The farther away from the spotlight an object is, the larger the apparent radius will be. But we may want the radius and falloff to be a particular size no matter how far away the spotlight is. For this reason, cylindrical light sources are needed. A cylindrical light source is just like a spotlight, except that the radius and falloff regions are the same no matter how far from the light source our object is. The shape is therefore a cylinder rather than a cone. We can specify a cylindrical light source by replacing the spotlight keyword with the cylinder keyword. We try this now with our scene by replacing all three spotlights with cylinder lights and rendering again. We see that the scene is much dimmer. This is because the cylindrical constraints do not let the light spread out like in a spotlight. Larger radius and falloff values are needed to do the job. We try a radius of 20 and a falloff of 30 for all three lights. That's the ticket!

2.2.4.4 The Area Light Source

So far all of our light sources have one thing in common. They produce sharp shadows. This is because the actual light source is a point that is infinitely small. Objects are either in direct sight of the light, in which case they are fully illuminated, or they are not, in which case they are fully shaded. In real life, this kind of stark light and shadow situation exists only in outer space where the direct light of the sun pierces the total blackness of space. But here on Earth, light bends around objects, bounces off objects, and usually the source has some dimension, meaning that it can be partially hidden from sight (shadows are not sharp anymore). They have what is known as an umbra, or an area of fuzziness where there is neither total light or shade. In order to simulate these soft shadows, a ray-tracer must give its light sources dimension. POV-Ray accomplishes this with a feature known as an area light.

Area lights have dimension in two axis'. These are specified by the first two vectors in the area light syntax. We must also specify how many lights are to be in the array. More will give us cleaner soft shadows but will take longer to render. Usually a 3*3 or a 5*5 array will suffice. We also have the option of specifying an adaptive value. The adaptive keyword tells the ray-tracer that it can adapt to the situation and send only the needed rays to determine the value of the pixel. If adaptive is not used, a separate ray will be sent for every light in the area light. This can really slow things down. The higher the adaptive value the cleaner the umbra will be but the longer the trace will take. Usually an adaptive value of 1 is sufficient. Finally, we probably should use the jitter keyword. This tells the ray-tracer to slightly move the position of each light in the area light so that the shadows appear truly soft instead of giving us an umbra consisting of closely banded shadows.

OK, let's try one. We comment out the cylinder lights and add the following:

  light_source {
    <2, 10, -3>
    color White
    area_light <5, 0, 0>, <0, 0, 5>, 5, 5
    adaptive 1
    jitter
  }

This is a white area light centered at <2,10,-3>. It is 5 units (along the x-axis) by 5 units (along the z-axis) in size and has 25 (5*5) lights in it. We have specified adaptive 1 and jitter. We render and right away we notice two things. The trace takes quite a bit longer than it did with a point or a spotlight and the shadows are no longer sharp! They all have nice soft umbrae around them. Wait, it gets better.

Spotlights and cylinder lights can be area lights too! Remember those sharp shadows from the spotlights in our scene? It would not make much sense to use a 5*5 array for a spotlight, but a smaller array might do a good job of giving us just the right amount of umbra for a spotlight. Let's try it. We comment out the area light and change the cylinder lights so that they read as follows:

  light_source {
    <2, 10, -3>
    color White
    spotlight
    radius 15
    falloff 18
    tightness 10
    area_light <1, 0, 0>, <0, 0, 1>, 2, 2
    adaptive 1
    jitter
    point_at <0, 0, 0>
  }
  light_source {
    <10, 10, -1>
    color Red
    spotlight
    radius 12
    falloff 14
    tightness 10
    area_light <1, 0, 0>, <0, 0, 1>, 2, 2
    adaptive 1
    jitter
    point_at <2, 0, 0>
  }
  light_source {
    <-12, 10, -1>
    color Blue
    spotlight
    radius 12
    falloff 14
    tightness 10
    area_light <1, 0, 0>, <0, 0, 1>, 2, 2
    adaptive 1
    jitter
    point_at <-2, 0, 0>
  }

We now have three area-spotlights, one unit square consisting of an array of four (2*2) lights, three different colors, all shining on our scene. We render this and it appears to work perfectly. All our shadows have small, tight umbrae, just the sort we would expect to find on an object under a real spotlight.

2.2.4.5 The Ambient Light Source

The ambient light source is used to simulate the effect of inter-diffuse reflection. If there was not inter-diffuse reflection all areas not directly lit by a light source would be completely dark. POV-Ray uses the ambient keyword to determine how much light coming from the ambient light source is reflected by a surface.

By default the ambient light source, which emits its light everywhere and in all directions, is pure white (rgb <1,1,1>). Changing its color can be used to create interesting effects. First of all the overall light level of the scene can be adjusted easily. Instead of changing all ambient values in every finish only the ambient light source is modified. By assigning different colors we can create nice effects like a moody reddish ambient lighting.

Below is an example of a red ambient light source.

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

See Ambient Light for more details.

2.2.4.6 Light Source Specials

2.2.4.6.1 Using Shadowless Lights

Light sources can be assigned the shadowless keyword and no shadows will be cast due to its presence in a scene. Sometimes, scenes are difficult to illuminate properly using the lights we have chosen to illuminate our objects. It is impractical and unrealistic to apply a higher ambient value to the texture of every object in the scene. So instead, we would place a couple of fill lights around the scene. Fill lights are simply dimmer lights with the shadowless keyword that act to boost the illumination of other areas of the scene that may not be lit well. Let's try using one in our scene.

Remember the three colored area spotlights? We go back and un-comment them and comment out any other lights we have made. Now we add the following:

  light_source {
    <0, 20, 0>
    color Gray50
    shadowless
  }

This is a fairly dim light 20 units over the center of the scene. It will give a dim illumination to all objects including the plane in the background. We render it and see.

2.2.4.6.2 Assigning an Object to a Light Source

Light sources are invisible. They are just a location where the light appears to be coming from. They have no true size or shape. If we want our light source to be a visible shape, we can use the looks_like keyword. We can specify that our light source can look like any object we choose. When we use looks_like, then no_shadow is applied to the object automatically. This is done so that the object will not block any illumination from the light source. If we want some blocking to occur (as in a lamp shade), it is better to simply use a union to do the same thing. Let's add such an object to our scene. Here is a light bulb we have made just for this purpose:

  #declare Lightbulb = union {
    merge {
      sphere { <0,0,0>,1 }
      cylinder {
        <0,0,1>, <0,0,0>, 1
        scale <0.35, 0.35, 1.0>
        translate  0.5*z
      }
      texture {
        pigment {color rgb <1, 1, 1>}
        finish {ambient .8 diffuse .6}
      }
    }
    cylinder {
      <0,0,1>, <0,0,0>, 1
      scale <0.4, 0.4, 0.5>
      texture { Brass_Texture }
      translate  1.5*z
    }
    rotate -90*x
    scale .5
  }

Now we add the light source:

  light_source {
    <0, 2, 0>
    color White
    looks_like { Lightbulb }
  }

Rendering this we see that a fairly believable light bulb now illuminates the scene. However, if we do not specify a high ambient value, the light bulb is not lit by the light source. On the plus side, all of the shadows fall away from the light bulb, just as they would in a real situation. The shadows are sharp, so let's make our bulb an area light:

  light_source {
    <0, 2, 0>
    color White
    area_light <1, 0, 0>, <0, 1, 0>, 2, 2
    adaptive 1
    jitter
    looks_like { Lightbulb }
  }

We note that we have placed this area light in the x-y-plane instead of the x-z-plane. We also note that the actual appearance of the light bulb is not affected in any way by the light source. The bulb must be illuminated by some other light source or by, as in this case, a high ambient value.

2.2.4.6.3 Using Light Fading

If it is realism we want, it is not realistic for the plane to be evenly illuminated off into the distance. In real life, light gets scattered as it travels so it diminishes its ability to illuminate objects the farther it gets from its source. To simulate this, POV-Ray allows us to use two keywords: fade_distance, which specifies the distance at which full illumination is achieved, and fade_power, an exponential value which determines the actual rate of attenuation. Let's apply these keywords to our fill light.

First, we make the fill light a little brighter by changing Gray50 to Gray75. Now we change that fill light as follows:

  light_source {
    <0, 20, 0>
    color Gray75
    fade_distance 5
    fade_power 1
    shadowless
  }

This means that the full value of the fill light will be achieved at a distance of 5 units away from the light source. The fade power of 1 means that the falloff will be linear (the light falls off at a constant rate). We render this to see the result.

That definitely worked! Now let's try a fade power of 2 and a fade distance of 10. Again, this works well. The falloff is much faster with a fade power of 2 so we had to raise the fade distance to 10.

2.2.5 Simple Texture Options

The pictures rendered so far where somewhat boring regarding the appearance of the objects. Let's add some fancy features to the texture.

2.2.5.1 Surface Finishes

One of the main features of a ray-tracer is its ability to do interesting things with surface finishes such as highlights and reflection. Let's add a nice little Phong highlight (shiny spot) to a sphere. To do this we need to add a finish keyword followed by a parameter. We change the definition of the sphere to this:

  sphere {
    <0, 1, 2>, 2
    texture {
      pigment { color Yellow } //Yellow is pre-defined in COLORS.INC
      finish { phong 1 }
    }
  }

We render the scene. The phong keyword adds a highlight the same color of the light shining on the object. It adds a lot of credibility to the picture and makes the object look smooth and shiny. Lower values of phong will make the highlight less bright (values should be between 0 and 1).

2.2.5.2 Adding Bumpiness

The highlight we have added illustrates how much of our perception depends on the reflective properties of an object. Ray-tracing can exploit this by playing tricks on our perception to make us see complex details that are not really there.

Suppose we wanted a very bumpy surface on the object. It would be very difficult to mathematically model lots of bumps. We can however simulate the way bumps look by altering the way light reflects off of the surface. Reflection calculations depend on a vector called a surface normal. This is a vector which points away from the surface and is perpendicular to it. By artificially modifying (or perturbing) this normal vector we can simulate bumps. We change the scene to read as follows and render it:

  sphere {
    <0, 1, 2>, 2
    texture {
      pigment { color Yellow }
      normal { bumps 0.4 scale 0.2 }
      finish { phong 1 }
    }
  }

This tells POV-Ray to use the bumps pattern to modify the surface normal. The value 0.4 controls the apparent depth of the bumps. Usually the bumps are about 1 unit wide which does not work very well with a sphere of radius 2. The scale makes the bumps 1/5th as wide but does not affect their depth.

2.2.5.3 Creating Color Patterns

We can do more than assigning a solid color to an object. We can create complex patterns in the pigment block like in these examples:

  sphere {
    <0, 1, 2>, 2
    texture {
      pigment {
        wood
        color_map {
          [0.0 color DarkTan]
          [0.9 color DarkBrown]
          [1.0 color VeryDarkBrown]
        }
        turbulence 0.05
        scale <0.2, 0.3, 1>
      }
      finish { phong 1 }
    }
  }

  sphere {
    <0, 1, 2>, 2
    texture {
      pigment {
        wood
        color_map {
          [0.0 color Red]
          [0.5 color Red]
          [0.5 color Blue]
          [1.0 color Blue]
        }
        scale <0.2, 0.3, 1>
      }
      finish { phong 1 }
    }
  }

The keyword wood specifies a pigment pattern of concentric rings like rings in wood. For every position in POV-space, a pattern returns a float value in the range from zero to one. Values outside the zero to one range are ignored. The color_map specifies what color vector is assigned to that float value. In the first example the color of the wood blends from DarkTan to DarkBrown over the first 90% of the vein and from DarkBrown to VeryDarkBrown over the remaining 10%. In the second example the colors do not blend from one to an other, but change abrupt. The turbulence keyword slightly stirs up the pattern so the veins are not perfect circles and the scale keyword adjusts the size of the pattern.

Most patterns are set up by default to give us one feature across a sphere of radius 1.0. A feature is very roughly defined as a color transition. For example, a wood texture would have one band on a sphere of radius 1.0. In this example we scale the pattern using the scale keyword followed by a vector. In this case we scaled 0.2 in the x direction, 0.3 in the y direction and the z direction is scaled by 1, which leaves it unchanged. Scale values larger than one will stretch an element. Scale values smaller than one will squish an element. A scale value of one will leave an element unchanged.

2.2.5.4 Pre-defined Textures

POV-Ray has some very sophisticated textures pre-defined in the standard include files glass.inc, metals.inc, stones.inc and woods.inc. Some are entire textures with pigment, normal and/or finish parameters already defined. Some are just pigments or just finishes.

We change the definition of our sphere to the following and then re-render it:

  sphere {
    <0, 1, 2>, 2
    texture {
      pigment {
        DMFWood4       // pre-defined in textures.inc
        scale 4        // scale by the same amount in all
                       // directions
      }
      finish { Shiny } // pre-defined in finish.inc
    }
  }

The pigment identifier DMFWood4 has already been scaled down quite small when it was defined. For this example we want to scale the pattern larger. Because we want to scale it uniformly we can put a single value after the scale keyword rather than a vector of x, y, z scale factors.

We look through the file textures.inc to see what pigments and finishes are defined and try them out. We just insert the name of the new pigment where DMFWood4 is now or try a different finish in place of Shiny and re-render our file.

Here is an example of using a complete texture identifier rather than just the pieces.

  sphere {
    <0, 1, 2>, 2
    texture { PinkAlabaster }
  }

2.2.6 Using the Camera

2.2.6.1 Using Focal Blur

Let's construct a simple scene to illustrate the use of focal blur. For this example we will use a pink sphere, a green box and a blue cylinder with the sphere placed in the foreground, the box in the center and the cylinder in the background. A checkered floor for perspective and a couple of light sources will complete the scene. We create a new file called focaldem.pov and enter the following text

  #include "colors.inc"
  #include "shapes.inc"
  #include "textures.inc"
  sphere {
    <1, 0, -6>, 0.5
    finish {
      ambient 0.1
      diffuse 0.6
    }
    pigment { NeonPink }
  }
  box {
    <-1, -1, -1>, < 1,  1,  1>
    rotate <0, -20, 0>
    finish {
      ambient 0.1
      diffuse 0.6
    }
    pigment { Green }
  }
  cylinder {
    <-6, 6, 30>, <-6, -1, 30>, 3
    finish {
      ambient 0.1
      diffuse 0.6
    }
    pigment {NeonBlue}
  }
  plane {
    y, -1.0
    pigment {
      checker color Gray65 color Gray30
    }
  }
  light_source { <5, 30, -30> color White }
  light_source { <-5, 30, -30> color White }

Now we can proceed to place our focal blur camera to an appropriate viewing position. Straight back from our three objects will yield a nice view. Adjusting the focal point will move the point of focus anywhere in the scene. We just add the following lines to the file:

  camera {
    location <0.0, 1.0, -10.0>
    look_at  <0.0, 1.0,  0.0>
  //  focal_point <-6, 1, 30>    // blue cylinder in focus
  //  focal_point < 0, 1,  0>    // green box in focus
    focal_point < 1, 1, -6>    // pink sphere in focus
    aperture 0.4     // a nice compromise
  //  aperture 0.05    // almost everything is in focus
  //  aperture 1.5     // much blurring
  //  blur_samples 4       // fewer samples, faster to render
    blur_samples 20      // more samples, higher quality image
  }

The focal point is simply the point at which the focus of the camera is at its sharpest. We position this point in our scene and assign a value to the aperture to adjust how close or how far away we want the focal blur to occur from the focused area.

The aperture setting can be considered an area of focus. Opening up the aperture has the effect of making the area of focus smaller while giving the aperture a smaller value makes the area of focus larger. This is how we control where focal blur begins to occur around the focal point.

The blur samples setting determines how many rays are used to sample each pixel. Basically, the more rays that are used the higher the quality of the resultant image, but consequently the longer it takes to render. Each scene is different so we have to experiment. This tutorial has examples of 4 and 20 samples but we can use more for high resolution images. We should not use more samples than is necessary to achieve the desired quality - more samples take more time to render. The confidence and variance settings are covered in the section Focal Blur.

We experiment with the focal point, aperture, and blur sample settings. The scene has lines with other values that we can try by commenting out the default line with double slash marks and un-commenting the line we wish to try out. We make only one change at a time to see the effect on the scene.

Two final points when tracing a scene using a focal blur camera. We need not specify anti-aliasing because the focal blur code uses its own sampling method that automatically takes care of anti-aliasing. Focal blur can only be used with the perspective camera.

2.2.7 POV-Ray Coordinate System

Objects, lights and the camera are positioned using a typical 3D coordinate system. The usual coordinate system for POV-Ray has the positive y-axis pointing up, the positive x-axis pointing to the right and the positive z-axis pointing into the screen. The negative values of the axes point the other direction as shown in the images in the section Understanding POV-Ray's Coordinate System.

Locations within that coordinate system are usually specified by a three component vector. The three values correspond to the x, y and z directions respectively. For example, the vector <1,2,3> means the point that is one unit to the right, two units up and three units in front of the center of the universe at <0,0,0>.

Vectors are not always points though. They can also refer to an amount to size, move or rotate a scene element or to modify the texture pattern applied to an object.

The size, location, orientation, and deformation of items within the coordinate system is controlled by modifiers called transformations. The follow sub-sections describe the transformations and their usage.

2.2.7.1 Transformations

The supported transformations are rotate, scale, and translate. They are used to turn, size and move an object or texture. A transformation matrix may also be used to specify complex transformations directly. Groups of transformations may be merged together and stored in a transformation identifier. The syntax for transformations is as follows.

TRANSFORMATION:
    rotate <Rotate_Amt> | scale <Scale_Amt> |
    translate <Translate_Amt> | transform TRANSFORM_IDENTIFIER |
    transform { TRANSFORMATION_BLOCK...} |
    matrix <Val00, Val01, Val02,
        Val10, Val11, Val12,
        Val20, Val21, Val22,
        Val30, Val31, Val32>
TRANSFORMATION_BLOCK:
    TRANSFORM_IDENTIFIER | TRANSFORMATION | inverse
TRANSFORM_DECLARATION:
    #declare IDENTIFIER = transform { TRANSFORMATION_BLOCK...} |
    #local IDENTIFIER = transform { TRANSFORMATION_BLOCK...}
2.2.7.1.1 Translate

Items may be moved by adding a translate modifier. It consists of the keyword translate followed by a vector expression. The three terms of the vector specify the number of units to move in each of the x, y and z directions. Translate moves the element relative to its current position. For example

 sphere { <10, 10, 10>, 1
  pigment { Green }
  translate <-5, 2, 1>
 }

will move the sphere from the location <10,10,10> to <5,12,11>. It does not move it to the absolute location <-5,2,1>. Translations are always relative to the item's location before the move. Translating by zero will leave the element unchanged on that axis. For example:

 sphere { <10, 10, 10>, 1
  pigment { Green }
  translate 3*x // evaluates to <3,0,0> so move 3 units
         // in the x direction and none along y or z
 }
2.2.7.1.2 Scale

You may change the size of an object or texture pattern by adding a scale modifier. It consists of the keyword scale followed by a vector expression. The three terms of the vector specify the amount of scaling in each of the x, y and z directions.

Uneven scaling is used to stretch or squish an element. Values larger than one stretch the element on that axis while values smaller than one are used to squish it. Scale is relative to the current element size. If the element has been previously re-sized using scale then scale will size relative to the new size. Multiple scale values may used.

For example

 sphere { <0,0,0>, 1
  scale <2,1,0.5>
 }

will stretch and smash the sphere into an ellipsoid shape that is twice the original size along the x-direction, remains the same size in the y-direction and is half the original size in the z-direction.

If a lone float expression is specified it is promoted to a three component vector whose terms are all the same. Thus the item is uniformly scaled by the same amount in all directions. For example:

 object {
  MyObject
  scale 5 // Evaluates as <5,5,5> so uniformly scale
      // by 5 in every direction.
 }

When one of the scaling components is zero, POV-Ray changes this component to 1 since it assumes that 0 means no scaling in this direction. A warning "Illegal Value: Scale X, Y or Z by 0.0. Changed to 1.0." is printed then.

2.2.7.1.3 Rotate

You may change the orientation of an object or texture pattern by adding a rotate modifier. It consists of the keyword rotate followed by a vector expression. The three terms of the vector specify the number of degrees to rotate about each of the x-, y- and z-axes.

Note: The order of the rotations does matter. Rotations occur about the x-axis first, then the y-axis, then the z-axis. If you are not sure if this is what you want then you should only rotate on one axis at a time using multiple rotation statements to get a correct rotation.

 rotate <0, 30, 0>  // 30 degrees around Y axis then,
 rotate <-20, 0, 0> // -20 degrees around X axis then,
 rotate <0, 0, 10>  // 10 degrees around Z axis.

Rotation is always performed relative to the axis. Thus if an object is some distance from the axis of rotation it will not only rotate but it will orbit about the axis as though it was swinging around on an invisible string.

POV-Ray uses a left-handed rotation system. Using the famous Computer Graphics Aerobics exercise, you hold up your left hand and point your thumb in the positive direction of the axis of rotation. Your fingers will curl in the positive direction of rotation. Similarly if you point your thumb in the negative direction of the axis your fingers will curl in the negative direction of rotation. See Understanding POV-Ray's Coordinate System for an illustration.

2.2.7.1.4 Matrix

The matrix keyword can be used to explicitly specify the transformation matrix to be used for objects or textures. Its syntax is:

MATRIX:
    matrix <Val00, Val01, Val02,
        Val10, Val11, Val12,
        Val20, Val21, Val22,
        Val30, Val31, Val32>

Where Val00 through Val32 are float expressions enclosed in angle brackets and separated by commas.

Note: This is not a vector. It is a set of 12 float expressions.

These floats specify the elements of a 4 by 4 matrix with the fourth column implicitly set to <0,0,0,1>. At any given point P, P=<px, py, pz>, is transformed into the point Q, Q=<qx, qy, qz> by

qx = Val00 * px + Val10 * py + Val20 * pz + Val30

qy = Val01 * px + Val11 * py + Val21 * pz + Val31

qz = Val02 * px + Val12 * py + Val22 * pz + Val32

Normally you will not use the matrix keyword because it is less descriptive than the transformation commands and harder to visualize. However the matrix command allows more general transformation effects like shearing. The following matrix causes an object to be sheared along the y-axis.

 object {
  MyObject
  matrix < 1, 1, 0,
       0, 1, 0,
       0, 0, 1,
       0, 0, 0 >
 }

2.2.7.2 Transformation Order

Because rotations are always relative to the axis and scaling is relative to the origin, you will generally want to create an object at the origin and scale and rotate it first. Then you may translate it into its proper position. It is a common mistake to carefully position an object and then to decide to rotate it. However because a rotation of an object causes it to orbit about the axis, the position of the object may change so much that it orbits out of the field of view of the camera!

Similarly scaling after translation also moves an object unexpectedly. If you scale after you translate the scale will multiply the translate amount.
For example

  translate <5, 6, 7>
  scale 4

will translate to <20,24,28> instead of <5,6,7>. Be careful when transforming to get the order correct for your purposes.

2.2.7.3 Inverse Transform

  transform { scale <20,24,28> translate y*3  inverse }

An inverse transform does the opposite of what the transform would normally do, and can be used to undo transforms without messing around with huge numbers of transformations. To do the same without this inverse, you would have to duplicate each transform, change them to do the opposite of what they would normally do (for example translate -y*3 instead of translate y*3)and reverse their order.

2.2.7.4 Transform Identifiers

At times it is useful to combine together several transformations and apply them in multiple places. A transform identifier may be used for this purpose. Transform identifiers are declared as follows:

TRANSFORM_DECLARATION:
  #declare IDENTIFIER = transform{ TRANSFORMATION... } |
  #local IDENTIFIER = transform{ TRANSFORMATION... }

Where IDENTIFIER is the name of the identifier up to 40 characters long and TRANSFORMATION is any valid transformation modifier. See #declare vs. #local for information on identifier scope. Here is an example...

  #declare MyTrans =
    transform {
      rotate THISWAY
      scale SOMUCH
      rotate -THISWAY
      scale BIGGER
      translate OVERTHERE
      rotate WAYAROUND
    }

A transform identifier is invoked by the transform keyword with or without brackets as shown here:

  object {
    MyObject              // Get a copy of MyObject
    transform MyTrans     // Apply the transformation
    translate -x*5        // Then move it 5 units left
  }
  object {
    MyObject              // Get another copy of MyObject
    transform { MyTrans } // Apply the same transformation
    translate x*5         // Then move this one 5 units right
  }

On extremely complex CSG objects with lots of components it may speed up parsing if you apply a declared transformation rather than the individual translate, rotate, scale, or matrix modifiers. The transform is attached just once to each component. Applying each individual translate, rotate, scale, or matrix modifiers takes longer. This only affects parsing - rendering works the same either way.

2.2.7.5 Transforming Textures and Objects

When an object is transformed all textures attached to the object at that time are transformed as well. This means that if you have a translate, rotate, scale, or matrix modifier in an object before a texture, then the texture will not be transformed. If the transformation is after the texture then the texture will be transformed with the object. If the transformation is inside the texture statement then only the texture is affected. The shape remains the same. For example:

 sphere { 0, 1
  texture { Jade } // texture identifier from TEXTURES.INC
  scale 3          // this scale affects both the
                   // shape and texture
 }
 sphere { 0, 1
  scale 3          // this scale affects the shape only
  texture { Jade }
 }
 sphere { 0, 1
  texture {
   Jade
   scale 3        // this scale affects the texture only
  }
 }

Transformations may also be independently applied to pigment patterns and surface normal patterns.

Note: Scaling a normal pattern not only affects the width and spacing. It does also affect the apparent height or depth of the bumps, for how to avoid this see Scaling normals.

For example:

 box { <0, 0, 0>, <1, 1, 1>
  texture {
   pigment {
    checker Red, White
    scale 0.25 // This affects only the color pattern
   }
   normal {
    bumps 0.3 // This specifies apparent height of bumps
    scale 0.2 // Scales diameter and space between bumps
              // and also the height. Has no effect on
              // color pattern.
   }
   rotate y*45 // This affects the entire texture but
  }            // not the object.
 }

2.2.8 Setting POV-Ray Options

POV-Ray was originally created as a command-line program for operating systems without graphical interfaces, dialog boxes and pull-down menus. Most versions of POV-Ray still use command-line switches to tell it what to do. This documentation assumes you are using the command-line version. All graphical versions of POV-Ray provide a means of using command-line switches and INI files from within the user interface, so you can use the below options in any version of POV-Ray. There is system-specific documentation for each system describing which of these commands are also able to be set via menus or dialogs.

There are two distinct ways of setting POV-Ray options (other than through the GUI interface, if applicable) : command line switches and INI file keywords. Both are explained in detail in the following sections.

2.2.8.1 Command Line Switches

Command line switches consist of a + (plus) or - (minus) sign, followed by one or more alphabetic characters and possibly a numeric value. Here is a typical command line with switches.

  povray +Isimple.pov +V +W80 +H60

povray is the name of the program and it is followed by several switches. Each switch begins with a plus or minus sign. The +I switch with the filename tells POV-Ray what scene file it should use as input and +V tells the program to output its status to the text screen as it is working. The +W and +H switches set the width and height of the image in pixels. This image will be 80 pixels wide by 60 pixels high.

In switches which toggle a feature, the plus turns it on and minus turns it off. For example +P turns on the pause for keypress when finished option while -P turns it off. Other switches are used to specify values and do not toggle a feature. Either plus or minus may be used in that instance. For example +W320 sets the width to 320 pixels. You could also use -W320 and get the same results.

Switches may be specified in upper or lower case. They are read left to right but in general may be specified in any order. If you specify a switch more than once, the previous value is generally overwritten with the last specification. The only exception is the +L switch for setting library paths.

Almost all + or - switches have an equivalent option which can be used in an INI file which is described in the next section. A detailed description of each switch is given in the option reference section.

2.2.8.2 Using INI Files

Note: Although the term 'INI file' is used by POV-Ray, this was implemented before the widespread acceptance of Microsoft Windows, and while POV-Ray's INI files are almost identical to those of Windows, there are some minor differences (the foremost being that it is legal to have multiple instances of the same item in a section). INI files are used on all platform versions of POV-Ray, not just on the Windows platform.

Because it is difficult to set more than a few options on a command line, you have the ability to put multiple options in one or more text files. These initialization files or INI files have .ini as their default extension.

The majority of options you use will be stored in INI files. The command line switches are recommended for options which you will turn off or on frequently as you perform test renderings of a scene you are developing. The file povray.ini is automatically read if present in the same directory as the scene; most platforms also have platform-specific INI files that are read prior to povray.ini. You may also specify additional INI files on the command-line by simply typing the file name on the command line. For example:

  povray myopts.ini

If no extension is given, then .ini is assumed. POV-Ray knows this is not a switch because it is not preceded by a plus or minus.

You may have multiple INI files on the command line along with switches. For example:

  povray myopts +V other

This reads options from myopts.ini, then sets the +V switch, then reads options from other.ini.

An INI file is a plain ASCII text file with options of the form...

  Option_keyword=VALUE ; Text after semicolon is a comment

For example the INI equivalent of the switch +Isimple.pov is...

  Input_File_Name=simple.pov

Options are read top to bottom in the file but in general may be specified in any order. If you specify an option more than once, the previous values are generally overwritten with the last specification. The only exception is the Library_Path=path option.

Almost all INI-style options have equivalent + or - switches. The option reference section gives a detailed description of all POV-Ray options. It includes both the INI-style settings and the +/- switches.

The INI keywords are not case sensitive. Only one INI option is permitted per line of text. You may also include switches in your INI file if they are easier for you. You may have multiple switches per line but you should not mix switches and INI options on the same line. You may nest INI files by simply putting the file name on a line by itself with no equals sign after it. Nesting may occur up to ten levels deep. For example:

  ; This is a sample INI file. This entire line is a comment.
  ; Blank lines are permitted.
  Input_File_Name=simple.pov ;This sets the input file name
  +W80 +H60 ; Traditional +/- switches are permitted too
  MOREOPT   ; Read MOREOPT.INI and continue with next line
  +V        ; Another switch
  ; That's all folks!

INI files may have labeled sections so that more than one set of options may be stored in a single file. Each section begins with a label in [] brackets. For example:

  ; RES.INI
  ; This sample INI file is used to set resolution.
  +W120 +H100  ; This section has no label.
               ; Select it with "RES"
  [Low]
  +W80 +H60    ; This section has a label.
               ; Select it with "RES[Low]"
  [Med]
  +W320 +H200  ; This section has a label.
               ; Select it with "RES[Med]"
  [High]
  +W640 +H480  ; Labels are not case sensitive.
               ; "RES[high]" works
  [Really High]
  +W800 +H600  ; Labels may contain blanks

When you specify the INI file you should follow it with the section label in brackets. For example...

  povray res[Med] +Imyfile.pov

POV-Ray reads res.ini and skips all options until it finds the label Med. It processes options after that label until it finds another label and then it skips. If no label is specified on the command line then only the unlabeled area at the top of the file is read. If a label is specified, the unlabeled area is ignored.

Note: If your shell treats '[' or ']' specially you may need to escape them.

If a file or path contains blanks the whole file and path specification has to be put in quotes. You may either use a double-quote or a single-quote, but you have to use the same at the beginning and end. For example:

 +I"my file.pov"
 +I'my file.pov'
 Input_File="my file.pov"
 Input_File='my file.pov'

By using either single or double quotes it is possible to specify files whose name or path contains either as part of the name. For example:

 +I"file's.pov"
 +I'my "big" file.pov'
 Input_File="file's.pov"
 Input_File='my "big" file.pov'

2.2.8.3 Using the POVINI Environment Variable

On some platforms the environment variable POVINI is used to specify the location and name of a default INI file that is read every time POV-Ray is executed. The Unix and Linux versions of POV-Ray, for example, support this whilst the Windows version does not.

If POVINI is not specified, or if your computer platform does not use environment variables, a default INI file may be read; see your platform-specific documentation for information.

On most operating systems the sequence of reading options is as follows:

  1. Read options from default INI file specified by the POVINI environment variable or platform specific INI file.
  2. Read switches from command line (this includes reading any specified INI files).

Note: The POVRAYOPT environment variable supported by some earlier POV-Ray versions is no longer available.


Tutorial Section 3

2.3 Advanced Features

2.3.1 Spline Based Shapes

After we have gained some experience with the simpler shapes available in POV-Ray it is time to go on to the more advanced, thrilling shapes.

We should be aware that the shapes described in this and the following two chapters are not trivial to understand. We need not be worried though if we do not know how to use them or how they work. We just try the examples and play with the features described in the reference chapter. There is nothing better than learning by doing.

You may wish to skip to the chapter Simple Texture Options before proceeding with these advanced shapes.

2.3.1.1 Lathe Object

In the real world, lathe refers to a process of making patterned rounded shapes by spinning the source material in place and carving pieces out as it turns. The results can be elaborate, smoothly rounded, elegant looking artefacts such as table legs, pottery, etc. In POV-Ray, a lathe object is used for creating much the same kind of items, although we are referring to the object itself rather than the means of production.

Here is some source for a really basic lathe.

  #include "colors.inc"
  background{White}
  camera {
    angle 10
    location <1, 9, -50>
    look_at <0, 2, 0>
  }
  light_source {
    <20, 20, -20> color White
  }
  lathe {
    linear_spline
    6,
    <0,0>, <1,1>, <3,2>, <2,3>, <2,4>, <0,4>
    pigment { Blue }
    finish {
      ambient .3
      phong .75
    }
  }

We render this, and what we see is a fairly simply type of lathe, which looks like a child's top. Let's take a look at how this code produced the effect.

First, a set of six points is declared which the raytracer connects with lines. We note that there are only two components in the vectors which describe these points. The lines that are drawn are assumed to be in the x-y-plane, therefore it is as if all the z-components were assumed to be zero. The use of a two-dimensional vector is mandatory, attempting to use a 3D vector would trigger an error... with one exception, which we will explore later in the discussion of splines.

Once the lines are determined, the ray-tracer rotates this line around the y-axis, and we can imagine a trail being left through space as it goes, with the surface of that trail being the surface of our object.

The specified points are connected with straight lines because we used the linear_spline keyword. There are other types of splines available with the lathe, which will result in smooth curving lines, and even rounded curving points of transition, but we will get back to that in a moment.

A simple lathe object.

First, we would like to digress a moment to talk about the difference between a lathe and a surface of revolution object (SOR). The SOR object, described in a separate tutorial, may seem terribly similar to the lathe at first glance. It too declares a series of points and connects them with curving lines and then rotates them around the y-axis. The lathe has certain advantages, such as different kinds of splines, linear, quadratic and cubic, and one more thing:

The simpler mathematics used by a SOR does not allow the curve to double back over the same y-coordinates, thus, if using a SOR, any sudden twist which cuts back down over the same heights that the curve previously covered will trigger an error. For example, suppose we wanted a lathe to arc up from <0,0> to <2,2>, then to dip back down to <4,0>. Rotated around the y-axis, this would produce something like a gelatin mold - a rounded semi torus, hollow in the middle. But with the SOR, as soon as the curve doubled back on itself in the y-direction, it would become an illegal declaration.

Still, the SOR has one powerful strong point: because it uses simpler order mathematics, it generally tends to render faster than an equivalent lathe. So in the end, it is a matter of: we use a SOR if its limitations will allow, but when we need a more flexible shape, we go with the lathe instead.

2.3.1.1.1 Understanding The Concept of Splines

It would be helpful, in order to understand splines, if we had a sort of Spline Workshop where we could practice manipulating types and points of splines and see what the effects were like. So let's make one! Now that we know how to create a basic lathe, it will be easy:

#include "colors.inc"
  camera {
    orthographic
    up <0, 5, 0>
    right <5, 0, 0>
    location <2.5, 2.5, -100>
    look_at <2.5, 2.5, 0>
  }
  /* set the control points to be used */
  #declare Red_Point    = <1.00, 0.00>;
  #declare Orange_Point = <1.75, 1.00>;
  #declare Yellow_Point = <2.50, 2.00>;
  #declare Green_Point  = <2.00, 3.00>;
  #declare Blue_Point   = <1.50, 4.00>;
  /* make the control points visible */
  cylinder { Red_Point, Red_Point - <0,0,20>, .1
    pigment { Red }
    finish { ambient 1 }
  }
  cylinder { Orange_Point, Orange_Point - <0,0,20>, .1
    pigment { Orange }
    finish { ambient 1 }
  }
  cylinder { Yellow_Point, Yellow_Point - <0,0,20>, .1
    pigment { Yellow }
    finish { ambient 1 }
  }
  cylinder { Green_Point, Green_Point - <0,0,20>, .1
    pigment { Green }
    finish { ambient 1 }
  }
  cylinder { Blue_Point, Blue_Point- <0,0,20>, .1
    pigment { Blue }
    finish { ambient 1 }
  }
  /* something to make the curve show up */
  lathe {
    linear_spline
    5,
    Red_Point,
    Orange_Point,
    Yellow_Point,
    Green_Point,
    Blue_Point
    pigment { White }
    finish { ambient 1 }
  }

Now, we take a deep breath. We know that all looks a bit weird, but with some simple explanations, we can easily see what all this does.

First, we are using the orthographic camera. If we have not read up on that yet, a quick summary is: it renders the scene flat, eliminating perspective distortion so that in a side view. The objects look like they were drawn on a piece of graph paper, like in the side view of a modeler or CAD package. There are several uses for this practical type of camera, but here it is allowing us to see our lathe and cylinders edge on, so that what we see is almost like a cross section of the curve which makes the lathe, rather than the lathe itself. To further that effect, we eliminated shadowing with the ambient 1 finish, which of course also eliminates the need for lighting. We have also positioned this particular side view so that <0,0> appears at the lower left of our scene.

A simple Spline Workshop

Next, we declared a set of points. We note that we used 3D vectors for these points rather than the 2D vectors we expect in a lathe. That is the exception we mentioned earlier. When we declare a 3D point, then use it in a lathe, the lathe only uses the first two components of the vector, and whatever is in the third component is simply ignored. This is handy here, since it makes this example possible.

Next we do two things with the declared points. First we use them to place small diameter cylinders at the locations of the points with the circular caps facing the camera. Then we re-use those same vectors to determine the lathe.

Since trying to declare a 2D vector can have some odd results, and is not really what our cylinder declarations need anyway, we can take advantage of the lathe's tendency to ignore the third component by just setting the z-coordinate in these 3D vectors to zero.

The end result is: when we render this code, we see a white lathe against a black background showing us how the curve we have declared looks, and the circular ends of the cylinders show us where along the x-y-plane our control points are. In this case, it is very simple. The linear spline has been used so our curve is just straight lines zig-zagging between the points.

We change the declarations of Red_Point and Blue_Point to read as follows:

  #declare Red_Point  = <2.00, 0.00>;
  #declare Blue_Point = <0.00, 4.00>;

We re-render and, as we can see, all that happens is that the straight line segments just move to accommodate the new position of the red and blue points. Linear splines are so simple, we could manipulate them in our sleep, no?

Moving some points of the spline.

Now let's examine the different types of splines that the lathe object supports:

First, we change the points to the following.

  #declare Red_Point    = <1.00, 0.00>;
  #declare Orange_Point = <2.00, 1.00>;
  #declare Yellow_Point = <3.50, 2.00>;
  #declare Green_Point  = <2.00, 3.00>;
  #declare Blue_Point   = <1.50, 4.00>;

We then find the lathe declaration and change linear_spline to quadratic_spline. We re-render and what do we have? Well, there is a couple of things worthy of note this time. First, we will see that instead of straight lines we have smooth arcs connecting the points. These arcs are made from quadratic curves, so our lathe looks much more interesting this time. Also, Red_Point is no longer connected to the curve. What happened?

A quadratic spline lathe.

Well, while any two points can determine a straight line, it takes three to determine a quadratic curve. POV-Ray looks not only to the two points to be connected, but to the point immediately preceding them to determine the formula of the quadratic curve that will be used to connect them. The problem comes in at the beginning of the curve. Beyond the first point in the curve there is no previous point. So we need to declare one. Therefore, when using a quadratic spline, we must remember that the first point we specify is only there so that POV-Ray can determine what curve to connect the first two points with. It will not show up as part of the actual curve.

There is just one more thing about this lathe example. Even though our curve is now put together with smooth curving lines, the transitions between those lines is... well, kind of choppy, no? This curve looks like the lines between each individual point have been terribly mismatched. Depending on what we are trying to make, this could be acceptable, or, we might need a more smoothly curving shape. Fortunately, if the latter is true, we have another option.

The quadratic spline takes longer to render than a linear spline. The math is more complex. Taking longer still is the cubic spline, yet for a really smoothed out shape this is the only way to go. We go back into our example, and simply replace quadratic_spline with cubic_spline. We render one more time, and take a look at what we have.

 | While a quadratic spline takes three points to determine the curve, a cubic needs four. So, as we might expect, Blue_Point has now dropped out of the curve, just as Red_Point did, as the first and last points of our curve are now only control points for shaping the curves between the remaining points. But look at the transition from Orange_Point to Yellow_Point and then back to Green_Point. Now, rather than looking mismatched, our curve segments look like one smoothly joined curve.
A cubic spline lathe. |

Finally there is another kind of quadratic spline, the bezier_spline. This one takes four points per section. The start point, the end points and in between, two control points. To use it, we will have to make a few changes to our work shop. Delete the Yellow point, delete the Yellow cylinder. Change the points to:

  #declare Red_Point    = <2.00, 1.00>;
  #declare Orange_Point = <3.00, 1.50>;
  #declare Green_Point  = <3.00, 3.50>;
  #declare Blue_Point   = <2.00, 4.00>;

And change the lathe to:

  lathe {
    bezier_spline
    4,
    Red_Point,
    Orange_Point,
    Green_Point,
    Blue_Point
    pigment { White }
    finish { ambient 1 }
  }

The green and orange control points are not connected to the curve. Move them around a bit, for example:

#declare Orange_Point = <1.00, 1.50>;

The line that can be drawn from the start point to its closest control point (red to orange) shows the tangent of the curve at the start point. Same for the end point, blue to green.

A bezier spline lathe.

One spline segment is nice, two is nicer. So we will add another segment and connect it to the blue point. One segment has four points, so two segments have eight. The first point of the second segment is the same as the last point of the first segment. The blue point. So we only have to declare three more points. Also we have to move the camera a bit and add more cylinders. Here is the complete scene again:

#include "colors.inc"
  camera {
    orthographic
    up <0, 7, 0>
    right <7, 0, 0>
    location <3.5, 4, -100>
    look_at <3.5, 4, 0>
  }
  /* set the control points to be used */
  #declare Red_Point    = <2.00, 1.00>;
  #declare Orange_Point = <1.00, 1.50>;
  #declare Green_Point  = <3.00, 3.50>;
  #declare Blue_Point   = <2.00, 4.00>;
  #declare Green_Point2 = <3.00, 4.50>;
  #declare Orange_Point2= <1.00, 6.50>;
  #declare Red_Point2   = <2.00, 7.00>;
  /* make the control points visible */

  cylinder { Red_Point, Red_Point - <0,0,20>, .1
    pigment { Red } finish { ambient 1 }
  }
  cylinder { Orange_Point, Orange_Point - <0,0,20>, .1
    pigment { Orange } finish { ambient 1 }
  }
  cylinder { Green_Point, Green_Point - <0,0,20>, .1
    pigment { Green } finish { ambient 1 }
  }
  cylinder { Blue_Point, Blue_Point- <0,0,20>, .1
    pigment { Blue } finish { ambient 1 }
  }
  cylinder { Green_Point2, Green_Point2 - <0,0,20>, .1
    pigment { Green } finish { ambient 1 }
  }
  cylinder { Orange_Point2, Orange_Point2 - <0,0,20>, .1
    pigment { Orange } finish { ambient 1 }
  }
  cylinder { Red_Point2, Red_Point2 - <0,0,20>, .1
    pigment { Red } finish { ambient 1 }
  }
  /* something to make the curve show up */
  lathe {
    bezier_spline
    8,
    Red_Point, Orange_Point, Green_Point, Blue_Point
    Blue_Point, Green_Point2, Orange_Point2, Red_Point2
    pigment { White }
    finish { ambient 1 }
  }

 | A nice curve, but what if we want a smooth curve? Let us have a look at the tangents on the Blue_Point, draw the lines Green_Point, Blue_Point and Green_Point2, Blue_Point. Look at the angle they make, it is as sharp as the dent in the curve. What if we make the angle bigger? What if we make the angle 180Â°?
Two bezier spline segments, not smooth. |

Try a few positions for Green_Point2 and end with:

#declare Green_Point2 = <1.00, 4.50>;

 | It's a smooth curve. If we make sure that the two control points and the connection point are on one line, the curve is perfectly smooth.
A smooth bezier spline lathe. |

In general this can be achieved by:

#declare Green_Point2 = Blue_Point + (Blue_Point - Green_Point);

The concept of splines is a handy and necessary one, which will be seen again in the prism and polygon objects. It's easy to see, that with a little tinkering, how quickly we can get a feel for working with splines.

2.3.1.2 Surface of Revolution Object

Bottles, vases and glasses make nice objects in ray-traced scenes. We want to create a golden cup using the surface of revolution object (SOR object).

We first start by thinking about the shape of the final object. It is quite difficult to come up with a set of points that describe a given curve without the help of a modeling program supporting POV-Ray's surface of revolution object. If such a program is available we should take advantage of it.

The point configuration of our cup object.

We will use the point configuration shown in the figure above. There are eight points describing the curve that will be rotated about the y-axis to get our cup. The curve was calculated using the method described in the reference section (see Surface of Revolution).

Now it is time to come up with a scene that uses the above SOR object. We create a file called sordemo.pov and enter the following text.

  #include "colors.inc"
  #include "golds.inc"
  camera {
    location <10, 15, -20>
    look_at <0, 5, 0>
    angle 45
  }
  background { color rgb<0.2, 0.4, 0.8>  }
  light_source { <100, 100, -100> color rgb 1 }
  plane {
    y, 0
    pigment { checker color Red, color Green scale 10 }
  }
  sor {
    8,
    <0.0,  -0.5>,
    <3.0,   0.0>,
    <1.0,   0.2>,
    <0.5,   0.4>,
    <0.5,   4.0>,
    <1.0,   5.0>,
    <3.0,  10.0>,
    <4.0,  11.0>
    open
    texture { T_Gold_1B }
  }

The scene contains our cup object resting on a checkered plane. Tracing this scene results in the image below.

A surface of revolution object.

The surface of revolution is described by starting with the number of points followed by the points. Points from second to last but one are listed with ascending heights. Each of them determines the radius of the curve for a given height. E. g. the first valid point (second listed) tells POV-Ray that at height 0.0 the radius is 3. We should take care that each point has a larger height than its predecessor. If this is not the case the program will abort with an error message. First and last point from the list are used to determine slope at beginning and end of curve and can be defined for any height.

2.3.1.3 Prism Object

The prism is essentially a polygon or closed curve which is swept along a linear path. We can imagine the shape so swept leaving a trail in space, and the surface of that trail is the surface of our prism. The curve or polygon making up a prism's face can be a composite of any number of sub-shapes, can use any kind of three different splines, and can either keep a constant width as it is swept, or slowly tapering off to a fine point on one end. But before this gets too confusing, let's start one step at a time with the simplest form of prism. We enter and render the following POV code (see file prismdm1.pov).

  #include "colors.inc"
  background{White}
  camera {
    angle 20
    location <2, 10, -30>
    look_at <0, 1, 0>
  }
  light_source { <20, 20, -20> color White }
  prism {
    linear_sweep
    linear_spline
    0, // sweep the following shape from here ...
    1, // ... up through here
    7, // the number of points making up the shape ...
    <3,5>, <-3,5>, <-5,0>, <-3,-5>, <3, -5>, <5,0>, <3,5>
    pigment { Green }
  }

A hexagonal prism shape.

This produces a hexagonal polygon, which is then swept from y=0 through y=1. In other words, we now have an extruded hexagon. One point to note is that although this is a six sided figure, we have used a total of seven points. That is because the polygon is supposed to be a closed shape, which we do here by making the final point the same as the first. Technically, with linear polygons, if we did not do this, POV-Ray would automatically join the two ends with a line to force it to close, although a warning would be issued. However, this only works with linear splines, so we must not get too casual about those warning messages!

2.3.1.3.1 Teaching An Old Spline New Tricks

If we followed the section on splines covered under the lathe tutorial (see the section Understanding The Concept of Splines), we know that there are two additional kinds of splines besides linear: the quadratic and the cubic spline. Sure enough, we can use these with prisms to make a more free form, smoothly curving type of prism.

There is just one catch, and we should read this section carefully to keep from tearing our hair out over mysterious too few points in prism messages which keep our prism from rendering. We can probably guess where this is heading: how to close a non-linear spline. Unlike the linear spline, which simply draws a line between the last and first points if we forget to make the last point equal to the first, quadratic and cubic splines are a little more fussy.

First of all, we remember that quadratic splines determine the equation of the curve which connects any two points based on those two points and the previous point, so the first point in any quadratic spline is just control point and will not actually be part of the curve. What this means is: when we make our shape out of a quadratic spline, we must match the second point to the last, since the first point is not on the curve - it is just a control point needed for computational purposes.

Likewise, cubic splines need both the first and last points to be control points, therefore, to close a shape made with a cubic spline, we must match the second point to the second from last point. If we do not match the correct points on a quadratic or cubic shape, that is when we will get the too few points in prism error. POV-Ray is still waiting for us to close the shape, and when it runs out of points without seeing the closure, an error is issued.

Confused? Okay, how about an example? We replace the prism in our last bit of code with this one (see file prismdm2.pov).

  prism {
    cubic_spline
    0, // sweep the following shape from here ...
    1, // ... up through here
    6, // the number of points making up the shape ...
    < 3, -5>, // point#1 (control point... not on curve)
    < 3,  5>, // point#2  ... THIS POINT ...
    <-5,  0>, // point#3
    < 3, -5>, // point#4
    < 3,  5>, // point#5 ... MUST MATCH THIS POINT
    <-5,  0>  // point#6 (control point... not on curve)
    pigment { Green }
  }

A cubic, triangular prism shape.

This simple prism produces what looks like an extruded triangle with its corners sanded smoothly off. Points two, three and four are the corners of the triangle and point five closes the shape by returning to the location of point two. As for points one and six, they are our control points, and are not part of the shape - they are just there to help compute what curves to use between the other points.

2.3.1.3.2 Smooth Transitions

Now a handy thing to note is that we have made point one equal point four, and also point six equals point three. Yes, this is important. Although this prism would still be legally closed if the control points were not what we have made them, the curve transitions between points would not be as smooth. We change points one and six to <4,6> and <0,7> respectively and re-render to see how the back edge of the shape is altered (see file prismdm3.pov).

To put this more generally, if we want a smooth closure on a cubic spline, we make the first control point equal to the third from last point, and the last control point equal to the third point. On a quadratic spline, the trick is similar, but since only the first point is a control point, make that equal to the second from last point.

2.3.1.3.3 Multiple Sub-Shapes

Just as with the polygon object (see section Polygon Object) the prism is very flexible, and allows us to make one prism out of several sub-prisms. To do this, all we need to do is keep listing points after we have already closed the first shape. The second shape can be simply an add on going off in another direction from the first, but one of the more interesting features is that if any even number of sub-shapes overlap, that region where they overlap behaves as though it has been cut away from both sub-shapes. Let's look at another example. Once again, same basic code as before for camera, light and so forth, but we substitute this complex prism (see file prismdm4.pov).

  prism {
    linear_sweep
    cubic_spline
    0,  // sweep the following shape from here ...
    1,  // ... up through here
    18, // the number of points making up the shape ...
    <3,-5>, <3,5>, <-5,0>, <3, -5>, <3,5>, <-5,0>,//sub-shape #1
    <2,-4>, <2,4>, <-4,0>, <2,-4>, <2,4>, <-4,0>, //sub-shape #2
    <1,-3>, <1,3>, <-3,0>, <1, -3>, <1,3>, <-3,0> //sub-shape #3
    pigment { Green }
  }

Using sub-shapes to create a more complex shape.

For readability purposes, we have started a new line every time we moved on to a new sub-shape, but the ray-tracer of course tells where each shape ends based on whether the shape has been closed (as described earlier). We render this new prism, and look what we have got. It is the same familiar shape, but it now looks like a smaller version of the shape has been carved out of the center, then the carved piece was sanded down even smaller and set back in the hole.

Simply, the outer rim is where only sub-shape one exists, then the carved out part is where sub-shapes one and two overlap. In the extreme center, the object reappears because sub-shapes one, two, and three overlap, returning us to an odd number of overlapping pieces. Using this technique we could make any number of extremely complex prism shapes!

2.3.1.3.4 Conic Sweeps And The Tapering Effect

In our original prism, the keyword linear_sweep is actually optional. This is the default sweep assumed for a prism if no type of sweep is specified. But there is another, extremely useful kind of sweep: the conic sweep. The basic idea is like the original prism, except that while we are sweeping the shape from the first height through the second height, we are constantly expanding it from a single point until, at the second height, the shape has expanded to the original points we made it from. To give a small idea of what such effects are good for, we replace our existing prism with this (see file prismdm4.pov):

  prism {
    conic_sweep
    linear_spline
    0, // height 1
    1, // height 2
    5, // the number of points making up the shape...
    <4,4>,<-4,4>,<-4,-4>,<4,-4>,<4,4>
    rotate <180, 0, 0>
    translate <0, 1, 0>
    scale <1, 4, 1>
    pigment { gradient y scale .2 }
  }

Creating a pyramid using conic sweeping.

The gradient pigment was selected to give some definition to our object without having to fix the lights and the camera angle right at this moment, but when we render it, what have we created? A horizontally striped pyramid! By now we can recognize the linear spline connecting the four points of a square, and the familiar final point which is there to close the spline.

Notice all the transformations in the object declaration. That is going to take a little explanation. The rotate and translate are easy. Normally, a conic sweep starts full sized at the top, and tapers to a point at y=0, but of course that would be upside down if we are making a pyramid. So we flip the shape around the x-axis to put it right side up, then since we actually orbited around the point, we translate back up to put it in the same position it was in when we started.

The scale is to put the proportions right for this example. The base is eight units by eight units, but the height (from y=1 to y=0) is only one unit, so we have stretched it out a little. At this point, we are probably thinking, why not just sweep up from y=0 to y=4 and avoid this whole scaling thing?

That is a very important gotcha! with conic sweeps. To see what is wrong with that, let's try and put it into practice (see file prismdm5.pov). We must make sure to remove the scale statement, and then replace the line which reads

  1, // height 2

with

  4, // height 2

This sets the second height at y=4, so let's re-render and see if the effect is the same.

Choosing a second height larger than one for the conic sweep.

Whoa! Our height is correct, but our pyramid's base is now huge! What went wrong here? Simple. The base, as we described it with the points we used actually occurs at y=1 no matter what we set the second height for. But if we do set the second height higher than one, once the sweep passes y=1, it keeps expanding outward along the same lines as it followed to our original base, making the actual base bigger and bigger as it goes.

To avoid losing control of a conic sweep prism, it is usually best to let the second height stay at y=1, and use a scale statement to adjust the height from its unit size. This way we can always be sure the base's corners remain where we think they are.

That leads to one more interesting thing about conic sweeps. What if we for some reason do not want them to taper all the way to a point? What if instead of a complete pyramid, we want more of a ziggurat step? Easily done. After putting the second height back to one, and replacing our scale statement, we change the line which reads

  0, // height 1

to

  0.251, // height 1

Increasing the first height for the conic sweep.

When we re-render, we see that the sweep stops short of going all the way to its point, giving us a pyramid without a cap. Exactly how much of the cap is cut off depends on how close the first height is to the second height.

2.3.1.4 Sphere Sweep Object

A Sphere Sweep Object is the space a sphere occupies during its movement along a spline.
So we need to specify the kind of spline we want and a list of control points to define that spline. To help POV-Ray we tell how many control points will be used. In addition, we also define the radius the moving sphere should have when passing through each of these control points.

The syntax of the sphere_sweep object is:

  sphere_sweep {
    linear_spline | b_spline | cubic_spline
    NUM_OF_SPHERES,

    CENTER, RADIUS,
    CENTER, RADIUS,
    ...
    CENTER, RADIUS
    [tolerance DEPTH_TOLERANCE]
    [OBJECT_MODIFIERS]
  }

An example for a linear Sphere Sweep would be:

  sphere_sweep {
    linear_spline
    4,
    <-5, -5, 0>, 1
    <-5,  5, 0>, 1
    < 5, -5, 0>, 1
    < 5,  5, 0>, 1
  }

This object is described by four spheres. You can use as many spheres as you like to describe the object, but you will need at least two spheres for a linear Sphere Sweep, and four spheres for one approximated with a cubic_spline or b_spline.

The example above would result in an object shaped like the letter "N". The sphere sweep goes through all points which are connected with straight cones.

Changing the kind of interpolation to a cubic_spline produces a quite different, slightly bent, object. It then starts at the second sphere and ends at the last but one. Since the first and last points are used to control the spline, you need two more points to get a shape that can be compared to the linear sweep. Let's add them:

  sphere_sweep {
    cubic_spline
    6,
    <-4, -5, 0>, 1
    <-5, -5, 0>, 1
    <-5,  5, 0>, 0.5
    < 5, -5, 0>, 0.5
    < 5,  5, 0>, 1
    < 4,  5, 0>, 1
    tolerance 0.1
 }

So the cubic sweep creates a smooth sphere sweep actually going through all points (except the first and last one). In this example the radius of the second and third spheres have been changed. We also added the tolerance keyword, because dark spots appeared on the surface with the default value (0.000001).

When using a b_spline, the resulting object is somewhat similar to the cubic sweep, but does not actually go through the control points. It lies somewhere between them.

2.3.1.5 Bicubic Patch Object

Bicubic patches are useful surface representations because they allow an easy definition of surfaces using only a few control points. The control points serve to determine the shape of the patch. Instead of defining the vertices of triangles, we simply give the coordinates of the control points. A single patch has 16 control points, one at each corner, and the rest positioned to divide the patch into smaller sections. POV-Ray does not ray trace the patches directly, they are approximated using triangles as described in the Scene Description Language section.

Bicubic patches are almost always created by using a third party modeler, but for this tutorial we will manipulate them by hand. Modelers that support Bicubic patches and export to POV-Ray can be found in the »links collection on our server
Let's set up a basic scene and start exploring the Bicubic patch.

#version 3.5;
global_settings {assumed_gamma 1.0}
background {rgb <1,0.9,0.9>}
camera {location <1.6,5,-6> look_at <1.5,0,1.5> angle 40}
light_source {<500,500,-500> rgb 1 }

#declare B11=<0,0,3>; #declare B12=<1,0,3>; //
#declare B13=<2,0,3>; #declare B14=<3,0,3>; // row 1

#declare B21=<0,0,2>; #declare B22=<1,0,2>; //
#declare B23=<2,0,2>; #declare B24=<3,0,2>; // row 2

#declare B31=<0,0,1>; #declare B32=<1,0,1>; //
#declare B33=<2,0,1>; #declare B34=<3,0,1>; // row 3

#declare B41=<0,0,0>; #declare B42=<1,0,0>; //
#declare B43=<2,0,0>; #declare B44=<3,0,0>; // row 4

bicubic_patch {
   type 1 flatness 0.001
   u_steps 4 v_steps 4
   uv_vectors
   <0,0> <1,0> <1,1> <0,1>
   B11, B12, B13, B14
   B21, B22, B23, B24
   B31, B32, B33, B34
   B41, B42, B43, B44
   uv_mapping
   texture {
      pigment {
         checker
         color rgbf <1,1,1,0.5>
         color rgbf <0,0,1,0.7>
         scale 1/3
      }
      finish {phong 0.6 phong_size 20}
   }
   no_shadow
}

The points B11, B14, B41, B44 are the corner points of the patch. All other points are control points. The names of the declared points are as follows: B for the colour of the patch, the first digit gives the row number, the second digit the column number. If you render the above scene, you will get a blue & white checkered square, not very exciting. First we will add some spheres to make the control points visible. As we do not want to type the code for 16 spheres, we will use an array and a while loop to construct the spheres.

#declare Points=array[16]{
   B11, B12, B13, B14
   B21, B22, B23, B24
   B31, B32, B33, B34
   B41, B42, B43, B44
}
#declare I=0;
#while (I<16)
   sphere {
      Points[I],0.1
      no_shadow
      pigment{
         #if (I=0|I=3|I=12|I=15)
            color rgb <1,0,0>
         #else
            color rgb <0,1,1>
         #end
      }
   }
   #declare I=I+1;
#end

Rendering this scene will show the patch with its corner points in red and its control points in cyan. Now it is time to start exploring.
Change B41 to <-1,0,0> and render.
Change B41 to <-1,1,0> and render.
Change B41 to < 1,2,1> and render.

Let's do some exercise with the control points. Start with a flat patch again.
Change B42 to <1,2,0> and B43 to <2,-2,0> and render.
Change B42 and B43 back to their original positions and try B34 to <4,2,1> and B24 to <2,-2,2> and render. Move the points around some more, also try the control points in the middle.

Bicubic_patch with control points.

After all this we notice two things:

  • The patch always goes through the corner points.
  • In most situations the patch does not go through the control points.

Now go back to our spline work shop and have a look at the bezier_spline again. Indeed, the points B11, B12, B13, B14, make up a bezier_spline. So do the points B11, B21, B31, B41 and B41, B42, B43, B44 and B14, B24, B34, B44.

So far we have only been looking at one single patch, but one of the strengths of the Bicubic patch lays in the fact that they can be connected smoothly, to form bigger shapes. The process of connecting is relatively simple as there are actually only two rules to follow. It can be done by using a well set up set of macros or by using a modeler. To give an idea what is needed we will do a simple example by hand.

First put the patch in our scene back to its flat position.

Next change:

#declare B14 = <3,0,3>;
#declare B24 = <3,2,2>;
#declare B34 = <3.5,1,1>;
#declare B44 = <3,-1,0>;
#declare B41 = <0,-1,0>;

Move the camera a bit back:

camera { location <3.1,7,-8> look_at <3,-2,1.5> angle 40 }

... and delete all the code for the spheres. We will now try and stitch a patch to the right side of the current one. Off course the points on the left side (column 1) of the new patch have to be in the same position as the points on the right side (column 4) of the blue one.

Render the scene, including our new patch:

#declare R11=B14; #declare R12=<4,0,3>;     //
#declare R13=<5,0,3>; #declare R14=<6,0,3>; // row 1

#declare R21=B24; #declare R22=<4,0,2>;     //
#declare R23=<5,0,2>; #declare R24=<6,0,2>; // row 2

#declare R31=B34; #declare R32=<4,0,1>;     //
#declare R33=<5,0,1>; #declare R34=<6,0,1>; // row 3

#declare R41=B44; #declare R42=<4,0,0>;     //
#declare R43=<5,0,0>; #declare R44=<6,0,0>; // row 4

bicubic_patch {
   type 1 flatness 0.001
   u_steps 4 v_steps 4
   uv_vectors
   <0,0> <1,0> <1,1> <0,1>
   R11, R12, R13, R14
   R21, R22, R23, R24
   R31, R32, R33, R34
   R41, R42, R43, R44
   uv_mapping
   texture {
      pigment {
         checker
         color rgbf <1,1,1,0.5>
         color rgbf <1,0,0,0.7>
         scale 1/3
      }
      finish {phong 0.6 phong_size 20}
   }
   no_shadow
}

This is a rather disappointing result. The patches are connected, but not exactly smooth. In connecting patches the same principles apply as for connecting two 2D bezier splines as we see in the spline workshop. Control point, connection point and the next control point should be on one line to give a smooth result. Also it is preferred, not required, that the distances from both control points to the connection point are the same. For the Bicubic patch we have to do the same, for all connection points involved in the joint. So, in our case, the following points should be on one line:

  • B13, B14=R11, R12
  • B23, B24=R21, R22
  • B33, B34=R31, R32
  • B43, B44=R41, R42

To achieve this we do:

#declare R12=B14+(B14-B13);
#declare R22=B24+(B24-B23);
#declare R32=B34+(B34-B33);
#declare R42=B44+(B44-B43);

patches, (un)smoothly connected.

This renders a smooth surface. Adding a third patch in front is relative simple now:

#declare G11=B41;      #declare G12=B42;                //
#declare G13=B43;      #declare G14=B44;                // row 1

#declare G21=B41+(B41-B31); #declare G22=B42+(B42-B32); //
#declare G23=B43+(B43-B33); #declare G24=B44+(B44-B34); // row 2

#declare G31=<0,0,-2>; #declare G32=<1,0,-2>;           //
#declare G33=<2,0,-2>; #declare G34=<3,2,-2>;           // row 3

#declare G41=<0,0,-3>; #declare G42=<1,0,-3>;           //
#declare G43=<2,0,-3>; #declare G44=<3,0,-3>            // row 4

bicubic_patch {
   type 1 flatness 0.001
   u_steps 4 v_steps 4
   uv_vectors
   <0,0> <1,0> <1,1> <0,1>
   G11, G12, G13, G14
   G21, G22, G23, G24
   G31, G32, G33, G34
   G41, G42, G43, G44
   uv_mapping
   texture {
      pigment {
         checker
         color rgbf <1,1,1,0.5>
         color rgbf <0,1,0,0.7>
         scale 1/3
      }
      finish {phong 0.6 phong_size 20}
   }
   no_shadow
}

Finally, let's put a few spheres back in the scene and add some cylinders to visualize what is going on. See what happens if you move for example B44, B43, B33 or B34.

#declare Points=array[8]{B33,B34,R32,B43,B44,R42,G23,G24}
#declare I=0;
#while (I<8)
   sphere {
      Points[I],0.1
      no_shadow
      pigment{
         #if (I=4)
            color rgb <1,0,0>
         #else
            color rgb <0,1,1>
         #end
      }
   }
   #declare I=I+1;
#end
union {
   cylinder {B33,B34,0.04} cylinder {B34,R32,0.04}
   cylinder {B43,B44,0.04} cylinder {B44,R42,0.04}
   cylinder {G23,G24,0.04}
   cylinder {B33,B43,0.04} cylinder {B43,G23,0.04}
   cylinder {B34,B44,0.04} cylinder {B44,G24,0.04}
   cylinder {R32,R42,0.04}
   no_shadow
   pigment {color rgb <1,1,0>}
}

The hard part in using the Bicubic patch is not in connecting several patches. The difficulty is keeping control over the shape you want to build. As patches are added, in order to keep the result smooth, control over the position of many points gets restrained.

3 patches, some control points.

2.3.1.6 Text Object

The text object is a primitive that can use TrueType fonts and TrueType Collections to create text objects. These objects can be used in CSG, transformed and textured just like any other POV primitive.

For this tutorial, we will make two uses of the text object. First, let's just make some block letters sitting on a checkered plane. Any TTF font should do, but for this tutorial, we will use the timrom.ttf or cyrvetic.ttf which come bundled with POV-Ray.

We create a file called textdemo.pov and edit it as follows:

  #include "colors.inc"
  camera {
    location <0, 1, -10>
    look_at 0
    angle 35
  }
  light_source { <500,500,-1000> White }
  plane {
    y,0
    pigment { checker Green White }
  }

Now let's add the text object. We will use the font timrom.ttf and we will create the string "POV-RAY 3.0". For now, we will just make the letters red. The syntax is very simple. The first string in quotes is the font name, the second one is the string to be rendered. The two floats are the thickness and offset values. The thickness float determines how thick the block letters will be. Values of .5 to 2 are usually best for this. The offset value will add to the kerning distance of the letters. We will leave this a 0 for now.

  text {
    ttf "timrom.ttf" "POV-RAY 3.0" 1, 0
    pigment { Red }
  }

Rendering this we notice that the letters are off to the right of the screen. This is because they are placed so that the lower left front corner of the first letter is at the origin. To center the string we need to translate it -x some distance. But how far? In the docs we see that the letters are all 0.5 to 0.75 units high. If we assume that each one takes about 0.5 units of space on the x-axis, this means that the string is about 6 units long (12 characters and spaces). Let's translate the string 3 units along the negative x-axis.

  text {
    ttf "timrom.ttf" "POV-RAY 3.0" 1, 0
    pigment { Red }
    translate -3*x
  }

That is better. Now let's play around with some of the parameters of the text object. First, let's raise the thickness float to something outlandish... say 25!

  text {
    ttf "timrom.ttf" "POV-RAY 3.0" 25, 0
    pigment { Red }
    translate -2.25*x
  }

Actually, that is kind of cool. Now let's return the thickness value to 1 and try a different offset value. Change the offset float from 0 to 0.1 and render it again.

Wait a minute?! The letters go wandering off up at an angle! That is not what the docs describe! It almost looks as if the offset value applies in both the x- and y-axis instead of just the x axis like we intended. Could it be that a vector is called for here instead of a float? Let's try it. We replace 0.1 with 0.1*x and render it again.

That works! The letters are still in a straight line along the x-axis, just a little further apart. Let's verify this and try to offset just in the y-axis. We replace 0.1*x with 0.1*y. Again, this works as expected with the letters going up to the right at an angle with no additional distance added along the x-axis. Now let's try the z-axis. We replace 0.1*y with 0.1*z. Rendering this yields a disappointment. No offset occurs! The offset value can only be applied in the x- and y-directions.

Let's finish our scene by giving a fancier texture to the block letters, using that cool large thickness value, and adding a slight y-offset. For fun, we will throw in a sky sphere, dandy up our plane a bit, and use a little more interesting camera viewpoint (we render the following scene at 640x480 +A0.2):

  #include "colors.inc"
  camera {
    location <-5,.15,-2>
    look_at <.3,.2,1>
    angle 35
  }
  light_source { <500,500,-1000> White }
  plane {
    y,0
    texture {
      pigment { SeaGreen }
      finish { reflection .35 specular 1 }
      normal { ripples .35 turbulence .5 scale .25 }
    }
  }
  text {
    ttf "timrom.ttf" "POV-RAY 3.0" 25, 0.1*y
    pigment { BrightGold }
    finish { reflection .25 specular 1 }
    translate -3*x
  }
  #include "skies.inc"
  sky_sphere { S_Cloud5 }

Let's try using text in a CSG object. We will attempt to create an inlay in a stone block using a text object. We create a new file called textcsg.pov and edit it as follows:

  #include "colors.inc"
  #include "stones.inc"
  background { color rgb 1 }
  camera {
    location <-3, 5, -15>
    look_at 0
    angle 25
  }
  light_source { <500,500,-1000> White }

Now let's create the block. We want it to be about eight units across because our text string "POV-RAY 3.0" is about six units long. We also want it about four units high and about one unit deep. But we need to avoid a potential coincident surface with the text object so we will make the first z-coordinate 0.1 instead of 0. Finally, we will give this block a nice stone texture.

  box {
    <-3.5, -1, 0.1>, <3.5, 1, 1>
    texture { T_Stone10 }
  }

Next, we want to make the text object. We can use the same object we used in the first tutorial except we will use slightly different thickness and offset values.

  text {
    ttf "timrom.ttf" "POV-RAY 3.0" 0.15, 0
    pigment { BrightGold }
    finish { reflection .25 specular 1 }
    translate -3*x
  }

We remember that the text object is placed by default so that its front surface lies directly on the x-y-plane. If the front of the box begins at z=0.1 and thickness is set at 0.15, the depth of the inlay will be 0.05 units. We place a difference block around the two objects.

  difference {
    box {
      <-3.5, -1, 0.1>, <3.5, 1, 1>
      texture { T_Stone10 }
    }
    text {
      ttf "timrom.ttf" "POV-RAY 3.0" 0.15, 0
      pigment { BrightGold }
      finish { reflection .25 specular 1 }
      translate -3*x
    }
  }

Text carved from stone.

When we render this at a low resolution we can see the inlay clearly and that it is indeed a bright gold color. We can render at a higher resolution and see the results more clearly but be forewarned... this trace will take a little time.

2.3.2 Polygon Based Shapes

2.3.2.1 Mesh Object

Mesh objects are very useful because they allow us to create objects containing hundreds or thousands of triangles. Compared to a simple union of triangles the mesh object stores the triangles more efficiently. Copies of mesh objects need only a little additional memory because the triangles are stored only once.

Almost every object can be approximated using triangles but we may need a lot of triangles to create more complex shapes. Thus we will only create a very simple mesh example. This example will show a very useful feature of the triangles meshes though: a different texture can be assigned to each triangle in the mesh.

Now let's begin. We will create a simple box with differently colored sides. We create an empty file called meshdemo.pov and add the following lines. Note that a mesh is - not surprisingly - declared using the keyword mesh.

  camera {
    location <20, 20, -50>
    look_at <0, 5, 0>
  }
  light_source { <50, 50, -50> color rgb<1, 1, 1> }
  #declare Red = texture {
    pigment { color rgb<0.8, 0.2, 0.2> }
    finish { ambient 0.2 diffuse 0.5 }
  }
  #declare Green = texture {
    pigment { color rgb<0.2, 0.8, 0.2> }
    finish { ambient 0.2 diffuse 0.5 }
  }
  #declare Blue = texture {
    pigment { color rgb<0.2, 0.2, 0.8> }
    finish { ambient 0.2 diffuse 0.5 }
  }

We must declare all textures we want to use inside the mesh before the mesh is created. Textures cannot be specified inside the mesh due to the poor memory performance that would result.

Now we add the mesh object. Three sides of the box will use individual textures while the other will use the global mesh texture.

  mesh {
    /* top side */
    triangle {
      <-10, 10, -10>, <10, 10, -10>, <10, 10, 10>
      texture { Red }
    }
    triangle {
      <-10, 10, -10>, <-10, 10, 10>, <10, 10, 10>
      texture { Red }
    }
    /* bottom side */
    triangle { <-10, -10, -10>, <10, -10, -10>, <10, -10, 10> }
    triangle { <-10, -10, -10>, <-10, -10, 10>, <10, -10, 10> }
    /* left side */
    triangle { <-10, -10, -10>, <-10, -10, 10>, <-10, 10, 10> }
    triangle { <-10, -10, -10>, <-10, 10, -10>, <-10, 10, 10> }
    /* right side */
    triangle {
      <10, -10, -10>, <10, -10, 10>, <10, 10, 10>
      texture { Green }
    }
    triangle {
      <10, -10, -10>, <10, 10, -10>, <10, 10, 10>
      texture { Green }
    }
    /* front side */
    triangle {
      <-10, -10, -10>, <10, -10, -10>, <-10, 10, -10>
      texture { Blue }
    }
    triangle {
      <-10, 10, -10>, <10, 10, -10>, <10, -10, -10>
      texture { Blue }
    }
    /* back side */
    triangle { <-10, -10, 10>, <10, -10, 10>, <-10, 10, 10> }
    triangle { <-10, 10, 10>, <10, 10, 10>, <10, -10, 10> }
    texture {
      pigment { color rgb<0.9, 0.9, 0.9> }
      finish { ambient 0.2 diffuse 0.7 }
    }
  }

Tracing the scene at 320x240 we will see that the top, right and front side of the box have different textures. Though this is not a very impressive example it shows what we can do with mesh objects. More complex examples, also using smooth triangles, can be found under the scene directory as chesmsh.pov.

2.3.2.2 Mesh2 Object

The mesh2 is a representation of a mesh, that is much more like POV-Ray's internal mesh representation than the standard mesh. As a result, it parses faster and it file size is smaller.

Due to its nature, mesh2 is not really suitable for building meshes by hand, it is intended for use by modelers and file format converters. An other option is building the meshes by macros. Yet, to understand the format, we will do a small example by hand and go through all options.

To be written as mesh2.

We will turn the mesh sketched above into a mesh2 object. The mesh is made of 8 triangles, each with 3 vertices, many of these vertices are shared among the triangles. This can later be used to optimize the mesh. First we will set it up straight forward.

In mesh2 all the vertices are listed in a list named vertex_vectors{}. A second list, face_indices{}, tells us how to put together three vertices to create one triangle, by pointing to the index number of a vertex. All lists in mesh2 are zero based, the number of the first vertex is 0. The very first item in a list is the amount of vertices, normals or uv_vectors it contains. mesh2 has to be specified in the order VECTORS..., LISTS..., INDICES....

Lets go through the mesh above, we do it counter clockwise. The total amount of vertices is 24 (8 triangle * 3 vertices).

mesh2 {
   vertex_vectors {
      24,
      ...

Now we can add the coordinates of the vertices of the first triangle:

mesh2 {
   vertex_vectors {
      24,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>
      ..

Next step, is to tell the mesh how the triangle should be created; There will be a total of 8 face_indices (8 triangles). The first point in the first face, points to the first vertex_vector (0: <0,0,0>), the second to the second (1: <0.5,0,0>), etc...

mesh2 {
   vertex_vectors {
      24,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>
      ...
   }
   face_indices {
      8,
      <0,1,2>
      ...

The complete mesh:

mesh2 {
   vertex_vectors {
      24,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>, //1
      <0.5,0,0>, <1,0,0>, <0.5,0.5,0>, //2
      <1,0,0>, <1,0.5,0>, <0.5,0.5,0>, //3
      <1,0.5,0>, <1,1,0>, <0.5,0.5,0>, //4
      <1,1,0>, <0.5,1,0>, <0.5,0.5,0>, //5
      <0.5,1,0>, <0,1,0>, <0.5,0.5,0>, //6
      <0,1,0>, <0,0.5,0>, <0.5,0.5,0>, //7
      <0,0.5,0>, <0,0,0>, <0.5,0.5,0>  //8
   }
   face_indices {
      8,
      <0,1,2>,    <3,4,5>,       //1 2
      <6,7,8>,    <9,10,11>,     //3 4
      <12,13,14>, <15,16,17>,    //5 6
      <18,19,20>, <21,22,23>     //7 8
   }
   pigment {rgb 1}
}

As mentioned earlier, many vertices are shared by triangles. We can optimize the mesh by removing all duplicate vertices but one. In the example this reduces the amount from 24 to 9.

mesh2 {
   vertex_vectors {
      9,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>,
      /*as 1*/ <1,0,0>,   /*as 2*/
      /*as 3*/ <1,0.5,0>, /*as 2*/
      /*as 4*/ <1,1,0>,   /*as 2*/
      /*as 5*/ <0.5,1,0>, /*as 2*/
      /*as 6*/ <0,1,0>,   /*as 2*/
      /*as 7*/ <0,0.5,0>, /*as 2*/
      /*as 8*/ /*as 0*/   /*as 2*/
   }
   ...
   ...

Next step is to rebuild the list of face_indices, as they now point to indices in the vertex_vector{} list that do not exist anymore.

   ...
   ...
   face_indices {
      8,
      <0,1,2>, <1,3,2>,
      <3,4,2>, <4,5,2>,
      <5,6,2>, <6,7,2>,
      <7,8,2>, <8,0,2>
   }
   pigment {rgb 1}
}
2.3.2.2.1 Smooth triangles and mesh2

In case we want a smooth mesh, the same steps we did also apply to the normals in a mesh. For each vertex there is one normal vector listed in normal_vectors{}, duplicates can be removed. If the number of normals equals the number of vertices then the normal_indices{} list is optional and the indexes from the face_indices{} list are used instead.

mesh2 {
   vertex_vectors {
      9,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>,
      <1,0,0>, <1,0.5,0>, <1,1,0>,
      <0.5,1,0>, <0,1,0>, <0,0.5,0>
   }
   normal_vectors {
      9,
     <-1,-1,0>,<0,-1,0>, <0,0,1>,
      /*as 1*/ <1,-1,0>, /*as 2*/
      /*as 3*/ <1,0,0>,  /*as 2*/
      /*as 4*/ <1,1,0>,  /*as 2*/
      /*as 5*/ <0,1,0>,  /*as 2*/
      /*as 6*/ <-1,1,0>, /*as 2*/
      /*as 7*/ <-1,0,0>, /*as 2*/
      /*as 8*/ /*as 0*/  /*as 2*/
   }
   face_indices {
      8,
      <0,1,2>, <1,3,2>,
      <3,4,2>, <4,5,2>,
      <5,6,2>, <6,7,2>,
      <7,8,2>, <8,0,2>
   }
   pigment {rgb 1}
}

When a mesh has a mix of smooth and flat triangles a list of normal_indices{} has to be added, where each entry points to what vertices a normal should be applied. In the example below only the first four normals are actually used.

mesh2 {
   vertex_vectors {
      9,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>,
      <1,0,0>, <1,0.5,0>, <1,1,0>,
      <0.5,1,0>, <0,1,0>,   <0,0.5,0>
   }
   normal_vectors {
      9,
      <-1,-1,0>, <0,-1,0>, <0,0,1>,
      <1,-1,0>, <1,0,0>, <1,1,0>,
      <0,1,0>, <-1,1,0>, <-1,0,0>
   }
   face_indices {
      8,
      <0,1,2>, <1,3,2>,
      <3,4,2>, <4,5,2>,
      <5,6,2>, <6,7,2>,
      <7,8,2>, <8,0,2>
   }
   normal_indices {
      4,
      <0,1,2>, <1,3,2>,
      <3,4,2>, <4,5,2>
   }
   pigment {rgb 1}
}
2.3.2.2.2 UV mapping and mesh2

uv_mapping is a method of 'sticking' 2D textures on an object in such a way that it follows the form of the object. For uv_mapping on triangles imagine it as follows; First you cut out a triangular section of a texture form the xy-plane. Then stretch, shrink and deform the piece of texture to fit to the triangle and stick it on.

Now, in mesh2 we first build a list of 2D-vectors that are the coordinates of the triangular sections in the xy-plane. This is the uv_vectors{} list. In the example we map the texture from the rectangular area <-0.5,-0.5>, <0.5,0.5> to the triangles in the mesh. Again we can omit all duplicate coordinates

mesh2 {
   vertex_vectors {
      9,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>,
      <1,0,0>, <1,0.5,0>, <1,1,0>,
      <0.5,1,0>, <0,1,0>,   <0,0.5,0>
   }
   uv_vectors {
      9
     <-0.5,-0.5>,<0,-0.5>,  <0,0>,
      /*as 1*/   <0.5,-0.5>,/*as 2*/
      /*as 3*/   <0.5,0>,   /*as 2*/
      /*as 4*/   <0.5,0.5>, /*as 2*/
      /*as 5*/   <0,0.5>,   /*as 2*/
      /*as 6*/   <-0.5,0.5>,/*as 2*/
      /*as 7*/   <-0.5,0>,  /*as 2*/
      /*as 8*/   /*as 0*/   /*as 2*/
   }
   face_indices {
      8,
      <0,1,2>, <1,3,2>,
      <3,4,2>, <4,5,2>,
      <5,6,2>, <6,7,2>,
      <7,8,2>, <8,0,2>
   }
   uv_mapping
   pigment {wood scale 0.2}
}

Just as with the normal_vectors, if the number of uv_vectors equals the number of vertices then the uv_indices{} list is optional and the indices from the face_indices{} list are used instead.

In contrary to the normal_indices list, if the uv_indices list is used, the amount of indices should be equal to the amount of face_indices. In the example below only 'one texture section' is specified and used on all triangles, using the uv_indices.

mesh2 {
   vertex_vectors {
      9,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>,
      <1,0,0>, <1,0.5,0>, <1,1,0>,
      <0.5,1,0>, <0,1,0>,   <0,0.5,0>
   }
   uv_vectors {
      3
      <0,0>, <0.5,0>, <0.5,0.5>
   }
   face_indices {
      8,
      <0,1,2>, <1,3,2>,
      <3,4,2>, <4,5,2>,
      <5,6,2>, <6,7,2>,
      <7,8,2>, <8,0,2>
   }
   uv_indices {
      8,
      <0,1,2>, <0,1,2>,
      <0,1,2>, <0,1,2>,
      <0,1,2>, <0,1,2>,
      <0,1,2>, <0,1,2>
   }
   uv_mapping
   pigment {gradient x scale 0.2}
}
2.3.2.2.3 A separate texture per triangle

By using the texture_list it is possible to specify a texture per triangle or even per vertex in the mesh. In the latter case the three textures per triangle will be interpolated. To let POV-Ray know what texture to apply to a triangle, the index of a texture is added to the face_indices list, after the face index it belongs to.

mesh2 {
   vertex_vectors {
      9,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>,
      <1,0,0>, <1,0.5,0>, <1,1,0>
      <0.5,1,0>, <0,1,0>, <0,0.5,0>
   }
   texture_list {
      2,
      texture{pigment{rgb<0,0,1>}}
      texture{pigment{rgb<1,0,0>}}
   }
   face_indices {
      8,
      <0,1,2>,0,  <1,3,2>,1,
      <3,4,2>,0,  <4,5,2>,1,
      <5,6,2>,0,  <6,7,2>,1,
      <7,8,2>,0,  <8,0,2>,1
   }
}

To specify a texture per vertex, three texture_list indices are added after the face_indices

mesh2 {
   vertex_vectors {
      9,
      <0,0,0>, <0.5,0,0>, <0.5,0.5,0>,
      <1,0,0>, <1,0.5,0>, <1,1,0>
      <0.5,1,0>, <0,1,0>, <0,0.5,0>
   }
   texture_list {
      3,
      texture{pigment{rgb <0,0,1>}}
      texture{pigment{rgb 1}}
      texture{pigment{rgb <1,0,0>}}
   }
   face_indices {
      8,
      <0,1,2>,0,1,2,  <1,3,2>,1,0,2,
      <3,4,2>,0,1,2,  <4,5,2>,1,0,2,
      <5,6,2>,0,1,2,  <6,7,2>,1,0,2,
      <7,8,2>,0,1,2,  <8,0,2>,1,0,2
   }
}

Assigning a texture based on the texture_list and texture interpolation is done on a per triangle base. So it is possible to mix triangles with just one texture and triangles with three textures in a mesh. It is even possible to mix in triangles without any texture indices, these will get their texture from a general texture statement in the mesh2. uv_mapping is supported for texturing using a texture_list.

2.3.2.3 Polygon Object

The polygon object can be used to create any planar, n-sided shapes like squares, rectangles, pentagons, hexagons, octagons, etc.

A polygon is defined by a number of points that describe its shape. Since polygons have to be closed the first point has to be repeated at the end of the point sequence.

In the following example we will create the word "POV" using just one polygon statement.

We start with thinking about the points we need to describe the desired shape. We want the letters to lie in the x-y-plane with the letter O being at the center. The letters extend from y=0 to y=1. Thus we get the following points for each letter (the z coordinate is automatically set to zero).

Letter P (outer polygon):

    <-0.8, 0.0>, <-0.8, 1.0>,
    <-0.3, 1.0>, <-0.3, 0.5>,
    <-0.7, 0.5>, <-0.7, 0.0>

Letter P (inner polygon):

    <-0.7, 0.6>, <-0.7, 0.9>,
    <-0.4, 0.9>, <-0.4, 0.6>

Letter O (outer polygon):

    <-0.25, 0.0>, <-0.25, 1.0>,
    < 0.25, 1.0>, < 0.25, 0.0>

Letter O (inner polygon):

    <-0.15, 0.1>, <-0.15, 0.9>,
    < 0.15, 0.9>, < 0.15, 0.1>

Letter V:

    <0.45, 0.0>, <0.30, 1.0>,
    <0.40, 1.0>, <0.55, 0.1>,
    <0.70, 1.0>, <0.80, 1.0>,
    <0.65, 0.0>

Both letters P and O have a hole while the letter V consists of only one polygon. We will start with the letter V because it is easier to define than the other two letters.

We create a new file called polygdem.pov and add the following text.

  camera {
    orthographic
    location <0, 0, -10>
    right 1.3 * 4/3 * x
    up 1.3 * y
    look_at <0, 0.5, 0>
  }
  light_source { <25, 25, -100> color rgb 1 }
  polygon {
    8,
    <0.45, 0.0>, <0.30, 1.0>, // Letter "V"
    <0.40, 1.0>, <0.55, 0.1>,
    <0.70, 1.0>, <0.80, 1.0>,
    <0.65, 0.0>,
    <0.45, 0.0>
    pigment { color rgb <1, 0, 0> }
  }

As noted above the polygon has to be closed by appending the first point to the point sequence. A closed polygon is always defined by a sequence of points that ends when a point is the same as the first point.

After we have created the letter V we will continue with the letter P. Since it has a hole we have to find a way of cutting this hole into the basic shape. This is quite easy. We just define the outer shape of the letter P, which is a closed polygon, and add the sequence of points that describes the hole, which is also a closed polygon. That is all we have to do. There will be a hole where both polygons overlap.

In general we will get holes whenever an even number of sub-polygons inside a single polygon statement overlap. A sub-polygon is defined by a closed sequence of points.

The letter P consists of two sub-polygons, one for the outer shape and one for the hole. Since the hole polygon overlaps the outer shape polygon we will get a hole.

After we have understood how multiple sub-polygons in a single polygon statement work, it is quite easy to add the missing O letter.

Finally, we get the complete word POV.

  polygon {
    30,
    <-0.8, 0.0>, <-0.8, 1.0>,    // Letter "P"
    <-0.3, 1.0>, <-0.3, 0.5>,    // outer shape
    <-0.7, 0.5>, <-0.7, 0.0>,
    <-0.8, 0.0>,
    <-0.7, 0.6>, <-0.7, 0.9>,    // hole
    <-0.4, 0.9>, <-0.4, 0.6>,
    <-0.7, 0.6>
    <-0.25, 0.0>, <-0.25, 1.0>,  // Letter "O"
    < 0.25, 1.0>, < 0.25, 0.0>,  // outer shape
    <-0.25, 0.0>,
    <-0.15, 0.1>, <-0.15, 0.9>,  // hole
    < 0.15, 0.9>, < 0.15, 0.1>,
    <-0.15, 0.1>,
    <0.45, 0.0>, <0.30, 1.0>,    // Letter "V"
    <0.40, 1.0>, <0.55, 0.1>,
    <0.70, 1.0>, <0.80, 1.0>,
    <0.65, 0.0>,
    <0.45, 0.0>
    pigment { color rgb <1, 0, 0> }
  }

The word "POV" made with one polygon statement.

2.3.3 Other Shapes

2.3.3.1 Blob Object

Blobs are described as spheres and cylinders covered with goo which stretches to smoothly join them (see section Blob).

Ideal for modeling atoms and molecules, blobs are also powerful tools for creating many smooth flowing organic shapes.

A slightly more mathematical way of describing a blob would be to say that it is one object made up of two or more component pieces. Each piece is really an invisible field of force which starts out at a particular strength and falls off smoothly to zero at a given radius. Where ever these components overlap in space, their field strength gets added together (and yes, we can have negative strength which gets subtracted out of the total as well). We could have just one component in a blob, but except for seeing what it looks like there is little point, since the real beauty of blobs is the way the components interact with one another.

Let us take a simple example blob to start. Now, in fact there are a couple different types of components but we will look at them a little later. For the sake of a simple first example, let us just talk about spherical components. Here is a sample POV-Ray code showing a basic camera, light, and a simple two component blob:

  #include "colors.inc"
  background{White}
  camera {
    angle 15
    location <0,2,-10>
    look_at <0,0,0>
  }
  light_source { <10, 20, -10> color White }
  blob {
    threshold .65
    sphere { <.5,0,0>, .8, 1 pigment {Blue} }
    sphere { <-.5,0,0>,.8, 1 pigment {Pink} }
    finish { phong 1 }
  }

A simple, two-part blob.

The threshold is simply the overall strength value at which the blob becomes visible. Any points within the blob where the strength matches the threshold exactly form the surface of the blob shape. Those less than the threshold are outside and those greater than are inside the blob.

We note that the spherical component looks a lot like a simple sphere object. We have the sphere keyword, the vector representing the location of the center of the sphere and the float representing the radius of the sphere. But what is that last float value? That is the individual strength of that component. In a spherical component, that is how strong the component's field is at the center of the sphere. It will fall off in a linear progression until it reaches exactly zero at the radius of the sphere.

Before we render this test image, we note that we have given each component a different pigment. POV-Ray allows blob components to be given separate textures. We have done this here to make it clearer which parts of the blob are which. We can also texture the whole blob as one, like the finish statement at the end, which applies to all components since it appears at the end, outside of all the components. We render the scene and get a basic kissing spheres type blob.

The image we see shows the spheres on either side, but they are smoothly joined by that bridge section in the center. This bridge represents where the two fields overlap, and therefore stay above the threshold for longer than elsewhere in the blob. If that is not totally clear, we add the following two objects to our scene and re-render. We note that these are meant to be entered as separate sphere objects, not more components in the blob.

  sphere { <.5,0,0>, .8
    pigment { Yellow transmit .75 }
  }
  sphere { <-.5,0,0>, .8
    pigment { Green transmit .75 }
  }

The spherical components made visible.

Now the secrets of the kissing spheres are laid bare. These semi-transparent spheres show where the components of the blob actually are. If we have not worked with blobs before, we might be surprised to see that the spheres we just added extend way farther out than the spheres that actually show up on the blobs. That of course is because our spheres have been assigned a starting strength of one, which gradually fades to zero as we move away from the sphere's center. When the strength drops below the threshold (in this case 0.65) the rest of the sphere becomes part of the outside of the blob and therefore is not visible.

See the part where the two transparent spheres overlap? We note that it exactly corresponds to the bridge between the two spheres. That is the region where the two components are both contributing to the overall strength of the blob at that point. That is why the bridge appears: that region has a high enough strength to stay over the threshold, due to the fact that the combined strength of two spherical components is overlapping there.

2.3.3.1.1 Component Types and Other New Features

The shape shown so far is interesting, but limited. POV-Ray has a few extra tricks that extend its range of usefulness however. For example, as we have seen, we can assign individual textures to blob components, we can also apply individual transformations (translate, rotate and scale) to stretch, twist, and squash pieces of the blob as we require. And perhaps most interestingly, the blob code has been extended to allow cylindrical components.

Before we move on to cylinders, it should perhaps be mentioned that the old style of components used in previous versions of POV-Ray still work. Back then, all components were spheres, so it was not necessary to say sphere or cylinder. An old style component had the form:

component Strength, Radius, <Center>

This has the same effect as a spherical component, just as we already saw above. This is only useful for backwards compatibility. If we already have POV-Ray files with blobs from earlier versions, this is when we would need to recognize these components. We note that the old style components did not put braces around the strength, radius and center, and of course, we cannot independently transform or texture them. Therefore if we are modifying an older work into a new version, it may arguably be of benefit to convert old style components into spherical components anyway.

Now for something new and different: cylindrical components. It could be argued that all we ever needed to do to make a roughly cylindrical portion of a blob was string a line of spherical components together along a straight line. Which is fine, if we like having extra to type, and also assuming that the cylinder was oriented along an axis. If not, we would have to work out the mathematical position of each component to keep it is a straight line. But no more! Cylindrical components have arrived.

We replace the blob in our last example with the following and re-render. We can get rid of the transparent spheres too, by the way.

  blob {
    threshold .65
    cylinder { <-.75,-.75,0>, <.75,.75,0>, .5, 1 }
    pigment { Blue }
    finish { phong 1 }
  }

We only have one component so that we can see the basic shape of the cylindrical component. It is not quite a true cylinder - more of a sausage shape, being a cylinder capped by two hemispheres. We think of it as if it were an array of spherical components all closely strung along a straight line.

As for the component declaration itself: simple, logical, exactly as we would expect it to look (assuming we have been awake so far): it looks pretty much like the declaration of a cylinder object, with vectors specifying the two endpoints and a float giving the radius of the cylinder. The last float, of course, is the strength of the component. Just as with spherical components, the strength will determine the nature and degree of this component's interaction with its fellow components. In fact, next let us give this fellow something to interact with, shall we?

2.3.3.1.2 Complex Blob Constructs and Negative Strength

Beginning a new POV-Ray file, we enter this somewhat more complex example:

#include "colors.inc"
background{White}
camera {
  angle 20
  location<0,2,-10>
  look_at<0,0,0>
}
light_source { <10, 20, -10> color White }
blob {
  threshold .65
  sphere{<-.23,-.32,0>,.43, 1 scale <1.95,1.05,.8>}   //palm
  sphere{<+.12,-.41,0>,.43, 1 scale <1.95,1.075,.8>}  //palm
  sphere{<-.23,-.63,0>, .45, .75 scale <1.78, 1.3,1>} //midhand
  sphere{<+.19,-.63,0>, .45, .75 scale <1.78, 1.3,1>} //midhand
  sphere{<-.22,-.73,0>, .45, .85 scale <1.4, 1.25,1>} //heel
  sphere{<+.19,-.73,0>, .45, .85 scale <1.4, 1.25,1>} //heel
  cylinder{<-.65,-.28,0>, <-.65,.28,-.05>, .26, 1}    //lower pinky
  cylinder{<-.65,.28,-.05>, <-.65, .68,-.2>, .26, 1}  //upper pinky
  cylinder{<-.3,-.28,0>, <-.3,.44,-.05>, .26, 1}      //lower ring
  cylinder{<-.3,.44,-.05>, <-.3, .9,-.2>, .26, 1}     //upper ring
  cylinder{<.05,-.28,0>, <.05, .49,-.05>, .26, 1}     //lower middle
  cylinder{<.05,.49,-.05>, <.05, .95,-.2>, .26, 1}    //upper middle
  cylinder{<.4,-.4,0>, <.4, .512, -.05>, .26, 1}      //lower index
  cylinder{<.4,.512,-.05>, <.4, .85, -.2>, .26, 1}    //upper index
  cylinder{<.41, -.95,0>, <.85, -.68, -.05>, .25, 1}  //lower thumb
  cylinder{<.85,-.68,-.05>, <1.2, -.4, -.2>, .25, 1}  //upper thumb
  pigment{ Flesh }
}

A hand made with blobs.

As we can guess from the comments, we are building a hand here. After we render this image, we can see there are a few problems with it. The palm and heel of the hand would look more realistic if we used a couple dozen smaller components rather than the half dozen larger ones we have used, and each finger should have three segments instead of two, but for the sake of a simplified demonstration, we can overlook these points. But there is one thing we really need to address here: This poor fellow appears to have horrible painful swelling of the joints!

A review of what we know of blobs will quickly reveal what went wrong. The joints are places where the blob components overlap, therefore the combined strength of both components at that point causes the surface to extend further out, since it stays over the threshold longer. To fix this, what we need are components corresponding to the overlap region which have a negative strength to counteract part of the combined field strength. We add the following components to our blob.

sphere{<-.65,.28,-.05>, .26, -1} //counteract pinky knucklebulge
sphere{<-.65,-.28,0>, .26, -1}   //counteract pinky palm bulge
sphere{<-.3,.44,-.05>, .26, -1}  //counteract ring knuckle bulge
sphere{<-.3,-.28,0>, .26, -1}    //counteract ring palm bulge
sphere{<.05,.49,-.05>, .26, -1}  //counteract middle knuckle bulge
sphere{<.05,-.28,0>, .26, -1}    //counteract middle palm bulge
sphere{<.4,.512,-.05>, .26, -1}  //counteract index knuckle bulge
sphere{<.4,-.4,0>, .26, -1}      //counteract index palm bulge
sphere{<.85,-.68,-.05>, .25, -1} //counteract thumb knuckle bulge
sphere{<.41,-.7,0>, .25, -.89}   //counteract thumb heel bulge

The hand without the swollen joints.

Much better! The negative strength of the spherical components counteracts approximately half of the field strength at the points where to components overlap, so the ugly, unrealistic (and painful looking) bulging is cut out making our hand considerably improved. While we could probably make a yet more realistic hand with a couple dozen additional components, what we get this time is a considerable improvement. Any by now, we have enough basic knowledge of blob mechanics to make a wide array of smooth, flowing organic shapes!

2.3.3.2 Height Field Object

A height_field is an object that has a surface that is determined by the color value or palette index number of an image designed for that purpose. With height fields, realistic mountains and other types of terrain can easily be made. First, we need an image from which to create the height field. It just so happens that POV-Ray is ideal for creating such an image.

We make a new file called image.pov and edit it to contain the following:

  #include "colors.inc"
  global_settings {
    assumed_gamma 2.2
    hf_gray_16
  }

The hf_gray_16 keyword causes the output to be in a special 16 bit grayscale that is perfect for generating height fields. The normal 8 bit output will lead to less smooth surfaces.

Now we create a camera positioned so that it points directly down the z-axis at the origin.

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

We then create a plane positioned like a wall at z=0. This plane will completely fill the screen. It will be colored with white and gray wrinkles.

  plane { z, 10
    pigment {
      wrinkles
      color_map {
       [0 0.3*White]
       [1 White]
      }
    }
  }

Finally, create a light source.

  light_source { <0, 20, -100> color White }

We render this scene at 640x480 +A0.1 +FT. We will get an image that will produce an excellent height field. We create a new file called hfdemo.pov and edit it as follows:

Note: Unless you specify +FT as above, you will get a PNG file, the default cross-platform output file type. In this case you will need to use png instead of tga in the height_field statement below.

  #include "colors.inc"

We add a camera that is two units above the origin and ten units back ...

  camera{
    location <0, 2, -10>
    look_at 0
    angle 30
  }

... and a light source.

  light_source{ <1000,1000,-1000> White }

Now we add the height field. In the following syntax, a Targa image file is specified, the height field is smoothed, it is given a simple white pigment, it is translated to center it around the origin and it is scaled so that it resembles mountains and fills the screen.

  height_field {
    tga "image.tga"
    smooth
    pigment { White }
    translate <-.5, -.5, -.5>
    scale <17, 1.75, 17>
  }

We save the file and render it at 320x240 -A. Later, when we are satisfied that the height field is the way we want it, we render it at a higher resolution with anti-aliasing.

A height field created completely with POV-Ray.

Wow! The Himalayas have come to our computer screen!

2.3.3.3 Isosurface Object

Isosurfaces are shapes described by mathematical functions.

In contrast to the other mathematically based shapes in POV-Ray, isosurfaces are approximated during rendering and therefore they are sometimes more difficult to handle. However, they offer many interesting possibilities, like real deformations and surface displacements

Some knowledge about mathematical functions and geometry is useful, but not necessarily required to work with isosurfaces.

2.3.3.3.1 Simple functions

Let's begin with something simple. In this first series of images, let's explore the user defined function shown as function { x } that we see in the code example below. It produces the first image on the left, a simple box. The container, which is a requirement for the isosurface object, is represented by the box object and the contained_by keyword in the isosurface definition.

  isosurface {
    function { x }
    contained_by { box { -2, 2 } }
  }

You should have also noticed that in the image on the left, only half the box was produced, that's because the threshold keyword was omitted, so the default value 0 was used to evaluate the x-coordinate.

In this next code example threshold 1 was added to produce the center image.

  isosurface {
    function { x }
    threshold 1
    contained_by { box { -2, 2 } }
  }

It is also possible to remove the visible surfaces of the container by adding the open keyword to the isosurface definition.

For the final image on the right, the following code example was used. Notice that the omission of the threshold keyword causes the x-coordinate to be again evaluated to zero.

  isosurface {
    function { x }
    open
    contained_by { box { -2, 2 } }
  }

function { x } | function { x } with threshold 1 | function { x } with open

Hint: The checkered ground plane is scaled to one unit squares.

For the last series of images in this section, let's try something different. These next two code examples were used to show the results of changing the user defined function to function { x+y } and function { x+y+z } respectively. They describe planes going through the origin, the function just describes the normal vector of the plane.

  isosurface {
    function { x+y }
    max_gradient 4
    contained_by { box { -2, 2 } }
  }

Note: To properly render these examples max_gradient 4 was added to the isosurface definition, and will be explained later.

  isosurface {
    function { x+y+z }
    max_gradient 4
    contained_by { box { -2, 2 } }
  }

plane function { x+y } | plane function { x+y+z }

Note: When appropriate, to better visualize the difference between the isosurface and the container object, the images in this tutorial have been color coded.

2.3.3.3.2 Several surfaces

Now that you're starting to become familiar with isosurface syntax, there really isn't any need to show a code example for each and every image. You can always look back at the earlier examples when needed. The image captions will most often contain additional keyword hints when appropriate.

Note: The user defined function portion will always use this color coded format: function { x+y+z }

For the first image on the left, these two functions lead to identical results: function { abs(x)-1 } and function { sqrt(x*x)-1 } because both of these formulas have the same solution where the function value is 0, specifically x=-1 and x=1 in this example.

You can easily mix any of these elements in different combinations, but the results always produce planar surfaces. The last two images in this series used function { abs(x)-1+y } and function { abs(x)+abs(y)+abs(z)-2 } respectively.

identical results with open | linear functions x & y axis | linear functions x, y & z axis
2.3.3.3.3 Non-linear functions
 | Curved surfaces of many different kinds can be achieved with non-linear functions. A square function creates the parabolic shape: function { pow(x,2)+y }
a parabolic shape |
If you describe a circle in 2 dimensions with a constant in the 3rd dimension you get a cylinder: function { sqrt(pow(x,2)+pow(z,2))-1 } |
 | the cylinder shape
 | It's easy to change a cylinder into a cone, we just need to add a linear component in y-direction: function { sqrt(pow(x,2)+pow(z,2))+y }
the cone shape |
No worries, creating a sphere is easy too. In this example 2 specifies the radius: function { sqrt(pow(x,2)+pow(y,2)+pow(z,2))-2 } |
 | the sphere shape
2.3.3.3.4 Specifying functions

Until now, we have seen, the functions used to define the isosurface were literally written in the function {...} block:

#declare Threshold = 1;

isosurface {
function {pow(x,2) + pow(y,2) + pow(z,2)}
  threshold Threshold
  ...
}

Let's expand on that concept, and add some flexibility. Remember that user defined functions (like equations), all float expressions and operators which are legal in POV-Ray can be used, and that functions should be declared first, and then used in the isosurface. See the section user defined function for more information.

This next example takes the above equation, and rewrites it as a user defined function. By default a function that takes three parameters (x,y,z) does not require you to explicitly specify the parameter names when declaring it, however when using the identifier, the parameters must be specified.

#declare Threshold = 1;

#declare Sphere = function {pow(x,2) + pow(y,2) + pow(z,2)};

isosurface {
  function { Sphere(x,y,z) }
  threshold Threshold
  ...
}

However, if you need more or less than three parameters when declaring a function, you will also have to explicitly specify the parameter names.

#declare Sphere = function (x,y,z,Radius) {pow(x,2) + pow(y,2) + pow(z,2) - pow(Radius,2)};

isosurface {
  function { Sphere(x,y,z,1) }
  ...
}
2.3.3.3.5 Internal functions

There are a lot of internal functions available in POV-Ray. For example a sphere could also be generated with function { f_sphere(x, y, z, 2) }, for these and other functions, see the functions.inc include file. Most of them are more complicated and it is usually faster to use them instead of a hand coded equivalent.

See the complete list for details.

The following makes a torus just like POV-Ray's torus object:

  #include "functions.inc"

  isosurface {
    function { f_torus(x, y, z, 1.6, 0.4) }
    contained_by { box { -2, 2 } }
  }

The 4th and 5th parameters are the major and minor radius, just like the corresponding values in the torus{} object.

The parameters x, y and z are required, because it is a declared function. You can also declare functions yourself like it is explained in the reference section.

the torus function
2.3.3.3.6 Combining isosurface functions

We can also simulate some Constructive Solid Geometry with isosurface functions. If you do not know about CSG we suggest you have a look at What is CSG? or the corresponding part of the reference section first.

For this next group of images, consider the two functions for a cylinder and a rotated box:

  #declare fn_A = function { sqrt(pow(y,2) + pow(z,2)) - 0.8 }
  #declare fn_B = function { abs(x)+abs(y)-1 }
  1. If we combine them the following way, we get a merge:
    function { min(fn_A(x, y, z), fn_B(x, y, z)) }
  2. An intersection can be obtained by using max() instead of min():
    function { max(fn_A(x, y, z), fn_B(x, y, z)) }
  3. A difference is possible, by adding a minus (-) before the second function:
    function { max(fn_A(x, y, z), -fn_B(x, y, z)) }
merge example | intersection example | difference example

Apart from basic CSG you can also obtain smooth transits between the different surfaces, for instance the blob object:

  #declare Blob_Threshold=0.01;

  isosurface {
    function {
      (1+Blob_Threshold)
      -pow(Blob_Threshold, fn_A(x,y,z))
      -pow(Blob_Threshold, fn_B(x,y,z))
    }
    max_gradient 4
    contained_by { box { -2, 2 } }
  }

The Blob_Threshold value influences the smoothness of the transit between the shapes. A lower value leads to sharper edges, and it's function looks like:

function{fn_A(x,y,z) + pow(Blob_Threshold,(fn_B(x,y,z) + Strength))}

smooth transitions using blob
2.3.3.3.7 Noise and pigment functions

Some of the internal functions have a random or noise-like structure

Together with the pigment functions they are one of the most powerful tools for designing isosurfaces. We can add real surface displacement to the objects rather than only normal perturbation known from the normal statement.

The relevant internal functions are:

  • f_noise3d(x,y,z)
    uses the noise generator specified in global_settings and generates structures like the bozo pattern.
  • f_noise_generator(x, y, z, noise_generator)
    generates noise with a specified noise generator.
  • f_ridged_mf(x, y, z, H, Lacunarity, Octaves, Offset, Gain, noise_generator)
    generates a ridged multifractal pattern.
  • f_ridge(x, y, z, Lambda, Octaves, Omega, Offset, Ridge, noise_generator)
    generates another noise with ridges.
  • f_hetero_mf(x, y, z, H, Lacunarity, Octaves, Offset, T, noise_generator)
    generates heterogenic multifractal noise.
Using this simple noise3d function results in the image on the right. The value -0.5 matches the default threshold value of zero. The f_noise3d function returns values between 0 and 1: function { f_noise3d(x,y,z)-0.5 } |
 | simple noise3d function

In these next two images the noise function was added to a plane function. The x-parameter was set to 0 so the noise function is constant in x-direction. This way we achieve the typical heightfield structure.

 | With this and the other functions you can generate objects similar to heightfields, having the advantage that a high resolution can be achieved without high memory requirements: function { x + f_noise3d(0,y,z) }
a noise3d heightfield |
The noise function can of course also be subtracted which results in an inverted version: function { x - f_noise3d(0,y,z) } |
 | a noise3d heightfield - inverted
 | Of course we can also add noise to any other function. If the noise function is very strong this can result in several separated surfaces. function { f_sphere(x,y,z,1.2) - f_noise3d(x,y,z) }
noise3d on a sphere |

This is a noise function applied to a sphere surface, we can influence the intensity of the noise by multiplying it with a factor and change the scale by multiplying the coordinate parameters:

function {
  f_sphere(x,y,z,1.6) -
    f_noise3d(x*5,y*5,z* ) * 0.5
    }

noise3d on a sphere - scaled

As alternative to noise functions we can also use any pigment in a function:

  #declare fn_Pigm=function {
    pigment {
      agate
      color_map {
        [0 color rgb 0]
        [1 color rgb 1]
      }
    }
  }

This is a vector function, it returns a color vector for use in isosurface functions. They must be pre-declared first. When using the identifier, you have to specify which component of the color vector should be used.

To do this, the dot notation is used. Refer to the above example: fn_Pigm(x,y,z).red

A color vector has five components, their supported dot types to access these components are:

  1. fn_Pigm( ).x | fn_Pigm( ).u | fn_Pigm( ).red
    to get the red value of the color vector
  2. fn_Pigm( ).y | fn_Pigm( ).v | fn_Pigm( ).green
    to get the green value of the color vector
  3. fn_Pigm( ).z | fn_Pigm( ).blue
    to get the blue value of the color vector
  4. fn_Pigm( ).filter | fn_Pigm( ).f
    to get the filter value of the color vector
  5. fn_Pigm( ).transmit | fn_Pigm( ).t
    to get the transmit value of the color vector

And two special purpose operators, their supported dot types to access these operators are:

Note: The .hf operator is experimental and will generate a warning.

  1. fn_Pigm( ).gray to get the gray value of the color vector
    gray value = Red*29.7% + Green*58.9% + Blue*11.4%
  2. fn_Pigm( ).hf to get the height_field value of the color vector
    hf value = (Red + Green/255)*0.996093

There are quite a lot of things possible with pigment functions. However, it should be noted that, some functions can cause longer render times:

function {
  f_sphere(x, y, z, 1.6) -
    fn_Pigm(x/2, y/2, z/2).gray*0.5
    }

noise using a pigment function
2.3.3.3.8 Conditional directives and loops

Conditional directives are allowed in functions:

#declare Rough = yes;
#include "functions.inc"
isosurface {
  function { y #if(Rough=1)-f_noise3d(x/0.5,y/0.3,z/0.4)*0.8 #end }
  ...
}

Loops can also be used in functions:

#include "functions.inc"
#declare Thr = 1/1000;
#declare Ang = radians(45);
#declare Offset = 1.5;
#declare Scale = 1.2;
#declare TrSph = function { f_sphere(x-Offset,y,z,0.7*Scale) }

function {
  (1-Thr)
  #declare A = 0;
  #while (A<8)
  -pow(Thr, TrSph(x*cos(A*Ang) + y*sin(A*Ang),
                  y*cos(A*Ang) -x*sin(A*Ang), z) )
    #declare A=A+1;
  #end
}

Note: The loops and conditionals are evaluated at parse time, not at render time.

2.3.3.3.9 Transformations on functions

Transforming an isosurface object is done like transforming any POV-Ray object. Simply use the object modifiers, scale, translate, and rotate. However, when you want to transform functions within the contained_by object, you have to substitute parameters in the functions.

The results seem inverted to what you would normally expect, here's why:

Remember the sphere function we created earlier in this tutorial: Sphere(x,y,z)

We know it sits at the origin because x=0. If we want to translate it 2 units to the right to x=2 we need to write the second equation in the same form: x-2=0. Now that both equations equal zero, we can replace the parameter x with x-2, call our function as: Sphere(x-2,y,z) and it's translated two units to the right.

Let's look at how to scale our test sphere by 0.5 in the y direction. Given the default value of y=1 one unit we'd want y=0.5. To do this we need to have the equation in the same form as the first one, so we'll multiply both sides by two: y*2 = 0.5*2 which gives y*2=1.

Now we can replace the y parameter in our sphere: Sphere(x,y*2,z). This scales the y-size of the sphere by half.

Here is an overview of some useful substitutions, we'll be using a pseudo-object designated as P(x,y,z) in the following examples:

Scale:

To scale x replace x with x/scale:
P(x/2,y,z)

Scale Infinitely:

To scale y infinitely replace y with 0:
P(x,0,z)

Translate:

To translate z replace z with z - translation:
P(x,y,z-3)

Shear:

To shear in xy-plane replace x with x + y*tan(radians(Angle)):
P(x+y*tan(radians(Angle)),y,z)

Rotate:

Note: These rotation substitutions work like normal POV-rotations, they already compensate for the inverse behavior.

To rotate around the X-axis:

replace y with z*sin(radians(Angle)) + y*cos(radians(Angle))

replace z with z*cos(radians(Angle)) - y*sin(radians(Angle))

To rotate around the Y-axis:

replace x with x*cos(radians(Angle)) - z*sin(radians(Angle))

replace z with x*sin(radians(Angle)) + z*cos(radians(Angle))

To rotate around the Z-axis:

replace x with x*cos(radians(Angle)) + y*sin(radians(Angle))

replace y with -x*sin(radians(Angle)) + y*cos(radians(Angle))

Flip:

To flip X - Y:

replace x with y AND replace y with -x

To flip Y - Z:

replace y with z AND replace z with -y

To flip X - Z:

replace x with -z AND replace z with x

Twist:

To twist N turns/unit around the x axis:

replace y with z*sin(x*2*pi*N) + y*cos(x*2*pi*N)

replace z with z*cos(x*2*pi*N) - y*sin(x*2*pi*N)

2.3.3.3.10 Improving Isosurface Speed

To optimize the approximation of the isosurface and to get maximum rendering speed it is important to adapt certain values:

accuracy:

The accuracy value influences how accurate the surface geometry is calculated. Lower values lead to a more precise, but slower result. The default value of 0.001 is fairly low. We used this value in all the previous samples, but often you can raise this quite a lot and thereby make things faster.

max_gradient:

For finding the actual surface it is important for POV-Ray to know the maximum gradient of the function, meaning how fast the function value changes. We can specify a value with the max_gradient keyword. Lower max_gradient values lead to faster rendering, but if the specified value is below the actual maximum gradient of the function, there can be holes or other artefact's in the surface.

For the same reason functions with an infinite gradient should not be used. This applies for pigment functions with brick or checker patterns for example. You should also be careful when using select() in isosurface functions because of this.

If the real maximum gradient differs too much from the specified value POV-Ray issues a warning together with the found maximum gradient. It is usually sufficient to use this number for the max_gradient parameter to get fast and correct results.

POV-Ray can also dynamically change the max_gradient when you specify evaluate with 3 parameters in the isosurface definition. Concerning the details on this and other things see the evaluate keyword in the reference section.

contained_by:

Make sure your contained_by object fits as tightly as possible. An oversized container can sky-rocket the render time. When the container has a lot of empty space around the actual isosurface, POV-Ray has to do a lot of superfluous sampling: especially with complex functions this can become very time consuming. On top of this, the max_gradient needed to get a proper surface will also increase rapidly, almost proportional to the oversize! You could use a transparent copy of the container (using exactly the same transformations) to check how it fits. Getting the min_extent and max_extent of the isosurface is not useful because it only gives the extent of the container and not of the actual isosurface.

2.3.3.4 Poly Object

The polynomial object (and its shortcut versions: cubic, quartic and quadric) of POV-Ray is one of the most complex and mathematical primitives of the program. One could think that it is seldom used and more or less obsolete, but we have to remember that for example the torus primitive is just a shortcut for the equivalent quartic, which is just a shortcut for the equivalent poly object. Polys are, however, seldom used in scenes due to the fact that they are so difficult to define and it is far from trivial to get the desired shape with just a polynomial equation. It is mostly used by the most mathematically oriented POV-Ray users.

This tutorial explains the process of making a polynomial object in POV-Ray.

Note: Since version 3.5, POV-Ray includes the new isosurface object which makes the polynomial object more or less obsolete. The isosurface is more versatile (you can specify any mathematical function, not just polynomials) and easier to use. You can write the function as is, without needing to put values in a gigantic vector. Isosurfaces also often (although not always) render considerably faster than equivalent polys.

However, the most mathematically oriented still like polys because isosurfaces are calculated just by approximating the right value, while the poly is calculated in a mathematically exact way. Usually isosurfaces are more than good enough for most applications, though.

Note: A maximum of 35th degree polynomial can be represented with the poly object. If a higher degree polynomial or other non-polynomial function has to be represented, then it is necessary to use the isosurface object.

2.3.3.4.1 Creating the polynomial function

The first step is to create the polynomial function to be represented. You will need some (high-school level) mathematical knowledge for this.

1) Let's start with an easy example, a sphere:

The sphere function is:

sphere function

Now we have to convert this to polynomial form, we will need a polynomial of the 2nd degree to represent this:

sphere polynomial

2) A more elaborated example:

Let's take the function:

function

Converting this to polynomial form we get:

polynomial

Although the highest power is 4 we will need a 5th order polynomial to represent this function (because we cannot represent y4z with a 4th order polynomial).

3) And since we talked about the torus, let's also take it as an example.

A torus can be represented with the function:

torus function

where r1 is the major radius and r2 is the minor radius.

Now, this is tougher to convert to polynomial form, but finally we get:

torus polynomial

A 4th order polynomial is enough to represent this.

Note: Not every function can be represented in polynomial form. Only functions that use addition (and substraction), multiplication (and division) and scalar powers (including rational powers, eg. the square root) can be represented. Also, the poly primitive supports only polynomials of the 35th degree at max.

Converting a function to polynomial form may be a very laborious task for certain functions. Some mathematical programs are very helpful in this matter.

2.3.3.4.2 Writing the polynomial vector

Now that we have the function in polynomial form, we have to write it in POV-Ray syntax. The syntax is specified in the sections on polynomial and quadric of the reference section. There is also a table in this chapter which we will be using to make the polynomial vector. It is easier to have this table printed on paper.

Note: It is also possible to make a little program with your favorite programming language which will print the poly vector from the polynomial function, but making a program like this is up to you.

1) Let's start with the easy one, ie. the sphere.

Since the sphere can be represented with a polynomial of 2nd degree, we look at the column titled 2nd in the table. We see that it has 10 items, ie. we need a vector of size 10. Each item of the vector will be the factor of the term listed in the table.

The polynomial was:

sphere polynomial function

Writing the poly in this way we get:

#declare Radius=1;
poly
{ 2,
  <1,0,0,0,1,
   0,0,1,0,-Radius*Radius>
}

Put each group of factors (separated with lines in the table) in their own lines.

In the table we see that the first item is the factor for x2, which is 1 in the function. The next item is xy. Since it is not in the function, its factor is 0. Likewise the next item, which is xz. And so on. The last item is the scalar term, which is in this case -r2.

If we make a proper scene and render it, we get:

camera { location y*4-z*5 look_at 0 angle 35 }
light_source { <100,200,-50> 1 }
background { rgb <0,.25,.5> }

#declare Radius=1;
poly
{ 2,
  <1,0,0,0,1,
   0,0,1,0,-Radius*Radius>
  pigment { rgb <1,.7,.3> } finish { specular .5 }
}

sphere polynomial image

Note: There is a shortcut for 2nd degree polynomials: The quadric primitive. Using a shortcut version, whenever possible, can lead to faster renderings. We can write the sphere code described above in the following way:

quadric
{ <1,1,1>, <0,0,0>, <0,0,0>, -Radius*Radius
  pigment { rgb <1,.7,.3> } finish { specular .5 }
}

2) Now lets try the second one. We do it similarly, but this time we need to look at the column titled 5th in the table.

The polynomial was:

5th order polynomial function

Writing the poly primitive we get:

poly
{ 5,
  <0,0,0,0,0,
   0,0,0,0,0,
   0,0,0,0,0,
   0,0,0,1,0,
   0,0,0,0,0,
   -2,0,0,0,0,
   0,0,0,0,0,
   0,1,0,0,0,
   0,0,0,0,0,
   0,0,0,0,0,
   0,0,0,0,0,0>
}

With the proper scene we get:

camera { location <8,20,-10>*.7 look_at x*.01 angle 35 }
light_source { <100,200,20> 1 }
background { rgb <0,.25,.5> }

poly
{ 5,
  <0,0,0,0,0,
   0,0,0,0,0,
   0,0,0,0,0,
   0,0,0,1,0,
   0,0,0,0,0,
   -2,0,0,0,0,
   0,0,0,0,0,
   0,1,0,0,0,
   0,0,0,0,0,
   0,0,0,0,0,
   0,0,0,0,0,0>
  clipped_by { box { <-4,-4,-1><4,4,1> } }
  bounded_by { clipped_by }
  pigment { rgb <1,.7,.3> } finish { specular .5 }
  rotate <0,90,-90>
}

5th order polynomial image

3) And finally the torus:

The polynomial was:

torus polynomial function

And we get the proper 4th degree poly primitive:

camera { location y*4-z*5 look_at 0 angle 35 }
light_source { <100,200,-50> 1 }
background { rgb <0,.25,.5> }

#declare r1=1;
#declare r2=.5;
poly
{ 4,
  <1,0,0,0,2,
   0,0,2,0,-2*(r1*r1+r2*r2),
   0,0,0,0,0,
   0,0,0,0,0,
   1,0,0,2,0,
   2*(r1*r1-r2*r2),0,0,0,0,
   1,0,-2*(r1*r1+r2*r2),0,pow(r1,4)+pow(r2,4)-2*r1*r1*r2*r2>
  pigment { rgb <1,.7,.3> } finish { specular .5 }
}

When rendered we get:

torus polynomial image

There is a shortcut for 4th order polynomials: The quartic primitive. We can write the torus like this:

quartic
{ <1,0,0,0,2,
   0,0,2,0,-2*(r1*r1+r2*r2),
   0,0,0,0,0,
   0,0,0,0,0,
   1,0,0,2,0,
   2*(r1*r1-r2*r2),0,0,0,0,
   1,0,-2*(r1*r1+r2*r2),0,pow(r1,4)+pow(r2,4)-2*r1*r1*r2*r2>
  pigment { rgb <1,.7,.3> } finish { specular .5 }
}
2.3.3.4.3 Polynomial made easy

Since consulting the table in the section Polynomial or writing a program to get the right poly vector can be a bit cumbersome, especially when the poly vector is not a write-once-only expression and that you want to get it back, so let's examine how those equations would be rewritten using the simplified syntax.

You should refer to the images in the previous section, as these examples produce exactly the same results.

1) The sphere example can be rewritten as:

#declare Radius=1;
polynomial { 2,
  xyz(2,0,0):1,
  xyz(0,2,0):1,
  xyz(0,0,2):1,
  xyz(0,0,0):-Radius*Radius
}

2) Let's now see the second one:

polynomial { 5,
  xyz(2,0,1):1,
  xyz(0,4,1):1,
  xyz(1,2,0):-2
}

3) And finally the torus example:

polynomial { 4,
  xyz(4,0,0):1,
  xyz(2,2,0):2,
  xyz(2,0,2):2,
  xyz(2,0,0):-2*(r1*r1+r2*r2),
  xyz(0,4,0):1,
  xyz(0,2,2):2,
  xyz(0,2,0):2*(r1*r1-r2*r2),
  xyz(0,0,4):1,
  xyz(0,0,2):-2*(r1*r1+r2*r2),
  xyz(0,0,0):pow((r1*r1-r2*r2),2)
}

2.3.3.5 Superquadric Ellipsoid Object

Sometimes we want to make an object that does not have perfectly sharp edges like a box does. Then, the superquadric ellipsoid shape made by the superellipsoid is a useful object. It is described by the simple syntax:

  superellipsoid { <Value_E, Value_N >}

Where Value_E and Value_N are float values greater than zero and less than or equal to one. Let's make a superellipsoid and experiment with the values of Value_E and Value_N to see what kind of shapes we can make. We create a file called supellps.pov and edit it as follows:

  #include "colors.inc"
  camera {
    location <10, 5, -20>
    look_at 0
    angle 15
  }
  background { color rgb <.5, .5, .5> }
  light_source { <10, 50, -100> White }

The addition of a gray background makes it a little easier to see our object. We now type:

  superellipsoid { <.25, .25>
    pigment { Red }
  }

We save the file and render it to see the shape. It will look like a box, but the edges will be rounded off. Now let's experiment with different values of Value_E and Value_N. For the next trace, try <1, 0.2>. The shape now looks like a cylinder, but the top edges are rounded. Now try <0.1, 1>. This shape is an odd one! We do not know exactly what to call it, but it is interesting. Finally, let's try <1, 1>. Well, this is more familiar... a sphere!

There are a couple of facts about superellipsoids we should know. First, we should not use a value of 0 for either Value_E nor Value_N. This will cause POV-Ray to incorrectly make a black box instead of our desired shape. Second, very small values of Value_E and Value_N may yield strange results so they should be avoided. Finally, the Sturmian root solver will not work with superellipsoids.

Superellipsoids are finite objects so they respond to auto-bounding and can be used in CSG.

Now let's use the superellipsoid to make something that would be useful in a scene. We will make a tiled floor and place a couple of superellipsoid objects hovering over it. We can start with the file we have already made.

We rename it to tiles.pov and edit it so that it reads as follows:

  #include "colors.inc"
  #include "textures.inc"
  camera {
    location <10, 5, -20>
    look_at 0
    angle 15
  }
  background { color rgb <.5, .5, .5> }
  light_source{ <10, 50, -100> White }

Note: We have added #include "textures.inc" so we can use pre-defined textures. Now we want to define the superellipsoid which will be our tile.

  #declare Tile = superellipsoid { <0.5, 0.1>
    scale <1, .05, 1>
  }

Superellipsoids are roughly 2*2*2 units unless we scale them otherwise. If we wish to lay a bunch of our tiles side by side, they will have to be offset from each other so they do not overlap. We should select an offset value that is slightly more than 2 so that we have some space between the tiles to fill with grout. So we now add this:

  #declare Offset = 2.1;

We now want to lay down a row of tiles. Each tile will be offset from the original by an ever-increasing amount in both the +z and -z directions. We refer to our offset and multiply by the tile's rank to determine the position of each tile in the row. We also union these tiles into a single object called Row like this:

  #declare Row = union {
    object { Tile }
    object { Tile translate z*Offset }
    object { Tile translate z*Offset*2 }
    object { Tile translate z*Offset*3 }
    object { Tile translate z*Offset*4 }
    object { Tile translate z*Offset*5 }
    object { Tile translate z*Offset*6 }
    object { Tile translate z*Offset*7 }
    object { Tile translate z*Offset*8 }
    object { Tile translate z*Offset*9 }
    object { Tile translate z*Offset*10 }
    object { Tile translate -z*Offset }
    object { Tile translate -z*Offset*2 }
    object { Tile translate -z*Offset*3 }
    object { Tile translate -z*Offset*4 }
    object { Tile translate -z*Offset*5 }
    object { Tile translate -z*Offset*6 }
  }

This gives us a single row of 17 tiles, more than enough to fill the screen. Now we must make copies of the Row and translate them, again by the offset value, in both the +x and -x directions in ever increasing amounts in the same manner.

  object { Row }
  object { Row translate x*Offset }
  object { Row translate x*Offset*2 }
  object { Row translate x*Offset*3 }
  object { Row translate x*Offset*4 }
  object { Row translate x*Offset*5 }
  object { Row translate x*Offset*6 }
  object { Row translate x*Offset*7 }
  object { Row translate -x*Offset }
  object { Row translate -x*Offset*2 }
  object { Row translate -x*Offset*3 }
  object { Row translate -x*Offset*4 }
  object { Row translate -x*Offset*5 }
  object { Row translate -x*Offset*6 }
  object { Row translate -x*Offset*7 }

Finally, our tiles are complete. But we need a texture for them. To do this we union all of the Rows together and apply a White Marble pigment and a somewhat shiny reflective surface to it:

  union{
    object { Row }
    object { Row translate x*Offset }
    object { Row translate x*Offset*2 }
    object { Row translate x*Offset*3 }
    object { Row translate x*Offset*4 }
    object { Row translate x*Offset*5 }
    object { Row translate x*Offset*6 }
    object { Row translate x*Offset*7 }
    object { Row translate -x*Offset }
    object { Row translate -x*Offset*2 }
    object { Row translate -x*Offset*3 }
    object { Row translate -x*Offset*4 }
    object { Row translate -x*Offset*5 }
    object { Row translate -x*Offset*6 }
    object { Row translate -x*Offset*7 }
    pigment { White_Marble }
    finish { phong 1 phong_size 50 reflection .35 }
  }

We now need to add the grout. This can simply be a white plane. We have stepped up the ambient here a little so it looks whiter.

  plane {
    y, 0  //this is the grout
    pigment { color White }
    finish { ambient .4 diffuse .7 }
  }

To complete our scene, let's add five different superellipsoids, each a different color, so that they hover over our tiles and are reflected in them.

  superellipsoid {
    <0.1, 1>
    pigment { Red }
    translate <5, 3, 0>
    scale .45
  }
  superellipsoid {
    <1, 0.25>
    pigment { Blue }
    translate <-5, 3, 0>
    scale .45
  }
  superellipsoid {
    <0.2, 0.6>
    pigment { Green }
    translate <0, 3, 5>
    scale .45
  }
  superellipsoid {
    <0.25, 0.25>
    pigment { Yellow }
    translate <0, 3, -5>
    scale .45
  }
  superellipsoid {
    <1, 1>
    pigment { Pink }
    translate y*3
    scale .45
  }

Some superellipsoids hovering above a tiled floor.

We trace the scene at 320x200 -A to see the result. If we are happy with that, we do a final trace at 640x480 +A0.2.

2.3.4 Gamma Handling

In this section, we will explain how to use the experimental gamma handling framework introduced with POV-Ray version 3.7. However, first we may need to introduce the term gamma, and why it needs handling anyway:

Note: In a nutshell, gamma handling is the compensation for non-linearities in the representation of color values.

As a raytracing engine, POV-Ray internally needs to represent colors using linear brightness values to produce physically accurate results. However, the majority of contemporary digital image processing tools and file formats do not. This comes as a surprise to most people, probably because the human visual perception is non-linear as well, as can be demonstrated in the render to the right, generated with POV-Ray using physically realistic settings: |
 | gamma handling reference image

Both front and second row show spheres with pigments increasing from rgb 0.0 to rgb 1.0. When asked which of them increases linearly, with a medium grey at the center, most people will go for the front row without too much hesitation. And in fact the pigment of the front center sphere does correspond to what Photoshop or similar image processing software would normally call 50% grey, but the pigment is a mere 21.8% as bright as the rightmost one. The true 50% brightness sphere sits right behind it.

A corresponding nonlinearity can be found in the traditional internal representation of colors in digital image processing, as implemented in file formats, graphics cards frame buffers, display APIs and so forth. Using one byte per colour component, and black and white represented by (0;0;0) and (255;255;255) respectively, a value of (128;128;128) will typically be used to encode a light intensity of just about 20%. To make matters a bit more complicated, the actual light intensity seen on the computer display may vary from one computer to the next, not only due to a historical lack of standardization in the PC display and graphics hardware market, but also due to factors such as electrical tolerances and even aging of the display. In professional environments, displays are therefore calibrated at regular intervals.

The non-linear relationship between color values and actual light intensity is usually approximated by (or calibrated to match) a power-law function (aka gamma function, hence the technical term gamma), i.e.:

f(x) = x ̂ γ

where x is the internal representation normalized to the range [0...1], f(x) is the actual output light intensity, and γ is a value typically somewhere between 2.0 to 2.4, though in the professional image processing world a value of 1.8 is also common.

Another formula becoming more and more popular is the so-called sRGB transfer function as defined in the sRGB color space standard, which has been adopted as the official standard on the World Wide Web. This function roughly corresponds to a power-law gamma of 2.2.

2.3.4.1 Setting Up Your Display

Using POV-Ray's gamma handling framework will not make much sense unless your display is set up properly; ideally, this would be done with a colorimeter and professional display calibration software. However, for hobbyists' purposes, less expensive solutions will suffice:

  • Your graphics card drivers may come with a wizard to help you adjust your display.
  • Various versions of Photoshop shipped with a utility called "Adobe Gamma".
  • There are numerous sites on the internet dedicated to »getting your display settings straight.

Note: We disagree with the author of the site linked to above, about which display gamma to aim for, and strongly recommend a gamma of 2.2, unless you know exactly what you're doing.

As an additional sanity check of your system display settings (and also of your image viewing software) POV-Ray provides a sample scene custom-tailored to this purpose, to be found at scenes/gamma/gamma_showcase.pov. Render the scene twice as PNG, using the following options:

  +w640 +h480 +a0.3 +am1 +fN -d File_Gamma=sRGB Output_File_Name=gamma_showcase.png
  +w640 +h480 +a0.3 +am1 +fN -d File_Gamma=1.0  Output_File_Name=gamma_showcase_linear.png

At 100% zoom, both images should look identical in your viewing software (if they don't, then by all means get rid of that obsolete software). Moreover, all the spheres should look uniform, like in the introductory image above. It is ok if you notice stripes on the spheres, but the overall brightness and hue should not be perceived as varying between the left and right hemispheres of any single sphere.

If however the image appears like shown below, then your system display gamma is either higher (left) or lower (right) than what your image viewing software expects. Note that in the PC world, most contemporary software will expect the display to either have a gamma of 2.2 or comply with the sRGB transfer function, unless there's a way to tell the software otherwise.

Note: LCD owners should make sure their display resolution is set to match the maximum resolution of the LCD, as interpolation might mess up the intended effect. Furthermore, it is not uncommon for LCDs to exhibit variations of gamma depending on viewing angle and, as a result, also across the display area. In that case, we recommend to adjust your display so that you get the desired gamma at the center of the screen when sitting as you usually do.

higher example | lower example

Just for the sake of it, here's a render of that showcase scene (note however that due to conversion of the original documentation source to whatever format you are currently reading it in, whether it be PDF, HTML or whatever, the image may have undergone some conversion, and may therefore be unsuited to serve as a good reference):

refer to: scenes/gamma/gamma_showcase.pov

2.3.4.2 Setting Up POV-Ray

Now that you can be sure that your operating system in general and your image viewing software in particular behave well regarding gamma, it is time to set up POV-Ray to do the same.

If you know that your system matches the sRGB standard, or have chosen to go for an approximate display gamma of 2.2, or used a tool that doesn't explicitly mention the gamma it has helped you to set up (in which case it will typically be 2.2 or sRGB as well), you're probably done already, as POV-Ray expects sRGB compliance by default, which is close enough to a display gamma of 2.2 for starters. Otherwise (or if you want an exact display gamma of 2.2) you should edit your master povray.ini to add the following line (e.g. for a display gamma of 1.8):

  Display_Gamma=1.8

Instead of a numerical value, you can also specify Display_Gamma=sRGB to explicitly tell POV-Ray that your system is calibrated to match the sRGB standard (which, as already mentioned, is actually the default setting).

Again, the gamma showcase scene can be used as a sanity check; use the following parameters:

  +w640 +h480 +a0.3 +am1 -f +d

Make sure you set the preview to windowed mode to get a 100% zoom. If everything works as expected, the preview window should look just like the PNG files already created, with each sphere again appearing to have a uniform color and brightness. If this is not the case for some mysterious reason, you may need to tweak the Display_Gamma setting accordingly; increase it if the left hemispheres appear too dark, or decrease it if they appear too bright. When you're done testing, update your povray.ini again.

2.3.4.3 Gamma in Output Images

Besides being used internally in most contemporary digital image processing software, non-linear color representations are also used in most conventional image file formats. This is often called gamma pre-correction, in the sense that the original linear brightness information has already been transformed by a gamma function to compensate for display non-linearity. Unfortunately, due to the large variety of display gamma in the world of computing, the gamma value used for pre-correction traditionally followed no set standard either.

In recent years the situation has changed, partly due to the adoption of the sRGB standard as the official recommendation for the World Wide Web, with major file format specifications following suit, and partly due to the advent of new file formats like PNG designed right from the start for a standardized way of gamma handling. (For such file formats, it is customary to speak of non-linear color representation not as gamma pre-correction, but rather as gamma encoding.) By now, for virtually all contemporary file formats there exists either a clear specification of how to handle gamma, or an official recommendation to adhere to the sRGB standard.

POV-Ray's gamma handling defaults are set to comply with the official file format standards or recommendations, so normally you will not need to worry about gamma handling. However, should the need arise, you can tell POV-Ray to ignore gamma recommendations and pre-correct the output file for a different display gamma, using the File_Gamma INI file option, e.g.:

  File_Gamma=1.8

Again, sRGB is a valid value, specifying that POV-Ray should apply the sRGB transfer function.

Note: Some of the file formats supported by POV-Ray are explicitly specified to never use gamma pre-correction or gamma encoding. For such file types (currently OpenEXR and Radiance HDR), File_Gamma has no effect whatsoever. For certain other file types (currently PNG), File_Gamma does have an effect on the encoding of the image, but not on the general visual appearance.

For output files, POV-Ray handles gamma according to the following rules:

  • For OpenEXR and Radiance HDR, which are officially specified to store linear brightness values, POV-Ray always stores linear values, ignoring the File_Gamma setting.
  • For PNG, which explicitly allows different encoding gamma values, POV-Ray will interpret the File_Gamma setting as the decoding gamma to encode for, and always write corresponding meta information into the header; as a result, the image will always look virtually identical irregardless of the File_Gamma setting; however, to minimize visible encoding artifacts like color banding, it is strongly recommended to use a setting of around 2.2, or sRGB.
  • For all other file formats, POV-Ray will interpret the File_Gamma setting as the display gamma to pre-correct for; as a result, the image will look different depending on the value used. It will also look different than the preview if you use a value other than your system's display gamma.

2.3.4.4 Setting Up Your Scene

As stated above, POV-Ray needs to work with linear colors to produce the most physically accurate output. However, if you prefer you can coax POV-Ray to work directly with non-linear color values. This is controlled via the assumed_gamma statement in the scene file's global settings, e.g.:

  global_settings { assumed_gamma 1.8 }

This enables the experimental gamma handling feature, and instructs POV-Ray to work with colors pre-corrected for a display gamma of whatever value you specify (in this example obviously a gamma of 1.8). You can also specify srgb instead of a numerical value, instructing POV-Ray to work with colors pre-corrected according to the sRGB standard.

Note: It is highly recommended to either set assumed_gamma to your system's display gamma for convenience, or set it to 1.0 for maximum realism. Using it for purely artistic purposes is strongly discouraged.

POV-Ray will take this setting into account when pre-correcting the computed image according to the Display_Gamma and File_Gamma settings.

Note: Sometimes you may want to use POV-Ray to generate other data than images in the strict sense, using the output image file as a mere data container, e.g. for height field data, bump maps, transparency maps or the like. In such cases, it is highly recommended to set both assumed_gamma and File_Gamma to 1.0 to avoid unexpected results.

2.3.4.5 Gamma in Literal Colors

By default, POV-Ray will expect each and every color value you enter to match your assumed_gamma, normalized to a range from 0.0 to 1.0. When using assumed_gamma 1.0 for realism, this can make it cumbersome to copy color values from other applications because those values will typically be non-linear representations of the respective colors; some people may also feel more at home with non-linear colors. To mitigate this issue, a special color literal syntax has been introduced to specify color values conforming to the sRGB standard; the syntax is as follows:

  color srgb <Rp,Gp,Bp>
  color srgbf <Rp,Gp,Bp,F>
  color srgbt <Rp,Gp,Bp,T>
  color srgbft <Rp,Gp,Bp,F,T>

where Rp, Gp and Bp are pre-corrected color component values in the range from 0.0 to 1.0, while F and T are linear color component values in the same range.

Note: The filter and transmit components are always interpreted as linear values, and the use of this alternative syntax will have no effect on them.

The following is also valid and gives the expected results:
  color srgb <255,240,0>/255

Note: This alternative syntax for colors does not constitute a new flavor of colors; instead, when encountering such a statement POV-Ray will immediately convert the specified non-linear color values into a linear ones. Any access to the individual components or computations done with the resulting color will therefore access the linear values.

2.3.4.6 Gamma in Input Images

Normally, gamma handling of input image files will work fine without intervention, but in some cases it may fail. To resolve such problems, the default handling can be overridden using the gamma SDL keyword, e.g:

  image_map { jpeg "foo.jpg" gamma 1.8 }

Instead of a numerical value, you can also use the srgb keyword to inform POV-Ray that the file conforms to the sRGB standard.

For input files in general, the following rules apply:

  • When using an image file in an image_map, POV-Ray will always convert the image data to the scene's assumed_gamma, according to whatever gamma the file is presumably pre-corrected for; you can override any file-specific presumtions by explicitly specifying the gamma you presume it to be pre-corrected for.
  • When using an image file in a height_field, bump_map or image_pattern, POV-Ray will convert the image data to linear values if you explicitly specify a gamma for that particular file; if you don't, no gamma adjustment will be performed (or, in other words, the file will be presued to carry linear data, regardless of file format).

For image_map input files, the following file-specific rules apply:

  • For OpenEXR and Radiance HDR, POV-Ray will presume the data to be linear, as per official file format specification.
  • For PNG, POV-Ray will presume the image data to be encoded according to file header information (currently sRGB or gAMA chunks); in the absence of such information, POV-Ray will presume sRGB-compliant encoding as per official recommendation.
  • For PPM and PGM. POV-Ray will currently presume the image data to match the assumed_gamma (in other words, no gamma adjustment will be performed by default).
  • For any other file formats, POV-Ray will presume sRGB-compliant encoding, to match either official recommendations or common practice.

Note: If you explicitly specify gamma for a particular file, POV-Ray will ignore any file format specifications, recommendations or meta information, and always presume the file to be pre-corrected for the specified gamma, or encoded for the specified decoding gamma. This applies in all contexts and to all file formats without exception.

2.3.4.7 Gamma in Legacy Scenes

POV-Ray version 3.6 used slightly different rules for its (optional) gamma handling, while yet earlier versions used no gamma correction at all. To provide backward compatibility with legacy scenes, POV-Ray does its best to mimic the behavior of these older versions in the following cases:

  • If the scene contains an assumed_gamma statement, and does not explicitly specify a version of 3.7 or later, gamma handling will follow the 3.6 rules.
  • If the scene does neither specify an assumed_gamma statement, nor explicitly specify a version of 3.7 or later, gamma correction will be turned off.

The 3.6 rules differ from standard behaviour with regards to image_map input files as follows:

  • For OpenEXR, Radiance HDR and PNG, the behaviour is the same as described above.
  • For any other file formats, in "3.6 mode" POV-Ray will currently presume the image data to match the assumed_gamma (in other words, no gamma adjustment will be performed by default).

As POV-Ray 3.6 did not have a File_Gamma setting, and used Display_Gamma for both purposes, you will have to set File_Gamma to whatever you used to set Display_Gamma to (or leave it undefined if you did not specify Display_Gamma either) in order to get the same output.

Furthermore, backward compatibility with 3.6 for PNG input files is subject to the following restrictions:

  • For palette-based PNG files (an uncommon flavor of PNG), backward compatibility is provided only if gamma correction is disabled (i.e. assumed_gamma is not specified). This is due to fixes in the handling of this PNG flavor.
  • For non-palette-based PNG files, backward compatibility is provided only if gamma correction is enabled (i.e. assumed_gamma is specified). This is due to inconsistencies in POV-Ray 3.6's PNG file handling which would have been prohibitively difficult to reproduce with the architectural changes in POV-Ray 3.7.
  • For PNG files carrying both an sRGB chunk and a fitting gAMA chunk, results will slightly differ, while for PNG files carrying an sRGB chunk but no gAMA chunk (or a wrong one), backward compatibility is not provided. This is due to POV-Ray 3.6 honoring only gAMA chunks, while POV-Ray 3.7 honors sRGB chunks as well, giving them precedence over gAMA chunks to comply with the official file format specification.

If you experience problems with a PNG input file in a legacy scene, explicitly specify the decoding gamma to be applied for that particular image using the gamma statement may help. When using e.g. assumed gamma 1.8, some values worth trying would be gamma 1, gamma 1/1.8, gamma 2.2/1.8 or gamma 1.8. (With POV-Ray 3.6's PNG file handling having been quite a mess, it is difficult to be more specific.)

2.3.5 Advanced Texture Options

The extremely powerful texturing ability is one thing that really sets POV-Ray apart from other raytracers. So far we have not really tried anything too complex but by now we should be comfortable enough with the program's syntax to try some of the more advanced texture options.

Obviously, we cannot try them all. It would take a tutorial a lot more pages to use every texturing option available in POV-Ray. For this limited tutorial, we will content ourselves to just trying a few of them to give an idea of how textures are created. With a little practice, we will soon be creating beautiful textures of our own.

Note: Early versions of POV-Ray made a distinction between pigment and normal patterns, i. e. patterns that could be used inside a normal or pigment statement. Since POV-Ray 3.0 this restriction was removed so that all patterns listed in section Pattern can be used as a pigment or normal pattern.

2.3.5.1 Pigments

Every surface must have a color. In POV-Ray this color is called a pigment. It does not have to be a single color. It can be a color pattern, a color list or even an image map. Pigments can also be layered one on top of the next so long as the uppermost layers are at least partially transparent so the ones beneath can show through. Let's play around with some of these kinds of pigments.

We create a file called texdemo.pov and edit it as follows:

  #include "colors.inc"
  camera {
    location <1, 1, -7>
    look_at 0
    angle 36
  }
  light_source { <1000, 1000, -1000> White }
  plane {
    y, -1.5
    pigment { checker Green, White }
  }
  sphere {
    <0,0,0>, 1
    pigment { Red }
  }

Giving this file a quick test render we see that it is a simple red sphere against a green and white checkered plane. We will be using the sphere for our textures.

2.3.5.1.1 Using Color List Pigments

Before we begin we should note that we have already made one kind of pigment, the color list pigment. In the previous example we have used a checkered pattern on our plane. There are three other kinds of color list pigments, brick, hexagon and the object pattern. Let's quickly try each of these. First, we change the plane's pigment as follows:

  pigment { hexagon Green, White, Yellow }

Rendering this we see a three-color hexagonal pattern. Note that this pattern requires three colors. Now we change the pigment to...

  pigment { brick Gray75, Red rotate -90*x scale .25 }

Looking at the resulting image we see that the plane now has a brick pattern. We note that we had to rotate the pattern to make it appear correctly on the flat plane. This pattern normally is meant to be used on vertical surfaces. We also had to scale the pattern down a bit so we could see it more easily. We can play around with these color list pigments, change the colors, etc. until we get a floor that we like.

2.3.5.1.2 Using Pigment and Patterns

Let's begin texturing our sphere by using a pattern and a color map consisting of three colors. We replace the pigment block with the following.

  pigment {
    gradient x
    color_map {
      [0.00 color Red]
      [0.33 color Blue]
      [0.66 color Yellow]
      [1.00 color Red]
    }
  }

Rendering this we see that the gradient pattern gives us an interesting pattern of vertical stripes. We change the gradient direction to y. The stripes are horizontal now. We change the gradient direction to z. The stripes are now more like concentric rings. This is because the gradient direction is directly away from the camera. We change the direction back to x and add the following to the pigment block.

  pigment {
    gradient x
    color_map {
      [0.00 color Red]
      [0.33 color Blue]
      [0.66 color Yellow]
      [1.00 color Red]
    }
    rotate -45*z          // <- add this line
  }

The vertical bars are now slanted at a 45 degree angle. All patterns can be rotated, scaled and translated in this manner. Let's now try some different types of patterns. One at a time, we substitute the following keywords for gradient x and render to see the result: bozo, marble, agate, granite, leopard, spotted and wood (if we like we can test all patterns listed in section Pattern).

Rendering these we see that each results in a slightly different pattern. But to get really good results each type of pattern requires the use of some pattern modifiers.

2.3.5.1.3 Using Pattern Modifiers

Let's take a look at some pattern modifiers. First, we change the pattern type to bozo. Then we add the following change.

  pigment {
    bozo
    frequency 3            // <- add this line
    color_map {
      [0.00 color Red]
      [0.33 color Blue]
      [0.66 color Yellow]
      [1.00 color Red]
    }
    rotate -45*z
  }

The frequency modifier determines the number of times the color map repeats itself per unit of size. This change makes the bozo pattern we saw earlier have many more bands in it. Now we change the pattern type to marble. When we rendered this earlier, we saw a banded pattern similar to gradient y that really did not look much like marble at all. This is because marble really is a kind of gradient and it needs another pattern modifier to look like marble. This modifier is called turbulence. We change the line frequency 3 to turbulence 1 and render again. That's better! Now let's put frequency 3 back in right after the turbulence and take another look. Even more interesting!

But wait, it gets better! Turbulence itself has some modifiers of its own. We can adjust the turbulence several ways. First, the float that follows the turbulence keyword can be any value with higher values giving us more turbulence. Second, we can use the keywords omega, lambda and octaves to change the turbulence parameters.

Let's try this now:

  pigment {
    marble
    turbulence 0.5
    lambda 1.5
    omega 0.8
    octaves 5
    frequency 3
    color_map {
      [0.00 color Red]
      [0.33 color Blue]
      [0.66 color Yellow]
      [1.00 color Red]
    }
    rotate 45*z
  }

Rendering this we see that the turbulence has changed and the pattern looks different. We play around with the numerical values of turbulence, lambda, omega and octaves to see what they do.

2.3.5.1.4 Using Transparent Pigments and Layered Textures

Pigments are described by numerical values that give the rgb value of the color to be used (like color rgb<1,0,0> giving us a red color). But this syntax will give us more than just the rgb values. We can specify filtering transparency by changing it as follows: color rgbf<1,0,0,1>. The f stands for filter, POV-Ray's word for filtered transparency. A value of one means that the color is completely transparent, but still filters the light according to what the pigment is. In this case, the color will be a transparent red, like red cellophane.

There is another kind of transparency in POV-Ray. It is called transmittance or non-filtering transparency (the keyword is transmit; see also rgbt). It is different from filter in that it does not filter the light according to the pigment color. It instead allows all the light to pass through unchanged. It can be specified like this: rgbt <1,0,0,1>.

Let's use some transparent pigments to create another kind of texture, the layered texture. Returning to our previous example, declare the following texture.

  #declare LandArea = texture {
      pigment {
        agate
        turbulence 1
        lambda 1.5
        omega .8
        octaves 8
        color_map {
          [0.00 color rgb <.5, .25, .15>]
          [0.33 color rgb <.1, .5, .4>]
          [0.86 color rgb <.6, .3, .1>]
          [1.00 color rgb <.5, .25, .15>]
        }
      }
    }

This texture will be the land area. Now let's make the oceans by declaring the following.

  #declare OceanArea = texture {
      pigment {
        bozo
        turbulence .5
        lambda 2
        color_map {
          [0.00, 0.33 color rgb <0, 0, 1>
                      color rgb <0, 0, 1>]
          [0.33, 0.66 color rgbf <1, 1, 1, 1>
                      color rgbf <1, 1, 1, 1>]
          [0.66, 1.00 color rgb <0, 0, 1>
                      color rgb <0, 0, 1>]
        }
      }
    }

Note: Now the ocean is the opaque blue area and the land is the clear area which will allow the underlying texture to show through.

Now, let's declare one more texture to simulate an atmosphere with swirling clouds.

  #declare CloudArea = texture {
    pigment {
      agate
      turbulence 1
      lambda 2
      frequency 2
      color_map {
        [0.0 color rgbf <1, 1, 1, 1>]
        [0.5 color rgbf <1, 1, 1, .35>]
        [1.0 color rgbf <1, 1, 1, 1>]
      }
    }
  }

Now apply all of these to our sphere.

  sphere {
    <0,0,0>, 1
    texture { LandArea }
    texture { OceanArea }
    texture { CloudArea }
  }

We render this and have a pretty good rendition of a little planetoid. But it could be better. We do not particularly like the appearance of the clouds. There is a way they could be done that would be much more realistic.

2.3.5.1.5 Using Pigment Maps

Pigments may be blended together in the same way as the colors in a color map using the same pattern keywords and a pigment_map. Let's just give it a try.

We add the following declarations, making sure they appear before the other declarations in the file.

  #declare Clouds1 = pigment {
      bozo
      turbulence 1
      color_map {
        [0.0 color White filter 1]
        [0.5 color White]
        [1.0 color White filter 1]
      }
    }
  #declare Clouds2 = pigment {
    agate
    turbulence 1
    color_map {
      [0.0 color White filter 1]
      [0.5 color White]
      [1.0 color White filter 1]
      }
    }
  #declare Clouds3 = pigment {
    marble
    turbulence 1
    color_map {
      [0.0 color White filter 1]
      [0.5 color White]
      [1.0 color White filter 1]
    }
  }
  #declare Clouds4 = pigment {
    granite
    turbulence 1
    color_map {
      [0.0 color White filter 1]
      [0.5 color White]
      [1.0 color White filter 1]
    }
  }

Now we use these declared pigments in our cloud layer on our planetoid. We replace the declared cloud layer with.

  #declare CloudArea = texture {
    pigment {
      gradient y
      pigment_map {
        [0.00 Clouds1]
        [0.25 Clouds2]
        [0.50 Clouds3]
        [0.75 Clouds4]
        [1.00 Clouds1]
      }
    }
  }

We render this and see a remarkable pattern that looks very much like weather patterns on the planet earth. They are separated into bands, simulating the different weather types found at different latitudes.

2.3.5.2 Normals

Objects in POV-Ray have very smooth surfaces. This is not very realistic so there are several ways to disturb the smoothness of an object by perturbing the surface normal. The surface normal is the vector that is perpendicular to the angle of the surface. By changing this normal the surface can be made to appear bumpy, wrinkled or any of the many patterns available. Let's try a couple of them.

2.3.5.2.1 Using Basic Normal Modifiers

We comment out the planetoid sphere for now and, at the bottom of the file, create a new sphere with a simple, single color texture.

  sphere {
    <0,0,0>, 1
    pigment { Gray75 }
    normal { bumps 1 scale .2 }
  }

Here we have added a normal block in addition to the pigment block (note that these do not have to be included in a texture block unless they need to be transformed together or need to be part of a layered texture). We render this to see what it looks like. Now, one at a time, we substitute for the keyword bumps the following keywords: dents, wrinkles, ripples and waves (we can also use any of the patterns listed in Pattern). We render each to see what they look like. We play around with the float value that follows the keyword. We also experiment with the scale value.

For added interest, we change the plane texture to a single color with a normal as follows.

  plane {
    y, -1.5
    pigment { color rgb <.65, .45, .35> }
    normal { dents .75 scale .25 }
  }
2.3.5.2.2 Blending Normals

Normals can be layered similar to pigments but the results can be unexpected. Let's try that now by editing the sphere as follows.

  sphere {
    <0,0,0>, 1
    pigment { Gray75 }
      normal { radial frequency 10 }
      normal { gradient y scale .2 }
  }

As we can see, the resulting pattern is neither a radial nor a gradient. It is instead the result of first calculating a radial pattern and then calculating a gradient pattern. The results are simply additive. This can be difficult to control so POV-Ray gives the user other ways to blend normals.

One way is to use normal maps. A normal map works the same way as the pigment map we used earlier. Let's change our sphere texture as follows.

  sphere {
    <0,0,0>, 1
    pigment { Gray75 }
    normal {
      gradient y
      frequency 3
      turbulence .5
      normal_map {
        [0.00 granite]
        [0.25 spotted turbulence .35]
        [0.50 marble turbulence .5]
        [0.75 bozo turbulence .25]
        [1.00 granite]
      }
    }
  }

Rendering this we see that the sphere now has a very irregular bumpy surface. The gradient pattern type separates the normals into bands but they are turbulated, giving the surface a chaotic appearance. But this gives us an idea.

Suppose we use the same pattern for a normal map that we used to create the oceans on our planetoid and applied it to the land areas. Does it follow that if we use the same pattern and modifiers on a sphere the same size that the shape of the pattern would be the same? Would not that make the land areas bumpy while leaving the oceans smooth? Let's try it. First, let's render the two spheres side-by-side so we can see if the pattern is indeed the same. We un-comment the planetoid sphere and make the following changes.

  sphere {
    <0,0,0>, 1
    texture { LandArea }
    texture { OceanArea }
    //texture { CloudArea }  // <-comment this out
    translate -x             // <- add this transformation
  }

Now we change the gray sphere as follows.

  sphere {
    <0,0,0>, 1
    pigment { Gray75 }
    normal {
      bozo
      turbulence .5
      lambda 2
      normal_map {
        [0.4 dents .15 scale .01]
        [0.6 agate turbulence 1]
        [1.0 dents .15 scale .01]
      }
    }
    translate x // <- add this transformation
  }

We render this to see if the pattern is the same. We see that indeed it is. So let's comment out the gray sphere and add the normal block it contains to the land area texture of our planetoid. We remove the transformations so that the planetoid is centered in the scene again.

  #declare LandArea = texture {
    pigment {
      agate
      turbulence 1
      lambda 1.5
      omega .8
      octaves 8
      color_map {
        [0.00 color rgb <.5, .25, .15>]
        [0.33 color rgb <.1, .5, .4>]
        [0.86 color rgb <.6, .3, .1>]
        [1.00 color rgb <.5, .25, .15>]
      }
    }
    normal {
      bozo
      turbulence .5
      lambda 2
      normal_map {
        [0.4 dents .15 scale .01]
        [0.6 agate turbulence 1]
        [1.0 dents .15 scale .01]
      }
    }
  }

Looking at the resulting image we see that indeed our idea works! The land areas are bumpy while the oceans are smooth. We add the cloud layer back in and our planetoid is complete.

There is much more that we did not cover here due to space constraints. On our own, we should take the time to explore slope maps, average and bump maps.

2.3.5.2.3 Slope Map Tutorial

One of the most powerful texturing features of POV-Ray is normal perturbation (which is specified using the normal block of an object texture). With this feature it's possible to emulate small surface displacement in a very efficient way, without actually having to modify the actual surface (which often would increase the complexity of the object considerably, resulting in much slower renders).

Slope maps are used to define more precisely how the normal perturbation is generated from a specified pattern. Slope maps are a very powerful feature often dismissed by many.

As an example, let's create a simple scene with an object using normal perturbation:

camera { location <0, 10, -7>*1.4 look_at 0 angle 35 }
light_source
{ <100, 80, -30>, 1 area_light z*20, y*20, 12, 12 adaptive 0 }
plane { y, 0 pigment { rgb 1 } }

cylinder
{ 0, y, 4
  pigment { rgb <1, .9, .2> }
  finish { specular 1 }
  normal
  { wood 1
    rotate x*90
  }
}

Normal modifier example

By default the wood pattern uses a ramp wave (going from 0 to 1 and then back to 0) arranged in concentric circles, as we can see from the image.

By default POV-Ray simply takes the values of the pattern as they are in order to calculate the normal perturbation of the surface. However, using a slope_map we can more precisely define how these values are interpreted. For example, if we add this slope_map (the meaning of the values are explained later in this tutorial) to the normal block in the example above:

    slope_map
    { [0 <0, 0>]
      [.2 <1, 1>]
      [.2 <1, 0>]
      [.8 <1, 0>]
      [.8 <1, -1>]
      [1 <0, 0>]
    }

we get a much more interesting result:

Slope map example 1

We can also use a slope map to simply smooth out the original ramp wave pattern like this:

    slope_map
    { [0 <0, 0>]
      [.5 <.5, 1>]
      [1 <1, 0>]
    }

Slope map example 2
2.3.5.2.3.1 Slopes, what are they?

Mathematically speaking the slope of a curve (also called gradient) at a certain point is the tan() of the angle of the tangent line of that curve at that point. In other words, it's the amount of change of the vertical coordinate with respect to the change of the horizontal coordinate.

In a more colloquial way, the slope of a completely horizontal part of the curve is 0. The slope of a 45-degree line is 1 (because for each unit in the horizontal direction the line goes up by the same amount). Lines between 0 and 45 degrees have corresponding slopes between 0 and 1 (the relation between them is not linear, though, but one usually doesn't have to worry about that). Lines with an angle of over 45 degrees have correspondently slopes increasingly larger than 1 (a line of 90 degrees has an infinite slope).

Usually when defining slope maps it's enough to keep between slopes of 0 and 1, even though higher slopes are sometimes useful too to get steeper changes. Usually it's enough to think that a slope of 0 means a horizontal part of the curve while a slope of 1 means a 45-degree steep part of the curve (and slopes between 0 and 1 correspond to degrees between 0 and 45 respectively).

A slope can be negative too. A negative slope simply means that the curve is going down instead of going up.

The following figure shows some basic slopes in a curve (note that the slope values are only approximate):

Slopes in a curve
2.3.5.2.3.2 Syntax of a slope map

In the exact same way as for example a color_map assigns colors to pattern values, a slope_map assign slopes to pattern values. If you are fluent in defining color maps for a pattern, defining a slope map shouldn't be any more difficult.

Each entry in a slope map takes two values: The displacement of the surface (although one should remember that this displacement is only simulated, not real) and the slope of the surface at that point.

You can think of the first parameter as an altitude value which tells how much the surface (in relative terms) is displaced from its original location. Usually values between 0 and 1 are used for this. You can think of 0 meaning that the surface is not displaced and 1 as the surface having maximum displacement (outwards).

Let's examine the slope map we used to smooth out the wood pattern at the beginning of this tutorial:

    slope_map
    { [0 <0, 0>]
      [.5 <.5, 1>]
      [1 <1, 0>]
    }

This means:

  • When the pattern has a value of 0, the surface is not displaced and the slope of the surface is 0 (ie. it's horizontal).
  • When the pattern has a value of 0.5, the surface is displaced by 0.5 and the slope of the surface is 1.
  • When the pattern has a value of 1, the surface has maximum displacement and the slope is again 0, ie. horizontal.

When the pattern is linear (as the wood pattern is), this kind of slope map corresponds approximately to a half sine wave. Since the wood pattern uses a ramp wave (ie. after going from 0 to 1 it then goes from 1 to 0), the result is basically a complete (approximate) sine wave.

As with a color map, all the values in between are interpolated and that's why we get a smooth transition between these values.

2.3.5.2.3.3 Examples of slope maps

As we saw in the first slope map example in this tutorial, it is possible to create sharp transitions, not just smooth ones. This is achieved in the same way as how sharp transitions are achieved with color maps: By repeating the same pattern value. Here is an example:

    slope_map
    { [0 <0, 1>]
      [.5 <1, 1>]
      [.5 <1, -.3>]
      [1 <.7, -.3>]
    }

Slope map example 3

There's a sharp transition at the pattern value 0.5, where the surface goes from slope 1 to slope -0.3 (ie. from going strongly upwards to going slightly downwards). Due to how the wood pattern repeats itself, there are also sharp transitions at the pattern values 0 and 1.

We can combine sharp and smooth transitions for nice effects. For example, this simple slope map achieves a nice result:

    slope_map
    { [0 <0, 1>]
      [1 <1, 0>]
    }

Slope map example 4
  • At the pattern value 0 the displacement of the surface is 0 and the slope is 1 (ie. strongly upwards).
  • At the pattern value 1 the surface is fully displaced and horizontal.
  • Due to the ramp-wave-repetition quality of the wood pattern (which effectively reverses this pattern), the surface then continues smoothly from this point until it descends to 0, where the slope is now effectively -1. Now there's a sharp transition from -1 back to 1 as the pattern starts over.

One application where slope maps are really useful is when creating tiled floors. When the tiles on a floor are not too close to the camera and there is a very large amount of tiles, instead of creating hundreds or thousands of individual tile objects, it may be more efficient to simply create a normal pattern which emulates the tiles.

This example shows how to create a floor made of wooden planks:

camera { location <2, 10, -12>*.5 look_at 0 angle 35 }
light_source
{ <100, 150, 0>, 1 area_light z*40, y*40, 12, 12 adaptive 0 }
sphere { y*.5, .5 pigment { rgb x } finish { specular .5 } }

plane
{ y, 0
  pigment
  { wood color_map { [0 rgb <.9,.7,.3>][1 rgb <.8,.5,.2>] }
    turbulence .5
    scale <1, 1, 20>*.2
  }
  finish { specular 1 }
  normal
  { gradient x 1
    slope_map
    { [0 <0, 1>] // 0 height, strong slope up
      [.05 <1, 0>] // maximum height, horizontal
      [.95 <1, 0>] // maximum height, horizontal
      [1 <0, -1>] // 0 height, strong slope down
    }
  }
}

Slope map example 5

In this case a gradient pattern was used. Since the gradient pattern goes from 0 to 1 and then immediately back to 0, we have to mirror the slope map (around 0.5) in order to get a repetitive symmetric result.

In this example the slope map starts from 0 height and a strong slope up, and goes quickly to maximum height, where the surface is horizontal. Then there's a large horizontal area (from pattern value 0.5 to 0.95) after which the slope goes rapidly back down to 0 height and a strong slope down. (After this there's a sharp transition to the beginning due to the gradient pattern starting over.)

If we want square tiles instead of just planks, we can achieve that by eg. using an average normal map like this:

  #declare TileNormal =
    normal
    { gradient x 2 // Double the strength because of the averaging
      slope_map
      { [0 <0, 1>] // 0 height, strong slope up
        [.05 <1, 0>] // maximum height, horizontal
        [.95 <1, 0>] // maximum height, horizontal
        [1 <0, -1>] // 0 height, strong slope down
      }
    }
  normal
  { average normal_map
    { [1 TileNormal]
      [1 TileNormal rotate y*90]
    }
  }

Slope map example 6

If we change the pigment of the plane a bit, we get a nice tiled floor:

  pigment
  { checker
    pigment { granite color_map { [0 rgb 1][1 rgb .9] } }
    pigment { granite color_map { [0 rgb .9][1 rgb .7] } }
  }

Slope map example 7

As you can see in the image, close to the camera it's more evident that the tiles are not truely three-dimensional (and that only a normal perturbation trick has been used), but farther away from the camera the effect is pretty convincing.

2.3.5.3 Finishes

The final part of a POV-Ray texture is the finish. It controls the properties of the surface of an object. It can make it shiny and reflective, or dull and flat. It can also specify what happens to light that passes through transparent pigments, what happens to light that is scattered by less-than-perfectly-smooth surfaces and what happens to light that is reflected by surfaces with thin-film interference properties. There are twelve different properties available in POV-Ray to specify the finish of a given object. These are controlled by the following keywords: ambient, diffuse, brilliance, phong, specular, metallic, reflection, crand and iridescence. Let's design a couple of textures that make use of these parameters.

2.3.5.3.1 Using Ambient

Since objects in POV-Ray are illuminated by light sources, the portions of those objects that are in shadow would be completely black were it not for the first two finish properties, ambient and >diffuse. Ambient is used to simulate the light that is scattered around the scene that does not come directly from a light source. Diffuse determines how much of the light that is seen comes directly from a light source. These two keywords work together to control the simulation of ambient light. Let's use our gray sphere to demonstrate this. Let's also change our plane back to its original green and white checkered pattern.

  plane {
    y, -1.5
    pigment {checker Green, White}
  }
  sphere {
    <0,0,0>, 1
    pigment { Gray75 }
    finish {
      ambient .2
      diffuse .6
    }
  }

In the above example, the default values for ambient and diffuse are used. We render this to see what the effect is and then make the following change to the finish.

  ambient 0
  diffuse 0

The sphere is black because we have specified that none of the light coming from any light source will be reflected by the sphere. Let's change diffuse back to the default of 0.6.

Now we see the gray surface color where the light from the light source falls directly on the sphere but the shaded side is still absolutely black. Now let's change diffuse to 0.3 and ambient to 0.3.

The sphere now looks almost flat. This is because we have specified a fairly high degree of ambient light and only a low amount of the light coming from the light source is diffusely reflected towards the camera. The default values of ambient and diffuse are pretty good averages and a good starting point. In most cases, an ambient value of 0.1 ... 0.2 is sufficient and a diffuse value of 0.5 ... 0.7 will usually do the job. There are a couple of exceptions. If we have a completely transparent surface with high refractive and/or reflective values, low values of both ambient and diffuse may be best. Here is an example:

sphere {
   <0,0,0>, 1
   pigment { White filter 1 }
   finish {
      ambient 0
      diffuse 0
      reflection .25
      specular 1
      roughness .001
   }
   interior { ior 1.33 }
}

This is glass, obviously. Glass is a material that takes nearly all of its appearance from its surroundings. Very little of the surface is seen because it transmits or reflects practically all of the light that shines on it. See glass.inc for some other examples.

Note: As of POV-Ray 3.7, ambient is disabled when using radiosity, as both mechanisms are intended to simulate the same thing (albeit with different quality) and don't play well together.

2.3.5.3.2 Using Emission

If we ever need an object to be completely illuminated independently of the lighting situation in a given scene we can do this artificially by specifying an emission value of 1 and an ambient and diffuse value of 0. This will eliminate all shading and simply give the object its fullest and brightest color value at all points. This is good for simulating objects that emit light like light bulbs and for skies in scenes where the sky may not be adequately lit by any other means.

Let's try this with our sphere now.

  sphere {
     <0,0,0>, 1
     pigment { White }
     finish {
        emission 1
        ambient 0
        diffuse 0
     }
  }

Rendering this we get a blinding white sphere with no visible highlights or shaded parts. It would make a pretty good street light.

Note: Versions of POV-Ray prior to 3.7 did not provide the emission keyword for finish, and it was customary to resort to ambient instead for such purpose. This is now discouraged, as ambient is now disabled when using radiosity.

2.3.5.3.3 Using Surface Highlights

In the glass example above, we noticed that there were bright little hotspots on the surface. This gave the sphere a hard, shiny appearance. POV-Ray gives us two ways to specify surface specular highlights. The first is called phong highlighting. Usually, phong highlights are described using two keywords: phong and phong_size. The float that follows phong determines the brightness of the highlight while the float following phong_size determines its size. Let's try this.

  sphere {
    <0,0,0>, 1
    pigment { Gray50 }
    finish {
      ambient .2
      diffuse .6
      phong .75
      phong_size 25
    }
  }

Rendering this we see a fairly broad, soft highlight that gives the sphere a kind of plastic appearance. Now let's change phong_size to 150. This makes a much smaller highlight which gives the sphere the appearance of being much harder and shinier.

There is another kind of highlight that is calculated by a different means called specular highlighting. It is specified using the keyword specular and operates in conjunction with another keyword called roughness. These two keywords work together in much the same way as phong and phong_size to create highlights that alter the apparent shininess of the surface. Let's try using specular in our sphere.

  sphere {
     <0,0,0>, 1
     pigment { Gray50 }
     finish {
        ambient .2
        diffuse .6
        specular .75
        roughness .1
    }
  }

Looking at the result we see a broad, soft highlight similar to what we had when we used phong_size of 25. Change roughness to .001 and render again. Now we see a small, tight highlight similar to what we had when we used phong_size of 150. Generally speaking, specular is slightly more accurate and therefore slightly more realistic than phong but you should try both methods when designing a texture. There are even times when both phong and specular may be used on a finish.

2.3.5.3.4 Using Reflection, Metallic and Metallic

There is another surface parameter that goes hand in hand with highlights, reflection. Surfaces that are very shiny usually have a degree of reflection to them. Let's take a look at an example.

  sphere {
     <0,0,0>, 1
     pigment { Gray50 }
     finish {
        ambient .2
        diffuse .6
        specular .75
        roughness .001
        reflection {
           .5
        }
     }
  }

We see that our sphere now reflects the green and white checkered plane and the black background but the gray color of the sphere seems out of place. This is another time when a lower diffuse value is needed. Generally, the higher reflection is the lower diffuse should be. We lower the diffuse value to 0.3 and the ambient value to 0.1 and render again. That is much better. Let's make our sphere as shiny as a polished gold ball bearing.

  sphere {
     <0,0,0>, 1
     pigment { BrightGold }
     finish {
        ambient .1
        diffuse .1
        specular 1
        roughness .001
        reflection {
           .75
        }
     }
   }

That is close but there is something wrong, the colour of the reflection and the highlight. To make the surface appear more like metal the keyword metallic is used. We add it now to see the difference.

  sphere {
     <0,0,0>, 1
     pigment { BrightGold }
     finish {
        ambient .1
        diffuse .1
        specular 1
        roughness .001
        reflection {
          .75
          metallic
        }
     }
  }

The reflection has now more of the gold color than the color of its environment. Last detail, the highlight. We add another metallic statement, now to the finish and not inside the reflection block.

  sphere {
     <0,0,0>, 1
     pigment { BrightGold }
     finish {
        ambient .1
        diffuse .1
        specular 1
        roughness .001
        metallic
        reflection {
          .75
          metallic
        }
     }
  }

We see that the highlight has taken on the color of the surface rather than the light source. This gives the surface a more metallic appearance.

2.3.5.3.5 Using Iridescence

Iridescence is what we see on the surface of an oil slick when the sun shines on it. The rainbow effect is created by something called thin-film interference (read section Iridescence for details). For now let's just try using it. Iridescence is specified by the irid statement and three values: amount, thickness and turbulence. The amount is the contribution to the overall surface color. Usually 0.1 to 0.5 is sufficient here. The thickness affects the busyness of the effect. Keep this between 0.25 and 1 for best results. The turbulence is a little different from pigment or normal turbulence. We cannot set octaves, lambda or omega but we can specify an amount which will affect the thickness in a slightly different way from the thickness value. Values between 0.25 and 1 work best here too. Finally, iridescence will respond to the surface normal since it depends on the angle of incidence of the light rays striking the surface. With all of this in mind, let's add some iridescence to our glass sphere.

sphere {
     <0,0,0>, 1
     pigment { White filter 1 }
     finish {
        ambient .1
        diffuse .1
        reflection .2
        specular 1
        roughness .001
        irid {
          0.35
          thickness .5
          turbulence .5
        }
     }
     interior{
        ior 1.5
        fade_distance 5
        fade_power 1
        caustics 1
     }
}

We try to vary the values for amount, thickness and turbulence to see what changes they make. We also try to add a normal block to see what happens.

2.3.5.4 Working With Pigment Maps

Let's look at the pigment map. We must not confuse this with a color map, as color maps can only take individual colors as entries in the map, while pigment maps can use entire other pigment patterns. To get a feel for these, let's begin by setting up a basic plane with a simple pigment map. Now, in the following example, we are going to declare each of the pigments we are going to use before we actually use them. This is not strictly necessary (we could put an entire pigment description in each entry of the map) but it just makes the whole thing more readable.

  // simple Black on White checkerboard... it's a classic
  #declare Pigment1 = pigment {
    checker color Black color White
    scale .1
  }
  // kind of a "psychedelic rings" effect
  #declare Pigment2 = pigment {
    wood
    color_map {
      [ 0.0 Red ]
      [ 0.3 Yellow ]
      [ 0.6 Green ]
      [ 1.0 Blue ]
    }
  }
  plane {
    -z, 0
    pigment {
      gradient x
      pigment_map {
        [ 0.0 Pigment1 ]
        [ 0.5 Pigment2 ]
        [ 1.0 Pigment1 ]
      }
    }
  }

Okay, what we have done here is very simple, and probably quite recognizable if we have been working with color maps all along anyway. All we have done is substituted a pigment map where a color map would normally go, and as the entries in our map, we have referenced our declared pigments. When we render this example, we see a pattern which fades back and forth between the classic checkerboard, and those colorful rings. Because we fade from Pigment1 to Pigment2 and then back again, we see a clear blending of the two patterns at the transition points. We could just as easily get a sudden transition by amending the map to read.

  pigment_map {
    [ 0.0 Pigment1 ]
    [ 0.5 Pigment1 ]
    [ 0.5 Pigment2 ]
    [ 1.0 Pigment2 ]
  }

Blending individual pigment patterns is just the beginning.

2.3.5.5 Working With Normal Maps

For our next example, we replace the plane in the scene with this one.

  plane {
    -z, 0
    pigment { White }
    normal {
      gradient x
      normal_map {
        [ 0.0 bumps 1 scale .1]
        [ 1.0 ripples 1 scale .1]
      }
    }
  }

First of all, we have chosen a solid white color to show off all bumping to best effect. Secondly, we notice that our map blends smoothly from all bumps at 0.0 to all ripples at 1.0, but because this is a default gradient, it falls off abruptly back to bumps at the beginning of the next cycle. We Render this and see just enough sharp transitions to clearly see where one normal gives over to another, yet also an example of how two normal patterns look while they are smoothly blending into one another.

The syntax is the same as we would expect. We just changed the type of map, moved it into the normal block and supplied appropriate bump types. It is important to remember that as of POV-Ray 3, all patterns that work with pigments work as normals as well (and vice versa, except for facets) so we could just as easily have blended from wood to granite, or any other pattern we like. We experiment a bit and get a feel for what the different patterns look like.

After seeing how interesting the various normals look blended, we might like to see them completely blended all the way through rather than this business of fading from one to the next. Well, that is possible too, but we would be getting ahead of ourselves. That is called the average function, and we will return to it a little bit further down the page.

2.3.5.6 Working With Texture Maps

We know how to blend colors, pigment patterns, and normals, and we are probably thinking what about finishes? What about whole textures? Both of these can be kind of covered under one topic. While there is no finish map per se, there are texture maps, and we can easily adapt these to serve as finish maps, simply by putting the same pigment and/or normal in each of the texture entries of the map. Here is an example. We eliminate the declared pigments we used before and the previous plane, and add the following.

  #declare Texture1 = texture {
    pigment { Grey }
    finish { reflection 1 }
  }
  #declare Texture2 = texture {
    pigment { Grey }
    finish { reflection 0 }
  }
  cylinder {
    <-2, 5, -2>, <-2, -5, -2>, 1
    pigment { Blue }
  }
  plane {
    -z, 0
    rotate y * 30
    texture {
      gradient y
      texture_map {
        [ 0.0 Texture1 ]
        [ 0.4 Texture1 ]
        [ 0.6 Texture2 ]
        [ 1.0 Texture2 ]
      }
      scale 2
    }
  }

Now, what have we done here? The background plane alternates vertically between two textures, identical except for their finishes. When we render this, the cylinder has a reflection part of the way down the plane, and then stops reflecting, then begins and then stops again, in a gradient pattern down the surface of the plane. With a little adaptation, this could be used with any pattern, and in any number of creative ways, whether we just wanted to give various parts of an object different finishes, as we are doing here, or whole different textures altogether.

One might ask: if there is a texture map, why do we need pigment and normal maps? Fair question. The answer: speed of calculation. If we use a texture map, for every in-between point, POV-Ray must make multiple calculations for each texture element, and then run a weighted average to produce the correct value for that point. Using just a pigment map (or just a normal map) decreases the overall number of calculations, and our texture renders a bit faster in the bargain. As a rule of thumb: we use pigment or normal maps where we can and only fall back on texture maps if we need the extra flexibility.

2.3.5.7 Working With List Textures

If we have followed the corresponding tutorials on simple pigments, we know that there are three patterns called color list patterns, because rather than using a color map, these simple but useful patterns take a list of colors immediately following the pattern keyword. We are talking about checker, hexagon, the brick pattern and the object pattern.

Naturally they also work with whole pigments, normals, and entire textures, just as the other patterns do above. The only difference is that we list entries in the pattern (as we would do with individual colors) rather than using a map of entries. Here is an example. We strike the plane and any declared pigments we had left over in our last example, and add the following to our basic file.

  #declare Pigment1 = pigment {
    hexagon
    color Yellow color Green color Grey
    scale .1
  }
  #declare Pigment2 = pigment {
    checker
    color Red color Blue
    scale .1
  }
  #declare Pigment3 = pigment {
    brick
    color White color Black
    rotate -90*x
    scale .1
  }
  box {
    -5, 5
    pigment {
      hexagon
      pigment {Pigment1}
      pigment {Pigment2}
      pigment {Pigment3}
      rotate 90*x
    }
  }

We begin by declaring an example of each of the color list patterns as individual pigments. Then we use the hexagon pattern as a pigment list pattern, simply feeding it a list of pigments rather than colors as we did above. There are two rotate statements throughout this example, because bricks are aligned along the z-direction, while hexagons align along the y-direction, and we wanted everything to face toward the camera we originally declared out in the -z-direction so we can really see the patterns within patterns effect here.

Of course color list patterns used to be only for pigments, but as of POV-Ray 3, everything that worked for pigments can now also be adapted for normals or entire textures. A couple of quick examples might look like

  normal {
    brick
    normal { granite .1 }
    normal { bumps 1 scale .1 }
  }

or...

  texture {
    checker
    texture { Gold_Metal }
    texture { Silver_Metal }
  }

2.3.5.8 What About Tiles?

In earlier versions of POV-Ray, there was a texture pattern called tiles. By simply using a checker texture pattern (as we just saw above), we can achieve the same thing as tiles used to do, so it is now obsolete. It is still supported by POV-Ray 3 for backwards compatibility with old scene files, but now is a good time to get in the habit of using a checker pattern instead.

2.3.5.9 Average Function

Now things get interesting. Above, we began to see how pigments and normals can fade from one to the other when we used them in maps. But how about if we want a smooth blend of patterns all the way through? That is where a new feature called average can come in very handy. Average works with pigment, normal, and texture maps, although the syntax is a little bit different, and when we are not expecting it, the change can be confusing. Here is a simple example. We use our standard includes, camera and light source from above, and enter the following object.

  plane { -z, 0
    pigment { White }
    normal {
      average
      normal_map {
        [1, gradient x ]
        [1, gradient y ]
      }
    }
  }

What we have done here is pretty self explanatory as soon as we render it. We have combined a vertical with a horizontal gradient bump pattern, creating crisscrossing gradients. Actually, the crisscrossing effect is a smooth blend of gradient x with gradient y all the way across our plane. Now, what about that syntax difference?

We see how our normal map has changed from earlier examples. The floating point value to the left-hand side of each map entry has a different meaning now. It gives the weight factor per entry in the map. Try some different values for the 'gradient x' entry and see how the normal changes.

The weight factor can be omitted, the result then will be the same as if each entry had a weight factor of 1.

2.3.5.10 Working With Layered Textures

With the multitudinous colors, patterns, and options for creating complex textures in POV-Ray, we can easily become deeply engrossed in mixing and tweaking just the right textures to apply to our latest creations. But as we go, sooner or later there is going to come that special texture. That texture that is sort of like wood, only varnished, and with a kind of spotty yellow streaking, and some vertical gray flecks, that looks like someone started painting over it all, and then stopped, leaving part of the wood visible through the paint.

Only... now what? How do we get all that into one texture? No pattern can do that many things. Before we panic and say image map there is at least one more option: layered textures.

With layered textures, we only need to specify a series of textures, one after the other, all associated with the same object. Each texture we list will be applied one on top of the other, from bottom to top in the order they appear.

It is very important to note that we must have some degree of transparency (filter or transmit) in the pigments of our upper textures, or the ones below will get lost underneath. We will not receive a warning or an error - technically it is legal to do this: it just does not make sense. It is like spending hours sketching an elaborate image on a bare wall, then slapping a solid white coat of latex paint over it.

Let's design a very simple object with a layered texture, and look at how it works. We create a file called LAYTEX.POV and add the following lines.

  #include "colors.inc"
  #include "textures.inc"
  camera {
    location <0, 5, -30>
    look_at <0, 0, 0>
  }
  light_source { <-20, 30, -50> color White }
  plane { y, 0 pigment { checker color Green color Yellow  } }
  background { rgb <.7, .7, 1> }
  box {
    <-10, 0, -10>, <10, 10, 10>
    texture {
      Silver_Metal // a metal object ...
      normal {     // ... which has suffered a beating
        dents 2
        scale 1.5
      }
    } // (end of base texture)
    texture { // ... has some flecks of rust ...
      pigment {
        granite
        color_map {
          [0.0 rgb <.2, 0, 0> ]
          [0.2 color Brown ]
          [0.2 rgbt <1, 1, 1, 1> ]
          [1.0 rgbt <1, 1, 1, 1> ]
        }
        frequency 16
      }
    } // (end rust fleck texture)
    texture { // ... and some sooty black marks
      pigment {
        bozo
        color_map {
          [0.0 color Black ]
          [0.2 color rgbt <0, 0, 0, .5> ]
          [0.4 color rgbt <.5, .5, .5, .5> ]
          [0.5 color rgbt <1, 1, 1, 1> ]
          [1.0 color rgbt <1, 1, 1, 1> ]
        }
        scale 3
      }
    } // (end of sooty mark texture)
  } // (end of box declaration)

Whew. This gets complicated, so to make it easier to read, we have included comments showing what we are doing and where various parts of the declaration end (so we do not get lost in all those closing brackets!). To begin, we created a simple box over the classic checkerboard floor, and give the background sky a pale blue color. Now for the fun part...

To begin with we made the box use the Silver_Metal texture as declared in textures.inc (for bonus points, look up textures.inc and see how this standard texture was originally created sometime). To give it the start of its abused state, we added the dents normal pattern, which creates the illusion of some denting in the surface as if our mysterious metal box had been knocked around quite a bit.

The flecks of rust are nothing but a fine grain granite pattern fading from dark red to brown which then abruptly drops to fully transparent for the majority of the color map. True, we could probably come up with a more realistic pattern of rust using pigment maps to cluster rusty spots, but pigment maps are a subject for another tutorial section, so let's skip that just now.

Lastly, we have added a third texture to the pot. The randomly shifting bozo texture gradually fades from blackened centers to semi-transparent medium gray, and then ultimately to fully transparent for the latter half of its color map. This gives us a look of sooty burn marks further marring the surface of the metal box. The final result leaves our mysterious metal box looking truly abused, using multiple texture patterns, one on top of the other, to produce an effect that no single pattern could generate!

2.3.5.10.1 Declaring Layered Textures

In the event we want to reuse a layered texture on several objects in our scene, it is perfectly legal to declare a layered texture. We will not repeat the whole texture from above, but the general format would be something like this:

  #declare Abused_Metal =
    texture { /* insert your base texture here... */ }
    texture { /* and your rust flecks here... */ }
    texture { /* and of course, your sooty burn marks here */ }

POV-Ray has no problem spotting where the declaration ends, because the textures follow one after the other with no objects or directives in between. The layered texture to be declared will be assumed to continue until it finds something other than another texture, so any number of layers can be added in to a declaration in this fashion.

One final word about layered textures: whatever layered texture we create, whether declared or not, we must not leave off the texture wrapper. In conventional single textures a common shorthand is to have just a pigment, or just a pigment and finish, or just a normal, or whatever, and leave them outside of a texture statement. This shorthand does not extend to layered textures. As far as POV-Ray is concerned we can layer entire textures, but not individual pieces of textures. For example

  #declare Bad_Texture =
    texture { /* insert your base texture here... */ }
    pigment { Red filter .5 }
    normal { bumps 1 }

will not work. The pigment and the normal are just floating there without being part of any particular texture. Inside an object, with just a single texture, we can do this sort of thing, but with layered textures, we would just generate an error whether inside the object or in a declaration.

2.3.5.10.2 Another Layered Textures Example

To further explain how layered textures work another example is described in detail. A tablecloth is created to be used in a picnic scene. Since a simple red and white checkered cloth looks entirely too new, too flat, and too much like a tiled floor, layered textures are used to stain the cloth.

We are going to create a scene containing four boxes. The first box has that plain red and white texture we started with in our picnic scene, the second adds a layer meant to realistically fade the cloth, the third adds some wine stains, and the final box adds a few wrinkles (not another layer, but we must note when and where adding changes to the surface normal have an effect in layered textures).

We start by placing a camera, some lights, and the first box. At this stage, the texture is plain tiling, not layered. See file layered1.pov.

  #include "colors.inc"
  camera {
    location <0, 0, -6>
    look_at <0, 0, 0>
  }
  light_source { <-20, 30, -100> color White }
  light_source { <10, 30, -10> color White }
  light_source { <0, 30, 10> color White }
  #declare PLAIN_TEXTURE =
    // red/white check
    texture {
      pigment {
        checker
        color rgb<1.000, 0.000, 0.000>
        color rgb<1.000, 1.000, 1.000>
        scale <0.2500, 0.2500, 0.2500>
      }
    }
  // plain red/white check box
  box {
    <-1, -1, -1>, <1, 1, 1>
    texture {
      PLAIN_TEXTURE
    }
    translate  <-1.5, 1.2, 0>
  }

We render this scene. It is not particularly interesting, is it? That is why we will use some layered textures to make it more interesting.

First, we add a layer of two different, partially transparent grays. We tile them as we had tiled the red and white colors, but we add some turbulence to make the fading more realistic. We add the following box to the previous scene and re-render (see file layered2.pov).

  #declare FADED_TEXTURE =
    // red/white check texture
    texture {
      pigment {
        checker
        color rgb<0.920, 0.000, 0.000>
        color rgb<1.000, 1.000, 1.000>
        scale <0.2500, 0.2500, 0.2500>
      }
    }
    // greys to fade red/white
    texture {
      pigment {
        checker
        color rgbf<0.632, 0.612, 0.688, 0.698>
        color rgbf<0.420, 0.459, 0.520, 0.953>
        turbulence 0.500
        scale <0.2500, 0.2500, 0.2500>
      }
    }
  // faded red/white check box
  box {
    <-1, -1, -1>, <1, 1, 1>
    texture {
      FADED_TEXTURE
    }
    translate  <1.5, 1.2, 0>
  }

Even though it is a subtle difference, the red and white checks no longer look quite so new.

Since there is a bottle of wine in the picnic scene, we thought it might be a nice touch to add a stain or two. While this effect can almost be achieved by placing a flattened blob on the cloth, what we really end up with is a spill effect, not a stain. Thus it is time to add another layer.

Again, we add another box to the scene we already have scripted and re-render (see file layered3.pov).

  #declare STAINED_TEXTURE =
    // red/white check
    texture {
      pigment {
        checker
        color rgb<0.920, 0.000, 0.000>
        color rgb<1.000, 1.000, 1.000>
        scale <0.2500, 0.2500, 0.2500>
      }
    }
    // greys to fade check
    texture {
      pigment {
        checker
        color rgbf<0.634, 0.612, 0.688, 0.698>
        color rgbf<0.421, 0.463, 0.518, 0.953>
        turbulence 0.500
        scale <0.2500, 0.2500, 0.2500>
      }
    }
    // wine stain
    texture {
      pigment {
        spotted
        color_map {
          [ 0.000  color rgb<0.483, 0.165, 0.165> ]
          [ 0.329  color rgbf<1.000, 1.000, 1.000, 1.000> ]
          [ 0.734  color rgbf<1.000, 1.000, 1.000, 1.000> ]
          [ 1.000  color rgb<0.483, 0.165, 0.165> ]
        }
        turbulence 0.500
        frequency 1.500
      }
    }
  // stained box
  box {
    <-1, -1, -1>, <1, 1, 1>
    texture {
      STAINED_TEXTURE
    }
    translate  <-1.5, -1.2, 0>
  }

Now there is a tablecloth texture with personality.

Another touch we want to add to the cloth are some wrinkles as if the cloth had been rumpled. This is not another texture layer, but when working with layered textures, we must keep in mind that changes to the surface normal must be included in the uppermost layer of the texture. Changes to lower layers have no effect on the final product (no matter how transparent the upper layers are).

We add this final box to the script and re-render (see file layered4.pov)

  #declare WRINKLED_TEXTURE =
    // red and white check
    texture {
      pigment {
        checker
        color rgb<0.920, 0.000, 0.000>
        color rgb<1.000, 1.000, 1.000>
        scale <0.2500, 0.2500, 0.2500>
      }
    }
    // greys to "fade" checks
    texture {
      pigment {
        checker
        color rgbf<0.632, 0.612, 0.688, 0.698>
        color rgbf<0.420, 0.459, 0.520, 0.953>
        turbulence 0.500
        scale <0.2500, 0.2500, 0.2500>
      }
    }
    // the wine stains
    texture {
      pigment {
        spotted
        color_map {
          [ 0.000  color rgb<0.483, 0.165, 0.165> ]
          [ 0.329  color rgbf<1.000, 1.000, 1.000, 1.000> ]
          [ 0.734  color rgbf<1.000, 1.000, 1.000, 1.000> ]
          [ 1.000  color rgb<0.483, 0.165, 0.165> ]
        }
        turbulence 0.500
        frequency 1.500
      }
      normal {
        wrinkles 5.0000
      }
    }
  // wrinkled box
  box {
    <-1, -1, -1>, <1, 1, 1>
    texture {
      WRINKLED_TEXTURE
    }
    translate  <1.5, -1.2, 0>
  }

Well, this may not be the tablecloth we want at any picnic we are attending, but if we compare the final box to the first, we see just how much depth, dimension, and personality is possible just by the use of creative texturing.

One final note: the comments concerning the surface normal do not hold true for finishes. If a lower layer contains a specular finish and an upper layer does not, any place where the upper layer is transparent, the specular will show through.

2.3.5.11 When All Else Fails: Material Maps

We have some pretty powerful texturing tools at our disposal, but what if we want a more free form arrangement of complex textures? Well, just as image maps do for pigments, and bump maps do for normals, whole textures can be mapped using a material map, should the need arise.

Just as with image maps and bump maps, we need a source image in bitmapped format which will be called by POV-Ray to serve as the map of where the individual textures will go, but this time, we need to specify what texture will be associated with which palette index. To make such an image, we can use a paint program which allows us to select colors by their palette index number (the actual color is irrelevant, since it is only a map to tell POV-Ray what texture will go at that location). Now, if we have the complete package that comes with POV-Ray, we have in our include files an image called povmap.gif which is a bitmapped image that uses only the first four palette indices to create a bordered square with the words "Persistence of Vision" in it. This will do just fine as a sample map for the following example. Using our same include files, the camera and light source, we enter the following object.

  plane {
    -z, 0
    texture {
      material_map {
        gif "povmap.gif"
        interpolate 2
        once
        texture { PinkAlabaster }          // the inner border
        texture { pigment { DMFDarkOak } } // outer border
        texture { Gold_Metal }             // lettering
        texture { Chrome_Metal }           // the window panel
      }
      translate <-0.5, -0.5, 0>
      scale 5
    }
  }

The position of the light source and the lack of foreground objects to be reflected do not show these textures off to their best advantage. But at least we can see how the process works. The textures have simply been placed according to the location of pixels of a particular palette index. By using the once keyword (to keep it from tiling), and translating and scaling our map to match the camera we have been using, we get to see the whole thing laid out for us.

Of course, that is just with palette mapped image formats, such as GIF and certain flavors of PNG. Material maps can also use non-paletted formats, such as the TGA files that POV-Ray itself outputs. That leads to an interesting consequence: We can use POV-Ray to produce source maps for POV-Ray! Before we wrap up with some of the limitations of special textures, let's do one more thing with material maps, to show how POV-Ray can make its own source maps.

To begin with, if using a non-paletted image, POV-Ray looks at the 8 bit red component of the pixel's color (which will be a value from 0 to 255) to determine which texture from the list to use. So to create a source map, we need to control very precisely what the red value of a given pixel will be. We can do this by

  1. Using an rgb statement to choose our color such as rgb <N/255,0,0>, where "N" is the red value we want to assign that pigment, and then...
  2. Use no light sources and apply a finish of finish { ambient 1 } to all objects, to ensure that highlighting and shadowing will not interfere.

Confused? Alright, here is an example, which will generate a map very much like povmap.gif which we used earlier, except in TGA file format. We notice that we have given the pigments blue and green components too. POV-Ray will ignore that in our final map, so this is really for us humans, whose unaided eyes cannot tell the difference between red variances of 0 to 4/255ths. Without those blue and green variances, our map would look to our eyes like a solid black screen. That may be a great way to send secret messages using POV-Ray (plug it into a material map to decode) but it is no use if we want to see what our source map looks like to make sure we have what we expected to.

We create the following code, name it povmap.pov, then render it. This will create an output file called povmap.png

  camera {
    orthographic
    up <0, 5, 0>
    right <5, 0, 0>
    location <0, 0, -25>
    look_at <0, 0, 0>
  }
  plane {
    -z, 0
    pigment { rgb <1/255, 0, 0.5> }
    finish { ambient 1 }
  }
  box {
    <-2.3, -1.8, -0.2>, <2.3, 1.8, -0.2>
    pigment { rgb <0/255, 0, 1> }
    finish { ambient 1 }
  }
  box {
    <-1.95, -1.3, -0.4>, <1.95, 1.3, -0.3>
    pigment { rgb <2/255, 0.5, 0.5> }
    finish { ambient 1 }
  }
  text {
    ttf "crystal.ttf", "The vision", 0.1, 0
    scale <0.7, 1, 1>
    translate <-1.8, 0.25, -0.5>
    pigment { rgb <3/255, 1, 1> }
    finish { ambient 1 }
  }
  text {
    ttf "crystal.ttf", "Persists!", 0.1, 0
    scale <0.7, 1, 1>
    translate <-1.5, -1, -0.5>
    pigment { rgb <3/255, 1, 1> }
    finish { ambient 1 }
  }

All we have to do is modify our last material map example by changing the material map from GIF to TGA and modifying the filename. When we render using the new map, the result is extremely similar to the palette mapped GIF we used before, except that we did not have to use an external paint program to generate our source: POV-Ray did it all!

2.3.5.12 Limitations Of Special Textures

There are a couple limitations to all of the special textures we have seen (from textures, pigment and normal maps through material maps). First, if we have used the default directive to set the default texture for all items in our scene, it will not accept any of the special textures discussed here. This is really quite minor, since we can always declare such a texture and apply it individually to all objects. It does not actually prevent us from doing anything we could not otherwise do.

The other is more limiting, but as we will shortly see, can be worked around quite easily. If we have worked with layered textures, we have already seen how we can pile multiple texture patterns on top of one another (as long as one texture has transparency in it). This very useful technique has a problem incorporating the special textures we have just seen as a layer. But there is an answer!

For example, say we have a layered texture called Speckled_Metal, which produces a silver metallic surface, and then puts tiny specks of rust all over it. Then we decide, for a really rusty look, we want to create patches of concentrated rust, randomly over the surface. The obvious approach is to create a special texture pattern, with transparency to use as the top layer. But of course, as we have seen, we would not be able to use that texture pattern as a layer. We would just generate an error message. The solution is to turn the problem inside out, and make our layered texture part of the texture pattern instead, like this

  // This part declares a pigment for use
  // in the rust patch texture pattern
  #declare Rusty = pigment {
    granite
    color_map {
      [ 0 rgb <0.2, 0, 0> ]
      [ 1 Brown ]
    }
    frequency 20
  }
  // And this part applies it
  // Notice that our original layered texture
  // "Speckled_Metal" is now part of the map
  #declare Rust_Patches = texture {
    bozo
    texture_map {
      [ 0.0  pigment {Rusty} ]
      [ 0.75 Speckled_Metal ]
      [ 1.0  Speckled_Metal ]
    }
  }

And the ultimate effect is the same as if we had layered the rust patches on to the speckled metal anyway.

With the full array of patterns, pigments, normals, finishes, layered and special textures, there is now practically nothing we cannot create in the way of amazing textures. An almost infinite number of new possibilities are just waiting to be created!

2.3.6 Using Atmospheric Effects

POV-Ray offers a variety of atmospheric effects, i. e. features that affect the background of the scene or the air by which everything is surrounded.

It is easy to assign a simple color or a complex color pattern to a virtual sky sphere. You can create anything from a cloud free, blue summer sky to a stormy, heavy clouded sky. Even starfields can easily be created.

You can use different kinds of fog to create foggy scenes. Multiple fog layers of different colors can add an eerie touch to your scene.

A much more realistic effect can be created by using an atmosphere, a constant fog that interacts with the light coming from light sources. Beams of light become visible and objects will cast shadows into the fog.

Last but not least you can add a rainbow to your scene.

2.3.6.1 The Background

The background feature is used to assign a color to all rays that do not hit any object. This is done in the following way.

  camera {
    location <0, 0, -10>
    look_at <0, 0, 0>
  }
  background { color rgb <0.2, 0.2, 0.3> }
  sphere {
    0, 1
    pigment { color rgb <0.8, 0.5, 0.2> }
  }

The background color will be visible if a sky sphere is used and if some translucency remains after all sky sphere pigment layers are processed.

2.3.6.2 The Sky Sphere

The sky_sphere can be used to easily create a cloud covered sky, a nightly star sky or whatever sky you have in mind.

In the following examples we will start with a very simple sky sphere that will get more and more complex as we add new features to it.

2.3.6.2.1 Creating a Sky with a Color Gradient

Beside the single color sky sphere that is covered with the background feature the simplest sky sphere is a color gradient. You may have noticed that the color of the sky varies with the angle to the earth's surface normal. If you look straight up the sky normally has a much deeper blue than it has at the horizon.

We want to model this effect using the sky sphere as shown in the scene skysph1.pov below.

  #include "colors.inc"
  camera {
    location <0, 1, -4>
    look_at <0, 2, 0>
    angle 80
  }
  light_source { <10, 10, -10> White }
  sphere {
    2*y, 1
    pigment { color rgb <1, 1, 1> }
    finish { ambient 0.2 diffuse 0 reflection 0.6 }
  }
  sky_sphere {
    pigment {
      gradient y
      color_map {
        [0 color Red]
        [1 color Blue]
      }
      scale 2
      translate -1
    }
  }

The interesting part is the sky sphere statement. It contains a pigment that describes the look of the sky sphere. We want to create a color gradient along the viewing angle measured against the earth's surface normal. Since the ray direction vector is used to calculate the pigment colors we have to use the y-gradient.

The scale and translate transformation are used to map the points derived from the direction vector to the right range. Without those transformations the pattern would be repeated twice on the sky sphere. The scale statement is used to avoid the repetition and the translate -1 statement moves the color at index zero to the bottom of the sky sphere (that is the point of the sky sphere you will see if you look straight down).

After this transformation the color entry at position 0 will be at the bottom of the sky sphere, i. e. below us, and the color at position 1 will be at the top, i. e. above us.

The colors for all other positions are interpolated between those two colors as you can see in the resulting image.

A simple gradient sky sphere.

If you want to start one of the colors at a specific angle you will first have to convert the angle to a color map index. This is done by using the formula color_map_index = (1 - cos(angle)) / 2 where the angle is measured against the negated earth's surface normal. This is the surface normal pointing towards the center of the earth. An angle of 0 degrees describes the point below us while an angle of 180 degrees represents the zenith.

In POV-Ray you first have to convert the degree value to radians as it is shown in the following example.

  sky_sphere {
    pigment {
      gradient y
      color_map {
        [(1-cos(radians( 30)))/2 color Red]
        [(1-cos(radians(120)))/2 color Blue]
      }
      scale 2
      translate -1
    }
  }

This scene uses a color gradient that starts with a red color at 30 degrees and blends into the blue color at 120 degrees. Below 30 degrees everything is red while above 120 degrees all is blue.

2.3.6.2.2 Adding the Sun

In the following example we will create a sky with a red sun surrounded by a red color halo that blends into the dark blue night sky. We will do this using only the sky sphere feature.

The sky sphere we use is shown below. A ground plane is also added for greater realism (skysph2.pov).

  sky_sphere {
    pigment {
      gradient y
      color_map {
        [0.000 0.002 color rgb <1.0, 0.2, 0.0>
                     color rgb <1.0, 0.2, 0.0>]
        [0.002 0.200 color rgb <0.8, 0.1, 0.0>
                     color rgb <0.2, 0.2, 0.3>]
      }
      scale 2
      translate -1
    }
    rotate -135*x
  }
  plane {
    y, 0
    pigment { color Green }
    finish { ambient .3 diffuse .7 }
  }

The gradient pattern and the transformation inside the pigment are the same as in the example in the previous section.

The color map consists of three colors. A bright, slightly yellowish red that is used for the sun, a darker red for the halo and a dark blue for the night sky. The sun's color covers only a very small portion of the sky sphere because we do not want the sun to become too big. The color is used at the color map values 0.000 and 0.002 to get a sharp contrast at value 0.002 (we do not want the sun to blend into the sky). The darker red color used for the halo blends into the dark blue sky color from value 0.002 to 0.200. All values above 0.200 will reveal the dark blue sky.

The rotate -135*x statement is used to rotate the sun and the complete sky sphere to its final position. Without this rotation the sun would be at 0 degrees, i.e. right below us.

A red sun descends into the night.

Looking at the resulting image you will see what impressive effects you can achieve with the sky sphere.

2.3.6.2.3 Adding Some Clouds

To further improve our image we want to add some clouds by adding a second pigment. This new pigment uses the bozo pattern to create some nice clouds. Since it lays on top of the other pigment it needs some transparent colors in the color map (look at entries 0.5 to 1.0).

  sky_sphere {
    pigment {
      gradient y
      color_map {
        [0.000 0.002 color rgb <1.0, 0.2, 0.0>
                     color rgb <1.0, 0.2, 0.0>]
        [0.002 0.200 color rgb <0.8, 0.1, 0.0>
                     color rgb <0.2, 0.2, 0.3>]
      }
      scale 2
      translate -1
    }
    pigment {
      bozo
      turbulence 0.65
      octaves 6
      omega 0.7
      lambda 2
      color_map {
          [0.0 0.1 color rgb <0.85, 0.85, 0.85>
                   color rgb <0.75, 0.75, 0.75>]
          [0.1 0.5 color rgb <0.75, 0.75, 0.75>
                   color rgbt <1, 1, 1, 1>]
          [0.5 1.0 color rgbt <1, 1, 1, 1>
                   color rgbt <1, 1, 1, 1>]
      }
      scale <0.2, 0.5, 0.2>
    }
    rotate -135*x
  }

A cloudy sky with a setting sun.

The sky sphere has one drawback as you might notice when looking at the final image (skysph3.pov). The sun does not emit any light and the clouds will not cast any shadows. If you want to have clouds that cast shadows you will have to use a real, large sphere with an appropriate texture and a light source somewhere outside the sphere.

2.3.6.3 The Fog

You can use the fog feature to add fog of two different types to your scene: constant fog and ground fog. The constant fog has a constant density everywhere while the ground fog's density decreases as you move upwards.

The usage of both fog types will be described in the next sections in detail.

2.3.6.3.1 A Constant Fog

The simplest fog type is the constant fog that has a constant density in all locations. It is specified by a distance keyword which actually describes the fog's density and a fog color.

The distance value determines the distance at which 36.8% of the background is still visible (for a more detailed explanation of how the fog is calculated read the reference section Fog).

The fog color can be used to create anything from a pure white to a red, blood-colored fog. You can also use a black fog to simulate the effect of a limited range of vision.

The following example will show you how to add fog to a simple scene (fog1.pov).

  #include "colors.inc"
  camera {
    location  <0, 20, -100>
  }
  background { color SkyBlue }
  plane {
    y, -10
    pigment {
      checker color Yellow color Green
      scale 20
    }
  }
  sphere {
    <0, 25, 0>, 40
    pigment { Red }
    finish { phong 1.0 phong_size 20 }
  }
  sphere {
    <-100, 150, 200>,  20
    pigment { Green }
    finish { phong 1.0 phong_size 20 }
  }
  sphere {
    <100, 25, 100>, 30
    pigment { Blue }
    finish { phong 1.0 phong_size 20 }
  }
  light_source { <100, 120, 40> color White }
  fog {
    distance 150
    color rgb<0.3, 0.5, 0.2>
  }

A foggy scene.

According to their distance the spheres in this scene more or less vanish in the greenish fog we used, as does the checkerboard plane.

2.3.6.3.2 Setting a Minimum Translucency

If you want to make sure that the background does not completely vanish in the fog you can set the transmittance channel of the fog's color to the amount of background you always want to be visible.

Using as transmittance value of 0.2 as in

  fog {
    distance 150
    color rgbt<0.3, 0.5, 0.2, 0.2>
  }

the fog's translucency never drops below 20% as you can see in the resulting image (fog2.pov).

Fog with translucency threshold added.
2.3.6.3.3 Creating a Filtering Fog

The greenish fog we have used so far does not filter the light passing through it. All it does is to diminish the light's intensity. We can change this by using a non-zero filter channel in the fog's color (fog3.pov).

  fog {
    distance 150
    color rgbf<0.3, 0.5, 0.2, 1.0>
  }

The filter value determines the amount of light that is filtered by the fog. In our example 100% of the light passing through the fog will be filtered by the fog. If we had used a value of 0.7 only 70% of the light would have been filtered. The remaining 30% would have passed unfiltered.

A filtering fog.

You will notice that the intensity of the objects in the fog is not only diminished due to the fog's color but that the colors are actually influenced by the fog. The red and especially the blue sphere got a green hue.

2.3.6.3.4 Adding Some Turbulence to the Fog

In order to make our somewhat boring fog a little bit more interesting we can add some turbulence, making it look like it had a non-constant density (fog4.pov).

  fog {
    distance 150
    color rgbf<0.3, 0.5, 0.2, 1.0>
    turbulence 0.2
    turb_depth 0.3
  }

Fog made more interesting with turbulence.

The turbulence keyword is used to specify the amount of turbulence used while the turb_depth value is used to move the point at which the turbulence value is calculated along the viewing ray. Values near zero move the point to the viewer while values near one move it to the intersection point (the default value is 0.5). This parameter can be used to avoid noise that may appear in the fog due to the turbulence (this normally happens at very far away intersection points, especially if no intersection occurs, i. e. the background is hit). If this happens just lower the turb_depth value until the noise vanishes.

You should keep in mind that the actual density of the fog does not change. Only the distance-based attenuation value of the fog is modified by the turbulence value at a point along the viewing ray.

2.3.6.3.5 Using Ground Fog

The much more interesting and flexible fog type is the ground fog, which is selected with the fog_type statement. Its appearance is described with the fog_offset and fog_alt keywords. The fog_offset specifies the height, i. e. y value, below which the fog has a constant density of one. The fog_alt keyword determines how fast the density of the fog will approach zero as one moves along the y axis. At a height of fog_offset+fog_alt the fog will have a density of 25%.

The following example (fog5.pov) uses a ground fog which has a constant density below y=25 (the center of the red sphere) and quickly falls off for increasing altitudes.

  fog {
    distance 150
    color rgbf<0.3, 0.5, 0.2, 1.0>
    fog_type 2
    fog_offset 25
    fog_alt 1
  }

An example of ground fog.
2.3.6.3.6 Using Multiple Layers of Fog

It is possible to use several layers of fog by using more than one fog statement in your scene file. This is quite useful if you want to get nice effects using turbulent ground fogs. You could add up several, differently colored fogs to create an eerie scene for example.

Just try the following example (fog6.pov).

  fog {
    distance 150
    color rgb<0.3, 0.5, 0.2>
    fog_type 2
    fog_offset 25
    fog_alt 1
    turbulence 0.1
    turb_depth 0.2
  }
  fog {
    distance 150
    color rgb<0.5, 0.1, 0.1>
    fog_type 2
    fog_offset 15
    fog_alt 4
    turbulence 0.2
    turb_depth 0.2
  }
  fog {
    distance 150
    color rgb<0.1, 0.1, 0.6>
    fog_type 2
    fog_offset 10
    fog_alt 2
  }

Using multiple layers of fog.

You can combine constant density fogs, ground fogs, filtering fogs, non-filtering fogs, fogs with a translucency threshold, etc.

2.3.6.3.7 Fog and Hollow Objects

Whenever you use the fog feature and the camera is inside a non-hollow object you will not get any fog effects. For a detailed explanation why this happens see Empty and Solid Objects.

In order to avoid this problem you have to make all those objects hollow by either making sure the camera is outside these objects (using the inverse keyword) or by adding the hollow to them (which is much easier).

2.3.6.4 The Rainbow

The rainbow feature can be used to create rainbows and maybe other more strange effects. The rainbow is a fog like effect that is restricted to a cone-like volume.

2.3.6.4.1 Starting With a Simple Rainbow

The rainbow is specified with a lot of parameters: the angle under which it is visible, the width of the color band, the direction of the incoming light, the fog-like distance based particle density and last but not least the color map to be used.

The size and shape of the rainbow are determined by the angle and width keywords. The width keyword is used to set the direction of the incoming light, thus setting the rainbow's position. The rainbow is visible when the angle between the direction vector and the incident light direction is larger than angle-width/2 and smaller than angle+width/2.

The incoming light is the virtual light source that is responsible for the rainbow. There need not be a real light source to create the rainbow effect.

The rainbow is a fog-like effect, i.e. the rainbow's color is mixed with the background color based on the distance to the intersection point. If you choose small distance values the rainbow will be visible on objects, not just in the background. You can avoid this by using a very large distance value.

The color map is the crucial part of the rainbow since it contains all the colors that normally can be seen in a rainbow. The color of the innermost color band is taken from the color map entry 0 while the outermost band is take from entry 1. You should note that due to the limited color range any monitor can display it is impossible to create a real rainbow. There are just some colors that you cannot display.

The filter channel of the rainbow's color map is used in the same way as with fogs. It determines how much of the light passing through the rainbow is filtered by the color.

The following example shows a simple scene with a ground plane, three spheres and a somewhat exaggerated rainbow (rainbow1.pov).

  #include "colors.inc"
  camera {
    location <0, 20, -100>
    look_at <0, 25, 0>
    angle 80
  }
  background { color SkyBlue }
  plane { y, -10 pigment { color Green } }
  light_source { <100, 120, 40> color White }
  // declare rainbow's colors
  #declare r_violet1 = color rgbf<1.0, 0.5, 1.0, 1.0>;
  #declare r_violet2 = color rgbf<1.0, 0.5, 1.0, 0.8>;
  #declare r_indigo  = color rgbf<0.5, 0.5, 1.0, 0.8>;
  #declare r_blue    = color rgbf<0.2, 0.2, 1.0, 0.8>;
  #declare r_cyan    = color rgbf<0.2, 1.0, 1.0, 0.8>;
  #declare r_green   = color rgbf<0.2, 1.0, 0.2, 0.8>;
  #declare r_yellow  = color rgbf<1.0, 1.0, 0.2, 0.8>;
  #declare r_orange  = color rgbf<1.0, 0.5, 0.2, 0.8>;
  #declare r_red1    = color rgbf<1.0, 0.2, 0.2, 0.8>;
  #declare r_red2    = color rgbf<1.0, 0.2, 0.2, 1.0>;
  // create the rainbow
  rainbow {
    angle 42.5
    width 5
    distance 1.0e7
    direction <-0.2, -0.2, 1>
    jitter 0.01
    color_map {
      [0.000  color r_violet1]
      [0.100  color r_violet2]
      [0.214  color r_indigo]
      [0.328  color r_blue]
      [0.442  color r_cyan]
      [0.556  color r_green]
      [0.670  color r_yellow]
      [0.784  color r_orange]
      [0.900  color r_red1]
    }
  }

Some irregularity is added to the color bands using the jitter keyword.

A colorful rainbow.

The rainbow in our sample is much too bright. You will never see a rainbow like this in reality. You can decrease the rainbow's colors by decreasing the RGB values in the color map.

2.3.6.4.2 Increasing the Rainbow's Translucency

The result we have so far looks much too bright. Just reducing the rainbow's color helps but it is much better to increase the translucency of the rainbow because it is more realistic if the background is visible through the rainbow.

We can use the transmittance channel of the colors in the color map to specify a minimum translucency, just like we did with the fog. To get realistic results we have to use very large transmittance values as you can see in the following example (rainbow2.pov).

  rainbow {
    angle 42.5
    width 5
    distance 1.0e7
    direction <-0.2, -0.2, 1>
    jitter 0.01
    color_map {
      [0.000  color r_violet1 transmit 0.98]
      [0.100  color r_violet2 transmit 0.96]
      [0.214  color r_indigo  transmit 0.94]
      [0.328  color r_blue    transmit 0.92]
      [0.442  color r_cyan    transmit 0.90]
      [0.556  color r_green   transmit 0.92]
      [0.670  color r_yellow  transmit 0.94]
      [0.784  color r_orange  transmit 0.96]
      [0.900  color r_red1    transmit 0.98]
    }
  }

The transmittance values increase at the outer bands of the rainbow to make it softly blend into the background.

A much more realistic rainbow.

The resulting image looks much more realistic than our first rainbow.

2.3.6.4.3 Using a Rainbow Arc

Currently our rainbow has a circular shape, even though most of it is hidden below the ground plane. You can easily create a rainbow arc by using the arc_angle keyword with an angle below 360 degrees.

If you use arc_angle 120 for example you will get a rainbow arc that abruptly vanishes at the arc's ends. This does not look good. To avoid this the falloff_angle keyword can be used to specify a region where the arc smoothly blends into the background.

As explained in the rainbow's reference section (see Rainbow) the arc extends from -arc_angle/2 to arc_angle/2 while the blending takes place from -arc_angle/2 to -falloff_angle/2 and falloff_angle/2 to arc_angle/2. This is the reason why the falloff_angle has to be smaller or equal to the arc_angle.

In the following examples we use an 120 degrees arc with a 45 degree falloff region on both sides of the arc (rainbow3.pov).

  rainbow {
    angle 42.5
    width 5
    arc_angle 120
    falloff_angle 30
    distance 1.0e7
    direction <-0.2, -0.2, 1>
    jitter 0.01
    color_map {
      [0.000  color r_violet1 transmit 0.98]
      [0.100  color r_violet2 transmit 0.96]
      [0.214  color r_indigo  transmit 0.94]
      [0.328  color r_blue    transmit 0.92]
      [0.442  color r_cyan    transmit 0.90]
      [0.556  color r_green   transmit 0.92]
      [0.670  color r_yellow  transmit 0.94]
      [0.784  color r_orange  transmit 0.96]
      [0.900  color r_red1    transmit 0.98]
    }
  }

The arc angles are measured against the rainbows up direction which can be specified using the up keyword. By default the up direction is the y-axis.

A rainbow arc.

We finally have a realistic looking rainbow arc.

2.3.7 Simple Media Tutorial

Media in POV-Ray is a very versatile feature and can be used for a very diverse set of special effects such as glows, smoke, dust, fog, etc. However, due to its versatility, media is not one of the easiest and simplest features of POV-Ray and often requires experience for getting things to look good.

2.3.7.1 Types of media

There are three types of media in POV-Ray: Emitting, absorbing and scattering. They have the following properties:

  • Emitting: This is an additive media, which is handled as if it only emits light (note: it does not emit light to its surroundings like a light_source does; this just describes how it affects the rays going through it). That is, the color of the media is added to the color of the ray passing through it. Light sources do not have any effect at all in it (ie. it does not affect shadows in any way).
  • Absorbing: This is a substractive media. This media substracts (absorbs) its coloration from the ray passing through it. Light sources are taken into account only in the shadow of the media (that is, absorbing media casts a shadow).
  • Scattering: This is the most advanced media type as it fully takes into account light passing through it. That is, this media is lit by light sources (and thus, for example, nearby objects can cast shadows into the scattering media).

Emitting and absorbing medias are the simplest and thus fastest ones. Emitting media can be used for things like glows, lasers, sparkles and similar light-emitting effects. Absorbing media can be used for things like smoke and fog (the difference between the fog feature of POV-Ray is that the density of an absorbing media can be modified by a pattern and the media can be contained inside an object).

Scattering media is the more advanced and slower type. It is somewhat similar to absorbing media except that it is fully lit by light sources. This can be used for smoke or fog with visible lightbeams and shadows.

2.3.7.2 Some media concepts

Media can be global to the whole universe, or it can be contained by an object. In the latter case the media is defined in the interior block of the object definition.

For an object to be able to contain media (or to allow media from other objects or the global media inside itself) it has to be defined as hollow (a common mistake is to forget adding this keyword). If an object with no media should not allow media inside itself (eg. a solid glass ball), then hollow should not be defined for that object.

If media is defined in the interior of an object or as a global media it will have a constant density throughout the object/universe. However, a density pattern can be specified for non-uniform media. Also all kinds of transformations can be applied to the media. This is specially useful for various effects (such as smoke with certain shape).

2.3.7.3 Simple media examples

2.3.7.3.1 Emitting media

Let's start with a very simple scene showing an emitting media using a spherical density map. Emitting media is used with the emission keyword followed by a color value. This color value tells the overall color of the media:

 global_settings { assumed_gamma 1 }
 background { rgb 1 }
 camera { location <3,4,-5>*.8 look_at 0 angle 35 }
 light_source { <20,40,10>, 1 }

 box // floor
 { <-1.5,-1.01,-1.5>, <1.5,-1.2,1.5>
   pigment { checker rgb 0.75, rgb 0.25 scale 0.2 }
 }

 sphere // transparent sphere containing media
 { 0,1 pigment { rgbt 1 } hollow
   interior
   { media
     { emission 1
       density
       { spherical density_map
         { [0 rgb 0]
           [0.4 rgb <1,0,0>]
           [0.8 rgb <1,1,0>]
           [1 rgb 1]
         }
       }
     }
  }
 }

Note: The spherical pattern gets values from 0 in the outer surface of a unit sphere to 1 in the origin (that is, the density with the index value 1 will be the density at the center of the media).

The color values in the density map tell what color the media is emitting at a certain point in the pattern. That is, for example when the pattern gets the value 0.4, the media will be completely red at that place. If the color is <0,0,0>, it means that the media does not emit any light at all in that location.

Note: The density map colors are multiplied by the color given with the emission keyword; since 1 is used in this case, the density map colors are not affected.

Thus, this will give us a media with a bright white center which fades to yellow and red at the outer limits of the unit sphere:

Simple emitting media example

As you can see from the image, the emitting media is invisible against white background. This is due to its additive nature (any color added to pure white gives pure white). In fact, emitting media gives usually best results for dark backgrounds.

2.3.7.3.2 Absorbing media

Modifying the previous example to use absorbing media is rather simple: Simply change the emission keyword for absorption. However, the colors we used above are not very illustrative for absorbing media, so let's change them a bit like this:

    media
    { absorption 1
      density
      { spherical density_map
        { [0 rgb 0]
          [0.4 rgb 0]
          [0.5 rgb <0,0.5,1>]
          [1 rgb <0,1,1>]
        }
      }
    }

Simple absorbing media example

The feature which we immediately notice in the image is that the media seems to be inverted from the colors specified in the density map: Blueish colors were specified in the map, but the image shows a reddish media. This is perfectly normal and to be expected from the substractive nature of absorbing media: The media actually absorbs the colors we specified in the density map. This means that for example specifying a white color (<1,1,1>) in the density map will absorb all colors, thus resulting in a dark media.

See how this media has a shadow: light rays passing through the media are absorbed.

Because of its subtractive nature, absorbing media works well with light backgrounds and not very well with dark ones.

2.3.7.3.3 Scattering media

Since scattering media fully takes light sources into account we need to make a slightly more complex scene to see this. Let's modify the above example by replacing the sphere with a box containing evenly distributed scattering media, and a cylinder which will cast a shadow onto the media:

 box
 { -1,1 pigment { rgbt 1 } hollow
   interior
   { media
     { scattering { 1, 0.5 }
     }
   }
 }
 cylinder
 { <0.9, -1, 0.7>, <0.9, 0.9, 0.7>, 0.5
   pigment { rgb <1, 0.8, 0.5> }
 }

Simple scattering media example

(The effect may look a bit unnatural for a fog effect because the media is contained inside a box and the cylinder is partially out of this box, but this is done to better visualize what is happening.)

The scattering keyword takes more parameters than the other two. The first number inside the curly brackets is the scattering media type. In this example we used scattering media type 1. A full list of scattering media types is given in the section scattering of the Media reference.

The second parameter is the overall color of the media, similar to the parameter of the other two media types.

An optional third parameter can be given with the extinction keyword inside the curly brackets. This keyword controls how fast the scattering media absorbs light and has to be used sometimes to get the desired effect, such as when the media absorbs too much light.

Tip: If you are getting a really dense or dark scattering media, try different values for the color and the extinction value (usually values between 0 and 1). It is usually enough to play with these two values to get the desired effect.

2.3.7.4 Multiple medias inside the same object

Emitting media works well with dark backgrounds. Absorbing media works well for light backgrounds. But what if we want a media which works with both type of backgrounds?

One solution for this is to use both types of medias inside the same object. This is possible in POV-Ray.

Let's take the very first example, which did not work well with the white background, and add a slightly absorbing media to the sphere:

 sphere
 { 0,1 pigment { rgbt 1 } hollow
   interior
   { media
     { emission 1
       density
       { spherical density_map
         { [0 rgb 0]
           [0.4 rgb <1,0,0>]
           [0.8 rgb <1,1,0>]
           [1 rgb 1]
         }
       }
     }
     media
     { absorption 0.2
     }
   }
 }

This will make the sphere not only add light to the rays passing through it, but also substract.

Emitting and absorbing media example.

Multiple medias in the same object can be used for several other effects as well.

2.3.7.5 Media and transformations

The density of a media can be modified with any pattern modifier, such as turbulence, scale, etc. This is a very powerful tool for making diverse effects.

As an example, let's make an absorbing media which looks like smoke. For this we take the absorbing media example and modify the sphere like this:

 sphere
 { 0,1.5 pigment { rgbt 1 } hollow
   interior
   { media
     { absorption 7
       density
       { spherical density_map
         { [0 rgb 0]
           [0.5 rgb 0]
           [0.7 rgb .5]
           [1 rgb 1]
         }
         scale 1/2
         warp { turbulence 0.5 }
         scale 2
       }
     }
   }
   scale <1.5,6,1.5> translate y
 }

Media transformation example.

A couple of notes:

The radius of the sphere is now a bit bigger than 1 because the turbulent pattern tends to take more space.

The absorption color can be larger than 1, making the absorption stronger and the smoke darker.

Note: When you scale an object containing media the media density is not scaled accordingly. This means that if you for example scale a container object larger the rays will pass through more media than before, giving a stronger result. If you want to keep the same media effect with the larger object, you will need to divide the color of the media by the scaling amount.

The question of whether the program should scale the density of the media with the object is a question of interpretation: For example, if you have a glass of colored water, a larger glass of colored water will be more colored because the light travels a larger distance. This is how POV-Ray behaves. Sometimes, however, the object needs to be scaled so that the media does not change; in this case the media color needs to be scaled inversely.

2.3.7.6 A more advanced example of scattering media

For a bit more advanced example of scattering media, let's make a room with a window and a light source illuminating from outside the room. The room contains scattering media, thus making the light beam coming through the window visible.

 global_settings { assumed_gamma 1 }
 camera { location <14.9, 1, -8> look_at -z angle 70 }
 light_source { <10,100,150>, 1 }
 background { rgb <0.3, 0.6, 0.9> }

 // A dim light source inside the room which does not
 // interact with media so that we can see the room:
 light_source { <14, -5, 2>, 0.5 media_interaction off }

 // Room
 union
 { difference
   { box { <-11, -7, -11>, <16, 7, 10.5> }
     box { <-10, -6, -10>, <15, 6, 10> }
     box { <-4, -2, 9.9>, <2, 3, 10.6> }
   }
   box { <-1.25, -2, 10>, <-0.75, 3, 10.5> }
   box { <-4, 0.25, 10>, <2, 0.75, 10.5> }
   pigment { rgb 1 }
 }

 // Scattering media box:
 box
 { <-5, -6.5, -10.5>, <3, 6.5, 10.25>
   pigment { rgbt 1 } hollow
   interior
   { media
     { scattering { 1, 0.07 extinction 0.01 }
       samples 30
     }
   }
 }

As suggested previously, the scattering color and extinction values were adjusted until the image looked good. In this kind of scene usually very small values are needed.

Note how the container box is quite smaller than the room itself. Container boxes should always be sized as minimally as possible. If the box were as big as the room much higher values for samples would be needed for a good result, thus resulting in a much slower rendering.

more advanced scattering media example

2.3.7.7 Media and photons

The photon mapping technique can be used in POV-Ray for making stunningly beautiful images with light reflecting and refracting from objects. By default, however, reflected and refracted light does not affect media. Making photons interact with media can be turned on with the media keyword in the photons block inside global_settings.

To visualize this, let's make the floor of our room reflective so that it will reflect the beam of light coming from the window.

Firstly, due to how photons work, we need to specify photons { pass_through } in our scattering media container box so that photons will pass through its surfaces.

Secondly, we will want to turn photons off for our fill-light since it's there only for us to see the interior of the room and not for the actual lighting effect. This can be done by specifying photons { reflection off } in that light source.

Thirdly, we need to set up the photons and add a reflective floor to the room. Let's make the reflection colored for extra effect:

 global_settings
 { photons
   { count 20000
     media 100
   }
 }

 // Reflective floor:
 box
 { <-10, -5.99, -10>, <15, -6, 10>
   pigment { rgb 1 }
   finish { reflection <0.5, 0.4, 0.2> }
   photons { target reflection on }
 }

Scattering media with photons example.

With all these fancy effects the render times start becoming quite high, but unfortunately this is a price which has to be paid for such effects.

2.3.8 Radiosity

2.3.8.1 Introduction

Radiosity is a lighting technique to simulate the diffuse exchange of radiation between the objects of a scene. With a raytracer like POV-Ray, normally only the direct influence of light sources on the objects can be calculated, all shadowed parts look totally flat. Radiosity can help to overcome this limitation. More details on the technical aspects can be found in the reference section.

To enable radiosity, you have to add a radiosity block to the global_settings in your POV-Ray scene file. Radiosity is more accurate than simplistic ambient light but it takes much longer to compute, so it can be useful to switch off radiosity during scene development. You can use a declared constant or an INI-file constant and an #if statement to do this:

  #declare RAD = off;

  global_settings {
     #if(RAD)
        radiosity {
           ...
        }
     #end
  }

Most important for radiosity are the emission and diffuse finish components of the objects. Their effect differs quite greatly from a conventionally lit scene.

  • emission: specifies the amount of light emitted by the object. This is the basis for radiosity without conventional lighting but also in scenes with light sources this can be important. In a radiosity scene, emission not only makes the object itself brighter, but effectively makes it a light source, illuminating nearby objects.
  • diffuse: influences the amount of diffuse reflection of incoming light. In a radiosity scene this does not only mean the direct appearance of the surface but also how much other objects are illuminated by indirect light from this surface.

Note: Previous versions of POV-Ray up to 3.6 inclusive did not provide the emission keyword, leading to the practice of using ambient instead. As of POV-Ray 3.7, this will no longer work, as ambient_light is effectively forced to zero when radiosity is enabled. For backward compatibility, an exception is made for scenes specifying a #version of 3.6 or earlier (or no version at all). In such scenes, it is strongly recommended to set the ambient of all materials to zero (unless you want them to emit light), or explicitly set ambient_light to zero.

2.3.8.2 Radiosity with conventional lighting

This section will introduce you to the technique of combining conventional and radiosity lighting. In this part of the tutorial, we'll be using basically the same sample scene that's located at ~/scenes/radiosity/radiosity2.pov, however by changing various radiosity parameters, we'll be able to explore the effects that those changes can have on the scenes appearance and in some cases the render time. Later on, in this tutorial, you can find examples of pure radiosity illumination.

Note: Unless otherwise stated all the images in this section were rendered with the following radiosity settings:

  global_settings {
    radiosity {
      pretrace_start 0.08
      pretrace_end   0.01
      count 150
      nearest_count 10
      error_bound 0.5
      recursion_limit 3
      low_error_factor 0.5
      gray_threshold 0.0
      minimum_reuse 0.005
      maximum_reuse 0.2
      brightness 1
      adc_bailout 0.005
    }
  }

Finally, a few more things about the scene setup. All objects except the sky have diffuse 0.65 and emission 0 in their finish block. The sky sphere has a bright blue pigment (what a surprise) with diffuse 0 and emission 1.0 as finish attributes.

Note: If using the sky_sphere object, which does not support the finish keyword, instead of a sphere object that does, you will need define a #default finish in order to affect it's finish properties.

For example:

#default {finish { diffuse 0 emission 1 }}

Hint: You can easily turn radiosity on/off with the use of a conditional statement.

#declare UseRad = yes;

  global_settings {
  #if (UseRad)
    radiosity {
      rad settings ...
    }
  #end
  }

OK, let's get started! In this set of images we first have the scene as it should appear without radiosity, in other words the radiosity block has been removed, next with the settings noted above, and finally an image showing the difference between the two. Looking at the difference image, you can see that radiosity greatly affects the shadowed areas when applied in combination with conventional lighting.

Note: The use of emission 1 in the finish block of the blue sky is what gives the bluish touch of the whole scene in the radiosity version, as it functions as kind of a diffuse light source.

no radiosity | radiosity | difference w/o radiosity

Radiosity is a highly tunable process, and it comes equipped with a variety of tunable parameters that make it easy to strike a balance between quality and rendering speed. However, as with most things, higher quality means more render time. Patience is a virtue.

For instance, let's examine our test object with default settings, with our reference settings, and finally with some maddeningly high-quality settings. For comparison, below each image you can see the difference to the high-quality version.

default settings | high-quality render | reference settings
default settings difference |  | reference settings difference

Changing the brightness changes the intensity of radiosity effects. Theoretically specifying brightness 0 would be the same as without radiosity, however in practice POV-Ray doesn't accept a zero value. As a rule brightness 1 should work correctly in most cases. If the effects are too strong you can reduce this, though this is not recommended, as it's usually an indication that your textures are too bright and your illumination too dim. Larger values can lead to quite strange results in most cases.

brightness 0.5 | brightness 1.0 | brightness 2.0

The recursion_limit setting primarily affects the brightness of shadows, nooks and corners. The following group of images show the results of setting this parameter to 1, 2 and 5 respectively ...

recursion_limit 1 | recursion_limit 2 | recursion_limit 5

... while this next grouping shows the difference when compared to our reference setting of recursion_limit 3. As you can see, values higher than 3 do not lead to any better results in such a quite simple scene. In most cases values of 1 or 2 are sufficient, especially for outdoor scenes.

recursion_limit 1 difference | recursion_limit 2 difference | recursion_limit 5 difference

The error_bound setting mainly affects the structures of the shadows. Values larger than the default of 1.8 do not have much effect, they make the shadows even flatter. Extremely low values can lead to very good results, but the rendering time can become very long, and you may need to modify other parameters to avoid a grainy appearance.

error_bound 0.01 | error_bound 1.0 | error_bound 1.8
error_bound 0.01 difference | error_bound 1.0 difference | error_bound 1.8 difference

Somewhat related to error_bound is low_error_factor. It reduces error_bound setting during the pretrace phase, changing this can be useful to eliminate artifacts. The difference images used the low_error_factor 0.5 case for comparison.

low_error_factor 0.01 | low_error_factor 0.5 | low_error_factor 1.0
low_error_factor 0.01 difference |  | low_error_factor 1.0 difference

This next sequence of images illustrate the effect of count. It is a general quality and accuracy parameter leading to higher quality and slower rendering at higher values. Keep in mind that higher count isn't necessarily a cure-for-all when it comes to quality. The difference images were compared to a count 150 case.

Note: Until otherwise noted the following settings are being used to emphasize the effects of the next parameters we'll be examining.

  • recursion_limit 1
  • error_bound 0.2
  • low_error_factor 1.0

count 2 | count 35 (default) | count 1000
count 2 difference | count 35 difference | count 1000 difference

Another parameter that affects quality is nearest_count. You can use values ranging from 1 to 20 the default is 5. Just like count, higher values can lead to less artifacts and smoother appearance but slower rendering. The nearest_count setting also accepts a second parameter, which activates adaptive pretrace, providing a good means of speeding up pretrace without significant loss of quality (not shown here) the value must be smaller than the first parameter (e.g. nearest_count 20,10). When set, POV-Ray will stop pretracing individual areas of the image where the average sample density already satisfies this second value, thereby avoiding tracing low-detail areas over and over again for little gain, while still being able to drill down deep into high-detail areas. A setting of nearest_count 10 was used for the comparison.

nearest_count 1 | nearest_count 5 (default) | nearest_count 20
nearest_count 1 difference | nearest_count 5 difference | nearest_count 20 difference

minimum_reuse influences at which minimum distance previous radiosity samples are always reused during calculation, affecting quality and smoothness in nooks and corners. Higher values generally give a smoother appearance, at the cost of corner detail, while lower values may cause corners to look splotchy unless the other parameters (most notably count and nearest_count) are set for higher quality as well.

As minimum_reuse must be lower than maximum_reuse, to avoid a parse error with the highest setting we're using maximum_reuse 0.4 and the minimum_reuse 0.005 case, was used for the comparison with these next three images.

minimum_reuse 0.2 | minimum_reuse 0.005 | minimum_reuse 0.015
minimum_reuse 0.2 difference |  | minimum_reuse 0.015 difference

Another important setting is pretrace_end. It specifies how many pretrace steps are calculated and thereby strongly influences the speed. Usually lower values lead to better quality, but it is important to keep this in good relation to error_bound.

pretrace_end 0.2 | pretrace_end 0.01 | pretrace_end 0.001
pretrace_end 0.2 |  | pretrace_end 0.001

Normally in the final trace no additional radiosity samples are taken unless absolutely needed. You can change this by adding always_sample on allowing you to increase pretrace_end to speed up rendering. Note however that this is very prone to artifacts such as visible render block boundaries and horizontal "smearing", so it is usually only useful for test renders. You should also use a low setting for nearest_count, or you may actually increase the rendering time, and the probability of getting the mentioned artifacts!.

always_sample off | always_sample on difference | always_sample on

The effect of max_sample is similar to brightness. It does not reduce the radiosity effect in general but weakens samples with brightness above the specified value.

max_sample 0.5 | max_sample 0.8 | max_sample not set (default)

You can strongly affect things with an object's finish attributes. In fact that is the most important thing about radiosity. Normal objects should have an emission 0 (the default) finish. Objects with an emission setting greater than zero actually act as light sources in radiosity scenes. Remember that the default finish values used until now were diffuse 0.65 and emission 0.

diffuse 0.65 emission 0.2 | diffuse 0.4 emission 0 | diffuse 1.0 emission 0

Finally you can vary the sky in outdoor radiosity scenes. In all these examples it is implemented with a sphere object. finish { emission 1 diffuse 0 } and the pigment of the original sample scene were used until now. The following images show some variations.

emission 0 diffuse 1 | emission 0 diffuse 0 (no sky) | rgb <1,0.8,0> to blue 1 gradient

2.3.8.3 Radiosity without conventional lighting

Radiosity also allows us to have scenes without conventional light sources. What's left is a situation that's similar to what you'd expect on a cloudy day where the light comes from no specific direction but from the whole sky.

Reminder: The following settings are still in effect.

  • recursion_limit 1
  • error_bound 0.2
  • low_error_factor 1.0

You can see that when the light source is removed the whole image takes on a noticeable blue tint. That's because the scene is now illuminated by our sky object, which in this case happens to be blue. Later on you'll see how varying the color of the sky influences the appearance of the scene.

with light source | without light source

Note: We'll be using the sample scene ~/scenes/radiosity/radiosity3.pov for the rest of this tutorial.

This next series of images show our new test object with the default settings, then our reference settings, and lastly those maddeningly high-quality settings we used earlier. Notice that with the default settings, the image looks much worse than in the first part of this tutorial. The reason being, those settings were mainly selected for use with a conventionally lit scene. Keep in mind, radiosity-only scenes are less forgiving of low-quality settings.

Note: As a reminder you might want to refer back to the reference settings used at the beginning of this tutorial.

default settings | tutorial reference settings | high-quality settings

The following images demonstrate the effect of different settings for recursion_limit.

recursion_limit 1 | recursion_limit 3 | recursion_limit 2
recursion_limit 1 difference |  | recursion_limit 2 difference

The next three images show the effect of error_bound. In scenes without light sources, this is even more important than than scenes that do. Good values mostly depend on the scenery and the other settings, lower values do not necessarily lead to better results. Note that we're using our error_bound 0.5 image as reference.

error_bound 0.01 | error_bound 1.0 | error_bound 1.8
error_bound 0.01 difference | error_bound 1.0 difference | error_bound 1.8 difference

If there are artifacts it often helps to increase count, it does affect quality in general and often helps removing them, the following three images use error_bound 0.2.

count 2 | count 50 | count 200
count 35 difference |  | count 150 difference

As can be seen upon closer inspection however, this is no magic cure-all, some bright speckles remain even with extremely high count values.

In this case, the reason is that the pretrace is simply too short to provide the number of samples we aim for. This is a job for pretrace_end: Together with pretrace_start it specifies how many pretrace steps are done, and how high their resolution is. Lower values of pretrace_end lead to more pretrace steps and more accurate results but also to significantly slower rendering.

We're still using error_bound 0.1 for these images.

pretrace_end 0.4 | pretrace_end 0.01 | pretrace_end 0.001
pretrace_end 0.4 difference |  | pretrace_end 0.001 difference

This next sequence shows the effect of nearest_count, the difference is not very strong, but larger values always lead to better results, the maximum is 20. We'll be using error_bound 0.5 again, but also the following modifications to emphasize the effect.

  • recursion_limit 1
  • low_error_factor 1.0
  • pretrace_end 0.001

Note: From now on we'll stick to these values.

nearest_count 2 | nearest_count 5 (default) | nearest_count 20
nearest_count 2 difference | nearest_count 5 difference | nearest_count 20 difference

The minimum_reuse is a geometric value related to the size of the render in pixels and affects whether previous radiosity calculations are reused at a new point. Lower values lead to more often and therefore more accurate calculations, but care must be taken to balance this setting with the others. The minimum_reuse 0.05 was used for the comparison.

minimum_reuse 0.1 | minimum_reuse 0.05 (default) | minimum_reuse 0.015
minimum_reuse 0.1 difference |  | minimum_reuse 0.015 difference

In most cases it is not necessary to change the low_error_factor. This setting reduces the error_bound value during the final pretrace step. Changing this value can sometimes help to remove persistent artifacts.

low_error_factor 0.01 | low_error_factor 0.5 (default) | low_error_factor 1.0
low_error_factor 0.01 difference |  | low_error_factor 1.0 difference

The gray_threshold setting reduces the color in the radiosity calculations. As mentioned above the blue sky affects the color of the whole scene when radiosity is calculated. To reduce this coloring effect without affecting radiosity in general you can increase gray_threshold. A value of 1.0 means no color in radiosity at all.

gray_threshold 0.0 (default) | gray_threshold 0.5 | gray_threshold 1.0

It is worth experimenting with the things affecting radiosity to get some feeling for how things work. The next 3 images show some more experiments. We're back with the original reference settings from now on.

emission 3 for two objects | all objects emission 0.3 sky is 0 | emission -3 for one object

Finally you can strongly change the appearance of the whole scene with the sky's texture. The following images give some examples.

rgb <1,0.8,0> to blue gradient | light-dark gradient left-right | light-dark gradient bottom-top

Really good results mostly depend on the single situation and how the scene is meant to look. We used these settings listed below, to get this example of a higher quality render of our test object. It's important to remember that requirements can be much different from scene to scene. |
 | higher quality radiosity scene
  global_settings {
    radiosity {
      pretrace_start 0.128
      pretrace_end   0.002
      count 500
      nearest_count 20
      error_bound 0.5
      recursion_limit 2
      low_error_factor 1.0
      gray_threshold 0.0
      minimum_reuse 0.005
      maximum_reuse 0.1
      brightness 1
      adc_bailout 0.005
    }
  }

2.3.8.4 Normals and Radiosity

When using a normal statement in combination with radiosity lighting, you will see that the shadowed parts of the objects are totally smooth, no matter how strong the normals are made. The reason is that POV-Ray by default does not take the normal into account when calculating radiosity. You can easily change this by adding normal on to the radiosity block. Be aware that this can slow things down quite a bit and will require more memory, however it usually leads to more realistic results.

When using normals you should also remember that they are only faked irregularities and do not generate real geometric disturbances of the surface. A more realistic approach is using an isosurface with a pigment function, but this can quickly lead to increased render times.

As you can see with this next series of images, the isosurface version does not have the same smooth-like appearance to it's circumference, as compared to the first two images. Notice that it also has a more realistic shadow-line.

normal off (default) | normal on | isosurface

2.3.8.5 Performance considerations

High quality radiosity can be very slow. To some extent this is the price to pay for realistic lighting, but there are a lot of things that can be done to improve speed.

If average to good quality radiosity will work for your scene, then it's probably a good idea to spend the time to find the sweet spot that strikes the best balance between quality and speed. Especially recursion_limit should be kept as low as possible. Sometimes 1 is sufficient, if not 2 or 3 should often be enough.

With high quality settings, radiosity data can take quite a lot of memory. Apart from that the other scene data is also used much more intensively than in a conventional scene. Therefore insufficient memory and swapping can slow down things even more. Here's a few radiosity options that might help.

Finally the scene geometry and textures are important too. Objects not visible in the camera usually only increase parsing time and memory use, but in a radiosity scene, also objects behind the camera can slow down the rendering process. See the section Configuring Radiosity for some helpful hints.

2.3.9 Making Animations

There are a number of programs available that will take a series of still image files (such as POV-Ray outputs) and assemble them into animations. Such programs can produce AVI, MPEG, FLI/FLC, QuickTime, or even animated GIF files (for use on the World Wide Web). The trick, therefore, is how to produce the frames. That, of course, is where POV-Ray comes in. In earlier versions producing an animation series was no joy, as everything had to be done manually. We had to set the clock variable, and handle producing unique file names for each individual frame by hand. We could achieve some degree of automation by using batch files or similar scripting devices, but still, We had to set it all up by hand, and that was a lot of work (not to mention frustration... imagine forgetting to set the individual file names and coming back 24 hours later to find each frame had overwritten the last).

Now, at last, with POV-Ray 3, there is a better way. We no longer need a separate batch script or external sequencing programs, because a few simple settings in our INI file (or on the command line) will activate an internal animation sequence which will cause POV-Ray to automatically handle the animation loop details for us.

Actually, there are two halves to animation support: those settings we put in the INI file (or on the command line), and those code modifications we work into our scene description file. If we have already worked with animation in previous versions of POV-Ray, we can probably skip ahead to the section INI File Settings below. Otherwise, let's start with basics. Before we get to how to activate the internal animation loop, let's look at a couple examples of how a couple of keywords can set up our code to describe the motions of objects over time.

2.3.9.1 The Clock Variable: Key To It All

POV-Ray supports an automatically declared floating point variable identified as clock (all lower case). This is the key to making image files that can be automated. In command line operations, the clock variable is set using the +k switch. For example, +k3.4 from the command line would set the value of clock to 3.4. The same could be accomplished from the INI file using Clock=3.4 in an INI file.

If we do not set clock for anything, and the animation loop is not used (as will be described a little later) the clock variable is still there - it is just set for the default value of 0.0, so it is possible to set up some POV code for the purpose of animation, and still render it as a still picture during the object/world creation stage of our project.

The simplest example of using this to our advantage would be having an object which is travelling at a constant rate, say, along the x-axis. We would have the statement

  translate <clock, 0, 0>

in our object's declaration, and then have the animation loop assign progressively higher values to clock. And that is fine, as long as only one element or aspect of our scene is changing, but what happens when we want to control multiple changes in the same scene simultaneously?

The secret here is to use normalized clock values, and then make other variables in your scene proportional to clock. That is, when we set up our clock, (we are getting to that, patience!) have it run from 0.0 to 1.0, and then use that as a multiplier to some other values. That way, the other values can be whatever we need them to be, and clock can be the same 0 to 1 value for every application. Let's look at a (relatively) simple example

  #include "colors.inc"
  camera {
    location <0, 3, -6>
    look_at <0, 0, 0>
  }
  light_source { <20, 20, -20> color White }
  plane {
    y, 0
    pigment { checker color White color Black }
  }
  sphere {
    <0, 0, 0> , 1
    pigment {
      gradient x
      color_map {
        [0.0 Blue  ]
        [0.5 Blue  ]
        [0.5 White ]
        [1.0 White ]
      }
      scale .25
    }
    rotate <0, 0, -clock*360>
    translate <-pi, 1, 0>
    translate <2*pi*clock, 0, 0>
  }

Assuming that a series of frames is run with the clock progressively going from 0.0 to 1.0, the above code will produce a striped ball which rolls from left to right across the screen. We have two goals here:

  1. Translate the ball from point A to point B, and,
  2. Rotate the ball in exactly the right proportion to its linear movement to imply that it is rolling -- not gliding -- to its final position.

Taking the second goal first, we start with the sphere at the origin, because anywhere else and rotation will cause it to orbit the origin instead of rotating. Throughout the course of the animation, the ball will turn one complete 360 degree turn. Therefore, we used the formula, 360*clock to determine the rotation in each frame. Since clock runs 0 to 1, the rotation of the sphere runs from 0 degrees through 360.

Then we used the first translation to put the sphere at its initial starting point. Remember, we could not have just declared it there, or it would have orbited the origin, so before we can meet our other goal (translation), we have to compensate by putting the sphere back where it would have been at the start. After that, we re-translate the sphere by a clock relative distance, causing it to move relative to the starting point. We have chosen the formula of 2*pi* r*clock (the widest circumference of the sphere times current clock value) so that it will appear to move a distance equal to the circumference of the sphere in the same time that it rotates a complete 360 degrees. In this way, we have synchronized the rotation of the sphere to its translation, making it appear to be smoothly rolling along the plane.

Besides allowing us to coordinate multiple aspects of change over time more cleanly, mathematically speaking, the other good reason for using normalized clock values is that it will not matter whether we are doing a ten frame animated GIF, or a three hundred frame AVI. Values of the clock are proportioned to the number of frames, so that same POV code will work without regard to how long the frame sequence is. Our rolling ball will still travel the exact same amount no matter how many frames our animation ends up with.

2.3.9.2 Clock Dependant Variables And Multi-Stage Animations

Okay, what if we wanted the ball to roll left to right for the first half of the animation, then change direction 135 degrees and roll right to left, and toward the back of the scene. We would need to make use of POV-Ray's new conditional rendering directives, and test the clock value to determine when we reach the halfway point, then start rendering a different clock dependant sequence. But our goal, as above, it to be working in each stage with a variable in the range of 0 to 1 (normalized) because this makes the math so much cleaner to work with when we have to control multiple aspects during animation. So let's assume we keep the same camera, light, and plane, and let the clock run from 0 to 2! Now, replace the single sphere declaration with the following...

  #if ( clock <= 1 )
    sphere { <0, 0, 0> , 1
      pigment {
        gradient x
        color_map {
          [0.0 Blue  ]
          [0.5 Blue  ]
          [0.5 White ]
          [1.0 White ]
        }
        scale .25
      }
      rotate <0, 0, -clock*360>
      translate <-pi, 1, 0>
      translate <2*pi*clock, 0, 0>
    }
  #else
    // (if clock is > 1, we're on the second phase)
    // we still want to work with  a value from 0 - 1
    #declare ElseClock = clock - 1;
    sphere { <0, 0, 0> , 1
      pigment {
        gradient x
        color_map {
          [0.0 Blue  ]
          [0.5 Blue  ]
          [0.5 White ]
          [1.0 White ]
        }
        scale .25
      }
      rotate <0, 0, ElseClock*360>
      translate <-2*pi*ElseClock, 0, 0>
      rotate <0, 45, 0>
      translate <pi, 1, 0>
    }
  #end

If we spotted the fact that this will cause the ball to do an unrealistic snap turn when changing direction, bonus points for us - we are a born animator. However, for the simplicity of the example, let's ignore that for now. It will be easy enough to fix in the real world, once we examine how the existing code works.

All we did differently was assume that the clock would run 0 to 2, and that we wanted to be working with a normalized value instead. So when the clock goes over 1.0, POV assumes the second phase of the journey has begun, and we declare a new variable Elseclock which we make relative to the original built in clock, in such a way that while clock is going 1 to 2, Elseclock is going 0 to 1. So, even though there is only one clock, there can be as many additional variables as we care to declare (and have memory for), so even in fairly complex scenes, the single clock variable can be made the common coordinating factor which orchestrates all other motions.

2.3.9.3 The Phase Keyword

There is another keyword we should know for purposes of animations: the phase keyword. The phase keyword can be used on many texture elements, especially those that can take a color, pigment, normal or texture map. Remember the form that these maps take. For example:

  color_map {
    [0.00 White ]
    [0.25 Blue ]
    [0.76 Green ]
    [1.00 Red ]
  }

The floating point value to the left inside each set of brackets helps POV-Ray to map the color values to various areas of the object being textured. Notice that the map runs cleanly from 0.0 to 1.0?

Phase causes the color values to become shifted along the map by a floating point value which follows the keyword phase. Now, if we are using a normalized clock value already anyhow, we can make the variable clock the floating point value associated with phase, and the pattern will smoothly shift over the course of the animation. Let's look at a common example using a gradient normal pattern

  #include "colors.inc"
  #include "textures.inc"
  background { rgb<0.8, 0.8, 0.8> }
  camera {
    location <1.5, 1, -30>
    look_at <0, 1, 0>
    angle 10
  }
  light_source { <-100, 20, -100> color White }
  // flag
  polygon {
    5, <0, 0>, <0, 1>, <1, 1>, <1, 0>, <0, 0>
    pigment { Blue }
    normal {
      gradient x
      phase clock
      scale <0.2, 1, 1>
      sine_wave
    }
    scale <3, 2, 1>
    translate <-1.5, 0, 0>
  }
  // flagpole
  cylinder {
    <-1.5, -4, 0>, <-1.5, 2.25, 0>, 0.05
    texture { Silver_Metal }
  }
  // polecap
  sphere {
    <-1.5, 2.25, 0>, 0.1
    texture { Silver_Metal }
  }

Now, here we have created a simple blue flag with a gradient normal pattern on it. We have forced the gradient to use a sine-wave type wave so that it looks like the flag is rolling back and forth as though flapping in a breeze. But the real magic here is that phase keyword. It has been set to take the clock variable as a floating point value which, as the clock increments slowly toward 1.0, will cause the crests and troughs of the flag's wave to shift along the x-axis. Effectively, when we animate the frames created by this code, it will look like the flag is actually rippling in the wind.

This is only one, simple example of how a clock dependant phase shift can create interesting animation effects. Trying phase will all sorts of texture patterns, and it is amazing the range of animation effects we can create simply by phase alone, without ever actually moving the object.

2.3.9.4 Do Not Use Jitter Or Crand

One last piece of basic information to save frustration. Because jitter is an element of anti-aliasing, we could just as easily have mentioned this under the INI file settings section, but there are also forms of anti-aliasing used in area lights, and the new atmospheric effects of POV-Ray, so now is as good a time as any.

Jitter is a very small amount of random ray perturbation designed to diffuse tiny aliasing errors that might not otherwise totally disappear, even with intense anti-aliasing. By randomizing the placement of erroneous pixels, the error becomes less noticeable to the human eye, because the eye and mind are naturally inclined to look for regular patterns rather than random distortions.

This concept, which works fantastically for still pictures, can become a nightmare in animations. Because it is random in nature, it will be different for each frame we render, and this becomes even more severe if we dither the final results down to, say 256 color animations (such as FLC's). The result is jumping pixels all over the scene, but especially concentrated any place where aliasing would normally be a problem (e.g., where an infinite plane disappears into the distance).

For this reason, we should always set jitter to off in area lights and anti-aliasing options when preparing a scene for an animation. The (relatively) small extra measure quality due to the use of jitter will be offset by the ocean of jumpies that results. This general rule also applies to any truly random texture elements, such as crand.

2.3.9.5 INI File Settings

Okay, so we have a grasp of how to code our file for animation. We know about the clock variable, user declared clock-relative variables, and the phase keyword. We know not to jitter or crand when we render a scene, and we are all set build some animations. Alright, let's have at it.

The first concept we will need to know is the INI file settings, Initial_Frame and Final_Frame. These are very handy settings that will allow us to render a particular number of frames and each with its own unique frame number, in a completely hands free way. It is of course, so blindingly simple that it barely needs explanation, but here is an example anyway. We just add the following lines to our favorite INI file settings

  Initial_Frame = 1
  Final_Frame = 20

and we will initiate an automated loop that will generate 20 unique frames. The settings themselves will automatically append a frame number onto the end of whatever we have set the output file name for, thus giving each frame an unique file number without having to think about it. Secondly, by default, it will cycle the clock variable up from 0 to 1 in increments proportional to the number of frames. This is very convenient, since, no matter whether we are making a five frame animated GIF or a 300 frame MPEG sequence, we will have a clock value which smoothly cycles from exactly the same start to exactly the same finish.

Next, about that clock. In our example with the rolling ball code, we saw that sometimes we want the clock to cycle through values other than the default of 0.0 to 1.0. Well, when that is the case, there are setting for that too. The format is also quite simple. To make the clock run, as in our example, from 0.0 to 2.0, we would just add to your INI file the lines

Initial_Clock = 0.0
Final_Clock = 2.0

Now, suppose we were developing a sequence of 100 frames, and we detected a visual glitch somewhere in frames, say 51 to 75. We go back over our code and we think we have fixed it. We would like to render just those 25 frames instead of redoing the whole sequence from the beginning. What do we change?

If we said make Initial_Frame = 51, and Final_Frame = 75, we are wrong. Even though this would re-render files named with numbers 51 through 75, they will not properly fit into our sequence, because the clock will begin at its initial value starting with frame 51, and cycle to final value ending with frame 75. The only time Initial_Frame and Final_Frame should change is if we are doing an essentially new sequence that will be appended onto existing material.

If we wanted to look at just 51 through 75 of the original animation, we need two new INI settings

Subset_Start_Frame = 51
Subset_End_Frame = 75

Added to settings from before, the clock will still cycle through its values proportioned from frames 1 to 100, but we will only be rendering that part of the sequence from the 51st to the 75th frames.

This should give us a basic idea of how to use animation. Although, this introductory tutorial does not cover all the angles. For example, the last two settings we just saw, subset animation, can take fractional values, like 0.5 to 0.75, so that the number of actual frames will not change what portion of the animation is being rendered. There is also support for efficient odd-even field rendering as would be useful for animations prepared for display in interlaced playback such as television (see the reference section for full details).

With POV-Ray 3 now fully supporting a complete host of animation options, a whole fourth dimension is added to the raytracing experience. Whether we are making a FLIC, AVI, MPEG, or simply an animated GIF for our web site, animation support takes a lot of the tedium out of the process. And do not forget that phase and clock can be used to explore the range of numerous texture elements, as well as some of the more difficult to master objects (hint: the julia fractal for example). So even if we are completely content with making still scenes, adding animation to our repertoire can greatly enhance our understanding of what POV-Ray is capable of. Adventure awaits!

2.3.10 While-loop tutorial

Usually people who have never programmed have great difficulties understanding how simple while-loops work and how they should be used. When you get into nested loops, the problem is even worse.

Sometimes even people who have programmed a bit with some language get confused with POV-Ray's while-loops. This usually happens when they have only used a for-loop which in itself has an index variable which is often incremented automatically.

2.3.10.1 What a while-loop is and what it is not

A while-loop in POV-Ray is just a control structure which tells POV-Ray to repeat a command block while the specified condition is true.

The while-loop syntax is as follows:

#while(condition)
  ...
#end

The commands between #while and #end are run over and over as long as the condition evaluates to true.

A while-loop is not a for-loop nor any kind of loop which has an index variable that may be incremented automatically with each iteration.

The while loop does not care what the conditions are between the parentheses as long as they evaluate to some value, nor what the block between #while and #end contains. It will just execute that block until the condition becomes false.

The while-loop does not do anything else. You can think of it as a "simple" loop, which does not do anything automatically. This is not necessarily a bad thing.

2.3.10.2 How does a single while-loop work?

The while loop works like this:

  1. If the condition between the parentheses evaluates to false, jump to the command after the #end statement. If the condition evaluates to true, just continue normally.
  2. At the #end statement jump to the #while statement and start again.

That is:

  • When POV-Ray gets to the #while statement it evaluates the condition between parentheses.
  • If the statement evaluated as true then it will just continue normally with the next command.
  • If the statement evaluated as false, POV-Ray will skip the entire body of the loop and continue with the command after the #end statement.
  • At an #end statement POV-Ray will just jump back to the corresponding #while statement, and will conditionally execute the commands, if the condition evaluates true.

Note that nowhere there is any mention about any index variable or anything else that could be used to automatically end the loop. As said, it is just a "simple" loop that continues forever if necessary, only testing the statement between the parentheses, and it is not interested in what it is, only in its evaluated value.

Although one could easily think that this kind of simple loop is bad, and it should be more intelligent, the fact is that this kind of simple loop is actually a lot more flexible and versatile. It allows you to make things not possible or very difficult to do with an intelligent for-loop with automatic index variables.

2.3.10.3 How do I make a while-loop?

It depends on what you are trying to accomplish.

The most common usage is to use it as a simple for-loop, that is, a loop which loops a certain number of times, with an index value getting successive values (for example 1, 2, 3, ..., 10).

For this you need to first declare your index identifier with the first value.

#declare Index = 1;

If you want to loop 10 times, remember how the condition worked: The while-loop repeats as long as the condition is true. So it should loop as long as our 'Index' identifier is less or equal to 10

#while(Index <= 10)

When the value of 'Index' is 11 the loop ends, as it should.

We only have to add 1 to 'Index' at the end of each loop

#declare Index = 1;
#while(Index <= 10)

  (some commands here)

  #declare Index = Index + 1;
#end

The incrementation before the #end is important. If we do not do it, 'Index' would always have the value 1 and the loop would go forever since 1 is always less or equal to 10.

What happens here?

  1. First POV-Ray sets the value 1 to 'Index'.
  2. Then it sees the #while statement and evaluates what is between the parentheses: Index <= 10
  3. As 'Index' has the value of 1 and 1 <= 10, the condition evaluates to true.
  4. So, it just continues normally, and executes the commands following the #while statement, as noted in the above example as (some commands here).
  5. Then it arrives normally to the last #declare command in the block. This causes the value 2 to be assigned to 'Index'.
  6. Now it arrives the the #end command and so it just jumps to the #while.
  7. After that it executes the steps 2-6 again because 2 is also less or equal to 10.
  8. After this has been done 10 times, the value 11 is assigned to 'Index' in the last command of the block.
  9. Now, when POV-Ray evaluates the condition it sees that it is false, because 11 is not less or equal to 10. This causes POV-Ray to jump to the command after the #end statement.
  10. The net effect of all this is that POV-Ray looped 10 times and the 'Index' variable was assigned successive values from 1 to 10 along the way.

If you read carefully the above description you will notice that the looping is done in a quite simple way, that is, there is no higher logic hidden inside the loop structure. In fact, POV-Ray does not have the slightest idea how many times the loop is executed and what variable is used to count the loops. It just follows orders.

The higher logic in this type of loop is in the combination of commands we wrote. The effect of this combination is that the loop works like a simple for-loop in most programming languages (like BASIC, etc).

2.3.10.4 What is a condition and how do I make one?

A condition is an expression that evaluates to a boolean value (ie. true or false) and is used in POV-Ray in #while loops and #if statements.

A condition is mainly a comparison between two values, although there are also some other ways of making a condition, that is not important now.

For example:

1 < 2  is true
1 > 2  is false
1 = 1  is true
1 = 2  is false

Usually it makes no sense to make comparisons like those. However, when comparing identifiers with some value or two identifiers together it starts to be very useful. Consider this:

#if(version < 3.1)
  #error "Wrong version!"
#end

If the identifier called 'version' has a value which is less than 3.1 the #error line will be executed. If 'version' has a value which is 3.1 or greater, the #error line is just skipped.

You can combine conditions together with the boolean operators & (and) and | (or). You can also invert the value of a condition with ! (not).

For example, if you want something to be done when 'a' is less than 10 and 'b' is greater or equal to 20, the condition would be:

a<10 & b>=20

For more information about these comparison operators, see the Operators section of the POV-Ray documentation.

2.3.10.5 What about loop types other than simple for-loops?

As POV-Ray does not care what the condition is and what we are using to make that condition, we can use the while-loop in many other ways.

For example, this is a typical use of the while-loop that is not just a simple for-loop:

#declare S = seed(0);
#declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
#while(vlength(Point) > 1)
  #declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
#end

We take a random point between <-1, -1, -1> and <1, 1, 1> and if it is not inside the unit sphere take another random point in that range until we get a point inside the unit sphere.

This is not an unrealistic example since it is very handy, and we can plainly see, this looks nothing like an ordinary for-loop.

  • It does not have any 'index' value which gets consecutive values during the loop.
  • We do not know how many times it will loop. In this case it loops a random number of times.
  • Usually for-loops are used to place or create a series of objects. For each iteration another instance of that object is created. Here, however, we are only interested in the value that results after the loop, not the values inside it.

As we can see, a while-loop can also be used for a variety of tasks, for instance, to calculate a value or some values until the result is inside a specified range.

By the way, there is a variant of this kind of loop where the task would be to calculate a value until the result is inside a specified range, but make only a certain number of tries. If the value does not get inside that range after that number of tries, stop trying. This is used when there is a possibility for the loop for going on forever.

In the above example about the point inside the unit sphere we do not need this because the random point will surely hit the inside of the sphere at some time. In some other situations, however, we cannot be so sure.

In this case we need a regular index variable to count the number of loops. If we reach a predetermined number of iterations, then we stop.

Suppose that we wanted to modify our point searching program to be completely safe and to try only up to 10 times. If the point does not hit the inside of the sphere after 10 tries, we just give up and use the point <0,0,0>.

#declare S = seed(0);
#declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
#declare Index = 1;
#while(Index <= 10 & vlength(Point) > 1)
  #declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
  #declare Index = Index + 1;
#end

#if(vlength(Point) > 1)
  #declare Point = <0,0,0>
#end

What did we do?

  • We added an 'Index' value which counts the amount of loops gone so far. It is quite similar to the index loop of a simple for-loop.
  • We added an extra condition to the while-loop: Besides testing that the point is outside the unit sphere it also tests that our index variable has not bailed out. So now there are two conditions for the loop to continue: The 'Index' value must be less or equal to 10 and the 'Point' has to be outside the unit sphere. If either one of them fails, the loop is ended.
  • Then we check if the point is still outside the unit sphere. If it is, we just take <0,0,0>.

Sometimes it is not convenient to make the test again in the #if statement. There is another way of determining whether the loop bailed out without successful termination. Since the loop ends when the 'Index' gets the value 11, we can use this to test the successfulness of the loop

#if(Index = 11)
  (loop was not successful)
#end

2.3.10.6 What about nested loops?

Even when one masters simple loops, nested loops can be a frightening thing, or at least hard to understand.

Nested loops are used for example in creating a 2D array of objects, that is rows and columns of objects. For example if you want to create a 10x20 array of spheres in your scene, a nested loop is up to the task.

There is nothing special about nested loops. You only have to pay attention to where you initialize and update your index variables.

Let's recall the form of a simple for-loop:

#declare Index = initial_value;
#while(Index <= final_value)

  [Something here]

  #declare Index = Index + index_step;
#end

The [Something here] part can be anything. If it is another while-loop, then we have nested loops. The inner loop should have the same structure as the outer one.

Note that proper indentation helps us distinguishing between the loops. It is always a good idea to use a good indentation scheme:

#declare Index1 = initial_value1;
#while(Index1 <= final_value1)

   #declare Index2 = initial_value2;
   #while(Index2 <= final_value2)

      [Something here]

      #declare Index2 = Index2 + index2_step;
   #end

   #declare Index1 = Index1 + index1_step;
#end

It is a common mistake for beginners to break this structure. For example it is common to declare the 'Index2' before the first #while. This breaks the for-loop structure and thus does not work. If you follow step by step what POV-Ray does, as explained earlier, you will see why it does not work. Do not mix the structures of the inner and the outer loops together or your code will simply not work as expected.

So, if we want to make our 10x20 array of spheres, it will look like this:

#declare Index1 = 0;
#while(Index1 <= 9)

   #declare Index2 = 0;
   #while(Index2 <= 19)

      sphere { <Index1, Index2, 0>, .5 }

      #declare Index2 = Index2 + 1;
   #end

   #declare Index1 = Index1 + 1;
#end

Notice how we now start from 0 and continue to 9 in the outer loop and from 0 to 19 in the inner loop. This has been done to get the sphere array start from the origin, instead of starting from <1, 1, 0>, of course we could have made the 'Index1' and 'Index2' go from 1 to 10 and from 1 to 20 respectively and then created the sphere in this way:

  sphere { <Index1-1, Index2-1, 0>, .5 }

Although you should not mix the loop structures together, you can perfectly use the values of the outer loop in the inner loop (eg. in its condition). For example, if we wanted to create a triangular array of spheres instead of a rectangular one, that is, we create only half of the spheres, we could have made the inner #while like this:

  #while(Index2 < Index1*2)

'Index2' will go from 0 to the value of 'Index1' multiplied by 2.

There is no reason why we should limit ourselves to just two nested loops. There is virtually no limit how many loops you can nest. For example, if we wanted to create a box-shape filled by spheres rows, columns and depth, we just make three nested loops, one for the x-axis, another for the y-axis and the third for the z-axis.

2.3.10.7 Mixed-type nested loops

It is perfectly possible to put a for-loop inside a non-for-loop or vice-versa. Again, you just have to be careful, with experience it gets easier.

For example, suppose that we want to create 50 spheres which are randomly placed inside the unit sphere.

So the distinction is clear: First we need a loop to create 50 spheres, a for-loop type suffices, and then we need another loop inside it to calculate the location of the sphere. It will look like this:

#declare S = seed(0);
#declare Index = 1;
#while(Index <= 50)

   #declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
   #while(vlength(Point) > 1)
      #declare Point = <2*rand(S)-1, 2*rand(S)-1, 2*rand(S)-1>;
   #end

   sphere { Point, .1 }

   #declare Index = Index + 1;
#end

There are some important things to note in this specific example:

  • Although this is a nested loop, the sphere is not created in the inner loop but in the outer one. The reason is clear: We want to create 50 spheres, so the sphere creation has to be inside the loop that counts to 50. The inner loop just calculates an appropriate location.
  • The seed value 'S' is declared outside all the loops although it is used only in the inner loop. Can you guess why? Putting it inside the outer loop would have caused an undesired result: Which one?

2.3.10.8 Other things to note

There is no reason why the index value in your simple for-loop should step one unit at a time. Since the while-loop does not care how the index changes, you can change it in whichever way you want. For example:

#declare Index = Index - 1;   // Decrements the index (be careful with the while loop condition)
#declare Index = Index + 0.2; // Increases by steps of 0.2
#declare Index = Index * 2;   // Doubles the value of the index at each step.

Note: Be careful where you put your while-loop.

The example below illustrates a very common mistake:

#declare Index = 1;
#while(Index <= 10)
   blob
   {  threshold 0.6
      sphere { <Index, 0, 0>, 2, 1 }
   }
   #declare Index = Index + 1;
#end

You will probably immediately see the problem.

This code creates 10 blobs with one component each. It does not seem to make much sense. Most probably the user wanted to make one blob with 10 components.

Why did this mistake happen? It may be that the user thought that the while-loop must be the outermost control structure and did not realize that while-loops can be anywhere. For example, inside objects to create subcomponents.

The correct code is, of course:

blob
{  threshold 0.6

   #declare Index = 1;
   #while(Index <= 10)

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

      #declare Index = Index + 1;
   #end
}

The essential difference here is that it is only the sphere code which is run 10 times instead of the whole blob code. The net result is the same as if we had written the sphere code 10 times with proper values of 'Index'.

Be also careful with the placement of the braces. If you put them in the wrong place you can end up accidentally repeating an opening or a closing brace 10 times. Again, a proper indentation usually helps a lot with this, as seen in the above example.

Tip: You can use while-loops in conjunction with arrays to automate the creation of long lists of elements with differing data.

Imagine that you are making something like this:

color_map {
  [0.00 rgb <.1,1,.6>]
  [0.05 rgb <.8,.3,.6>]
  [0.10 rgb <.3,.7,.9>]
  [0.15 rgb <1,.7,.3>]
  ...
  [1.0 rgb <.8,.2,.5>]
  }

It is tedious to have to write the same things over and over just changing the index value and the values in the vector, even if you use copy-paste to copy the lines.

There is also one very big problem here: If you ever want to add a new color to the color map or remove a color, you would have to renumber all the indices again, which can be extremely tedious and frustrating.

Wouldn't it be nice to automate the creation of the color map so that you only have to write the vectors and that's it?

Well, you can. Using a while-loop which reads an array of vectors:

#declare MyColors = array[20]
   {  <.1,1,.6>, <.8,.3,.6>, <.3,.7,.9>,
      <1,.7,.3>, ... , <.8,.2,.5>
   }

...

color_map {
  #declare LastIndex = dimension_size(MyColors, 1)-1;
  #declare Index = 0;
  #while(Index <= LastIndex)

     [Index/LastIndex rgb MyColors[Index]]

     #declare Index = Index + 1;
   #end
   }

Now it is easy to add, remove or modify colors in your color map. Just edit the vector array, remembering to change its size number accordingly, and the while-loop will automatically calculate the right values and create the color map for you.

2.3.11 SDL tutorial: A raytracer

2.3.11.1 Introduction

A raytracer made with POV-Ray sounds really weird, doesn't it? What is it anyways? POV-Ray is already a raytracer in itself, how can we use it to make a raytracer? What the...?

The idea is to make a simple sphere raytracer which supports colored spheres (with diffuse and specular lighting), colored light sources, reflections and shadows with the POV-Ray SDL (Scene Description Language), then just render the image created this way. That is, we do not use POV-Ray itself to raytrace the spheres, but we make our own raytracer with its SDL and use POV-Ray's raytracing part to just get the image on screen.

What obscure idea could be behind this weirdness? Why do not just use POV-Ray itself to raytrace the spheres a lot faster and that is it?

The idea is not speed nor quality, but to show the power of the POV-Ray SDL. If you know how to make such a thing as a raytracer with it, we can really grasp the expressive power of the SDL.

The idea of this document is to make a different approach to POV-Ray SDL teaching. It is intended to be a different type of tutorial: Instead of starting from the basics and give simple and dumb examples, we jump right into a high-end SDL code and see how it is done. However, this is done in a way that even beginners can learn something from it.

Another advantage is that you will learn how a simple sphere raytracer is done by reading this tutorial. There are lots of misconceptions about raytracing out there, and knowing how to make one helps clear most of them.

Although this tutorial tries to start from basics, it will go quite fast to very "high-end" scripting, so it might not be the best tutorial to read for a completely new user, but it should be enough to have some basic knowledge. Also more advanced users may get some new info from it.

Note: In some places some mathematics is needed, so you would better not be afraid of math.

If some specific POV-Ray SDL syntax is unclear you should consult the POV-Ray documentation for more help. This tutorial explains how they can be used, not so much what is their syntax.

2.3.11.2 The idea and the code

The idea is to raytrace a simple scene consisting of spheres and light sources into a 2-dimensional array containing color vectors which represents our screen.

After this we just have to put those colors on the actual scene for POV-Ray to show them. This is made by creating a flat colored triangle mesh. The mesh is just flat like a plane with a color map on it. We could as well have written the result to a format like PPM and then read it and apply it as an image map to a plane, but this way we avoid a temporary file.

The following image is done with the raytracer SDL. It calculated the image at a resolution of 160x120 pixels and then raytraced an 512x384 image from it. This causes the image to be blurred and jagged (because it is practically zoomed in by a factor of 3.2). Calculating the image at 320x240 gives a much nicer result, but it is also much slower:

Some spheres raytraced by the SDL at 160x120

Note: There are no real spheres nor light sources here (real from the point of view of POV-Ray), just a flat colored triangle mesh (like a plane with a pigment on it) and a camera, nothing else.

Here is the source code of the raytracer; we will look it part by part through this tutorial.

#declare ImageWidth = 160;
#declare ImageHeight = 120;
#declare MaxRecLev = 5;
#declare AmbientLight = <.2,.2,.2>;
#declare BGColor = <0,0,0>;

// Sphere information.
// Values are:
// Center, <Radius, Reflection, 0>, Color, <phong_size, amount, 0>
#declare Coord = array[5][4]
{ {<-1.05,0,4>, <1,.5,0>, <1,.5,.25>, <40, .8, 0>}
  {<1.05,0,4>, <1,.5,0>, <.5,1,.5>, <40, .8, 0>}
  {<0,-3,5>, <2,.5,0>, <.25,.5,1>, <30, .4, 0>}
  {<-1,2.3,9>, <2,.5,0>, <.5,.3,.1>, <30, .4, 0>}
  {<1.3,2.6,9>, <1.8,.5,0>, <.1,.3,.5>, <30, .4, 0>}
}

// Light source directions and colors:
#declare LVect = array[3][2]
{ {<-1, 0, -.5>, <.8,.4,.1>}
  {<1, 1, -.5>, <1,1,1>}
  {<0,1,0>, <.1,.2,.5>}
}

//==================================================================
// Raytracing calculations:
//==================================================================
#declare MaxDist = 1e5;
#declare ObjAmnt = dimension_size(Coord, 1);
#declare LightAmnt = dimension_size(LVect, 1);

#declare Ind = 0;
#while(Ind < LightAmnt)
  #declare LVect[Ind][0] = vnormalize(LVect[Ind][0]);
  #declare Ind = Ind+1;
#end

#macro calcRaySphereIntersection(P, D, sphereInd)
  #local V = P-Coord[sphereInd][0];
  #local R = Coord[sphereInd][1].x;

  #local DV = vdot(D, V);
  #local D2 = vdot(D, D);
  #local SQ = DV*DV-D2*(vdot(V, V)-R*R);
  #if(SQ < 0) #local Result = -1;
  #else
    #local SQ = sqrt(SQ);
    #local T1 = (-DV+SQ)/D2;
    #local T2 = (-DV-SQ)/D2;
    #local Result = (T1<T2 ? T1 : T2);
  #end
  Result
#end

#macro Trace(P, D, recLev)
  #local minT = MaxDist;
  #local closest = ObjAmnt;

  // Find closest intersection:
  #local Ind = 0;
  #while(Ind < ObjAmnt)
    #local T = calcRaySphereIntersection(P, D, Ind);
    #if(T>0 & T<minT)
      #local minT = T;
      #local closest = Ind;
    #end
    #local Ind = Ind+1;
  #end

  // If not found, return background color:
  #if(closest = ObjAmnt)
    #local Pixel = BGColor;
  #else
    // Else calculate the color of the intersection point:
    #local IP = P+minT*D;
    #local R = Coord[closest][1].x;
    #local Normal = (IP-Coord[closest][0])/R;

    #local V = P-IP;
    #local Refl = 2*Normal*(vdot(Normal, V)) - V;

    // Lighting:
    #local Pixel = AmbientLight;
    #local Ind = 0;
    #while(Ind < LightAmnt)
      #local L = LVect[Ind][0];

      // Shadowtest:
      #local Shadowed = false;
      #local Ind2 = 0;
      #while(Ind2 < ObjAmnt)
        #if(Ind2!=closest & calcRaySphereIntersection(IP,L,Ind2)>0)
          #local Shadowed = true;
          #local Ind2 = ObjAmnt;
        #end
        #local Ind2 = Ind2+1;
      #end

      #if(!Shadowed)
        // Diffuse:
        #local Factor = vdot(Normal, L);
        #if(Factor > 0)
          #local Pixel=Pixel+LVect[Ind][1]*Coord[closest][2]*Factor;
        #end

        // Specular:
        #local Factor = vdot(vnormalize(Refl), L);
        #if(Factor > 0)
          #local Pixel =
             Pixel +
             LVect[Ind][1]*pow(Factor, Coord[closest][3].x)*
             Coord[closest][3].y;
        #end
      #end
      #local Ind = Ind+1;
    #end

    // Reflection:
    #if(recLev < MaxRecLev & Coord[closest][1].y > 0)
      #local Pixel =
    Pixel + Trace(IP, Refl, recLev+1)*Coord[closest][1].y;
    #end
  #end

  Pixel
#end

#debug "Rendering...\n\n"
#declare Image = array[ImageWidth][ImageHeight]
#declare IndY = 0;
#while(IndY < ImageHeight)
  #declare CoordY = IndY/(ImageHeight-1)*2-1;
  #declare IndX = 0;
  #while(IndX < ImageWidth)
    #declare CoordX =
      (IndX/(ImageWidth-1)-.5)*2*ImageWidth/ImageHeight;
    #declare Image[IndX][IndY] =
      Trace(-z*3, <CoordX, CoordY, 3>, 1);
    #declare IndX = IndX+1;
  #end
  #declare IndY = IndY+1;
  #debug concat("\rDone ", str(100*IndY/ImageHeight, 0, 1),
    "%  (line ",str(IndY,0,0)," out of ",str(ImageHeight,0,0),")")
#end
#debug "\n"

//==================================================================
// Image creation (colored mesh):
//==================================================================
#default { finish { ambient 1 } }

#debug "Creating colored mesh to show image...\n"
mesh2
{ vertex_vectors
  { ImageWidth*ImageHeight*2,
    #declare IndY = 0;
    #while(IndY < ImageHeight)
      #declare IndX = 0;
      #while(IndX < ImageWidth)
        <(IndX/(ImageWidth-1)-.5)*ImageWidth/ImageHeight*2,
         IndY/(ImageHeight-1)*2-1, 0>,
        <((IndX+.5)/(ImageWidth-1)-.5)*ImageWidth/ImageHeight*2,
         (IndY+.5)/(ImageHeight-1)*2-1, 0>
        #declare IndX = IndX+1;
      #end
      #declare IndY = IndY+1;
    #end
  }
  texture_list
  { ImageWidth*ImageHeight*2,
    #declare IndY = 0;
    #while(IndY < ImageHeight)
      #declare IndX = 0;
      #while(IndX < ImageWidth)
        texture { pigment { rgb Image[IndX][IndY] } }
        #if(IndX < ImageWidth-1 & IndY < ImageHeight-1)
          texture { pigment { rgb
            (Image[IndX][IndY]+Image[IndX+1][IndY]+
             Image[IndX][IndY+1]+Image[IndX+1][IndY+1])/4 } }
        #else
          texture { pigment { rgb 0 } }
        #end
        #declare IndX = IndX+1;
      #end
      #declare IndY = IndY+1;
    #end
  }
  face_indices
  { (ImageWidth-1)*(ImageHeight-1)*4,
    #declare IndY = 0;
    #while(IndY < ImageHeight-1)
      #declare IndX = 0;
      #while(IndX < ImageWidth-1)
        <IndX*2+  IndY    *(ImageWidth*2),
         IndX*2+2+IndY    *(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)>,
         IndX*2+  IndY    *(ImageWidth*2),
         IndX*2+2+IndY    *(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2),

        <IndX*2+  IndY    *(ImageWidth*2),
         IndX*2+  (IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)>,
         IndX*2+  IndY    *(ImageWidth*2),
         IndX*2+  (IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2),

        <IndX*2+  (IndY+1)*(ImageWidth*2),
         IndX*2+2+(IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)>,
         IndX*2+  (IndY+1)*(ImageWidth*2),
         IndX*2+2+(IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2),

        <IndX*2+2+IndY    *(ImageWidth*2),
         IndX*2+2+(IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)>,
         IndX*2+2+IndY    *(ImageWidth*2),
         IndX*2+2+(IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)
        #declare IndX = IndX+1;
      #end
      #declare IndY = IndY+1;
    #end
  }
}

camera { orthographic location -z*2 look_at 0 }

2.3.11.3 Short introduction to raytracing

Before we start looking at the code, let's look briefly how raytracing works. This will help you understand what the script is doing.

The basic idea of raytracing is to shoot rays from the camera towards the scene and see what does the ray hit. If the ray hits the surface of an object then lighting calculations are performed in order to get the color of the surface at that place.

The following image shows this graphically:

The basic raytracing algorithm

First a ray is shot in a specified direction to see if there is something there. As this is solved mathematically, we need to know the mathematical representation of the ray and the objects in the scene so that we can calculate where does the ray intersect the objects. Once we get all the intersection points, we choose the closest one.

After this we have to calculate the lighting (ie. the illumination) of the object at the intersection point. In the most basic lighting model (as the one used in the script) there are three main things that affect the lighting of the surface:

  • The shadow test ray, which determines whether a light source illuminates the intersection point or not.
  • The normal vector, which is a vector perpendicular (ie. at 90 degrees) to the object surface at the intersection point. It determines the diffuse component of the lighting as well as the direction of the reflected ray (in conjunction with the incoming ray; that is, the angle alpha determines the direction of the reflected ray).
  • The reflected ray, which determines the specular component of the lighting and of course the color of the reflection (if the object is reflective).

Do not worry if these things sound a bit confusing. Full details of all these things will be given through this tutorial, as we look what does the raytracing script do. The most important thing at this stage is to understand how the basic raytracing algorithm works at theoretical level (the image above should say most of it).

Let's just look at the raytracer source code line by line and look what does it do

2.3.11.4 Global settings

#declare ImageWidth = 160;
#declare ImageHeight = 120;
#declare MaxRecLev = 5;
#declare AmbientLight = <.2,.2,.2>;
#declare BGColor = <0,0,0>;

These lines just declare some identifiers defining some general values which will be used later in the code. The keyword we use here is #declare and it means that we are declaring a global identifier, which will be seen in the whole code.

As you can see, we declare some identifiers to be of float type and others to be of vector type. The vector type identifiers are, in fact, used later for color definition (as their name implies).

The ImageWidth and ImageHeight define the resolution of the image we are going to render.

Note: This only defines the resolution of the image we are going to render in our SDL (ie. into the array we will define later); it does not set the resolution of the image which POV-Ray will render.

The MaxRecLev limits the maximum number of recursive reflections the code will calculate. It is equivalent to the max_trace_level value in global_settings which POV-Ray uses to raytrace.

The AmbientLight defines a color which is added to all surfaces. This is used to lighten up shadowed parts so that they are not completely dark. It is equivalent to the ambient_light value in global_settings.

Finally, BGColor defines the color of the rays which do not hit anything. It is equivalent to the background block of POV-Ray.

2.3.11.5 Scene definition

// Sphere information.
// Values are:
// Center, <Radius, Reflection, 0>, Color, <phong_size, amount, 0>
#declare Coord = array[5][4]
{ {<-1.05,0,4>, <1,.5,0>, <1,.5,.25>, <40, .8, 0>}
  {<1.05,0,4>, <1,.5,0>, <.5,1,.5>, <40, .8, 0>}
  {<0,-3,5>, <2,.5,0>, <.25,.5,1>, <30, .4, 0>}
  {<-1,2.3,9>, <2,.5,0>, <.5,.3,.1>, <30, .4, 0>}
  {<1.3,2.6,9>, <1.8,.5,0>, <.1,.3,.5>, <30, .4, 0>}
}

// Light source directions and colors:
#declare LVect = array[3][2]
{ {<-1, 0, -.5>, <.8,.4,.1>}
  {<1, 1, -.5>, <1,1,1>}
  {<0,1,0>, <.1,.2,.5>}
}

Here we use a bit more complex declarations: Array declarations.

In fact, they are even more complex than simple arrays, as we are declaring two-dimensional arrays.

A simple one-dimensional array can be declared like:

#declare MyArray = array[4] { 1, 2, 3, 4 }

and then values can be read from inside it with for example: MyArray[2] (which will return 3 in this case as the indexing starts from 0, ie. the index 0 gets the first value in the array).

A two-dimensional array can be thought as an array containing arrays. That is, if you say array[3][2], that means an array which has 3 elements; each one of those elements is an array with 2 elements. When you want to read a value from it, for example MyArray[1][3], you can think about it as get the fourth value from the second array (as indexing starts from 0, then the index value 3 actually means fourth value).

Note: Although you can put almost anything inside an array (floats, vectors, objects and so on) you can only put one type of things inside an array. That is, you cannot mix float values and objects inside the same array. (One nice feature is that all POV-Ray objects are considered equivalent, which means that an object array can contain any objects inside it.)

What we are doing here is to define the information for our spheres and light sources. The first array (called Coord) defines the information for the spheres and the second (LVect) defines the light sources.

For spheres we define their center as the first vector. The second vector has both the radius of the sphere and its reflection amount (which is equivalent to the reflection value in the finish block of an object). This is a trick we use to not to waste so much space, so we use two values of the same vector for defining two different things.

The third vector defines the color of the sphere and the fourth the specular component of the lighting (equivalent to phong_size and phong values in the finish block of an object).

The light source definition array contains direction vectors and colors. This means that the light sources are directional, that is, they just say which direction the light is coming from. It could have been equally easy to make point lights, though.

We will use the information inside these arrays later in order to raytrace the scene they define.

2.3.11.6 Initializing the raytracer

#declare MaxDist = 1e5;
#declare ObjAmnt = dimension_size(Coord, 1);
#declare LightAmnt = dimension_size(LVect, 1);

#declare Ind = 0;
#while(Ind < LightAmnt)
  #declare LVect[Ind][0] = vnormalize(LVect[Ind][0]);
  #declare Ind = Ind+1;
#end

Before being able to start the raytracing, we have to intialize a couple of things.

The MaxDist defines the maximum distance a surface can be from the starting point of a ray. This means that if a surface is farther away from the starting point of the ray than this value, it will not be seen. Strictly speaking this value is unnecessary and we can make the raytracer so that there is no such a limitation, but we save one extra step when we do it this way, and for scenes sized like ours it does not really matter. (If you really, really want to get rid of the limitation, I am sure you will figure out yourself how to do it after this tutorial.)

The ObjAmnt and LightAmnt identifiers are declared just to make it easier for us to see how many objects and lights are there (we need this info to loop through all the objects and lights). Calling the dimension_size() function is a really nice way of getting the number of items in an array.

All right, now we are getting to a bit more advanced stuff: What does the while-loop do there?

The #while-loop uses the Ind identifier as an index value going from 0 to LightAmnt-1 (yes, -1; when Ind gets the value LightAmnt the loop is ended right away). We also see that we are indexing the LVect array; thus, it is clear we are going through all the light sources (specifically through their direction vectors, as we only use the [0] part) and we assign something to them.

What we are doing is to assign a normalized version of each light source direction onto themselves, that is, just normalizing them.

Normalize is a synonym for convert to unit vector, that is, convert to a vector with the same direction as the original but with length 1.

Why? We will later see that for illumination calculations we will be needing unit vectors. It is more efficient to convert the light source directions to unit vectors once at the beginning than every time for each pixel later.

2.3.11.7 Ray-sphere intersection

#macro calcRaySphereIntersection(P, D, sphereInd)
  #local V = P-Coord[sphereInd][0];
  #local R = Coord[sphereInd][1].x;

  #local DV = vdot(D, V);
  #local D2 = vdot(D, D);
  #local SQ = DV*DV-D2*(vdot(V, V)-R*R);
  #if(SQ < 0) #local Result = -1;
  #else
    #local SQ = sqrt(SQ);
    #local T1 = (-DV+SQ)/D2;
    #local T2 = (-DV-SQ)/D2;
    #local Result = (T1<T2 ? T1 : T2);
  #end
  Result
#end

This is the core of the whole raytracing process.

First let's see how a macro works (if you know it, just skip the following section):

2.3.11.7.1 Inner workings of a macro

A macro works like a substitution command (similar to the #define macros in the C programming language). The body of the macro is in practice inserted in the place where the macro is called. For example you can use a macro like this:

#macro UnitSphere()
  sphere { 0,1 }
#end

object { UnitSphere() pigment { rgb 1 } }

The result of this code is, in effect, as if you had written:

object { sphere { 0,1 } pigment { rgb 1 } }

Of course there is no reason in making this, as you could have just #declared the UnitSphere as a sphere of radius 1. However, the power of macros kick in when you start using macro parameters. For example:

#macro Sphere(Radius)
  sphere { 0, Radius }
#end

object { Sphere(3) pigment { rgb 1 } }

Now you can use the macro Sphere to create a sphere with the specified radius. Of course this does not make much sense either, as you could just write the sphere primitive directly because it is so short, but this example is intentionally short to show how it works; the macros become very handy when they create something much more complicated than just a sphere.

There is one important difference between macros in POV-Ray and real substitution macros: Any #local statement inside the macro definition will be parsed at the visibility level of the macro only, that is, it will have no effect on the environment where the macro was called from. The following example shows what I am talking about:

#macro Sphere(Radius)
  #local Color = <1,1,1>;
  sphere { 0, Radius pigment { rgb Color } }
#end

#declare Color = <1,0,0>;
object { Sphere(3) }
   // 'Color' is still <1,0,0> here,
   // thus the following box will be red:
box { -1,1 pigment { rgb Color } }

In the example above, although the macro creates a local identifier called Color and there is an identifier with the same name at global level, the local definition does not affect the global one. Also even if there was not any global definition of Color, the one inside the macro is not seen outside it.

There is one important exception to this, and this is one of the most powerful features of macros (thanks to this they can be used as if they were functions): If an identifier (be it local or global) appears alone in the body of a macro (usually at the end), its value will be passed outside the macro (as if it was a return value). The following example shows how this works:

#macro Factorial(N)
  #local Result = 1;
  #local Ind = 2;
  #while(Ind <= N)
    #local Result = Result*Ind;
    #local Ind = Ind+1;
  #end
  Result
#end

#declare Value = Factorial(5);

Although the identifier Result is local to the macro, its value is passed as if it was a return value because of the last line of the macro (where Result appears alone) and thus the identifier Value will be set to the factorial of 5.

2.3.11.7.2 The ray-sphere intersection macro

Here is again the macro at the beginning of the page so that you do not have to scroll so much in order to see it:

#macro calcRaySphereIntersection(P, D, sphereInd)
  #local V = P-Coord[sphereInd][0];
  #local R = Coord[sphereInd][1].x;

  #local DV = vdot(D, V);
  #local D2 = vdot(D, D);
  #local SQ = DV*DV-D2*(vdot(V, V)-R*R);
  #if(SQ < 0) #local Result = -1;
  #else
    #local SQ = sqrt(SQ);
    #local T1 = (-DV+SQ)/D2;
    #local T2 = (-DV-SQ)/D2;
    #local Result = (T1<T2 ? T1 : T2);
  #end
  Result
#end

The idea behind this macro is that it takes a starting point (ie. the starting point of the ray) a direction vector (the direction where the ray is shot) and an index to the sphere definition array defined previously. The macro returns a factor value; this value expresses how much we have to multiply the direction vector in order to hit the sphere.

This means that if the ray hits the specified sphere, the intersection point will be located at:
StartingPoint + Result*Direction

The return value can be negative, which means that the intersection point was actually behind the starting point. A negative value will be just ignored, as if the ray did not hit anything. We can use this to make a little trick (which may seem obvious when said, but not so obvious when you have to figure it out for yourself): If the ray actually does not hit the sphere, we return just a negative value (does not really matter which).

And how does the macro do it? What is the theory behind those complicated-looking mathematical expressions?

I will use a syntax similar to POV-Ray syntax to express mathematical formulas here since that is probably the easiest way of doing it.

Let's use the following letters:

P = Starting point of the ray
D = Direction of the ray
C = Center of the sphere
R = Radius of the sphere

The theory behind the macro is that we have to see what is the value T for which holds that:

vlength(P+T*D-C) = R

This means: The length of the vector between the center of the sphere (C) and the intersection point (P+T*D) is equal to the radius (R).

If we use an additional letter so that:

V = P-C

then the formula is reduced to:

vlength(T*D+V) = R

which makes our life easier. This formula can be opened as:

(T*Dx+Vx)2 + (T*Dy+Vy)2 + (T*Dz+Vz)2 - R2 = 0

Solving T from that is rather trivial math. We get a 2nd order polynomial which has two solutions (I will use the "·" symbol to represent the dot-product of two vectors):

T = (-D·V ± sqrt((D·V)2 - D2(V2-R2))) / D2

Note: D2 means actually D·D)

When the discriminant (ie. the expression inside the square root) is negative, the ray does not hit the sphere and thus we can return a negative value (the macro returns -1). We must check this in order to avoid the square root of a negative number error; as it has a very logical meaning in this case, the checking is natural.

If the value is positive, there are two solutions (or just one if the value is zero, but that does not really matter here), which corresponds to the two intersection points of the ray with the sphere.

As we get two values, we have to return the one which is smaller (the closest intersection). This is what this portion of the code does:

    #local Result = (T1<T2 ? T1 : T2);

Note: This is an incomplete algorithm: If one value is negative and the other positive (this happens when the starting point is inside the sphere), we would have to return the positive one. The way it is now results in that we will not see the inner surface of the sphere if we put the camera inside one.

For our simple scene this is enough as we do not put our camera inside a sphere nor we have transparent spheres. We could add a check there which looks if one of the values is positive and the other negative and returns the positive one. However, this has an odd and very annoying result (you can try it if you want). This is most probably caused by the inaccuracy of floating point numbers and happens when calculating reflections (the starting point is exactly on the surface of the sphere). We could correct these problems by using epsilon values to get rid of accuracy problems, but in our simple scene this will not be necessary.

2.3.11.8 The Trace macro

#macro Trace(P, D, recLev)

If the ray-sphere intersection macro was the core of the raytracer, then the Trace-macro is practically everything else, the body of the raytracer.

The Trace-macro is a macro which takes the starting point of a ray, the direction of the ray and a recursion count (which should always be 1 when calling the macro from outside; 1 could be its default value if POV-Ray supported default values for macro parameters). It calculates and returns a color for that ray.

This is the macro we call for each pixel we want to calculate. That is, the starting point of the ray is our camera location and the direction is the direction of the ray starting from there and going through the pixel we are calculating. The macro returns the color of that pixel.

What the macro does is to see which sphere (if any) does the ray hit and then calculates the lighting for that intersection point (which includes calculating reflection), and returns the color.

The Trace-macro is recursive, meaning that it calls itself. More specifically, it calls itself when it wants to calculate the ray reflected from the surface of a sphere. The recLev value is used to stop this recursion when the maximum recursion level is reached (ie. it calculates the reflection only if recLev < MaxRecLev).

Let's examine this relatively long macro part by part:

2.3.11.8.1 Calculating the closest intersection
  #local minT = MaxDist;
  #local closest = ObjAmnt;

  // Find closest intersection:
  #local Ind = 0;
  #while(Ind < ObjAmnt)
    #local T = calcRaySphereIntersection(P, D, Ind);
    #if(T>0 & T<minT)
      #local minT = T;
      #local closest = Ind;
    #end
    #local Ind = Ind+1;
  #end

A ray can hit several spheres and we need the closest intersection point (and to know which sphere does it belong to). One could think that calculating the closest intersection is rather complicated, needing things like sorting all the intersection points and such. However, it is quite simple, as seen in the code above.

If we remember from the previous part, the ray-sphere intersection macro returns a factor value which tells us how much do we have to multiply the direction vector in order to get the intersection point. What we do is just to call the ray-sphere intersection macro for each sphere and take the smallest returned value (which is greater than zero).

First we initialize the minT identifier, which will hold this smallest value to something big (this is where we need the MaxDist value, although modifying this code to work around this limitation is trivial and left to the user). Then we go through all the spheres and call the ray-sphere intersection macro for each one. Then we look if the returned value was greater than 0 and smaller than minT, and if so, we assign the value to minT. When the loop ends, we have the smallest intersection point in it.

Note: We also assign the index to the sphere which the closest intersection belongs to in the closest identifier.

Here we use a small trick, and it is related to its initial value: ObjAmnt. Why did we initialize it to that? The purpose of it was to initialize it to some value which is not a legal index to a sphere (ObjAmnt is not a legal index as the indices go from 0 to ObjAmnt-1); a negative value would have worked as well, it really does not matter. If the ray does not hit any sphere, then this identifier is not changed and so we can see it afterwards.

2.3.11.8.2 If the ray doesn't hit anything
  // If not found, return background color:
  #if(closest = ObjAmnt)
    #local Pixel = BGColor;

If the ray did not hit any sphere, what we do is just to return the bacground color (defined by the BGColor identifier).

2.3.11.8.3 Initializing color calculations

Now comes one of the most interesting parts of the raytracing process: How do we calculate the color of the intersection point?

First we have to pre-calculate a couple of things:

  #else
    // Else calculate the color of the intersection point:
    #local IP = P+minT*D;
    #local R = Coord[closest][1].x;
    #local Normal = (IP-Coord[closest][0])/R;

    #local V = P-IP;
    #local Refl = 2*Normal*(vdot(Normal, V)) - V;

Naturally we need the intersection point itself (needed to calculate the normal vector and as the starting point of the reflected ray). This is calculated into the IP identifier with the formula which I have been repeating a few times during this tutorial.

Then we need the normal vector of the surface at the intersection point. A normal vector is a vector perpendicular (ie. at 90 degrees) to the surface. For a sphere this is very easy to calculate: It is just the vector from the center of the sphere to the intersection point.

Note: We normalize it (ie. convert it into a unit vector, ie. a vector of length 1) by dividing it by the radius of the sphere. The normal vector needs to be normalized for lighting calculation.

Now a tricky one: We need the direction of the reflected ray. This vector is of course needed to calculate the reflected ray, but it is also needed for specular lighting.

This is calculated into the Refl identifier in the code above. What we do is to take the vector from the intersection point to the starting point (P-IP) and mirror it with respect to the normal vector. The formula for mirroring a vector V with respect to a unit vector (let's call it Axis) is:

MirroredV = 2*Axis*(Axis·V) - V

(We could look at the theory behind this formula in more detail, but let's not go too deep into math in this tutorial, shall we?)

2.3.11.8.4 Going through the light sources
    // Lighting:
    #local Pixel = AmbientLight;
    #local Ind = 0;
    #while(Ind < LightAmnt)
      #local L = LVect[Ind][0];

Now we can calculate the lighting of the intersection point. For this we need to go through all the light sources.

Note: L contains the direction vector which points towards the light source, not its location.

We also initialize the color to be returned (Pixel) with the ambient light value (given in the global settings part). The goal is to add colors to this (the colors come from diffuse and specular lighting, and reflection).

2.3.11.8.5 Shadow test

The very first thing to do for calculating the lighting for a light source is to see if the light source is illuminating the intersection point in the first place (this is one of the nicest features of raytracing: shadow calculations are laughably easy to do):

      // Shadowtest:
      #local Shadowed = false;
      #local Ind2 = 0;
      #while(Ind2 < ObjAmnt)
        #if(Ind2!=closest & calcRaySphereIntersection(IP,L,nd2)>0)
          #local Shadowed = true;
          #local Ind2 = ObjAmnt;
        #end
        #local Ind2 = Ind2+1;
      #end

What we do is to go through all the spheres (we skip the current sphere although it is not necessary, but a little optimization is still a little optimization), take the intersection point as starting point and the light direction as the direction vector and see if the ray-sphere intersection test returns a positive value for any of them (and quit the loop immediately when one is found, as we do not need to check the rest anymore).

The result of the shadow test is put into the Shadowed identifier as a boolean value (true if the point is shadowed).

2.3.11.8.6 Diffuse lighting

The diffuse component of lighting is generated when a light ray hits a surface and it is reflected equally to all directions. The brightest part of the surface is where the normal vector points directly in the direction of the light. The lighting diminishes in relation to the cosine of the angle between the normal vector and the light vector.

      #if(!Shadowed)
        // Diffuse:
        #local Factor = vdot(Normal, L);
        #if(Factor > 0)
          #local Pixel =
             Pixel + LVect[Ind][1]*Coord[closest][2]*Factor;
        #end

The code for diffuse lighting is surprisingly short.

There is an extremely nice trick in mathematics to get the cosine of the angle between two unit vectors: It is their dot-product.

What we do is to calculate the dot-product of the normal vector and the light vector (both have been normalized previously). If the dot-product is negative it means that the normal vector points in the opposite direction than the light vector. Thus we are only interested in positive values.

Thus, we add to the pixel color the color of the light source multiplied by the color of the surface of the sphere multiplied by the dot-product. This gives us the diffuse component of the lighting.

2.3.11.8.7 Specular lighting

The specular component of lighting comes from the fact that most surfaces do not reflect light equally to all directions, but they reflect more light to the reflected ray direction, that is, the surface has some mirror properties. The brightest part of the surface is where the reflected ray points in the direction of the light.

Photorealistic lighting is a very complicated issue and there are lots of different lighting models out there, which try to simulate real-world lighting more or less accurately. For our simple raytracer we just use a simple Phong lighting model, which suffices more than enough.

        // Specular:
        #local Factor = vdot(vnormalize(Refl), L);
        #if(Factor > 0)
          #local Pixel = Pixel + LVect[Ind][1]*
                         pow(Factor, Coord[closest][3].x)*
                         Coord[closest][3].y;
        #end

The calculation is similar to the diffuse lighting with the following differences:

  • We do not use the normal vector, but the reflected vector.
  • The color of the surface is not taken into account (a very simple Phong lighting model).
  • We do not take the dot-product as is, but we raise it to a power given in the scene definition (phong size).
  • We use a brightness factor given in the scene definition to multiply the color (phong amount).

Thus, the color we add to the pixel color is the color of the light source multiplied by the dot-product (which is raised to the given power) and by the given brightness amount.

Then we close the code blocks:

      #end // if(!Shadowed)
      #local Ind = Ind+1;
    #end // while(Ind < LightAmnt)
2.3.11.8.8 Reflection Calculation
    // Reflection:
    #if(recLev < MaxRecLev & Coord[closest][1].y > 0)
      #local Pixel =
        Pixel + Trace(IP, Refl, recLev+1)*Coord[closest][1].y;
    #end

Another nice aspect of raytracing is that reflection is very easy to calculate.

Here we check that the recursion level has not reached the limit and that the sphere has a reflection component defined. If both are so, we add the reflected component (the color of the reflected ray multiplied by the reflection factor) to the pixel color.

This is where the recursive call happens (the macro calls itself). The recursion level (recLev) is increased by one for the next call so that somewhere down the line, the series of Trace() calls will know to stop (preventing a ray from bouncing back and forth forever between two mirrors). This is basically how the max_trace_level global setting works in POV-Ray.

Finally, we close the code blocks and return the pixel color from the macro:

  #end // else

  Pixel
#end

2.3.11.9 Calculating the image

#debug "Rendering...\n\n"
#declare Image = array[ImageWidth][ImageHeight]

#declare IndY = 0;
#while(IndY < ImageHeight)
  #declare CoordY = IndY/(ImageHeight-1)*2-1;
  #declare IndX = 0;
  #while(IndX < ImageWidth)
    #declare CoordX =
       (IndX/(ImageWidth-1)-.5)*2*ImageWidth/ImageHeight;
    #declare Image[IndX][IndY] =
      Trace(-z*3, <CoordX, CoordY, 3>, 1);
    #declare IndX = IndX+1;
  #end
  #declare IndY = IndY+1;
  #debug concat("\rDone ", str(100*IndY/ImageHeight,0,1),
    "%  (line ", str(IndY,0,0)," out of ",str(ImageHeight,0,0),")")
#end
#debug "\n"

Now we just have to calculate the image into an array of colors. This array is defined at the beginning of the code above; it is a two-dimensional array representing the final image we are calculating.

Notice how we use the #debug stream to output useful information about the rendering process while we are calculating. This is nice because the rendering process is quite slow and it is good to give the user some feedback about what is happening and how long it will take. (Also note that the "%" character in the string of the second #debug command will work ok only in the Windows version of POV-Ray; for other versions it may be necessary to convert it to "%%".)

What we do here is to go through each pixel of the image (ie. the array) and for each one calculate the camera location (fixed to -z*3 here) and the direction of the ray that goes through the pixel (in this code the viewing plane is fixed and located in the x-y-plane and its height is fixed to 1).

What the following line:

  #declare CoordY = IndY/(ImageHeight-1)*2-1;

does is to scale the IndY so that it goes from -1 to 1. It is first divided by the maximum value it gets (which is ImageHeight-1) and then it is multiplied by 2 and substracted by 1. This results in a value which goes from -1 to 1.

The CoordX is calculated similarly, but it is also multiplied by the aspect ratio of the image we are calculating (so that we do not get a squeezed image).

2.3.11.10 Creating the colored mesh

If you think that these things we have been examining are advanced, then you have not seen anything. Now comes real hard-core advanced POV-Ray code, so be prepared. This could be called The really advanced section.

We have now calculated the image into the array of colors. However, we still have to show these color pixels on screen, that is, we have to make POV-Ray to render our pixels so that it creates a real image.

There are several ways of doing this, all of them being more or less kludges (as there is currently no way of directly creating an image map from a group of colors). One could create colored boxes representing each pixel, or one could output to an ascii-formatted image file (mainly PPM) and then read it as an image map. The first one has the disadvantage of requiring huge amounts of memory and missing bilinear interpolation of the image; the second one has the disadvantage of requiring a temporary file.

What we are going to do is to calculate a colored mesh2 which represents the screen. As colors are interpolated between the vertices of a triangle, the bilinear interpolation comes for free (almost).

2.3.11.10.1 The structure of the mesh

Although all the triangles are located in the x-y plane and they are all the same size, the structure of the mesh is quite complicated (so complicated it deserves its own section here).

The following image shows how the triangles are arranged for a 4x3 pixels image:

Triangle arrangement for a 4x3 image

The number pairs in parentheses represent image pixel coordinates (eg. (0,0) refers to the pixel at the lower left corner of the image and (3,2) to the pixel at the upper right corner). That is, the triangles will be colored as the image pixels at these points. The colors will then be interpolated between them along the surface of the triangles.

The filled and non-filled circles in the image represent the vertex points of the triangles and the lines connecting them show how the triangles are arranged. The smaller numbers near these circles indicate their index value (the one which will be created inside the mesh2).

We notice two things which may seem odd: Firstly there are extra vertex points outside the mesh, and secondly, there are extra vertex points in the middle of each square.

Let's start with the vertices in the middle of the squares: We could have just made each square with two triangles instead of four, as we have done here. However, the color interpolation is not nice this way, as there appears a clear diagonal line where the triangle edges go. If we make each square with four triangles instead, then the diagonal lines are less apparent, and the interpolation resembles a lot better a true bilinear interpolation. And what is the color of the middle points? Of course it is the average of the color of the four points in the corners.

Secondly: Yes, the extra vertex points outside the mesh are completely obsolete and take no part in the creation of the mesh. We could perfectly create the exact same mesh without them. However, getting rid of these extra vertex points makes our lives more difficult when creating the triangles, as it would make the indexing of the points more difficult. It may not be too much work to get rid of them, but they do not take any considerable amount of resources and they make our lives easier, so let's just let them be (if you want to remove them, go ahead).

2.3.11.10.2 Creating the mesh

What this means is that for each pixel we create two vertex points, one at the pixel location and one shifted by 0.5 in the x and y directions. Then we specify the color for each vertex points: For the even vertex points it is directly the color of the correspondent pixel; for the odd vertex points it is the average of the four surrounding pixels.

Let's examine the creation of the mesh step by step:

2.3.11.10.3 Creating the vertex points
#default { finish { ambient 1 } }

#debug "Creating colored mesh to show image...\n"
mesh2
{ vertex_vectors
  { ImageWidth*ImageHeight*2,
    #declare IndY = 0;
    #while(IndY < ImageHeight)
      #declare IndX = 0;
      #while(IndX < ImageWidth)
        <(IndX/(ImageWidth-1)-.5)*ImageWidth/ImageHeight*2,
         IndY/(ImageHeight-1)*2-1, 0>,
        <((IndX+.5)/(ImageWidth-1)-.5)*ImageWidth/ImageHeight*2,
         (IndY+.5)/(ImageHeight-1)*2-1, 0>
        #declare IndX = IndX+1;
      #end
      #declare IndY = IndY+1;
    #end
  }

First of all we use a nice trick in POV-Ray: Since we are not using light sources and there is nothing illuminating our mesh, what we do is to set the ambient value of the mesh to 1. We do this by just making it the default with the #default command, so we do not have to bother later.

As we saw above, what we are going to do is to create two vertex points for each pixel. Thus we know without further thinking how many vertex vectors there will be: ImageWidth*ImageHeight*2

That was the easy part; now we have to figure out how to create the vertex points themselves. Each vertex location should correspond to the pixel location it is representing, thus we go through each pixel index (practically the number pairs in parentheses in the image above) and create vertex points using these index values. The location of these pixels and vertices are the same as we assumed when we calculated the image itself (in the previous part). Thus the y coordinate of each vertex point should go from -1 to 1 and similarly the x coordinate, but scaled with the aspect ratio.

If you look at the creation of the first vector in the code above, you will see that it is almost identical to the direction vector we calculated when creating the image.

The second vector should be shifted by 0.5 in both directions, and that is exactly what is done there. The second vector definition is identical to the first one except that the index values are shifted by 0.5. This creates the points in the middle of the squares.

The index values of these points will be arranged as shown in the image above.

2.3.11.10.4 Creating the textures
  texture_list
  { ImageWidth*ImageHeight*2,
    #declare IndY = 0;
    #while(IndY < ImageHeight)
      #declare IndX = 0;
      #while(IndX < ImageWidth)
        texture { pigment { rgb Image[IndX][IndY] } }
        #if(IndX < ImageWidth-1 & IndY < ImageHeight-1)
          texture { pigment { rgb
            (Image[IndX][IndY]+Image[IndX+1][IndY]+
             Image[IndX][IndY+1]+Image[IndX+1][IndY+1])/4 } }
        #else
          texture { pigment { rgb 0 } }
        #end
        #declare IndX = IndX+1;
      #end
      #declare IndY = IndY+1;
    #end
  }

Creating the textures is very similar to creating the vertex points (we could have done both inside the same loop, but due to the syntax of the mesh2 we have to do it separately).

So what we do is to go through all the pixels in the image and create textures for each one. The first texture is just the pixel color itself. The second texture is the average of the four surrounding pixels.

Note: We can calculate it only for the vertex points in the middle of the squares; for the extra vertex points outside the image we just define a dummy black texture.

The textures have the same index values as the vertex points.

2.3.11.10.5 Creating the triangles

This one is a bit trickier. Basically we have to create four triangles for each square between pixels. How many triangles will there be?

Let's examine the creation loop first:

  face_indices
  { (ImageWidth-1)*(ImageHeight-1)*4,
    #declare IndY = 0;
    #while(IndY < ImageHeight-1)
      #declare IndX = 0;
      #while(IndX < ImageWidth-1)

        ...

        #declare IndX = IndX+1;
      #end
      #declare IndY = IndY+1;
    #end
  }

The number of squares is one less than the number of pixels in each direction. That is, the number of squares in the x direction will be one less than the number of pixels in the x direction. The same for the y direction. As we want four triangles for each square, the total number of triangles will then be (ImageWidth-1)*(ImageHeight-1)*4.

Then to create each square we loop the amount of pixels minus one for each direction.

Now in the inside of the loop we have to create the four triangles. Let's examine the first one:

        <IndX*2+  IndY    *(ImageWidth*2),
         IndX*2+2+IndY    *(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)>,
         IndX*2+  IndY    *(ImageWidth*2),
         IndX*2+2+IndY    *(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2),

This creates a triangle with a texture in each vertex. The first three values (the indices to vertex points) are identical to the next three values (the indices to the textures) because the index values were exactly the same for both.

The IndX is always multiplied by 2 because we had two vertex points for each pixel and IndX is basically going through the pixels. Likewise IndY is always multiplied by ImageWidth*2 because that is how long a row of index points is (ie. to get from one row to the next at the same x coordinate we have to advance ImageWidth*2 in the index values).

These two things are identical in all the triangles. What decides which vertex point is chosen is the "+1" or "+2" (or "+0" when there is nothing). For IndX "+0" is the current pixel, "+1" chooses the point in the middle of the square and "+2" chooses the next pixel. For IndY "+1" chooses the next row of pixels.

Thus this triangle definition creates a triangle using the vertex point for the current pixel, the one for the next pixel and the vertex point in the middle of the square.

The next triangle definition is likewise:

        <IndX*2+  IndY    *(ImageWidth*2),
         IndX*2+  (IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)>,
         IndX*2+  IndY    *(ImageWidth*2),
         IndX*2+  (IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2),

This one defines the triangle using the current point, the point in the next row and the point in the middle of the square.

The next two definitions define the other two triangles:

        <IndX*2+  (IndY+1)*(ImageWidth*2),
         IndX*2+2+(IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)>,
         IndX*2+  (IndY+1)*(ImageWidth*2),
         IndX*2+2+(IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2),

        <IndX*2+2+IndY    *(ImageWidth*2),
         IndX*2+2+(IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)>,
         IndX*2+2+IndY    *(ImageWidth*2),
         IndX*2+2+(IndY+1)*(ImageWidth*2),
         IndX*2+1+IndY    *(ImageWidth*2)

2.3.11.11 The Camera-setup

The only thing left is the camera definition, so that POV-Ray can calculate the image correctly:

  camera { orthographic location -z*2 look_at 0 }

Why 2? As the default direction vector is <0,0,1> and the default up vector is <0,1,0> and we want the up direction to cover 2 units, we have to move the camera two units away.


Tutorial Section 4

2.4 Questions and Tips

Note: This section used to contain answers to frequently asked questions about POV-Ray as well as many useful tips not covered in other parts of this documentation. You should now refer to the online version of the POV-Ray »Questions and Tips


Tutorial Section 5

2.5 Appendices

2.5.1 Contacting the Authors

If you have a question regarding commercial use or distribution of POV-Ray, please contact the development team coordinator via the address listed at http://www.povray.org/povlegal.html. Please do not email us directly for technical support - use the below-mentioned forums. We generally do not answer emails requesting support if the sender has not first asked in the forums or read the documentation.

See our »web site and particularly our »forums for online peer support. The forums have a bug reporting group; please however discuss the issue in the »povray.general group and check our bugtracker at http://bugs.povray.org/ prior to lodging a report as we may already know of the issue (or it might not even be a bug).

2.5.2 POV-Ray License

Note: The following license applies to POV-Ray version 3.7 and later. It does not apply to any earlier version, including the 3.7 beta-test and release candidates.

                        GNU AFFERO GENERAL PUBLIC LICENSE
                           Version 3, 19 November 2007

     Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
     Everyone is permitted to copy and distribute verbatim copies
     of this license document, but changing it is not allowed.

                                Preamble

      The GNU Affero General Public License is a free, copyleft license for
    software and other kinds of works, specifically designed to ensure
    cooperation with the community in the case of network server software.

      The licenses for most software and other practical works are designed
    to take away your freedom to share and change the works.  By contrast,
    our General Public Licenses are intended to guarantee your freedom to
    share and change all versions of a program--to make sure it remains free
    software for all its users.

      When we speak of free software, we are referring to freedom, not
    price.  Our General Public Licenses are designed to make sure that you
    have the freedom to distribute copies of free software (and charge for
    them if you wish), that you receive source code or can get it if you
    want it, that you can change the software or use pieces of it in new
    free programs, and that you know you can do these things.

      Developers that use our General Public Licenses protect your rights
    with two steps: (1) assert copyright on the software, and (2) offer
    you this License which gives you legal permission to copy, distribute
    and/or modify the software.

      A secondary benefit of defending all users' freedom is that
    improvements made in alternate versions of the program, if they
    receive widespread use, become available for other developers to
    incorporate.  Many developers of free software are heartened and
    encouraged by the resulting cooperation.  However, in the case of
    software used on network servers, this result may fail to come about.
    The GNU General Public License permits making a modified version and
    letting the public access it on a server without ever releasing its
    source code to the public.

      The GNU Affero General Public License is designed specifically to
    ensure that, in such cases, the modified source code becomes available
    to the community.  It requires the operator of a network server to
    provide the source code of the modified version running there to the
    users of that server.  Therefore, public use of a modified version, on
    a publicly accessible server, gives the public access to the source
    code of the modified version.

      An older license, called the Affero General Public License and
    published by Affero, was designed to accomplish similar goals.  This is
    a different license, not a version of the Affero GPL, but Affero has
    released a new version of the Affero GPL which permits relicensing under
    this license.

      The precise terms and conditions for copying, distribution and
    modification follow.

                           TERMS AND CONDITIONS

      0. Definitions.

      "This License" refers to version 3 of the GNU Affero General Public License.

      "Copyright" also means copyright-like laws that apply to other kinds of
    works, such as semiconductor masks.

      "The Program" refers to any copyrightable work licensed under this
    License.  Each licensee is addressed as "you".  "Licensees" and
    "recipients" may be individuals or organizations.

      To "modify" a work means to copy from or adapt all or part of the work
    in a fashion requiring copyright permission, other than the making of an
    exact copy.  The resulting work is called a "modified version" of the
    earlier work or a work "based on" the earlier work.

      A "covered work" means either the unmodified Program or a work based
    on the Program.

      To "propagate" a work means to do anything with it that, without
    permission, would make you directly or secondarily liable for
    infringement under applicable copyright law, except executing it on a
    computer or modifying a private copy.  Propagation includes copying,
    distribution (with or without modification), making available to the
    public, and in some countries other activities as well.

      To "convey" a work means any kind of propagation that enables other
    parties to make or receive copies.  Mere interaction with a user through
    a computer network, with no transfer of a copy, is not conveying.

      An interactive user interface displays "Appropriate Legal Notices"
    to the extent that it includes a convenient and prominently visible
    feature that (1) displays an appropriate copyright notice, and (2)
    tells the user that there is no warranty for the work (except to the
    extent that warranties are provided), that licensees may convey the
    work under this License, and how to view a copy of this License.  If
    the interface presents a list of user commands or options, such as a
    menu, a prominent item in the list meets this criterion.

      1. Source Code.

      The "source code" for a work means the preferred form of the work
    for making modifications to it.  "Object code" means any non-source
    form of a work.

      A "Standard Interface" means an interface that either is an official
    standard defined by a recognized standards body, or, in the case of
    interfaces specified for a particular programming language, one that
    is widely used among developers working in that language.

      The "System Libraries" of an executable work include anything, other
    than the work as a whole, that (a) is included in the normal form of
    packaging a Major Component, but which is not part of that Major
    Component, and (b) serves only to enable use of the work with that
    Major Component, or to implement a Standard Interface for which an
    implementation is available to the public in source code form.  A
    "Major Component", in this context, means a major essential component
    (kernel, window system, and so on) of the specific operating system
    (if any) on which the executable work runs, or a compiler used to
    produce the work, or an object code interpreter used to run it.

      The "Corresponding Source" for a work in object code form means all
    the source code needed to generate, install, and (for an executable
    work) run the object code and to modify the work, including scripts to
    control those activities.  However, it does not include the work's
    System Libraries, or general-purpose tools or generally available free
    programs which are used unmodified in performing those activities but
    which are not part of the work.  For example, Corresponding Source
    includes interface definition files associated with source files for
    the work, and the source code for shared libraries and dynamically
    linked subprograms that the work is specifically designed to require,
    such as by intimate data communication or control flow between those
    subprograms and other parts of the work.

      The Corresponding Source need not include anything that users
    can regenerate automatically from other parts of the Corresponding
    Source.

      The Corresponding Source for a work in source code form is that
    same work.

      2. Basic Permissions.

      All rights granted under this License are granted for the term of
    copyright on the Program, and are irrevocable provided the stated
    conditions are met.  This License explicitly affirms your unlimited
    permission to run the unmodified Program.  The output from running a
    covered work is covered by this License only if the output, given its
    content, constitutes a covered work.  This License acknowledges your
    rights of fair use or other equivalent, as provided by copyright law.

      You may make, run and propagate covered works that you do not
    convey, without conditions so long as your license otherwise remains
    in force.  You may convey covered works to others for the sole purpose
    of having them make modifications exclusively for you, or provide you
    with facilities for running those works, provided that you comply with
    the terms of this License in conveying all material for which you do
    not control copyright.  Those thus making or running the covered works
    for you must do so exclusively on your behalf, under your direction
    and control, on terms that prohibit them from making any copies of
    your copyrighted material outside their relationship with you.

      Conveying under any other circumstances is permitted solely under
    the conditions stated below.  Sublicensing is not allowed; section 10
    makes it unnecessary.

      3. Protecting Users' Legal Rights From Anti-Circumvention Law.

      No covered work shall be deemed part of an effective technological
    measure under any applicable law fulfilling obligations under article
    11 of the WIPO copyright treaty adopted on 20 December 1996, or
    similar laws prohibiting or restricting circumvention of such
    measures.

      When you convey a covered work, you waive any legal power to forbid
    circumvention of technological measures to the extent such circumvention
    is effected by exercising rights under this License with respect to
    the covered work, and you disclaim any intention to limit operation or
    modification of the work as a means of enforcing, against the work's
    users, your or third parties' legal rights to forbid circumvention of
    technological measures.

      4. Conveying Verbatim Copies.

      You may convey verbatim copies of the Program's source code as you
    receive it, in any medium, provided that you conspicuously and
    appropriately publish on each copy an appropriate copyright notice;
    keep intact all notices stating that this License and any
    non-permissive terms added in accord with section 7 apply to the code;
    keep intact all notices of the absence of any warranty; and give all
    recipients a copy of this License along with the Program.

      You may charge any price or no price for each copy that you convey,
    and you may offer support or warranty protection for a fee.

      5. Conveying Modified Source Versions.

      You may convey a work based on the Program, or the modifications to
    produce it from the Program, in the form of source code under the
    terms of section 4, provided that you also meet all of these conditions:

        a) The work must carry prominent notices stating that you modified
        it, and giving a relevant date.

        b) The work must carry prominent notices stating that it is
        released under this License and any conditions added under section
        7.  This requirement modifies the requirement in section 4 to
        "keep intact all notices".

        c) You must license the entire work, as a whole, under this
        License to anyone who comes into possession of a copy.  This
        License will therefore apply, along with any applicable section 7
        additional terms, to the whole of the work, and all its parts,
        regardless of how they are packaged.  This License gives no
        permission to license the work in any other way, but it does not
        invalidate such permission if you have separately received it.

        d) If the work has interactive user interfaces, each must display
        Appropriate Legal Notices; however, if the Program has interactive
        interfaces that do not display Appropriate Legal Notices, your
        work need not make them do so.

      A compilation of a covered work with other separate and independent
    works, which are not by their nature extensions of the covered work,
    and which are not combined with it such as to form a larger program,
    in or on a volume of a storage or distribution medium, is called an
    "aggregate" if the compilation and its resulting copyright are not
    used to limit the access or legal rights of the compilation's users
    beyond what the individual works permit.  Inclusion of a covered work
    in an aggregate does not cause this License to apply to the other
    parts of the aggregate.

      6. Conveying Non-Source Forms.

      You may convey a covered work in object code form under the terms
    of sections 4 and 5, provided that you also convey the
    machine-readable Corresponding Source under the terms of this License,
    in one of these ways:

        a) Convey the object code in, or embodied in, a physical product
        (including a physical distribution medium), accompanied by the
        Corresponding Source fixed on a durable physical medium
        customarily used for software interchange.

        b) Convey the object code in, or embodied in, a physical product
        (including a physical distribution medium), accompanied by a
        written offer, valid for at least three years and valid for as
        long as you offer spare parts or customer support for that product
        model, to give anyone who possesses the object code either (1) a
        copy of the Corresponding Source for all the software in the
        product that is covered by this License, on a durable physical
        medium customarily used for software interchange, for a price no
        more than your reasonable cost of physically performing this
        conveying of source, or (2) access to copy the
        Corresponding Source from a network server at no charge.

        c) Convey individual copies of the object code with a copy of the
        written offer to provide the Corresponding Source.  This
        alternative is allowed only occasionally and noncommercially, and
        only if you received the object code with such an offer, in accord
        with subsection 6b.

        d) Convey the object code by offering access from a designated
        place (gratis or for a charge), and offer equivalent access to the
        Corresponding Source in the same way through the same place at no
        further charge.  You need not require recipients to copy the
        Corresponding Source along with the object code.  If the place to
        copy the object code is a network server, the Corresponding Source
        may be on a different server (operated by you or a third party)
        that supports equivalent copying facilities, provided you maintain
        clear directions next to the object code saying where to find the
        Corresponding Source.  Regardless of what server hosts the
        Corresponding Source, you remain obligated to ensure that it is
        available for as long as needed to satisfy these requirements.

        e) Convey the object code using peer-to-peer transmission, provided
        you inform other peers where the object code and Corresponding
        Source of the work are being offered to the general public at no
        charge under subsection 6d.

      A separable portion of the object code, whose source code is excluded
    from the Corresponding Source as a System Library, need not be
    included in conveying the object code work.

      A "User Product" is either (1) a "consumer product", which means any
    tangible personal property which is normally used for personal, family,
    or household purposes, or (2) anything designed or sold for incorporation
    into a dwelling.  In determining whether a product is a consumer product,
    doubtful cases shall be resolved in favor of coverage.  For a particular
    product received by a particular user, "normally used" refers to a
    typical or common use of that class of product, regardless of the status
    of the particular user or of the way in which the particular user
    actually uses, or expects or is expected to use, the product.  A product
    is a consumer product regardless of whether the product has substantial
    commercial, industrial or non-consumer uses, unless such uses represent
    the only significant mode of use of the product.

      "Installation Information" for a User Product means any methods,
    procedures, authorization keys, or other information required to install
    and execute modified versions of a covered work in that User Product from
    a modified version of its Corresponding Source.  The information must
    suffice to ensure that the continued functioning of the modified object
    code is in no case prevented or interfered with solely because
    modification has been made.

      If you convey an object code work under this section in, or with, or
    specifically for use in, a User Product, and the conveying occurs as
    part of a transaction in which the right of possession and use of the
    User Product is transferred to the recipient in perpetuity or for a
    fixed term (regardless of how the transaction is characterized), the
    Corresponding Source conveyed under this section must be accompanied
    by the Installation Information.  But this requirement does not apply
    if neither you nor any third party retains the ability to install
    modified object code on the User Product (for example, the work has
    been installed in ROM).

      The requirement to provide Installation Information does not include a
    requirement to continue to provide support service, warranty, or updates
    for a work that has been modified or installed by the recipient, or for
    the User Product in which it has been modified or installed.  Access to a
    network may be denied when the modification itself materially and
    adversely affects the operation of the network or violates the rules and
    protocols for communication across the network.

      Corresponding Source conveyed, and Installation Information provided,
    in accord with this section must be in a format that is publicly
    documented (and with an implementation available to the public in
    source code form), and must require no special password or key for
    unpacking, reading or copying.

      7. Additional Terms.

      "Additional permissions" are terms that supplement the terms of this
    License by making exceptions from one or more of its conditions.
    Additional permissions that are applicable to the entire Program shall
    be treated as though they were included in this License, to the extent
    that they are valid under applicable law.  If additional permissions
    apply only to part of the Program, that part may be used separately
    under those permissions, but the entire Program remains governed by
    this License without regard to the additional permissions.

      When you convey a copy of a covered work, you may at your option
    remove any additional permissions from that copy, or from any part of
    it.  (Additional permissions may be written to require their own
    removal in certain cases when you modify the work.)  You may place
    additional permissions on material, added by you to a covered work,
    for which you have or can give appropriate copyright permission.

      Notwithstanding any other provision of this License, for material you
    add to a covered work, you may (if authorized by the copyright holders of
    that material) supplement the terms of this License with terms:

        a) Disclaiming warranty or limiting liability differently from the
        terms of sections 15 and 16 of this License; or

        b) Requiring preservation of specified reasonable legal notices or
        author attributions in that material or in the Appropriate Legal
        Notices displayed by works containing it; or

        c) Prohibiting misrepresentation of the origin of that material, or
        requiring that modified versions of such material be marked in
        reasonable ways as different from the original version; or

        d) Limiting the use for publicity purposes of names of licensors or
        authors of the material; or

        e) Declining to grant rights under trademark law for use of some
        trade names, trademarks, or service marks; or

        f) Requiring indemnification of licensors and authors of that
        material by anyone who conveys the material (or modified versions of
        it) with contractual assumptions of liability to the recipient, for
        any liability that these contractual assumptions directly impose on
        those licensors and authors.

      All other non-permissive additional terms are considered "further
    restrictions" within the meaning of section 10.  If the Program as you
    received it, or any part of it, contains a notice stating that it is
    governed by this License along with a term that is a further
    restriction, you may remove that term.  If a license document contains
    a further restriction but permits relicensing or conveying under this
    License, you may add to a covered work material governed by the terms
    of that license document, provided that the further restriction does
    not survive such relicensing or conveying.

      If you add terms to a covered work in accord with this section, you
    must place, in the relevant source files, a statement of the
    additional terms that apply to those files, or a notice indicating
    where to find the applicable terms.

      Additional terms, permissive or non-permissive, may be stated in the
    form of a separately written license, or stated as exceptions;
    the above requirements apply either way.

      8. Termination.

      You may not propagate or modify a covered work except as expressly
    provided under this License.  Any attempt otherwise to propagate or
    modify it is void, and will automatically terminate your rights under
    this License (including any patent licenses granted under the third
    paragraph of section 11).

      However, if you cease all violation of this License, then your
    license from a particular copyright holder is reinstated (a)
    provisionally, unless and until the copyright holder explicitly and
    finally terminates your license, and (b) permanently, if the copyright
    holder fails to notify you of the violation by some reasonable means
    prior to 60 days after the cessation.

      Moreover, your license from a particular copyright holder is
    reinstated permanently if the copyright holder notifies you of the
    violation by some reasonable means, this is the first time you have
    received notice of violation of this License (for any work) from that
    copyright holder, and you cure the violation prior to 30 days after
    your receipt of the notice.

      Termination of your rights under this section does not terminate the
    licenses of parties who have received copies or rights from you under
    this License.  If your rights have been terminated and not permanently
    reinstated, you do not qualify to receive new licenses for the same
    material under section 10.

      9. Acceptance Not Required for Having Copies.

      You are not required to accept this License in order to receive or
    run a copy of the Program.  Ancillary propagation of a covered work
    occurring solely as a consequence of using peer-to-peer transmission
    to receive a copy likewise does not require acceptance.  However,
    nothing other than this License grants you permission to propagate or
    modify any covered work.  These actions infringe copyright if you do
    not accept this License.  Therefore, by modifying or propagating a
    covered work, you indicate your acceptance of this License to do so.

      10. Automatic Licensing of Downstream Recipients.

      Each time you convey a covered work, the recipient automatically
    receives a license from the original licensors, to run, modify and
    propagate that work, subject to this License.  You are not responsible
    for enforcing compliance by third parties with this License.

      An "entity transaction" is a transaction transferring control of an
    organization, or substantially all assets of one, or subdividing an
    organization, or merging organizations.  If propagation of a covered
    work results from an entity transaction, each party to that
    transaction who receives a copy of the work also receives whatever
    licenses to the work the party's predecessor in interest had or could
    give under the previous paragraph, plus a right to possession of the
    Corresponding Source of the work from the predecessor in interest, if
    the predecessor has it or can get it with reasonable efforts.

      You may not impose any further restrictions on the exercise of the
    rights granted or affirmed under this License.  For example, you may
    not impose a license fee, royalty, or other charge for exercise of
    rights granted under this License, and you may not initiate litigation
    (including a cross-claim or counterclaim in a lawsuit) alleging that
    any patent claim is infringed by making, using, selling, offering for
    sale, or importing the Program or any portion of it.

      11. Patents.

      A "contributor" is a copyright holder who authorizes use under this
    License of the Program or a work on which the Program is based.  The
    work thus licensed is called the contributor's "contributor version".

      A contributor's "essential patent claims" are all patent claims
    owned or controlled by the contributor, whether already acquired or
    hereafter acquired, that would be infringed by some manner, permitted
    by this License, of making, using, or selling its contributor version,
    but do not include claims that would be infringed only as a
    consequence of further modification of the contributor version.  For
    purposes of this definition, "control" includes the right to grant
    patent sublicenses in a manner consistent with the requirements of
    this License.

      Each contributor grants you a non-exclusive, worldwide, royalty-free
    patent license under the contributor's essential patent claims, to
    make, use, sell, offer for sale, import and otherwise run, modify and
    propagate the contents of its contributor version.

      In the following three paragraphs, a "patent license" is any express
    agreement or commitment, however denominated, not to enforce a patent
    (such as an express permission to practice a patent or covenant not to
    sue for patent infringement).  To "grant" such a patent license to a
    party means to make such an agreement or commitment not to enforce a
    patent against the party.

      If you convey a covered work, knowingly relying on a patent license,
    and the Corresponding Source of the work is not available for anyone
    to copy, free of charge and under the terms of this License, through a
    publicly available network server or other readily accessible means,
    then you must either (1) cause the Corresponding Source to be so
    available, or (2) arrange to deprive yourself of the benefit of the
    patent license for this particular work, or (3) arrange, in a manner
    consistent with the requirements of this License, to extend the patent
    license to downstream recipients.  "Knowingly relying" means you have
    actual knowledge that, but for the patent license, your conveying the
    covered work in a country, or your recipient's use of the covered work
    in a country, would infringe one or more identifiable patents in that
    country that you have reason to believe are valid.

      If, pursuant to or in connection with a single transaction or
    arrangement, you convey, or propagate by procuring conveyance of, a
    covered work, and grant a patent license to some of the parties
    receiving the covered work authorizing them to use, propagate, modify
    or convey a specific copy of the covered work, then the patent license
    you grant is automatically extended to all recipients of the covered
    work and works based on it.

      A patent license is "discriminatory" if it does not include within
    the scope of its coverage, prohibits the exercise of, or is
    conditioned on the non-exercise of one or more of the rights that are
    specifically granted under this License.  You may not convey a covered
    work if you are a party to an arrangement with a third party that is
    in the business of distributing software, under which you make payment
    to the third party based on the extent of your activity of conveying
    the work, and under which the third party grants, to any of the
    parties who would receive the covered work from you, a discriminatory
    patent license (a) in connection with copies of the covered work
    conveyed by you (or copies made from those copies), or (b) primarily
    for and in connection with specific products or compilations that
    contain the covered work, unless you entered into that arrangement,
    or that patent license was granted, prior to 28 March 2007.

      Nothing in this License shall be construed as excluding or limiting
    any implied license or other defenses to infringement that may
    otherwise be available to you under applicable patent law.

      12. No Surrender of Others' Freedom.

      If conditions are imposed on you (whether by court order, agreement or
    otherwise) that contradict the conditions of this License, they do not
    excuse you from the conditions of this License.  If you cannot convey a
    covered work so as to satisfy simultaneously your obligations under this
    License and any other pertinent obligations, then as a consequence you may
    not convey it at all.  For example, if you agree to terms that obligate you
    to collect a royalty for further conveying from those to whom you convey
    the Program, the only way you could satisfy both those terms and this
    License would be to refrain entirely from conveying the Program.

      13. Remote Network Interaction; Use with the GNU General Public License.

      Notwithstanding any other provision of this License, if you modify the
    Program, your modified version must prominently offer all users
    interacting with it remotely through a computer network (if your version
    supports such interaction) an opportunity to receive the Corresponding
    Source of your version by providing access to the Corresponding Source
    from a network server at no charge, through some standard or customary
    means of facilitating copying of software.  This Corresponding Source
    shall include the Corresponding Source for any work covered by version 3
    of the GNU General Public License that is incorporated pursuant to the
    following paragraph.

      Notwithstanding any other provision of this License, you have
    permission to link or combine any covered work with a work licensed
    under version 3 of the GNU General Public License into a single
    combined work, and to convey the resulting work.  The terms of this
    License will continue to apply to the part which is the covered work,
    but the work with which it is combined will remain governed by version
    3 of the GNU General Public License.

      14. Revised Versions of this License.

      The Free Software Foundation may publish revised and/or new versions of
    the GNU Affero General Public License from time to time.  Such new versions
    will be similar in spirit to the present version, but may differ in detail to
    address new problems or concerns.

      Each version is given a distinguishing version number.  If the
    Program specifies that a certain numbered version of the GNU Affero General
    Public License "or any later version" applies to it, you have the
    option of following the terms and conditions either of that numbered
    version or of any later version published by the Free Software
    Foundation.  If the Program does not specify a version number of the
    GNU Affero General Public License, you may choose any version ever published
    by the Free Software Foundation.

      If the Program specifies that a proxy can decide which future
    versions of the GNU Affero General Public License can be used, that proxy's
    public statement of acceptance of a version permanently authorizes you
    to choose that version for the Program.

      Later license versions may give you additional or different
    permissions.  However, no additional obligations are imposed on any
    author or copyright holder as a result of your choosing to follow a
    later version.

      15. Disclaimer of Warranty.

      THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
    APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
    HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
    OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
    IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
    ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

      16. Limitation of Liability.

      IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
    THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
    GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
    USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
    DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
    PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
    EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
    SUCH DAMAGES.

      17. Interpretation of Sections 15 and 16.

      If the disclaimer of warranty and limitation of liability provided
    above cannot be given local legal effect according to their terms,
    reviewing courts shall apply local law that most closely approximates
    an absolute waiver of all civil liability in connection with the
    Program, unless a warranty or assumption of liability accompanies a
    copy of the Program in return for a fee.

                         END OF TERMS AND CONDITIONS

                How to Apply These Terms to Your New Programs

      If you develop a new program, and you want it to be of the greatest
    possible use to the public, the best way to achieve this is to make it
    free software which everyone can redistribute and change under these terms.

      To do so, attach the following notices to the program.  It is safest
    to attach them to the start of each source file to most effectively
    state the exclusion of warranty; and each file should have at least
    the "copyright" line and a pointer to where the full notice is found.

        <one line to give the program's name and a brief idea of what it does.>
        Copyright (C) <year>  <name of author>

        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU Affero General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU Affero General Public License for more details.

        You should have received a copy of the GNU Affero General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Also add information on how to contact you by electronic and paper mail.

      If your software can interact with users remotely through a computer
    network, you should also make sure that it provides a way for users to
    get its source.  For example, if your program is a web application, its
    interface could display a "Source" link that leads users to an archive
    of the code.  There are many ways you could offer source, and different
    solutions will be better for different programs; see section 13 for the
    specific requirements.

      You should also get your employer (if you work as a programmer) or school,
    if any, to sign a "copyright disclaimer" for the program, if necessary.
    For more information on this, and how to apply and follow the GNU AGPL, see
    <http://www.gnu.org/licenses/>.

2.5.3 Contact Information

If you wish to contact us for purposes other than technical support, the following means are available:

Via email:

team-coord-[three-letter month]-[four-digit year]@povray.org

for example, team-coord-jun-2004@povray.org should be used if at the time you send the email it is the month of June 2004. The changing email addresses are necessary to combat spam and email viruses. Old email addresses may be deleted at our discretion.

Note: Please do not send bug reports or technical support requests to this address. Use our forums or »bugtracker for technical support or bug reports.

Via postal mail:

The following postal address is only for official business. Please note that it is preferred that initial queries about licensing be made via email; postal mail should only be used when email is not possible, or when written documents are being exchanged by prior arrangement.

Persistence of Vision Raytracer Pty. Ltd.
PO Box 407
Williamstown,
Victoria 3016
Australia

2.5.4 Support Library Licenses

Licenses for Support Libraries used by POV-Ray

2.5.4.1 OpenEXR

Copyright © 2004, Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd. Portions contributed and copyright held by others as indicated. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  • Neither the name of Industrial Light & Magic nor the names of any other contributors to this software may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

2.5.5 Citing POV-Ray in Academic Publications

To reference POV-Ray (e.g. in academic papers), you may use one of the below:

Note: The year should be replaced with the year of your publication.

  Persistence of Vision Pty. Ltd. (2013)
    Persistence of Vision Raytracer (Version 3.7)
    [Computer software].
      Retrieved from http://www.povray.org/download/

or

  Persistence of Vision Pty. Ltd. (2013).
  Persistence of Vision Raytracer.
  Persistence of Vision Pty. Ltd., Williamstown, Victoria, Australia.
   http://www.povray.org/

2.5.6 Contributors to POV-Ray

Primary POV-Ray 3.7 Core Architects/Developers: (alphabetically)

Chris Cason
Developer 1993-, team leader 1999-, Windows version, SMP implementation, mesh camera, BSP bounding, too many other contributions to list here
Thorsten Fröhlich
Developer 1996-, Mac developer, frontend-backend messaging system, SMP implementation, too many other contributions to list here
Christoph Lipka
Developer 2009-, core code improvements notably radiosity, gamma handling, sslt and too many others to list

With Assistance From: (alphabetically)

Nicolas Calimet
UNIX development
Jérôme Grimbert
Mapping warps, image meta-data, the ovus object, several list patterns, additional render block items, and other core code contributions.
James Holsenback
3.7 documentation, POV-Wiki, various Unix/Linux, and scene file contributions
Christoph Hormann
UNIX development
Nathan Kopp
Photons, u/v mapping, other contributions
Juha Nieminen
area_illumination, cubic pattern and cubic warp, fractal patterns, other contributions

Past POV-Team Members and other Note-Worthy Contributors: (alphabetically)

Claire Amundsen
Tutorials for the POV-Ray User Guide
Steve Anger
POV-Ray 2.0/3.0 developer
Randy Antler
MS-Dos display code enhancements
John Baily
RLE targa code
Eric Barish
Ground fog code
Thomas Baier
3.1 team member, tester
Dieter Bayer
Wrote sor, lathe, prism, media and many other features
Anthony Bennett
Scene files, documentation
Kendall Bennett
PMODE library support, paletted display code in Windows version
Steve Bennett
GIF support
Thomas Bily
Implicit and parametric surfaces
Dale C. Brodin
Alpha & Beta tester, forum support
Eric Brown
no_image, no_reflection, orient and circular area_light
Matthew Corey Brown
pigment function, warps, projected_through
David Buck
Original author of DKBTrace, POV-Ray 1.0 developer
Edward Coffey
Fade_color
Aaron Collins
Co-author of DKBTrace 2.12, POV-Ray 1.0 developer
Chris Dailey
POV-Ray 3.0 developer
Steve Demlow
POV-Ray 3.0 developer
Andreas Dilger
Former Unix coordinator, Linux developer, PNG support
Joris van Drunen Littel
Mac beta tester
Alexander Enzmann
POV-Ray 1.0/2.0/3.0 developer
Dan Farmer
POV-Ray 1.0/2.0/3.0 developer, author of many features, sample scenes, and textures
Daniel Fenner
Splines
Hans-Detlev Fink
Slope pattern
Charles Fusner
Blob, lathe and prism tutorial tutorials for the POV-Ray User Guide
Mark Gordon
Unix developer
David Harr
Mac balloon help and palette code
Michael Hazelgrove
Scene files
Jimmy Hoeks
Original Help file for v3.0 Windows user interface
Christoph Hormann
Scene & include files, documentation, insert menu
Chris Huff
Object pattern, Interior texture, inverse transform
Bob Hughes
Scene and include files, insert menu
Ingo Janssen
Scene & include files, documentation
Mike Hough
Spherical camera, Media method 2, uv_mapping for bicubic_patch
Rune S. Johansen
Scene & include files, documentation
Greg M. Johnson
Scene files
Terry Kanakis
Camera fix
Kari Kivisalo
Ground fog code
Alan Kong
Alpha & Beta tester, forum support
Lutz Kretzschmar
Moray author, MS-DOS 24-bit VGA, part of the anti-aliasing code
Tor Olav Kristensen
Scene files
Jochen Lippert
Sphere_sweep
Friedrich Lohmülller
Version 3.7 scene file clean-up and Windows insert menus.
Charles Marslett
MS-Dos display code
Pascal Massimino
Fractal objects
Jim McElhiney
POV-Ray 3.0 developer
Robert A. Mickelsen
Artist, 3.0 docs contributor
Mike Miller
Artist, scene files, stones.inc
Fabien Mosen
Scene & include files
Douglas Muir
Bump maps, height fields
Joel Newkirk
Former Amiga developer
»Jim Nitchals
Mac version, scene files (Jim - famous also for his anti-spam crusades - »passed away on 5 June 1998 but his contributions to POV-Ray and responsible use of the internet will not be forgotten)
Paul Novak
Texture contributions
Wolfgang Ortmann
Splines
Dave Park
Amiga support, AGA video code
Redaelli Paolo
Former Amiga developer
Ron Parker
Core code, jack-of-all-trades
David Payne
RLE targa code
Ansgar Philippsen
Smooth color triangle
Jaime Vives Piqueres
Mesh camera scene files
Bill Pulver
Time code
Anton Raves
Alpha & Beta tester, Mac contributor
Dan Richardson
3.0 Docs
Tim Rowley
PPM and Windows-specific BMP image format support
Eduard Schwan
Former Mac version coordinator, mosaic preview, docs
Daniel Skarda
Implicit and parametric surfaces
Wlodzimierz Skiba
Windows BMP file support, non-Microsoft compiler build support for POVWIN versions prior to 3.7, bug fixes
Robert Skinner
Noise functions
Yvo & René Smellenbergh
Clock & Image_size keywords
Erkki Sondergaard
Alpha & Beta tester, 3.0 Scene files
Ryoichi Suzuki
Isosurfaces
Zsolt Szalavari
Halo code which was later turned into media
Scott Taylor
Leopard and onion textures
Gilles Tran
Scene files
Massimo Valentini
Optimizations to sphere_sweep and superellipsoid, bug fixes.
John VanSickle
Cells pattern
Mark Wagner
Splines
Timothy Wegner
Fractal objects, PNG support
Drew Wells
POV-Ray 1.0 developer, POV-Ray 1.0 team coordinator
Daren Scot Wilson
Dispersion
Chris Young
Team leader 1992-1999, parser code, other contributions too numerous to list here

Other Support:

Brendan Scott of Open Source Law and the folks at »The Software Freedom Law Center
Advice and drafting of documents regarding licensing.
Intel Corp. and »AMD Corp.
Optimization advice, performance testing.
»DigiCert Inc.
Code signing and SSL certificates.
»Netplex LLC (Connecticut's largest independent ISP)
Dedicated hosting of the POV-Ray server for more than ten years.

2.5.7 Thanks

We would like to take this opportunity to thank everyone who has helped make POV-Ray what it is over the past two decades. We can't possibly list you all here but be assured that we appreciate your support - without you this project would not be here!

2.5.8 What to do if you don't have POV-Ray

This documentation assumes you already have POV-Ray installed and running however the POV-Team does distribute this file by itself in various formats including online on the internet. If you do not have POV-Ray or are not sure you have the official version or the latest version, then the following sections will tell you what to get and where to get it.

Note: We strongly recommend that you obtain POV-Ray directly from »the POV-Ray website (or your company/school intranet, if applicable). Some websites have been known to re-package the POV-Ray software in an installer that bundles adware. If the installation package is not signed by Persistence of Vision Raytracer Pty. Ltd., then it is not from us and may have been tampered with. The official installer supplied by us contains no adware or third-party software of any kind.

2.5.8.1 Which Version of POV-Ray should you use?

POV-Ray can be used under Windows™ XP or newer, x86 Apple™ Macintosh™, and Linux™ & UNIX™ on numerous hardware platforms. See section Where to Find POV-Ray Files for more info.

Older versions of POV-Ray supported many platforms no longer in regular use; we preserve such old versions in our »archives if you wish to access them.

If your platform is not supported and you are proficient in compiling source code programs written in C/C++, then you may like to retrieve the source for POV-Ray from our website and attempt to built it yourself.

2.5.8.1.1 Microsoft Windows

As of POV-Ray version 3.7 the Windows versions of POV-Ray require Windows XP and later. We have had reports of v3.7 working on Windows 2000 with all service packs installed, however we cannot guarantee that this will remain the case indefinitely, as we do not test against W2K. If you have an older system you may like to look at POV-Ray version 3.6, which works on Windows 95 and up.

We supply both 32 and 64-bit versions of POVWIN which have been tested to run with AMD™ and Intel™ x86 and x64 processors. As of version 3.7, SMP systems are fully supported; by default POVWIN will use all available processing cores when rendering. For 32-bit systems, we supply both non-SSE2 and SSE2-enabled binaries. The installer will determine which is the most appropriate for your system at install time and install shortcuts to that executable (note however all executables are always placed in the bin folder regardless of the platform). For 64-bit systems there is only a single executable - a separate SSE version is not needed as all x64 CPU's have SSE2 available.

We recommend 100mb free disk space (the installation does not require that much, but room for temporary files during rendering is generally required) and at least 1gb free (i.e. available to POV-Ray at runtime) memory. POV's actual RAM requirement can vary greatly; it's possible to render files with as little as 30mb of free RAM, but typical needs are much greater than this. The actual use depends on what SDL files are provided for rendering and the image output options in use. We strongly recommend that you have sufficient RAM for rendering your scene files without resorting to swap - if a render hits the pagefile regularly it will completely destroy rendering performance.

Note: Accelerated graphics hardware (such as 3D cards) will not improve rendering performance. This technology is not currently aimed at raytracing but is, generally speaking, optimized for single-precision scanline rendering as used in games or other simulations. POV-Ray, like all raytracers, requires double-precision floating-point in order to be able to accurately render scenes.

  • Required POV-Ray files: the setup EXE supplied via our »download page. This file will be timestamped and digitally signed by Persistence of Vision Raytracer Pty Ltd. The key in use at the time of writing is issued by DigiCert and remains current until August 2014. All binaries (DLL's and EXE's) supplied by us for version 3.7 are also signed by this key. If you come across an unsigned binary (or one signed by anyone other than the above) that claims to be an official release, it is not from us and should not be used.
  • Optional: The source code is not needed to use POV-Ray. It is provided for the curious and adventurous. See the source-code links on our »download page.

Note: System admins/lab techs who wish to do custom installs of POV-Ray for Windows should refer to the windows platform-specific documentation for more details.

2.5.8.1.2 Apple Macintosh

Documentation Pending

2.5.8.1.3 Linux/Unix

Because Linux/Unix run on a wide variety of hardware, the POV-Team cannot provide executable versions for every variation. Instead, we distribute a generic, portable C++ source code package suitable for generating binaries on Unix or Unix-like platforms. It is known to compile and run correctly on recent versions of GNU/Linux for x86/x64, and should be fairly straightforward to get running on any POSIX-compliant Unix-like operating system with a Bourne-compatible shell.

You will need a recent C++ compiler which follows the ISO C++ standard as closely as possible (g++ 4.x is known to work), and (optionally) SVGAlib for GNU/Linux based systems if you wish to enable render preview display.

Required POV-Ray files: povray-3.7.tar.bz2 - the C++ source code of POV-Ray for UNIX. Contains generic parts and UNIX/Linux specific parts. The package includes sample scenes, standard include files and documentation in HTML and plain text ASCII format.

2.5.8.1.4 All Versions

All versions of the program share the same ray-tracing features like shapes, lighting and textures. In other words, a Windows PC can create the same pictures as a supercomputer as long as it has enough memory and you are willing to wait enough time.

2.5.8.2 Where to Find POV-Ray Files

The internet home of POV-Ray is reachable on the World Wide Web at »http://www.povray.org/. There is also an active user community in our »forums.

2.5.9 Suggested Reading

Beside the POV-Ray material mentioned in Books, Magazines and CD-ROMs, there are several good books or periodicals that you should be able to locate in your local computer book store or your local university library.

  1. "An Introduction to Ray tracing" Andrew S. Glassner (editor)
    ISBN 0-12-286160-4; Academic Press; 1989
  2. "Realistic Image Synthesis Using Photon Mapping" Henrik Wann Jensen
    ISBN: 1568811470; AK Peters; July 2001
  3. "3D Artist" Newsletter, "The Only Newsletter about Affordable PC 3D Tools and Techniques")
    Publisher: Bill Allen; P.O. Box 4787; Santa Fe, NM 87502-4787; (505) 982-3532
  4. "Image Synthesis: Theory and Practice" Nadia Magnenat-Thalman and Daniel Thalmann;
    Springer-Verlag; 1987
  5. "The RenderMan Companion" Steve Upstill;
    Addison Wesley; 1989
  6. "Graphics Gems" Andrew S. Glassner (editor);
    Academic Press; 1990
  7. "Fundamentals of Interactive Computer Graphics" J. D. Foley and A. Van Dam;
    ISBN 0-201-14468-9; Addison-Wesley 1983
  8. "Computer Graphics: Principles and Practice (2nd Ed.)" J. D. Foley, A. van Dam, J. F. Hughes;
    ISBN 0-201-12110-7; Addison-Wesley; 1990
  9. "Computers, Pattern, Chaos, and Beauty" Clifford Pickover;
    St.Martin's Press;
  10. "SIGGRAPH Conference Proceedings";
    Association for Computing Machinery Special Interest Group on Computer Graphics
  11. "IEEE Computer Graphics and Applications"; The Computer Society;
    10662, Los Vaqueros Circle; Los Alamitos, CA 90720

The POV-Team no longer recommends books from CRC Press.


Reference Table of Contents

Introduction
Command-Line and INI-File Options
Animation Options
External Animation Loop
Internal Animation Loop
Subsets of Animation Frames
Cyclic Animation
Field Rendering
General Output Options
Height and Width of Output
Max Image Buffer Memory
Partial Output Options
Interrupting Options
Resuming Options
Display Output Options
Display Hardware Settings
Setting your Display Gamma
Display Related Settings
Mosaic Preview
File Output Options
Output File Type
Output File Name
Output File Buffer
Output File Dithering
Output File Gamma
CPU Utilization Histogram
Scene Parsing Options
Constant
Input File Name
Include File Name
Library Paths
Language Version
Shell Command Options
String Substitution in Shell Commands
Shell Command Sequencing
Shell Command Return Actions
Text Output Options
Text Streams
Console Text Output
Directing Text Streams to Files
Warning Level
Help Screen Switches
Tracing Options
Symmetric MultiProcessing
Render Block Size
Render Pattern
Render Block Step
Quality Settings
Automatic Bounding Control
Removing User Bounding
BSP Bounding
Anti-Aliasing Options
Radiosity Options
Radiosity High Reproducibility
Radiosity Load and Save
Radiosity Vain Pretrace
Scene Description Language
Language Basics
Notation and Basic Assumptions
Keywords
Identifiers
Comments
Numeric Expressions
Literals
Identifiers
Operators
Functions
Built-in Constants
Built-in Variables
Vector Expressions
Literals
Identifiers
Operators
Operator Promotion
Functions
Built-in Constants
Color Expressions
Color Vectors
sRGB Colors
Color Keywords
Color Identifiers
Color Operators
Common Color Pitfalls
Function
Sum and Product functions
Functions and Macros
Declaring User-Defined Float Functions
Declaring User-Defined Vector Functions
Declaring User-Defined Color Functions
Internal Pre-Defined Functions
Strings
String Literals
String Identifiers
String Relational Operators
String Functions
Built-in Variables
Array
Declaring Arrays
Array Initializers
Spline
Splines and Macros
Transformations
Translate
Scale
Rotate
Matrix
Language Directives
Include Directive
Declare and Local Directives
Declaring identifiers
declare vs. local
Identifier Name Collisions
Destroying Identifiers with undef
Deprecation Support
File I/O Directives
The fopen Directive
The fclose Directive
The read Directive
The write Directive
Default Directive
Version Directive
Conditional Directives
The if...else...end Directives
The ifdef and ifndef Directives
The for Directive
The switch, case, range and break Directives
The while...end Directive
User Message Directives
Text Message Streams
Text Formatting
User Defined Macros
The macro Directive
Invoking Macros
Are POV-Ray Macros a Function or a Macro?
Returning a Value Like a Function
Returning Values Via Parameters
Scene File Elements
Global Settings
ADC_Bailout
Ambient_Light
Assumed_Gamma
HF_Gray_16
Irid_Wavelength
Charset
Max_Trace_Level
Max_Intersections
Mm_Per_Unit
Number_Of_Waves
Noise_generator
Subsurface
Camera
Placing the Camera
Location and Look_At
The Sky Vector
Angles
The Direction Vector
Up and Right Vectors
Aspect Ratio
Handedness
Transforming the Camera
Types of Projection
Perspective projection
Orthographic projection
Mesh projection
Rays Per Pixel
Distribution Type
Max Distance
Mesh Object
About the Location Vector
About the Direction Vector
The Smooth Modifier
Fisheye projection
Ultra wide angle projection
Omnimax projection
Panoramic projection
Cylindrical projection
Spherical projection
Focal Blur
Camera Ray Perturbation
Camera Identifiers
Atmospheric Effects
Atmospheric Media
Background
Fog
Sky Sphere
Rainbow
Lighting Types
Light Source
Point Lights
Spotlights
Cylindrical Lights
Parallel Lights
Area Lights
Shadowless Lights
Looks_like
Projected_Through
Light Fading
Atmospheric Media Interaction
Atmospheric Attenuation
Light Group
Radiosity
Radiosity Basics
How Radiosity Works
Adjusting Radiosity
adc_bailout
always_sample
brightness
count
error_bound
gray_threshold
low_error_factor
max_sample
maximum_reuse
minimum_reuse
nearest_count
pretrace_start and pretrace_end
recursion_limit
Configuring Radiosity
Importance
Media and Radiosity
No Radiosity
Normal and Radiosity
Save and Load Radiosity Data
Subsurface and Radiosity
Tips on Radiosity
Photons
Examples
Using Photon Mapping in Your Scene
Photon Global Settings
Shooting Photons at an Object
Photons and Light Sources
Photons and Media
Photons FAQ
Photon Tips
Advanced Techniques
Autostop
Adaptive Search Radius
Photons and Dispersion
Saving and Loading Photon Maps
Object
Finite Solid Primitives
Blob
Box
Cone
Cylinder
Height Field
Isosurface
Julia Fractal
Lathe
Ovus
Parametric
Prism
Sphere
Sphere Sweep
Superquadric Ellipsoid
Surface of Revolution
Text
Torus
Finite Patch Primitives
Bicubic Patch
Disc
Mesh
Solid Mesh
Mesh2
Smooth and Flat triangles in the same mesh
Mesh Triangle Textures
Polygon
Triangle
Smooth Triangle
Infinite Solid Primitives
Plane
Poly
Cubic
Quartic
Polynomial
Quadric
Constructive Solid Geometry
Inside and Outside
Union
Split_Union
Intersection
Difference
Merge
Object Modifiers
Clipped By Object Modifier
Bounded By Object Modifier
Material
Hollow Object Modifier
Inverse Object Modifier
No Shadow Object Modifier
No Image Object Modifier
No Reflection Object Modifier
Double Illuminate Object Modifier
No Radiosity Object Modifier
Sturm Object Modifier
Texture
Pigment
Solid Color Pigments
Color Map
Pigment Map
Color List Pigments
Quick Color
Normal
Normal Map
Slope Map
Normals, Accuracy
Bump Map
Specifying a Bump Map
Bump_Size
Use_Index and Use_Color
Scaling normals
Finish
Ambient
Emission
Diffuse Reflection Items
Diffuse
Brilliance
Crand Graininess
Subsurface Light Transport
Highlights
Phong Highlights
Specular Highlight
Metallic Highlight Modifier
Specular Reflection
Conserve Energy for Reflection
Iridescence
Halo
Patterned Textures
Texture Maps
Tiles
Material Maps
Specifying a Material Map
Layered Textures
UV Mapping
Supported Objects
UV Vectors
Triangle Texture Interpolation
Interior Texture
Cutaway Textures
Pattern
General Patterns
Agate Pattern
Boxed Pattern
Bozo Pattern
Brick Pattern
Bumps Pattern
Cubic Pattern
Cylindrical Pattern
Density File Pattern
df3 file format
Dents Pattern
Facets Pattern
Fractal Pattern
Function Pattern
What can be used
Function Image
Gradient Pattern
Granite Pattern
Leopard Pattern
Marble Pattern
Onion Pattern
Pavement Pattern
Pigment Pattern
Planar Pattern
Quilted Pattern
Radial Pattern
Ripples Pattern
Spherical Pattern
Spiral1 Pattern
Spiral2 Pattern
Spotted Pattern
Tiling Pattern
Waves Pattern
Wood Pattern
Wrinkles Pattern
Discontinuous Patterns
Cells Pattern
Checker Pattern
Crackle Pattern
Hexagon Pattern
Object Pattern
Square Pattern
Triangular Pattern
Normal-Dependent Patterns
Aoi Pattern
Slope Pattern
Special Patterns
Average Pattern
Image Pattern
Pattern Modifiers
Transforming Patterns
Frequency and Phase
Waveforms
Noise Generators
Warp
Black Hole Warp
Repeat Warp
Turbulence Warp
Octaves
Lambda
Omega
Mapping using warps
Turbulence versus Turbulence Warp
Turbulence
Image Map
Specifying an Image Map
The Gamma Option
The Filter and Transmit Bitmap Modifiers
Using the Alpha Channel
Bitmap Modifiers
The once Option
The map_type Option
The interpolate Option
Media
Interior
Why are Interior and Media Necessary?
Empty and Solid Objects
Scaling objects with an interior
Refraction
Dispersion
Dispersion & Caustics
Attenuation
Simulated Caustics
Object-Media
Media Types
Absorption
Emission
Scattering
Sampling Parameters & Methods
Density
General Density Modifiers
Density with color_map
Density Maps and Density Lists
Multiple Density vs. Multiple Media
Include Files
Main Files
Arrays.inc
Chars.inc
Colors.inc
Predefined colors
Color macros
Consts.inc
Vector constants
Map type constants
Interpolation type constants
Fog type constants
Focal blur hexgrid constants
IORs
Dispersion amounts
Scattering media type constants
Debug.inc
Finish.inc
Functions.inc
Common Parameters
Cross Section Type
Field Strength
Field Limit
SOR Switch
SOR Offset
SOR Angle
Invert Isosurface
Internal Functions
Pre defined functions
Pattern functions
Glass.inc
Glass colors (with transparency)
Glass colors (without transparency, for fade_color)
Glass finishes
Glass interiors
Glass interior macros
Golds.inc
Logo.inc
Makegrass.inc
Math.inc
Float functions and macros
Vector functions and macros
Vector Analysis
Meshmaker.inc
Metals.inc
Rad_def.inc
Rand.inc
Flat Distributions
Other Distributions
Continuous Symmetric Distributions
Continuous Skewed Distributions
Discrete Distributions
Screen.inc
Shapes.inc
The HF Macros
Shapes2.inc
Shapes3.inc
Shapesq.inc
Skies.inc
Stars.inc
Stones.inc
Stdinc.inc
Strings.inc
Sunpos.inc
Textures.inc
Stones
Skies
Woods
Glass
Metals
Special textures
Texture and pattern macros
Transforms.inc
Woods.inc
Woodmaps.inc
Old Files
Glass_old.inc
Glass finishes
Glass textures
Shapes_old.inc
Stage1.inc
Stdcam.inc
Stones1.inc
Stones2.inc
Other Files
Font Files
Color Map Files
Image Files


Reference Section 1

3.1 Introduction

This is the Reference section, and it applies to all platforms for which this version of POV-Ray has been ported. The platform-specific documentation is available in a separate section.

Excluding this introduction, the reference section is divided into three main parts.

  1. The Command-line Options section for controlling and configuring POV-Ray.
  2. The Scene Description Language section for the programming rules and syntax used in POV-Ray.
  3. The Scene File Elements section that details the camera and lighting types that are available,
    and the vast array of built-in objects, patterns and textures used to construct scene files.

New users may find it more convenient to begin with the Introduction to Pov-Ray or tutorial section, followed by the platform-specific documentation, in order to become more familiar your versions platform-specific features.

Additional notes about this documentation are as follows:

  1. Windows documentation is accessible using the POV-Ray program's Help menu or by pressing the F1 key.
  2. Mac OS documentation is also available via the Help menu and for viewing with a web browser.
  3. Unix/Linux documentation is available in html only and by default is typically found in /usr/local/share/povray-3.?/html
  4. See the section Notation and Basic Assumptions for more about the notation used throughout this documentation.


Reference Section 2

3.2 Command-Line and INI-File Options

This section describes the command line switches and INI file keywords that are used to set the options of POV-Ray. It is supposed to be used as a reference for looking up things. It does not contain detailed explanations on how scenes are written or how POV-Ray is used. It just explains all features, their syntax, applications, limits, drawbacks, etc.

Options may be specified by switches or INI-style options. Almost all INI-style options have equivalent +/ - switches and most switches have equivalent INI-style option. The following sections give a detailed description of each POV-Ray option. It includes both the INI-style settings and the +/ - switches.

The notation and terminology used is described in the tables below.

Keyword=bool | Turn Keyword on if bool equals true, yes, on or 1 and Turn it off if it is any other value.
Keyword=true | Do this option if true, yes, on or 1 is specified.
Keyword=false | Do this option if false, no, off or 0 is specified.
Keyword=filename | Set Keyword to filename where filename is any valid file name. Note: Some options prohibit the use of any of the above true or false values as a file name. They are noted in later sections.
n | Any integer such as in +W320
n.n | Any float such as in Clock=3.45
0.n | Any float < 1.0 even if it has no leading 0
s | Any string of text
x or y | Any single character
path | Any directory name, drive optional, no final path separator ("\" or "/", depending on the operating system)

Unless otherwise specifically noted, you may assume that either a plus or minus sign before a switch will produce the same results.

3.2.1 Animation Options

Internal animation loop, automatic output file name numbering and the ability to shell out to the operating system to external utilities which can assemble individual frames into an animation, greatly improved the animation capability. The internal animation loop is simple yet flexible. You may still use external programs or batch files to create animations without the internal loop.

3.2.1.1 External Animation Loop

Clock=n.n | Sets clock float identifier to n.n
+Kn.n | Same as Clock=n.n

The Clock=n.n option or the +K n.n switch may be used to pass a single float value to the program for basic animation. The value is stored in the float identifier clock. If an object had a rotate <0,clock,0> attached then you could rotate the object by different amounts over different frames by setting +K10.0,+K20.0... etc. on successive renderings. It is up to the user to repeatedly invoke POV-Ray with a different Clock value and a different Output_File_Name for each frame.

3.2.1.2 Internal Animation Loop

Initial_Frame=n | Sets initial frame number to n
Final_Frame=n | Sets final frame number to n
Initial_Clock=n.n | Sets initial clock value to n.n
Final_Clock=n.n | Sets final clock value to n.n
+KFIn | Same as Initial_Frame=n
+KFFn | Same as Final_Frame=n
+KIn.n | Same as Initial_Clock=n.n
+KFn.n | Same as Final_Clock=n.n

The internal animation loop relieves the user of the task of generating complicated sets of batch files to invoke POV-Ray multiple times with different settings. While the multitude of options may look intimidating, the clever set of default values means that you will probably only need to specify the Final_Frame=n or the +KFF n option to specify the number of frames. All other values may remain at their defaults.

Any Final_Frame setting other than -1 will trigger POV-Ray's internal animation loop. For example Final_Frame=10 or +KFF10 causes POV-Ray to render your scene 10 times. If you specified Output_File_Name=file.tga then each frame would be output as file01.tga, file02.tga, file03.tga etc. The number of zero-padded digits in the file name depends upon the final frame number. For example +KFF100 would generate file001.tga through file100.tga. The frame number may encroach upon the file name. On MS-DOS with an eight character limit, myscene.pov would render to mysce001.tga through mysce100.tga.

The default Initial_Frame=1 will probably never have to be changed. You would only change it if you were assembling a long animation sequence in pieces. One scene might run from frame 1 to 50 and the next from 51 to 100. The Initial_Frame=n or +KFI n option is for this purpose.

Note: If you wish to render a subset of frames such as 30 through 40 out of a 1 to 100 animation, you should not change Initial_Frame or Final_Frame. Instead you should use the subset commands described in section Subsets of Animation Frames.

Unlike some animation packages, the action in POV-Ray animated scenes does not depend upon the integer frame numbers. Rather you should design your scenes based upon the float identifier clock. By default, the clock value is 0.0 for the initial frame and 1.0 for the final frame. All other frames are interpolated between these values. For example if your object is supposed to rotate one full turn over the course of the animation, you could specify rotate 360*clock*y. Then as clock runs from 0.0 to 1.0, the object rotates about the y-axis from 0 to 360 degrees.

The major advantage of this system is that you can render a 10 frame animation or a 100 frame or 500 frame or 329 frame animation yet you still get one full 360 degree rotation. Test renders of a few frames work exactly like final renders of many frames.

In effect you define the motion over a continuous float valued parameter (the clock) and you take discrete samples at some fixed intervals (the frames). If you take a movie or video tape of a real scene it works the same way. An object's actual motion depends only on time. It does not depend on the frame rate of your camera.

Many users have already created scenes for POV-Ray 2 that expect clock values over a range other than the default 0.0 to 1.0. For this reason we provide the Initial_Clock=n.n or +KI n.n and Final_Clock=n.n or +KF n.n options. For example to run the clock from 25.0 to 75.0 you would specify Initial_Clock=25.0 and Final_Clock=75.0. Then the clock would be set to 25.0 for the initial frame and 75.0 for the final frame. In-between frames would have clock values interpolated from 25.0 through 75.0 proportionally.

Users who are accustomed to using frame numbers rather than clock values could specify Initial_Clock=1.0 and Final_Clock=10.0 and Frame_Final=10 for a 10 frame animation.

For new scenes, we recommend you do not change the Initial_Clock or Final_Clock from their default 0.0 to 1.0 values. If you want the clock to vary over a different range than the default 0.0 to 1.0, we recommend you handle this inside your scene file as follows...

#declare Start    = 25.0;
#declare End      = 75.0;
#declare My_Clock = Start+(End-Start)*clock;

Then use My_Clock in the scene description. This keeps the critical values 25.0 and 75.0 in your .pov file.

Note: Details concerning the inner workings of the animation loop are in the section on shell-out operating system commands in section Shell-out to Operating System.

3.2.1.3 Subsets of Animation Frames

Subset_Start_Frame=n | Set subset starting frame to n
Subset_Start_Frame=0.n | Set subset starting frame to n percent
Subset_End_Frame=n | Set subset ending frame to n
Subset_End_Frame=0.n | Set subset ending frame to n percent
Frame_Step=n | Set the increment to the frame number, default to 1
+SF0.n | Same as Subset_Start_Frame
+EF0.n | Same as Subset_End_Frame
+STPn | Same as Frame_Step

When creating a long animation, it may be handy to render only a portion of the animation to see what it looks like. Suppose you have 100 frames but only want to render frames 30 through 40. If you set Initial_Frame=30 and Final_Frame=40 then the clock would vary from 0.0 to 1.0 from frames 30 through 40 rather than 0.30 through 0.40 as it should. Therefore you should leave Initial_Frame=1 and Final_Frame=100 and use Subset_Start_Frame=30 and Subset_End_Frame=40 to selectively render part of the scene. POV-Ray will then properly compute the clock values.

Similarly, if you only want to render a tenth of the frames, you can use Frame_Step=10 to jump over the nine non-rendered frames between the rendered frames. This option was inspired from megapov, but with two restrictions: only positive step value are supported (forward, no backward rendering) and the value is not available in the SDL

Usually you will specify the subset using the actual integer frame numbers however an alternate form of the subset commands takes a float value in the range 0.0 <=n.nnn <=1.0 which is interpreted as a fraction of the whole animation. For example, Subset_Start_Frame=0.333 and Subset_End_Frame=0.667 would render the middle 1/3rd of a sequence regardless of the number of frames.

3.2.1.4 Cyclic Animation

Cyclic_Animation=bool | Turn cyclic animation on/off
+KC | Turn cyclic animation on
-KC | Turn cyclic animation off

Many computer animation sequences are designed to be run in a continuous loop. Suppose you have an object that rotates exactly 360 degrees over the course of your animation and you did rotate 360*clock*y to do so. Both the first and last frames would be identical. Upon playback there would be a brief one frame jerkiness. To eliminate this problem you need to adjust the clock so that the last frame does not match the first. For example a ten frame cyclic animation should not use clock 0.0 to 1.0. It should run from 0.0 to 0.9 in 0.1 increments. However if you change to 20 frames it should run from 0.0 to 0.95 in 0.05 increments. This complicates things because you would have to change the final clock value every time you changed Final_Frame. Setting Cyclic_Animation=on or using +KC will cause POV-Ray to automatically adjust the final clock value for cyclic animation regardless of how many total frames. The default value for this setting is off.

3.2.1.5 Field Rendering

Field_Render=bool | Turn field rendering on/off
Odd_Field=bool | Set odd field flag
+UF | Turn field rendering on
-UF | Turn field rendering off
+UO | Set odd field flag on
-UO | Set odd field flag off

Field rendering is sometimes used for animations when the animation is being output for television. TVs only display alternate scan lines on each vertical refresh. When each frame is being displayed the fields are interlaced to give the impression of a higher resolution image. The even scan lines make up the even field, and are drawn first (i.e. scan lines 0, 2, 4, etc.), followed by the odd field, made up of the odd numbered scan lines are drawn afterwards. If objects in an animation are moving quickly, their position can change noticeably from one field to the next. As a result, it may be desirable in these cases to have POV-Ray render alternate fields at the actual field rate (which is twice the frame rate), rather than rendering full frames at the normal frame rate. This would save a great deal of time compared to rendering the entire animation at twice the frame rate, and then only using half of each frame.

By default, field rendering is not used. Setting Field_Render=on or using +UF will cause alternate frames in an animation to be only the even or odd fields of an animation. By default, the first frame is the even field, followed by the odd field. You can have POV-Ray render the odd field first by specifying Odd_Field=on, or by using the +UO switch.

3.2.2 General Output Options

3.2.2.1 Height and Width of Output

Height=n | Sets screen height to n pixels
Width=n | Sets screen width to n pixels
+Hn | Same as Height=n
+Wn | Same as Width=n

These switches set the height and width of the image in pixels. This specifies the image size for file output. The preview display, if on, will generally attempt to pick a video mode to accommodate this size but the display settings do not in any way affect the resulting file output.

3.2.2.2 Max Image Buffer Memory

Max_Image_Buffer_Memory=n | Sets the allowable size of the output image cache
+MIn | Same as Max_Image_Buffer_Memory=n

This INI parameter sets the number of megabytes of RAM to allow for output image caching. If the output image happens to use more than this, a file backed temporary image is used instead. If using this option you must specify a value. This option is on by default and its value is 128.

3.2.2.3 Partial Output Options

Start_Column=n | Set first column to n pixels
Start_Column=0.n | Set first column to n percent of width
+SCn | Same as Start_Column=n
+SC0.n | Same as Start_Column=0.n
Start_Row=n | Set first row to n pixels
Start_Row=0.n | Set first row to n percent of height
+SRn | Same as Start_Row=n
+SR0.n | Same as Start_Row=0.n
End_Column=n | Set last column to n pixels
End_Column=0.n | Set last column to n percent of width
+ECn | Same as End_Column=n
+EC0.n | Same as End_Column=0.n
End_Row=n | Set last row to n pixels
End_Row=0.n | Set last row to n percent of height
+ERn | Same as End_Row=n
+ER0.n | Same as End_Row=0.n

When doing test rendering it is often convenient to define a small, rectangular sub-section of the whole screen so you can quickly check out one area of the image. The Start_Row, End_Row, Start_Column and End_Column options allow you to define the subset area to be rendered. The default values are the full size of the image from (1,1) which is the upper left to (w,h) on the lower right where w and h are the Width=n and Height=n values you have set.

Note: If the number specified is greater than 1 then it is interpreted as an absolute row or column number in pixels. If it is a decimal value between 0.0 and 1.0 then it is interpreted as a percent of the total width or height of the image.

For example: Start_Row=0.75 and Start_Column=0.75 starts on a row 75% down from the top at a column 75% from the left. Thus it renders only the lower-right 25% of the image regardless of the specified width and height.

The +SR, +ER, +SC and +EC switches work in the same way as the corresponding INI-style settings for both absolute settings or percentages.

Note: Early versions of POV-Ray allowed only start and end rows to be specified with +S n and +E n. In version 3.7 support for those variants has been dropped.

When rendering a subset of columns (+sc/+ec) and/or rows (+sr/+er), POV-Ray generates a full width image and fills the not rendered columns with black pixels. This should not be a problem for any image reading program no matter what file format is used. Earlier versions of POV-Ray had problems when a subset of rows (+sr/+er) was rendered. The full height information was written into the image file header but it only wrote image data for those lines that were actually rendered. This made output files that were incompatible with various image processing tools. In version 3.7 this is no longer the case.

3.2.2.4 Interrupting Options

Test_Abort=bool | Turn test for user abort on/off
+X | Turn test abort on
-X | Turn test abort off
Test_Abort_Count=n | Set to test for abort every n pixels
+Xn | Set to test for abort every n pixels on
-Xn | Set to test for abort off (in future test every n pixels)

On some operating systems once you start a rendering you must let it finish. The Test_Abort=on option or +X switch causes POV-Ray to test the keyboard for keypress. If you have pressed a key, it will generate a controlled user abort. Files will be flushed and closed but only data through the last full row of pixels is saved. POV-Ray exits with an error code 2 (normally POV-Ray returns 0 for a successful run or 1 for a fatal error).

When this option is on, the keyboard is polled on every line while parsing the scene file and on every pixel while rendering. Because polling the keyboard can slow down a rendering, the Test_Abort_Count=n option or +X n switch causes the test to be performed only every n pixels rendered or scene lines parsed.

3.2.2.5 Resuming Options

Continue_Trace=bool | Sets continued trace on/off
+C | Sets continued trace on
-C | Sets continued trace off
Create_Ini=file | Generate an INI file to file
Create_Ini=true | Generate file.ini where file is scene name.
Create_Ini=false | Turn off generation of previously set file.ini
+GIfile | Same as Create_Ini=file

If you abort a render while it is in progress or if you used the End_Row option to end the render prematurely, you can use Continue_Trace=on or +C option to continue the render later at the point where you left off. This option reads in the previously generated output file, displays the partial image rendered so far, then proceeds with the ray-tracing. This option cannot be used if file output is disabled with Output_to_file=off or -F.

The Continue_Trace option may not work if the Start_Row option has been set to anything but the top of the file, depending on the output format being used. Also POV-Ray cannot continue the file once it has been opened and saved again by any program.

POV-Ray tries to figure out where to resume an interrupted trace by reading any previously generated data in the specified output file. All file formats contain the image size, so this will override any image size settings specified. Some file formats (namely TGA and PNG) also store information about where the file started (i. e. +SC n and +SR n options), alpha output +UA, and bit-depth +FN n, which will override these settings. It is up to the user to make sure that all other options are set the same as the original render.

The Create_Ini option or +GI switch provides an easy way to create an INI file with all of the rendering options, so you can re-run files with the same options, or ensure you have all the same options when resuming. This option creates an INI file with every option set at the value used for that rendering. This includes default values which you have not specified. For example if you run POV-Ray with...

POVRAY +Isimple.pov MYOPTS +GIrerun.ini MOREOPTS

POV-Ray will create a file called rerun.ini with all of the options used to generate this scene. The file is not written until all options have been processed. This means that in the above example, the file will include options from both myopts.ini and moreopts.ini despite the fact that the +GI switch is specified between them. You may now re-run the scene with...

POVRAY RERUN

or resume an interrupted trace with

POVRAY RERUN +C

If you add other switches with the rerun.ini reference, they will be included in future re-runs because the file is re-written every time you use it.

The Create_Ini option is also useful for documenting how a scene was rendered. If you render waycool.pov with Create_Ini=on then it will create a file waycool.ini that you could distribute along with your scene file so other users can exactly re-create your image.

3.2.3 Display Output Options

3.2.3.1 Display Hardware Settings

Display=bool | Turns graphic display on/off
+D | Turns graphic display on
-D | Turns graphic display off
Video_Mode=x | Set video mode to x; does not affect on/off
+Dx | Set display on; Set mode to x
-Dx | Set display off; but for future use mode x
Palette=y | Set display palette to y; does not affect on/off
+Dxy | Set display on; Set mode x; Set palette y
-Dxy | Set display off; use mode x, palette y in future
Display_Gamma=n.n | Sets the display gamma to n.n
Display_Gamma=sRGB | Sets the display gamma to match the sRGB standard (approximately corresponding to a gamma of 2.2)

The Display=on or +D switch will turn on the graphics display of the image while it is being rendered. Even on some non-graphics systems, POV-Ray may display an 80 by 24 character ASCII-Art version of your image. Where available, the display may be full, 24-bit true color. Setting Display=off or using the -D switch will turn off the graphics display which is the default.

On the Windows platform, the default is Display=on. Turning display off does not, of course, turn off the actual video display. Instead, POV-Ray will not open the output window that it normally shows a render in.

The Video_Mode=x option sets the display mode or hardware type chosen where x is a single digit or letter that is machine dependent. Generally Video_Mode=0 means the default or an auto-detected setting should be used. When using switches, this character immediately follows the switch. For example the +D0 switch will turn on the graphics display in the default mode.

The Palette=y option selects the palette to be used. Typically the single character parameter y is a digit which selects one of several fixed palettes or a letter such G for gray scale, H for 15-bit or 16-bit high color or T for 24-bit true color. When using switches, this character is the 2nd character after the switch. For example the +D0T switch will turn on the graphics display in the default mode with a true color palette.

The Display_Gamma setting overcomes the problem of images (whether ray-traced or not) having different brightness when being displayed on different monitors, different video cards, and under different operating systems. The Display_Gamma=n.n setting is not available as a command-line switch.

Note: The Display_Gamma is a setting based on your computer's display hardware, and should be set correctly once and not changed.

While the Display_Gamma can be different for each system, there are a few general rules that can be used for setting Display_Gamma if you do not know it exactly. If the Display_Gamma keyword does not appear in the INI file, POV-Ray assumes that the display gamma is approximately 2.2 (to precise, that it matches the sRGB standard). This is because most PC monitors have a gamma value in the range 1.6 to 2.6 (newer models seem to have a lower gamma value). Mac has the ability to do gamma correction inside the system software (based on a user setting in the gamma control panel). If the gamma control panel is turned off, or is not available, the default Macintosh system gamma is 1.8. Many newer PC graphics cards can do hardware gamma correction and should use the current Display_Gamma setting, usually sRGB (being approximately equivalent to a gamma of 2.2).

3.2.3.2 Setting your Display Gamma

The following gamma test image can be used to help you set your Display_Gamma accurately.

Before viewing the gamma image darken the room and set the monitor brightness and contrast to maximum. While viewing a black screen, lower the brightness gradually until the background is no longer noticeable (ie when it just fades from view). This may be difficult on monitors that use overscanning, unless you change the viewable area settings.

Display gamma test image.

Now, lower the contrast until the alternating white and black bars on the left edge of each column are equal in width. This is trying to get a 50% gray by using half white and half black. If this is not possible, choose a contrast setting which is about in the middle. While viewing the image from a distance, or with squinted eyes, one of the numbered swatches will best match the gray value approximated by the white and black bars. The number in this swatch is your display's actual gamma value.

Normal display gamma values are in the range 2.0 to 2.6. If your monitor is usually used in a dim environment, we often use a gamma value that is 15% - 25% lower than the actual display gamma to give the images more contrast. Some systems, such as Macs and SGIs, already do gamma correction, so they may have display gammas of 1.0 or 1.8.

See the Gamma Handling tutorial for additional information about setting up your display and why gamma handling is so important.

3.2.3.3 Display Related Settings

Pause_When_Done=bool | Sets pause when done on/off
+P | Sets pause when done on
-P | Sets pause when done off
Verbose=bool | Set verbose messages on/off
+V | Set verbose messages on
-V | Set verbose messages off
Draw_Vistas=bool | Turn draw vistas on/off
+UD | Turn draw vistas on
-UD | Turn draw vistas off

On some systems, when the image is complete, the graphics display is cleared and POV-Ray switches back into text mode to print the final statistics and to exit. Normally when the graphics display is on, you want to look at the image awhile before continuing. Using Pause_When_Done=on or +P causes POV-Ray to pause in graphics mode until you press a key to continue. The default is not to pause (-P).

When the graphics display is not used, it is often desirable to monitor progress of the rendering. Using Verbose=on or +V turns on verbose reporting of your rendering progress. This reports the number of the line currently being rendered, the elapsed time for the current frame and other information. On some systems, this textual information can conflict with the graphics display. You may need to turn this off when the display is on. The default setting is off (-V).

Note: Starting with version 3.7 the Draw_Vistas option has been deprecated. See the section Automatic Bounding Control for more details.

3.2.3.4 Mosaic Preview

Preview_Start_Size=n | Set mosaic preview start size to n
+SPn | Same as Preview_Start_Size=n
Preview_End_Size=n | Set mosaic preview end size to n
+EPn | Same as Preview_End_Size=n

Typically, while you are developing a scene, you will do many low resolution test renders to see if objects are placed properly. Often this low resolution version does not give you sufficient detail and you have to render the scene again at a higher resolution. A feature called mosaic preview solves this problem by automatically rendering your image in several passes.

The early passes paint a rough overview of the entire image using large blocks of pixels that look like mosaic tiles. The image is then refined using higher resolutions on subsequent passes. This display method very quickly displays the entire image at a low resolution, letting you look for any major problems with the scene. As it refines the image, you can concentrate on more details, like shadows and textures. You do not have to wait for a full resolution render to find problems, since you can interrupt the rendering early and fix the scene, or if things look good, you can let it continue and render the scene at high quality and resolution.

To use this feature you should first select a Width and Height value that is the highest resolution you will need. Mosaic preview is enabled by specifying how big the mosaic blocks will be on the first pass using Preview_Start_Size=n or +SP n. The value n should be a number greater than zero that is a power of two (1, 2, 4, 8, 16, 32, etc.) If it is not a power of two, the nearest power of two less than n is substituted. This sets the size of the squares, measured in pixels. A value of 16 will draw every 16th pixel as a 16*16 pixel square on the first pass. Subsequent passes will use half the previous value (such as 8*8, 4*4 and so on.)

The process continues until it reaches 1*1 pixels or until it reaches the size you set with Preview_End_Size=n or +EP n. Again the value n should be a number greater than zero that is a power of two and less than or equal to Preview_Start_Size. If it is not a power of two, the nearest power of two less than n is substituted. The default ending value is 1. If you set Preview_End_Size to a value greater than 1 the mosaic passes will end before reaching 1*1, but POV-Ray will always finish with a 1*1. For example, if you want a single 8*8 mosaic pass before rendering the final image, set Preview_Start_Size=8 and Preview_End_Size=8.

No file output is performed until the final 1*1 pass is reached. Although the preliminary passes render only as many pixels as needed, the 1*1 pass re-renders every pixel so that anti-aliasing and file output streams work properly. This makes the scene take up to 25% longer than the regular 1*1 pass to render, so it is suggested that mosaic preview not be used for final rendering. Also, the lack of file output until the final pass means that renderings which are interrupted before the 1*1 pass can not be resumed without starting over from the beginning.

Note: For performance reasons using a Preview_End_Size value thats less than 8 is not recommended. If you don't specify an end preview size the default +ep2 will be used.

3.2.4 File Output Options

Output_to_File=bool | Sets file output on/off
+F | Sets file output on (use default type)
-F | Sets file output off

By default, POV-Ray writes an image file to disk. When you are developing a scene and doing test renders, the graphic preview may be sufficient. To save time and disk activity you may turn file output off with Output_to_File=off or -F.

3.2.4.1 Output File Type

Output_File_Type=x | Sets file output format to x
+Fxn | Sets file output on; sets format x, depth n
-Fxn | Sets file output off; but in future use format x, depth n
Output_Alpha=bool | Sets alpha output on/off
+UA | Sets alpha output on
-UA | Sets alpha output off
Bits_Per_Color=n | Sets file output bits/color to n

Note: As of version 3.7 the default output file type for all supported platforms is PNG. You may select one of several different file types by using Output_File_Type=x or +F x where x is one of the following:

.. B | Universal Bitmap image file format
.. C | Compressed Targa-24 format (RLE, run length encoded)
.. E | OpenEXR High Dynamic-Range format
.. H | Radiance High Dynamic-Range format
.. J | JPEG format (Note: This format is not loss-free and will generate compression artifacts)
.. N | PNG (portable network graphics) format
.. P | Unix PPM format
.. S | System-specific format: See the notation at the end of this section.
.. T | Uncompressed Targa-24 format

PNG is an image format designed not only to replace GIF, but to improve on its shortcomings. PNG offers the highest compression available without loss for high quality applications, such as ray-tracing. The system specific format depends on the platform used and is covered in the appropriate system specific documentation.

JPEG is particularly good at achieving high compression rates with photographic or photorealistic images, making it one of the most frequently used formats on the Internet. However, it is not loss-free. Images generated with this option will always contain compression artifacts (image defects). If you need to keep a high-quality image you should render using one of the loss-free formats.

Note: Chroma sub-sampling has been disabled in JPEG output, and there has been a reduction in the default quality setting.

The JPEG compression quality can be controlled using the 'Compression' ini file option which, if set, needs to be an integer between 0 and 100. If values of 0 or 1 are specified then the default compression quality setting of 85% is used. Otherwise the value specified (2-100) is used as the compression quality setting. A value of 2 produces the smallest file (maximum compression), but looks terrible. A value of 100 produces the largest file (least compression) but can still contain some compression artifacts. Values lower than 0 are clipped to 0. Values greater than 100 are clipped to 100.

Most of these formats output 24 bits per pixel with 8 bits for each of red, green and blue data. PNG and PPM allow you to optionally specify the output bit depth from 5 to 16 bits for each of the red, green, and blue colors, giving from 15 to 48 bits of color information per pixel. The default output depth for all formats is 8 bits/color (16 million possible colors), but this may be changed for PNG and PPM format files by setting Bits_Per_Color=n or by specifying +FN n or +FP n, where n is the desired bit depth.

Specifying a smaller color depth like 5 bits/color (32768 colors) may be enough for people with 8- or 16-bit (256 or 65536 color) displays, and will improve compression of the PNG file. Higher bit depths like 10 or 12 may be useful for video or publishing applications, and 16 bits/color is good for grayscale height field output (See section Height Field for details on height fields).

Targa format also allows 8 bits of alpha transparency data to be output, while PNG format allows 5 to 16 bits of alpha transparency data, depending on the color bit depth as specified above. You may turn this option on with Output_Alpha=on or +UA. The default is off or -UA.

The alpha channel stores a transparency value for each pixel, just like there is also stored a value for red green and blue light for each pixel. In POV-Ray, when the alpha channel is turned on, all areas of the image where the background is partly or fully visible will be partly or fully transparent. Refractions of the background will also be transparent, but not reflections. Also anti-aliasing is taken into account

The philosophy of the alpha channel feature in POV-Ray is that the background color should not be present in the color of the image when the alpha channel is used. Instead, the amount of visible background is kept in the alpha and *only* in the alpha channel. That ensures that images look correct when viewed with the alpha channel.

See section Using the Alpha Channel for further details on using transparency in imagemaps in your scene.

Note: In version 3.7 alpha handling for image file output has changed. Effectively, the background now requires a filter or transmit value in order for alpha transparency to work properly.

Previous versions of POV-Ray always wrote associated alpha for output, this has been changed on a per-file-format basis as follows:

  • PNG will use straight alpha as per specification.
  • OpenEXR and TIFF will use associated alpha as per specifications.
  • TGA and BMP 32-bit RGBA will use straight alpha, retaining file input compatibility for now, until a final decision has been made on these formats.

In addition to support for variable bit-depths, alpha channel, and grayscale formats, PNG files also store the File_Gamma value so the image displays properly on all systems. The hf_gray_16 global setting, as described in section HF_Gray_16 will also affect the type of data written to the output file.

The Radiance Synthetic Imaging System or .hdr image format was originally developed to aid lighting designers and architects by predicting the light levels and appearance of a space prior to construction. »OpenEXR or .exr image file format developed by Industrial Light & Magic™ for use in computer imaging applications.

Most image formats now include metadata (BMP is a notable exception). This metadata contains the POV-Ray version, render date/time (GMT), platform (e.g. x86_64-pc-win), and compiler used to build the POV-Ray executable.

Note: System-specific or type "s" output file format is being retained for legacy support reasons. Windows and Unix mapping remains the same, BMP and TGA respectively, however on Macintosh it has been changed to PNG, and a warning is issued when type "s" is used.

3.2.4.2 Output File Name

Output_File_Name=file | Sets output file to file
+Ofile | Same as Output_File_Name=file

The default output filename is created from the scene name and need not be specified. The scene name is the input name with all drive, path, and extension information stripped. For example if the input file name is c:\povray3\mystuff\myfile.pov the scene name is myfile. The proper extension is appended to the scene name based on the file type. For example myfile.tga or myfile.png might be used.

You may override the default output name using Output_File_Name=file or +O file. For example:

Input_File_Name=myinput.pov
Output_File_Name=myoutput.tga

If an output file name of "-" is specified (a single minus sign), then the image will be written to standard output, usually the screen. The output can then be piped into another program or to a GUI if desired.

If the file specified is actually a path or directory or folder name and not a file name, then the default output name is used but it is written to the specified directory. For example:

Input_File_Name=myscene.pov
Output_File_Name=c:\povray3\myimages\

This will create c:\povray3\myimages\myscene.tga as the output file.

3.2.4.3 Output File Buffer

The output-file buffer options Buffer_Output and Buffer_Size are removed per POV-Ray 3.6

Note: The options are still accepted, but ignored, in order to be backward compatible with old INI files.

3.2.4.4 Output File Dithering

Dither=bool | Turns output file dithering on/off
Dither_Method=xx | Selects the output file dithering method, where xx is listed below:
+/-THxx | Command line equivalent
  • B2..B4: Bayer pattern dithering using 2x2, 3x3 or 4x4 patterns, respectively
  • D1: Simple 1-dimensional error diffusion dithering
  • D2: Simple 2-dimensional error diffusion dithering (needs extra memory for 2 pixel rows)
  • FS: Floyd-Steinberg error diffusion dithering (needs extra memory for 2 pixel rows)

The default is -THfs i.e: dithering is off, with Floyd-Steinberg being the default if only +TH is specified.

Dithering works for all file formats except JPEG (where dithering would be counter-productive) and OpenEXR (which provides sufficient precision to make dithering obsolete). These file formats simply ignore the setting.

Note: While dithering does help to reduce color banding, it may instead lead to artifacts in prints, due to interference with the printing device's own dithering algorithms; in that case, choosing a different dither method may help.

3.2.4.5 Output File Gamma

File_Gamma=x.x | Sets output file gamma to n.n
File_Gamma=sRGB | Selects the sRGB transfer function instead of a power-law output file gamma
Many file formats traditionally have no clearly specified gamma handling policy, and require images to be gamma pre-corrected for whatever target system they are to be displayed on. For such file formats (currently all except PNG, OpenEXR and Radiance HDR), the File_Gamma setting specifies the target display gamma for which to pre-correct (typically a value in the range from 1.6 to around 2.5, with 2.2 being the most commonly used), and will have an influence on the brightness and saturation of the image when displayed. Some other file formats do have a clearly specified gamma handling policy, but allow for gamma encoding with an arbitrary gamma value (currently only PNG). For such formats, File_Gamma specifies the decoding gamma or, in other words, the inverse of the encoding gamma to use, and will have no effect on the brightness and saturation of the image when displayed with contemporary software; the setting will however affect the likelihood of banding artifacts. The parameter has no effect on file formats mandating linear storage of color values (currently OpenEXR and Radiance HDR). Alternatively to a numeric value, sRGB can be specified, instructing POV-Ray to employ the sRGB transfer function, which is similar but not quite identical to a power-law gamma curve with a gamma of 2.2. sRGB is also the default on all platforms currently supported. See section Gamma Handling for more information on gamma.

3.2.4.6 CPU Utilization Histogram

The CPU Utilization Histogram feature has been removed as of POV-Ray v3.7.

3.2.5 Scene Parsing Options

POV-Ray reads in your scene file and processes it to create an internal model of your scene. The process is called parsing. As your file is parsed other files may be read along the way. This section covers options concerning what to parse, where to find it and what version specific assumptions it should make while parsing it.

3.2.5.1 Constant

Declare=IDENTIFIER=FLOAT Declares an identifier with a float value

You can now declare a constant in an INI file, and that constant will be available to the scene. Since INI file statements may also be laced on the command-line, you can therefore also declare on the command-line (though there is no switch for it).

  Declare=MyValue=24

This would be the same as a #declare MyValue=24; in a scene file. The value on the right-hand side must be a constant float value.

A possible use could be switching off radiosity or photons from command-line:

--in INI-file / on command-line

Declare=RAD=0

--in scenefile

global_settings {
  #if (RAD)
    radiosity {
    ...
    }
#end
}

3.2.5.2 Input File Name

Input_File_Name=file | Sets input file name to file
+Ifile | Same as Input_File_Name=file

Note: There may be no space between +I and file.

You will probably always set this option but if you do not the default input filename is object.pov. If you do not have an extension then .pov is assumed. On case-sensitive operating systems both .pov and .POV are tried. A full path specification may be used (on MS-DOS systems +Ic:\povray3\mystuff\myfile.pov is allowed for example). In addition to specifying the input file name this also establishes the scene name.

The scene name is the input name with drive, path and extension stripped. In the above example the scene name is myfile. This name is used to create a default output file name and it is referenced other places.

Note: As of version 3.5 you can now specify a POV file on the command-line without the use of the +i switch (i.e. it works the same way as specifying an INI file without a switch), the POV file then should be the last on the command-line.

If you use "-" as the input file name the input will be read from standard input. Thus you can pipe a scene created by a program to POV-Ray and render it without having a scene file.

Under MS-DOS you can try this feature by typing.

type ANYSCENE.POV | povray +I-

3.2.5.3 Include File Name

Include_Header=file | Sets primary include file name to file
+HIfile | Same as Include_Header=file

This option allows you to include a file as the first include file of a scene file. You can for example use this option to always include a specific set of default include files used by all your scenes.

3.2.5.4 Library Paths

Library_Path=path | Add path to list of library paths
+Lpath | Same as Library_Path=path

POV-Ray looks for files in the current directory. If it does not find a file it needs it looks in various other library directories which you specify. POV-Ray does not search your operating system path. It only searches the current directory and directories which you specify with this option. For example the standard include files are usually kept in one special directory. You tell POV-Ray to look there with...

Library_Path=c:\povray3\include

You must not specify any final path separators ("\" or "/") at the end.

Multiple uses of this option switch do not override previous settings. If you specify the exact same path twice it is only counted once. The current directory will be searched first followed by the indicated library directories in the order in which you specified them.

3.2.5.5 Language Version

Version=n.n | Set initial language compatibility to version n.n
+MVn.n | Same as Version=n.n

As POV-Ray has evolved from version 1.0 through to today we have made every effort to maintain some amount of backwards compatibility with earlier versions. Some old or obsolete features can be handled directly without any special consideration by the user. Some old or obsolete features can no longer be handled at all. However some old features can still be used if you warn POV-Ray that this is an older scene. In the POV-Ray scene language you can use the #version directive to switch version compatibility to different settings. See section The #version Directive for more details about the language version directive. Additionally you may use the Version=n.n option or the +MV n.n switch to establish the initial setting. For example one feature introduced in 2.0 that was incompatible with any 1.0 scene files is the parsing of float expressions. Setting Version=1.0 or using +MV1.0 turns off expression parsing as well as many warning messages so that nearly all 1.0 files will still work. Naturally the default setting for this option is the current version number.

The version directive and command-line setting no longer provide compatibility with most rendering bugs in versions prior to POV-Ray 3.5. However, compatibility with the scene language is provided for scenes as old as POV-Ray 1.0 just as in all previous versions of POV-Ray. Nevertheless, we strongly recommend you update scenes at least to POV-Ray 3.5 syntax if you plan to use them in future versions of POV-Ray.

3.2.6 Shell Command Options

Pre_Scene_Command=s | Set command before entire scene
Pre_Frame_Command=s | Set command before each frame
Post_Scene_Command=s | Set command after entire scene
Post_Frame_Command=s | Set command after each frame
User_Abort_Command=s | Set command when user aborts POV-Ray
Fatal_Error_Command=s | Set command when POV-Ray has fatal error

Note: No + or - switches are available for these options. They cannot be used from the command line. They may only be used from INI files.

POV-Ray offers you the opportunity to shell-out to the operating system at several key points to execute another program or batch file. Usually this is used to manage files created by the internal animation loop however the shell commands are available for any scene. The string s is a single line of text which is passed to the operating system to execute a program. For example

Post_Scene_Command=tga2gif -d -m myfile

would use the utility tga2gif with the -D and -M parameters to convert myfile.tga to myfile.gif after the scene had finished rendering.

Note: Individual platforms may provide means of preventing shell-outs from occurring. For example, the Windows version provides a menu command to turn shell-outs off (which is the default setting for that platform). The reason for this (along with file I/O restrictions) is to attempt to prevent untrusted INI files from doing harm to your system.

3.2.6.1 String Substitution in Shell Commands

It could get cumbersome to change the Post_Scene_Command every time you changed scene names. POV-Ray can substitute various values into a command string for you. For example:

Post_Scene_Command=tga2gif -d -m %s

POV-Ray will substitute the %s with the scene name in the command. The scene name is the Input_File_Name or +I setting with any drive, directory and extension removed. For example:

Input_File_Name=c:\povray3\scenes\waycool.pov

is stripped down to the scene name waycool which results in...

Post_Scene_Command=tga2gif -d -m waycool

In an animation it may be necessary to have the exact output file name with the frame number included. The string %o will substitute the output file name. Suppose you want to save your output files in a zip archive using the utility program pkzip. You could do...

Post_Frame_Command=pkzip -m %s %o

After rendering frame 12 of myscene.pov POV-Ray would shell to the operating system with

pkzip -m myscene mysce012.tga

The -M switch in pkzip moves mysce012.tga to myscene.zip and removes it from the directory. Note that %o includes frame numbers only when in an animation loop. During the Pre_Scene_Command and Post_Scene_Command there is no frame number so the original, unnumbered Output_File_Name is used. Any User_Abort_Command or Fatal_Error_Command not inside the loop will similarly give an unnumbered %o substitution.

Here is the complete list of substitutions available for a command string.

%o | Output file name with extension and embedded frame number if any
%s | Scene name derived by stripping path and ext from input name
%n | Frame number of this frame
%k | Clock value of this frame
%h | Height of image in pixels
%w | Width of image in pixels
%% | A single % sign.

3.2.6.2 Shell Command Sequencing

Here is the sequence of events in an animation loop. Non-animated scenes work the exact same way except there is no loop.

  1. Process all INI file keywords and command line switches just once.
  2. Open any text output streams and do Create_INI if any.
  3. Execute Pre_Scene_Command if any.
  4. Loop through frames (or just do once on non-animation).
    1. Execute Pre_Frame_Command if any.
    2. Parse entire scene file, open output file and read settings, turn on display, render the frame, destroy all objects, textures etc., close output file, close display.
    3. Execute Post_Frame_Command if any.
    4. Repeat above steps until all frames are done.
  5. Execute Post_Scene_Command if any.
  6. Finish

If the user interrupts processing the User_Abort_Command, if any, is executed. User aborts can only occur during the parsing and rendering parts of step (4b) above. If a fatal error occurs that POV-Ray notices the Fatal_Error_Command, if any, is executed. Sometimes an unforeseen bug or memory error could cause a total crash of the program in which case there is no chance to shell out. Fatal errors can occur just about anywhere including during the processing of switches or INI files. If a fatal error occurs before POV-Ray has read the Fatal_Error_Command string then obviously no shell can occur.

Note: The entire scene is re-parsed for every frame. Future versions of POV-Ray may allow you to hold over parts of a scene from one frame to the next but for now it starts from scratch every time.

Note: The Pre_Frame_Command occurs before the scene is parsed. You might use this to call some custom scene generation utility before each frame. This utility could rewrite your .pov or .inc files if needed. Perhaps you will want to generate new .gif or .tga files for image maps or height fields on each frame.

3.2.6.3 Shell Command Return Actions

Pre_Scene_Return=s | Set pre scene return actions
Pre_Frame_Return=s | Set pre frame return actions
Post_Scene_Return=s | Set post scene return actions
Post_Frame_Return=s | Set post frame return actions
User_Abort_Return=s | Set user abort return actions
Fatal_Error_Return=s | Set fatal return actions

Note: No + or - switches are available for these options. They cannot be used from the command line. They may only be used from INI files.

Most operating systems allow application programs to return an error code if something goes wrong. When POV-Ray executes a shell command it can make use of this error code returned from the shell process and take some appropriate action if the code is zero or non-zero. POV-Ray itself returns such codes. It returns 0 for success, 1 for fatal error and 2 for user abort.

The actions are designated by a single letter in the different ..._Return=s options. The possible actions are:

I | ignore the code
S | skip one step
A | all steps skipped
Q | quit POV-Ray immediately
U | generate a user abort in POV-Ray
F | generate a fatal error in POV-Ray

For example if your Pre_Frame_Command calls a program which generates your height field data and that utility fails then it will return a non-zero code. We would probably want POV-Ray to abort as well. The option Pre_Frame_Return=F will cause POV-Ray to do a fatal abort if the Pre_Frame_Command returns a non-zero code.

Sometimes a non-zero code from the external process is a good thing. Suppose you want to test if a frame has already been rendered. You could use the S action to skip this frame if the file is already rendered. Most utilities report an error if the file is not found. For example the command...

pkzip -V myscene mysce012.tga

tells pkzip you want to view the catalog of myscene.zip for the file mysce012.tga. If the file is not in the archive pkzip returns a non-zero code.

However we want to skip if the file is found. Therefore we need to reverse the action so it skips on zero and does not skip on non-zero. To reverse the zero vs. non-zero triggering of an action precede it with a "-" sign (note a "!" will also work since it is used in many programming languages as a negate operator).

Pre_Frame_Return=S will skip if the code shows error (non-zero) and will proceed normally on no error (zero). Pre_Frame_Return=-S will skip if there is no error (zero) and will proceed normally if there is an error (non-zero).

The default for all shells is I which means that the return action is ignored no matter what. POV-Ray simply proceeds with whatever it was doing before the shell command. The other actions depend upon the context. You may want to refer back to the animation loop sequence chart in the previous section Shell Command Sequencing. The action for each shell is as follows.

On return from any User_Abort_Command:

If there is an action triggered...

Specified Action: | Results:
F | Turn this user abort into a fatal error. Do the Fatal_Error_Command, if any. Exit POV-Ray with error code 1.
S, A, Q, or U | Proceed with the user abort. Exit POV-Ray with error code 2.

On return from any Fatal_Error_Command:

POV-Ray will proceed with the fatal error no matter what. It will exit POV-Ray with error code 1.

On return from any Pre_Scene_Command, Pre_Frame_Command, Post_Frame_Command or Post_Scene_Commands:

If there is an action triggered...

Specified Action: | Results:
F | Turn this user abort into a fatal error. Do the Fatal_Error_Command, if any. Exit POV-Ray with error code 1.
U | Generate a user abort. Do the User_Abort_Command, if any. Exit POV-Ray with an error code 2.
Q | Quit POV-Ray immediately. Acts as though POV-Ray never really ran. Do no further shells, not even a Post_Scene_Command. Exit POV-Ray with an error code 0.

On return from a Pre_Scene_Command:

If there is an action triggered...

Specified Action: | Results:
S | Skip rendering all frames. Acts as though the scene completed all frames normally. Do not do any Pre_Frame_Command or Post_Frame_Commands. Do the Post_Scene_Command, if any. Exit POV-Ray with error code 0. Note: See the chart, this means skip #4
A | Skip all scene activity. Works exactly like Q quit. Acts as though POV-Ray never really ran. Do no further shells, not even a Post_Scene_Command Exit POV-Ray with an error code 0. Note: See the chart, this means skip #6

On return from a Pre_Frame_Command:

If there is an action triggered...

Specified Action: | Results:
S | Skip only this frame. Acts as though this frame never existed. Do not do the Post_Frame_Command. Proceed with the next frame. Note: See the chart, this means skip #4b, #4c but loop back as needed in #4d
A | Skip rendering this frame and all remaining frames. Acts as though the scene completed all frames normally. Do not do any further Post_Frame_Commands. Do the Post_Scene_Command, if any. Exit POV-Ray with error code 0. Note: See the chart, this means skip the rest of #4 and proceed at #5

On return from a Post_Frame_Command:

If there is an action triggered...

Specified Action: | Results:
S or A | Skip all remaining frames. Acts as though the scene completed all frames normally. Do not do any further Post_Frame_Commands. Do the Post_Scene_Command, if any. Exit POV-Ray with error code 0. Note: See the chart, this means skip the rest of #4 and proceed at #5

On return from any Post_Scene_Command:

If there is an action triggered and you have specified S or A then no special action occurs. This is the same as I for this shell command.

3.2.7 Text Output Options

Text output is an important way that POV-Ray keeps you informed about what it is going to do, what it is doing and what it did. The program splits its text messages into 7 separate streams. Some versions of POV-Ray color-codes the various types of text. Some versions allow you to scroll back several pages of messages. All versions allow you to turn some of these text streams off/on or to direct a copy of the text output to one or several files. This section details the options which give you control over text output.

3.2.7.1 Text Streams

There are seven distinct text streams that POV-Ray uses for output. On some versions each stream is designated by a particular color. Text from these streams are displayed whenever it is appropriate so there is often an intermixing of the text. The distinction is only important if you choose to turn some of the streams off or to direct some of the streams to text files. On some systems you may be able to review the streams separately in their own scroll-back buffer.

Here is a description of each stream.

Banner: This stream displays the program's sign-on banner, copyright, contributor's list, and some help screens. It cannot be turned off or directed to a file because most of this text is displayed before any options or switches are read. Therefore you cannot use an option or switch to control it. There are switches which display the help screens. They are covered in section Help Screen Switches.

Debug: This stream displays debugging messages. It was primarily designed for developers but this and other streams may also be used by the user to display messages from within their scene files. See section Text Message Streams for details on this feature. This stream may be turned off and/or directed to a text file.

Fatal: This stream displays fatal error messages. After displaying this text, POV-Ray will terminate. When the error is a scene parsing error, you may be shown several lines of scene text that leads up to the error. This stream may be turned off and/or directed to a text file.

Render: This stream displays information about what options you have specified to render the scene. It includes feedback on all of the major options such as scene name, resolution, animation settings, anti-aliasing and others. This stream may be turned off and/or directed to a text file.

Statistics: This stream displays statistics after a frame is rendered. It includes information about the number of rays traced, the length of time of the processing and other information. This stream may be turned off and/or directed to a text file.

Status: This stream displays one-line status messages that explain what POV-Ray is doing at the moment. On some systems this stream is displayed on a status line at the bottom of the screen. This stream cannot be directed to a file because there is generally no need to. The text displayed by the Verbose option or +V switch is output to this stream so that part of the status stream may be turned off.

Warning: This stream displays warning messages during the parsing of scene files and other warnings. Despite the warning, POV-Ray can continue to render the scene. You will be informed if POV-Ray has made any assumptions about your scene so that it can proceed. In general any time you see a warning, you should also assume that this means that future versions of POV-Ray will not allow the warned action. Therefore you should attempt to eliminate warning messages so your scene will be able to run in future versions of POV-Ray. This stream may be turned off and/or directed to a text file.

3.2.7.2 Console Text Output

Debug_Console=bool | Turn console display of debug info text on/off
+GD | Same as Debug_Console=On
-GD | Same as Debug_Console=Off
Fatal_Console=bool | Turn console display of fatal error text on/off
+GF | Same as Fatal_Console=On
-GF | Same as Fatal_Console=Off
Render_Console=bool | Turn console display of render info text on/off
+GR | Same as Render_Console=On
-GR | Same as Render_Console=Off
Statistic_Console=bool | Turn console display of statistic text on/off
+GS | Same as Statistic_Console=On
-GS | Same as Statistic_Console=Off
Warning_Console=bool | Turn console display of warning text on/off
+GW | Same as Warning_Console=On
-GW | Same as Warning_Console=Off
All_Console=bool | Turn on/off all debug, fatal, render, statistic and warning text to console.
+GA | Same as All_Console=On
-GA | Same as All_Console=Off

You may suppress the output to the console of the debug, fatal, render, statistic or warning text streams. For example the Statistic_Console=off option or the -GS switch can turn off the statistic stream. Using on or +GS you may turn it on again. You may also turn all five of these streams on or off at once using the All_Console option or +GA switch.

Note: These options only take effect after the INI file has been read. An error in the INI file causes other options not to take effect because reading of the INI file is aborted prematurely.

3.2.7.3 Directing Text Streams to Files

Debug_File=true | Echo debug info text to DEBUG.OUT
Debug_File=false | Turn off file output of debug info
Debug_File=file | Echo debug info text to file
+GDfile | Both Debug_Console=On, Debug_File=file
-GDfile | Both Debug_Console=Off, Debug_File=file
Fatal_File=true | Echo fatal text to FATAL.OUT
Fatal_File=false | Turn off file output of fatal
Fatal_File=file | Echo fatal info text to file
+GFfile | Both Fatal_Console=On, Fatal_File=file
-GFfile | Both Fatal_Console=Off, Fatal_File=file
Render_File=true | Echo render info text to RENDER.OUT
Render_File=false | Turn off file output of render info
Render_File=file | Echo render info text to file
+GRfile | Both Render_Console=On, Render_File=file
-GRfile | Both Render_Console=Off, Render_File=file
Statistic_File=true | Echo statistic text to STATS.OUT
Statistic_File=false | Turn off file output of statistics
Statistic_File=file | Echo statistic text to file
+GSfile | Both Statistic_Console=On, Statistic_File=file
-GSfile | Both Statistic_Console=Off, Statistic_File=file
Warning_File=true | Echo warning info text to WARNING.OUT
Warning_File=false | Turn off file output of warning info
Warning_File=file | Echo warning info text to file
+GWfile | Both Warning_Console=On, Warning_File=file
-GWfile | Both Warning_Console=Off, Warning_File=file
All_File=true | Echo all debug, fatal, render, statistic, and warning text to ALLTEXT.OUT
All_File=false | Turn off file output of all debug, fatal, render, statistic, and warning text.
All_File=file | Echo all debug, fatal, render, statistic, and warning text to file
+GAfile | Both All_Console=On, All_File=file
-GAfile | Both All_Console=Off, All_File=file
Append_File=true | Enable appending to any files that the above streams are being directed to.
Append_File=false | Turn off appending to streams.
+GP | Same as Append_File=true
-GP | Same as Append_File=false

You may direct a copy of the text streams to a text file for the debug, fatal, render, statistic, or warning text streams. For example the Statistic_File=s option or the +GS s switch. If the string s is true or any of the other valid true strings then that stream is redirected to a file with a default name. Valid true values are true, yes, on or 1. If the value is false the direction to a text file is turned off. Valid false values are false, no, off or 0. Any other string specified turns on file output and the string is interpreted as the output file name.

Similarly you may specify such a true, false or file name string after a switch such as +GS file. You may also direct all five streams to the same file using the All_File option or +GA switch. You may not specify the same file for two or more streams because POV-Ray will fail when it tries to open or close the same file twice.

The Append_File option controls whether files to which streams are being directed are overwritten or appended to. If Append_File is true, then the files are appended to, otherwise the default action is to overwrite the files, thus erasing their previous content. The only exception to this is for the second and later frames of an animation. Animations act as if Append_File=true was specified if the frame is not the first one; for the first frame, the actual value of Append_File is used.

In either case, if a stream output file other than #debug is being appended to, a header will be written to make it clear where within the file the new render is starting. To achieve the same with #debug, you should add the appropriate header manually to your scene file.

Note: These options only take effect after the INI file has been read. An error in the INI file causes other options not to take effect because reading of the INI file is aborted prematurely. Additionally, specifying Append_File=false is only useful if it was previously turned on in another INI file, as the Append_File setting is not applied until the streams are opened on render startup (i.e. after all INI files and command-line options have been parsed). Using the command-line to turn Append_File on, then redirecting a stream to a file, and finally turning append off will not do anything useful

3.2.7.4 Warning Level

Warning_Level=n | Allows you to turn off classes of warnings.
+WLn | Same as Warning_Level=n

Level 0 turns off all warnings. Level 5 turns off all language version related warnings. The default is level 10 and it enables all warnings. All other levels are reserved and should not be specified.

3.2.7.5 Help Screen Switches

-? Show help screen 0 if this is the only switch

Note: There are no INI style equivalents to these options.

After displaying the help screens, POV-Ray terminates. Because some operating systems do not permit a question mark as a command line switch you may also use the +H switch.

Note: This switch is also used to specify the height of the image in pixels. Therefore the +H switch is only interpreted as a help switch if it is the only switch on the command line.

Graphical interface versions of POV-Ray such as Mac or Windows have extensive online help.

3.2.8 Tracing Options

There is more than one way to trace a ray. Sometimes there is a trade-off between quality and speed. Sometimes options designed to make tracing faster can slow things down. This section covers options that tell POV-Ray how to trace rays with the appropriate speed and quality settings.

3.2.8.1 Symmetric MultiProcessing

Central to the many feature enhancements offered with version 3.7, POV-Ray now supports Symmetric MultiProcessing or SMP. The command line option Work_Threads=n or the +WT n switch allows you to specify the number of work threads to be used while rendering a scene. On Windows systems, the default is the number of detected cores. On Linux/Unix and OSX based systems, the default is first based on the number of detected cores, otherwise, the number of configured cores. If detection is not possible the default is set to 4. In all cases the maximum value is 512.

3.2.8.2 Render Block Size

POV-Ray provides a mechanism to specify the render block size via either an INI-style option Render_Block_Size=n or on the command-line +BS n, where n is an integer larger than or equal to 4. This represents the edge size of the square used to distribute work to the render threads, and thus the number of pixels in each block will be n squared. The default value is 32. If you specify a value that is greater than the larger of the width or height of the image being rendered, it is clipped to that value. Using render block sizes of less than eight can impact performance, particularly on large images that render quickly, as it significantly increases the amount of message traffic between the render back-end and the graphical front-end, which communicate using a shared-memory queue.

3.2.8.2.1 Render Pattern

POV-Ray provides a mechanism to specify the order of render block via either an INI-style option Render_Pattern=n or on the command-line +RP n, where n is an integer between 0 and 5. This represents the various orders for the distribution of the blocks to the render threads. The default value is 0.

If you specify a value that is greater than the maximum number of patterns, it will revert to the default. Using a different Render_Pattern has only an effect on the preview of the rendered image, as the first blocks might be placed differently, but does not change the final image once the render has been completed.

 | Pattern 0: is the classical order. The first block is in the top left corner, and it progress from left to right, and then it continues on the next row of blocks. Just like reading text.
Pattern 0 |
Pattern 1: is the same as pattern 0, but the rows and columns are swapped. It starts at the top left corner and it progress from top to bottom. |
 | Pattern 1
 | Pattern 2: The top row is processed first, starting at each corner and meeting at the center of the row, then the bottom row is processed the same way. The last block is at the very center of the image.
Pattern 2 |
Pattern 3: Is the opposite order of pattern 2, the first block is at the center of the image, the expansion being firstly horizontal. |
 | Pattern 3
 | Pattern 4: Is the same as pattern 2, except that the rows and columns have been swapped.
Pattern 4 |
Pattern 5: Is the same as pattern 3, but the rows and columns are swapped, however the expansion from the center of the image is firstly vertical. |
 | Pattern 5
3.2.8.2.2 Render Block Step

Whatever the chosen pattern (with +RP), the number of the next processed block can be incremented by more than 1, to jump over blocks, via either an INI-style option Render_Block_Step=n or on the command-line +RS n, where n is a positive non zero integer. The provided value of n gets reduced automatically to a smaller value if the provided value would lead to a situation where the some blocks would not get rendered.

Assuming an image made of 40 blocks, with +RS9, the order of block numbers would be:

0, 9, 18, 27, 36, 5, 14, 23, 32, 1, 10, 19, 28, 37, 6, 15, 24, 33, 2, 11, 20, 29, 38, 7, 16, 25, 34, 3, 12, 21, 30, 39, 8, 17, 26, 35, 4, 13, 22, 31.

The same 40 blocks with +RS8 would in fact use +RS7 instead. As would a +RS2 in fact be reduced to +RS1 the default.

3.2.8.3 Quality Settings

Quality=n | Set quality value to n (0 <= n <= 11)
+Qn | Same as Quality=n

The Quality=n option or +Q n switch allows you to specify the image rendering quality. You may choose to lower the quality for test rendering and raise it for final renders. The quality adjustments are made by eliminating some of the calculations that are normally performed. For example settings below 4 do not render shadows. Settings below 8 do not use reflection or refraction. The duplicate values allow for future expansion. The values correspond to the following quality levels:

0, 1 | Just show quick colors. Use full ambient lighting only. Quick colors are used only at 5 or below.
2, 3 | Show specified diffuse and ambient light.
4 | Render shadows, but no extended lights.
5 | Render shadows, including extended lights.
6, 7 | Compute texture patterns, compute photons
8 | Compute reflected, refracted, and transmitted rays.
9, 10, 11 | Compute media, radiosity and subsurface light transport.

The default is 9 if not specified.

3.2.8.4 Automatic Bounding Control

Bounding=bool | Turn bounding on/off
+MB | Turn bounding on; Set threshold to 25 or previous amount
-MB | Turn bounding off
Bounding_Threshold=n | Set bound threshold to n
+MBn | Turn bounding on; bound threshold to n
-MBn | Turn bounding off; set future threshold to n
Light_Buffer=bool | Turn light buffer on/off
+UL | Turn light buffer on
-UL | Turn light buffer off
Vista_Buffer=bool | Turn vista buffer on/off
+UV | Turn vista buffer on
-UV | Turn vista buffer off

POV-Ray uses a variety of spatial sub-division systems to speed up ray-object intersection tests. The primary system uses a hierarchy of nested bounding boxes. This system compartmentalizes all finite objects in a scene into invisible rectangular boxes that are arranged in a tree-like hierarchy. Before testing the objects within the bounding boxes the tree is descended and only those objects are tested whose bounds are hit by a ray. This can greatly improve rendering speed. However for scenes with only a few objects the overhead of using a bounding system is not worth the effort. The Bounding=off option or -MB switch allows you to force bounding off. The default value is on.

The Bounding_Threshold=n or +MB n switch allows you to set the minimum number of objects necessary before bounding is used. The default is +MB25 which means that if your scene has fewer than 25 objects POV-Ray will automatically turn bounding off because the overhead is not worth it. Generally it is a good idea to use a much lower threshold like +MB5.

In general, any finite object and many types of CSG of finite objects will properly respond to this bounding system. In addition blobs and meshes use an additional internal bounding system. These systems are not affected by the above switch. They can be switched off using the appropriate syntax in the scene file (see Blob and Mesh for details).

Text objects are split into individual letters that are bounded using the bounding box hierarchy. Some CSG combinations of finite and infinite objects are also automatically bound. The end result is that you will rarely need to add manual bounding objects as was necessary in earlier versions of POV-Ray unless you use many infinite objects.

Note: As of version 3.7 the Vista_Buffer and Light_Buffer options have been deprecated.

3.2.8.5 Removing User Bounding

Remove_Bounds=bool | Turn unnecessary bounds removal on/off
+UR | Turn unnecessary bounds removal on
-UR | Turn unnecessary bounds removal off
Split_Unions=bool | Turn split bounded unions on/off
+SU | Turn split bounded unions on
-SU | Turn split bounded unions off

Early versions of POV-Ray had no system of automatic bounding or spatial sub-division to speed up ray-object intersection tests. Users had to manually create bounding boxes to speed up the rendering. Since version 3.0, POV-Ray has had more sophisticated automatic bounding than any previous version. In many cases the manual bounding on older scenes is slower than the new automatic systems. Therefore POV-Ray removes manual bounding when it knows it will help. In rare instances you may want to keep manual bounding. Some older scenes incorrectly used bounding when they should have used clipping. If POV-Ray removes the bounds in these scenes the image will not look right. To turn off the automatic removal of manual bounds you should specify Remove_Bounds=off or use -UR. The default is Remove_Bounds=on.

One area where the jury is still out is the splitting of manually bounded unions. Unbounded unions are always split into their component parts so that automatic bounding works better. Most users do not bound unions because they know that doing so is usually slower. If you do manually bound a union we presume you really want it bound. For safety sake we do not presume to remove such bounds. If you want to remove manual bounds from unions you should specify Split_Unions=on or use +SU. The default is Split_Unions=off.

3.2.8.6 BSP Bounding

BSP (Binary Space Partitioning) tree bounding is now available. To turn it on use +BM2 or Bounding_Method=2 in the INI file or on the command-line. When it is in use you will get some additional statistics in the output pane regarding the built tree.

Please keep in mind that this implementation of BSP is highly beta and will not speed up scenes in many cases (and in fact may slow some down). In particular the building of the tree can take a long time and lots of memory in severe cases. Using the BSP tree rather than our traditional BVH (Bounding Volume Hierarchy) system (default or +BM1) is a choice best made for specific scenes that will benefit from the way the BSP operates, and in particular if the render is long enough to offset the build time. The BSP tree build time will be constant for a given scene and set of BSP parameters, regardless of the output resolution. A 30-second BSP build may not be a good choice on a 60-second test render but may be acceptable for a 60-minute final render if the use of BSP adds a few pixels per second.

On some scenes the difference however will be dramatic, with short build times and radically increased render speed.

We have provided some BSP-related options via the INI file and encourage you to experiment with them to see if you can get better results than the default values built in to POV-Ray. We will listen to feedback from this and if necessary tweak the defaults.

Note: We do not guarantee that all of the following INI file settings will remain in the final release of 3.7

  BSP_MaxDepth=128
  BSP_BaseAccessCost=1.0
  BSP_ChildAccessCost=1.5
  BSP_IsectCost=150.0
  BSP_MissChance=0.2

The values shown above are the default. You can also get the defaults if you use a value of 0 for any of the above, or of course just by not specifying the option at all. For an explanation of what the values mean you may refer to Ray Tracing News »article by Eric Haines.

See the distribution file ~scenes/bsp/Tango.pov for a good example of a scene that benefits from the BSP bounding.

Tango.pov rendered at 800x600, no AA

  • With +BM1 : 70 seconds total
  • With +BM2 : 48 seconds total

3.2.8.7 Anti-Aliasing Options

Antialias=bool | Turns anti-aliasing on/off
+A | Turns aa on with threshold 0.3 or previous amount
-A | Turns anti-aliasing off
Sampling_Method=n | Sets aa-sampling method (only 1 or 2 are valid)
+AMn | Same as Sampling_Method=n
Antialias_Threshold=n.n | Sets anti-aliasing threshold
+An.n | Sets aa on with aa-threshold at n.n
-An.n | Sets aa off (aa-threshold n.n in future)
Jitter=bool | Sets aa-jitter on/off
+J | Sets aa-jitter on with 1.0 or previous amount
-J | Sets aa-jitter off
Jitter_Amount=n.n | Sets aa-jitter amount to n.n. If n.n <= 0 aa-jitter is set off
+Jn.n | Sets aa-jitter on; jitter amount to n.n. If n.n <= 0 aa-jitter is set off
-Jn.n | Sets aa-jitter off (jitter amount n.n in future)
Antialias_Depth=n | Sets aa-depth (1 <= n <= 9)
+Rn | Same as Antialias_Depth=n
Antialias_Gamma=n.n | Sets the anti-aliasing gamma to n.n
+AGn.n | Same as Antialias_Gamma=n.n

The ray-tracing process is in effect a discrete, digital sampling of the image with typically one sample per pixel. Such sampling can introduce a variety of errors. This includes a jagged, stair-step appearance in sloping or curved lines, a broken look for thin lines, moiré patterns of interference and lost detail or missing objects, which are so small they reside between adjacent pixels. The effect that is responsible for those errors is called aliasing.

Anti-aliasing is any technique used to help eliminate such errors or to reduce the negative impact they have on the image. In general, anti-aliasing makes the ray-traced image look smoother. The Antialias=on option or +A switch turns on POV-Ray's anti-aliasing system.

When anti-aliasing is turned on, POV-Ray attempts to reduce the errors by shooting more than one viewing ray into each pixel and averaging the results to determine the pixel's apparent color. This technique is called super-sampling and can improve the appearance of the final image but it drastically increases the time required to render a scene since many more calculations have to be done.

POV-Ray gives you the option to use one of two alternate super-sampling methods. The Sampling_Method=n option or +AM n switch selects either type 1 or type 2. Selecting one of those methods does not turn anti-aliasing on. This has to be done by using the +A command line switch or Antialias=on option.

Type 1 is an adaptive, non-recursive, super-sampling method. It is adaptive because not every pixel is super-sampled. Type 2 is an adaptive and recursive super-sampling method. It is recursive because the pixel is sub-divided and sub-sub-divided recursively. The adaptive nature of type 2 is the variable depth of recursion.

In the default, non-recursive method (+AM1), POV-Ray initially traces one ray per pixel. If the color of a pixel differs from its neighbors (to the left or above) by at least the set threshold value then the pixel is super-sampled by shooting a given, fixed number of additional rays. The default threshold is 0.3 but it may be changed using the Antialias_Threshold=n.n option. When the switches are used, the threshold may optionally follow the +A. For example +A0.1 turns anti-aliasing on and sets the threshold to 0.1.

The threshold comparison is computed as follows. If r1, g1, b1 and r2, g2, b2 are the rgb components of two pixels then the difference between pixels is computed by

diff = abs(r1-r2) + abs(g1-g2) + abs(b1-b2)

If this difference is greater than the threshold then both pixels are super-sampled. The rgb values are in the range from 0.0 to 1.0 thus the most two pixels can differ is 3.0. If the anti-aliasing threshold is 0.0 then every pixel is super-sampled. If the threshold is 3.0 then no anti-aliasing is done. Lower threshold means more anti-aliasing and less speed. Use anti-aliasing for your final version of a picture, not the rough draft. The lower the contrast, the lower the threshold should be. Higher contrast pictures can get away with higher tolerance values. Good values seem to be around 0.2 to 0.4.

When using the non-recursive method, the default number of super-samples is nine per pixel, located on a 3*3 grid. The Antialias_Depth=n option or +R n switch controls the number of rows and columns of samples taken for a super-sampled pixel. For example +R4 would give 4*4=16 samples per pixel.

The second, adaptive, recursive super-sampling method starts by tracing four rays at the corners of each pixel. If the resulting colors differ more than the threshold amount additional samples will be taken. This is done recursively, i.e. the pixel is divided into four sub-pixels that are separately traced and tested for further subdivision. The advantage of this method is the reduced number of rays that have to be traced. Samples that are common among adjacent pixels and sub-pixels are stored and reused to avoid re-tracing of rays. The recursive character of this method makes the super-sampling concentrate on those parts of the pixel that are more likely to need super-sampling (see figure below).

Example of how the recursive super-sampling works.

The maximum number of subdivisions is specified by the Antialias_Depth=n option or +R n switch. This is different from the adaptive, non-recursive method where the total number of super-samples is specified. A maximum number of n subdivisions results in a maximum number of samples per pixel that is given by the following table. Where the first column represents anti-alias depth or +R n option. The second column is the number of additional samples per super-sampled pixel for the non-recursive method +AM1. Lastly the third column is the maximum number of samples per super-sampled pixel for the recursive method +AM2.

1 | 1 | 9
2 | 4 | 25
3 | 9 | 81
4 | 16 | 289
5 | 25 | 1089
6 | 36 | 4225
7 | 49 | 16641
8 | 64 | 66049
9 | 81 | 263169

Note: The maximum number of samples in the recursive case is hardly ever reached for a given pixel. If the recursive method is used with no anti-aliasing each pixel will be the average of the rays traced at its corners. In most cases a recursion level of three is sufficient.

Another way to reduce aliasing artifacts is to introduce noise into the sampling process. This is called jittering and works because the human visual system is much more forgiving to noise than it is to regular patterns. The location of the super-samples is jittered or wiggled a tiny amount when anti-aliasing is used. Jittering is used by default but it may be turned off with the Jitter=off option or -J switch. The amount of jittering can be set with the Jitter_Amount=n.n option. When using switches the jitter scale may be specified after the +J n.n switch. For example +J0.5 uses half the normal jitter. The default amount of 1.0 is the maximum jitter which will insure that all super-samples remain inside the original pixel.

Note: The jittering noise is random and non-repeatable so you should avoid using jitter in animation sequences as the anti-aliased pixels will vary and flicker annoyingly from frame to frame.

If anti-aliasing is not used one sample per pixel is taken regardless of the super-sampling method specified.

As the human eye is more sensitive to absolute brightness differences at a low overall brigtness than at higher ones, super-sampling based on linear light intensity differences would yield either poor anti-aliasing in darker regions, or unnecessary super-sampling in brighter regions of the image. To avoid this, POV-Ray compares ''gamma-adjusted'' values instead. (Note that this only affects the comparison operation; the averaging of the super-samples is done in whatever working color space is specified in the scene file via the assumed_gamma keyword.) The Antialias_Gamma=n.n command line option or +AG n.n sets the gamma to apply before comparison, defaulting to 2.5. Note that the value is actually the inverse of the gamma applied, in order to use the same value range as the display and file gamma settings. Neutral behavior can be achieved using Antialias_Gamma=1.0

Note: The mesh_camera feature added in version 3.7 also makes extreme super-sampling possible. See the distribution file ~scenes/camera/mesh_camera/ess/README.txt for additional information.

3.2.8.8 Radiosity Options

3.2.8.8.1 Radiosity High Reproducibility

As of version 3.7 a new radiosity mode has been introduced. When specifying High_Reproducibility or +HR on the command line, POV-Ray will spend extra effort to make sure renders are deterministic despite SMP. Currently radiosity is the only code to use this flag; in +HR mode, radiosity pretrace starts out with fewer threads, and some extra rules are imposed on sample re-use that may cause surplus samples to be gathered.

Note: The high reproducibility mode is not intended for use with radiosity alone, and it will need more work to guarantee the same improved reproducibility in other features. Even though it works well with radiosity, this addition is still experimental.

3.2.8.8.2 Radiosity Load and Save

The following .ini / command line parameters are recognized:

Radiosity_File_Name="<name>"	or +RF"<name>"	to set the cache file name
Radiosity_From_File=<on/off>	or +RFI	to enable reading the radiosity file at startup
Radiosity_To_File=<on/off>	or +RFO	to enable writing new samples to the radiosity file

Note: The parameter names are preliminary, and may still be subject to change; there is a potential conflict between the shorthand forms.

If both +RFI and +RFO are specified, new samples gathered are appended; otherwise, +RFO causes the file to be overwritten if it exists.

New samples gathered are written whenever an SMP block is completed. Tests indicate that this is almost neutral regarding performance, compared to operation with radiosity file output disabled.

3.2.8.8.3 Radiosity Vain Pretrace

Also new as of version 3.7 an option has been added speed up radiosity pretrace:

As some computations don't contribute to the generation of radiosity samples, they can safely be skipped during radiosity pretrace to gain some speed if the pretrace's other role as a coarse preview is not required.

The following .ini file/command line options control whether pretrace performs all computations so it can double-feature as a coarse preview (vain pretrace):

Radiosity_Vain_Pretrace=bool	turns vain pretrace on/off
+RVP				turns vain pretrace on (default)
-RVP				turns vain pretrace off

Note: With vain pretrace off, preview will look remarkably odd during the radiosity pretrace phase; this is normal, and no reason to be alarmed.

At the moment, turning vain pretrace off will affect only classic lighting computations (diffuse lighting, highlights and iridescence); other features expendable during pretrace may follow in future versions.


Reference Section 3

3.3 Scene Description Language

This section describes the POV-Ray scene description language. It is supposed to be used as a reference for looking up things. It does not contain detailed explanations on how scenes are written or how POV-Ray is used. It just explains all features, their syntax, applications, limits, drawbacks, etc.

The scene description language allows you to describe the world in a readable and convenient way. Files are created in plain ASCII text using an editor of your choice. The input file name is specified using the Input_File_Name=file option or +I file switch. By default the files have the extension .pov. POV-Ray reads the file, processes it by creating an internal model of the scene and then renders the scene.

The overall syntax of a scene is shown below. See Notation and Basic Assumptions for more information on syntax notation.

SCENE:
  SCENE_ITEM...
SCENE_ITEM:
  LANGUAGE_DIRECTIVE |
  CAMERA             |
  LIGHT              |
  OBJECT             |
  ATMOSPHERIC_EFFECT |
  GLOBAL_SETTINGS

In plain English, this means that a scene contains one or more scene items and that a scene item may be any of the five items listed below it. The items may appear in any order. None is a required item. In addition to the syntax depicted above, a LANGUAGE_DIRECTIVE may also appear anywhere embedded in other statements between any two tokens. There are some restrictions on nesting directives also.

For details on those five items see section Language Directives, section Objects, section Camera, section Atomospheric Effects and section Global Settings for details.

3.3.1 Language Basics

The POV-Ray language consists of identifiers, reserved keywords, floating point expressions, strings, special symbols and comments. The text of a POV-Ray scene file is free format. You may put statements on separate lines or on the same line as you desire. You may add blank lines, spaces or indentations as long as you do not split any keywords or identifiers.

See the following for more details:

  1. Keywords
  2. Identifiers
  3. Comments
  4. Numeric Expressions
  5. Vector Expressions
  6. Color Expressions
  7. User-Defined Functions
  8. Strings
  9. Arrays
  10. Splines

3.3.1.1 Notation and Basic Assumptions

Throughout the tutorial and reference books, a consistent notation is used to mark keywords of the scene description language, command line switches, INI file keywords and file names.

For example:

Scene description language keywords and command-line switches:

  • sphere, 4.0 * sin(45.0)
  • +W640 +H480

Syntax, optional syntax, multiple syntax, and zero or more syntax items allowed respectively:

  • SYNTAX_ITEM
  • [SYNTAX_ITEM]
  • SYNTAX_ITEM...
  • [SYNTAX_ITEM...]

A float value or expression, and a vector value or expression:

  • Value_1
  • <Value_1>

Alternatives are represented by a vertical bar between syntax items; exactly one of the listed items must be present:

  • ITEM1 | ITEM2 | ITEM3

Arbitrary order is represented by an ampersand between syntax items:

  • ITEM1 & ITEM2 & ITEM3

Fixed order is represented by simple juxtaposition of syntax items:

  • ITEM1 ITEM2 ITEM3

The above notations can also appear in various combinations; parentheses are used to resolve ambiguities. For instance, the following notation would indicate that the optional items ITEM1 and ITEM2, as well as either ITEM3A or ITEM3B, may appear in any order:

  • [ITEM1] & [ITEM2] & (ITEM3A | ITEM3B)

Note: The ampersand notation to denote arbitrary order is just being phased in; some syntax descriptions may still use juxtaposition, regardless of whether the order of items is irrelevant or not; please be aware that those are (or at least should be) exceptions.

Certain lists and arrays also require square braces as part of the language rather than the language description:

  • [ ITEM ]

Note: POV-Ray is a command-line program on Unix and other text-based operating systems and is menu-driven on Windows and Macintosh platforms. Some of these operating systems use folders to store files while others use directories. Some separate the folders and sub-folders with a slash character (/), back-slash character (\), or others.

We have tried to make this documentation as generic as possible but sometimes we have to refer to folders, files, options etc. and there is noway to escape it. Here are some assumptions we make...

  1. You installed POV-Ray in the C:\POVRAY36 directory. For MS-Dos this is probably true but for Unix it might be /usr/povray3, or for Windows it might be C:\Program Files\POV-Ray for Windows v3.6, for Mac it might be MyHD:Apps:POV-Ray 36:, or you may have used some other drive or directory. So if we tell you that Include files are stored in the \povray36\include directory, we assume you can translate that to something like::POVRAY36:INCLUDE or C:\Program Files\POV-Ray for Windows v3.6\include or whatever is appropriate for your platform, operating system and installation.
  2. POV-Ray uses INI files and/or command-line switches (if available) to choose options in all versions, but Windows and Mac also use dialog boxes or menu choices to set options. We will describe options assuming you are using switches or INI files when describing what the options do. We have taken care to use the same terminology in designing menus and dialogs as we use in describing switches or INI keywords. See your version-specific documentation on menu and dialogs.
  3. Some of you are reading this using a help-reader, built-in help,web-browser, formatted printout, or plain text file. We assume you know how to get around in which ever medium you are using. We will say See the chapter on Setting POV-Ray Options we assume you can click, scroll, browse, flip pages or whatever to get there.

3.3.1.2 Keywords

POV-Ray has a number of reserved keywords which are listed below.

a
aa_level
aa_threshold
abs
absorption
accuracy
acos
acosh
adaptive
adc_bailout global setting
adc_bailout radiosity
agate
agate_turb
albedo diffuse
albedo phong
 albedo specular
all
all_intersections
alpha
altitude
always_sample
ambient
ambient_light
angle
aoi
aperture
append
arc_angle
area_illumination
 area_light
array
asc
ascii
asin
asinh
assumed_gamma
atan
atan2
atand
atanh
autostop
average
b
b_spline
background
bezier_spline
bicubic_patch
bitwise_and
bitwise_or
bitwise_xor
black_hole
 blob
blue
blur_samples
bokeh
bounded_by
box
boxed
bozo
 break
brick
brick_size
brightness
brilliance
bump_map
bump_size
bumps
c
camera
case
caustics
ceil
cells
charset
checker
chr
circular
clipped_by
clock
clock_delta
clock_on
collect
color
 color_map
colour
colour_map
component
composite
concat
cone
confidence
conic_sweep
conserve_energy
contained_by
control0
control1
coords
cos
 cosh
count
crackle
crand
cube
cubic object
cubic pattern
cubic warp
cubic_spline
cubic_wave
cutaway_textures
cylinder
cylindrical
d
datetime
debug
declare
default
defined
degrees
density
density_file
 density_map
dents
deprecated
df3
difference
diffuse
dimension_size
dimensions
 direction
disc
dispersion
dispersion_samples
dist_exp
distance
div
double_illuminate
e
eccentricity
else
elseif
emission finish
emission media
 end
error
error_bound
evaluate
exp
 expand_thresholds
exponent
exterior
extinction
f
face_indices
facets
fade_color
fade_colour
fade_distance
fade_power
falloff
falloff_angle
false
fclose
file_exists
 filter
final_clock
final_frame
finish
fisheye
flatness
flip
floor
focal_point
fog
fog_alt
 fog_offset
fog_type
fopen
for
form
frame_number
frequency
fresnel
function
g
gamma bump maps
gamma heightfield
gamma image map
gamma image pattern
gather
 gif
global_lights
global_settings
gradient
granite
 gray
gray_threshold
green
h
height_field
hexagon
 hf_gray_16
hierarchy
 hypercomplex
hollow
i
if
ifdef
iff
ifndef
image_height
image_map
image_pattern
image_width
importance
 include
initial_clock
initial_frame
input_file_name
inside
inside_vector
int
interior
interior_texture
 internal
interpolate
intersection
intervals
inverse
ior
irid
irid_wavelength
isosurface
j
jitter
jpeg
 julia
julia_fractal
l
lambda
lathe
leopard
light_group
light_source
 linear_spline
linear_sweep
ln
load_file
local
 location
log
look_at
looks_like
low_error_factor
m
macro
magnet
major_radius
mandel
map_type
marble
material
material_map
matrix
max
maximum_reuse
 max_extent
max_gradient
max_intersections
max_iteration
max_sample
max_trace
max_trace_level
media
media_attenuation
media_interaction
merge
 mesh
mesh2
metallic
method
metric
min
min_extent
minimum_reuse
mm_per_unit
mod
mortar
n
natural_spline
nearest_count
no
no_bump_scale
no_image
 no_radiosity
no_reflection
no_shadow
noise_generator
normal
 normal_indices
normal_map
normal_vectors
now
number_of_waves
o
object
octaves
off
offset
omega
 omnimax
on
once
onion
open
 orient
orientation
orthographic
ovus
p
panoramic
parallel
parametric
pass_through
pattern
pavement
perspective
pgm
phase
phong
phong_size
photons
 pi
pigment
pigment_map
pigment_pattern
planar
plane
png
point_at
poly
polynomial
poly_wave
polygon
 pot
pow
ppm
precision
precompute
premultiplied
pretrace_end
pretrace_start
prism
prod
projected_through
pwr
q
quadratic_spline
quadric
quartic
 quaternion
quick_color
quick_colour
 quilted
r
radial
radians
radiosity
radius
rainbow
ramp_wave
rand
range
ratio
 read
reciprocal
recursion_limit
red
reflection
reflection_exponent
refraction
render
repeat
 rgb
rgbf
rgbft
rgbt
right
ripples
rotate
roughness
s
samples
save_file
scale
scallop_wave
scattering
seed
select
shadowless
sin
sine_wave
sinh
sint8
sint16be
sint16le
sint32be
sint32le
size
sky
sky_sphere
slice
slope
slope_map
 smooth
smooth_triangle
solid
sor
spacing
specular
sphere
sphere_sweep
spherical
spiral1
spiral2
spline
split_union
spotlight
spotted
sqr
sqrt
square
srgb bump maps
srgb color literals
srgb heightfield
 srgb image maps
srgb image pattern
srgbf
srgbt
srgbft
statistics
str
strcmp
strength
strlen
strlwr
strupr
sturm
substr
subsurface
sum
superellipsoid
switch
sys
t
t
tan
tanh
target
text
texture
texture_list
texture_map
tga
thickness
threshold
 tiff
tightness
tile2
tiles
tiling
tolerance
toroidal
torus
trace
transform
translate
 translucency
transmit
triangle
triangle_wave
triangular
true
ttf
turb_depth
turbulence
type
u
u
uint8
uint16be
uint16le
u_steps
ultra_wide_angle
 undef
union
up
use_alpha
use_color
use_colour
 use_index
utf8
uv_indices
uv_mapping
uv_vectors
v
v
v_steps
val
variance
vaxis_rotate
 vcross
vdot
version
vertex_vectors
vlength
 vnormalize
vrotate
vstr
vturbulence
w
warning
warp
water_level
 waves
while
width
 wood
wrinkles
write
x
x
y
y
 yes
z
z

3.3.1.3 Identifiers

POV-Ray allows you to define identifiers for later use in the scene file. An identifier may be 1 to 40 characters long. It may consist of upper and lower case letters, the digits 0 through 9 or an underscore character ("_"). The first character must be an alphabetic character. The declaration of identifiers is covered later.

All keywords (reserved words) are fully lower case. Therefore it is recommended that your identifiers contain at least one upper case character so it is sure to avoid conflict with reserved words.

3.3.1.4 Comments

Comments are text in the scene file included to make the scene file easier to read or understand. They are ignored by the ray-tracer and are there for your information. There are two types of comments in POV-Ray.

Two slashes are used for single line comments. Anything on a line after a double slash (//) is ignored by the ray-tracer. For example:

// This line is ignored

You can have scene file information on the line in front of the comment as in:

object { FooBar } // this is an object

The other type of comment is used for multiple lines. It starts with "/*" and ends with "*/". Everything in-between is ignored. For example:

/* These lines
are ignored
by the
ray-tracer */

This can be useful if you want to temporarily remove elements from a scene file. /* ... */ comments can comment out lines containing other // comments and thus can be used to temporarily or permanently comment out parts of a scene. /* ... */ comments can be nested, the following is legal:

/* This is a comment
// This too
/* This also */
*/

Use comments liberally and generously. Well used, they really improve the readability of scene files.

3.3.1.5 Numeric Expressions

Many parts of the POV-Ray language require you to specify one or more floating point numbers. A floating point number is a number with a decimal point. Floats may be specified using literals, identifiers or functions which return float values. You may also create very complex float expressions from combinations of any of these using various familiar operators.

Where POV-Ray needs an integer value it allows you to specify a float value and it truncates it to an integer. When POV-Ray needs a logical or boolean value it interprets any non-zero float as true and zero as false. Because float comparisons are subject to rounding errors POV-Ray accepts values extremely close to zero as being false when doing boolean functions. Typically values whose absolute values are less than a preset value epsilon are considered false for logical expressions. The value of epsilon is system dependent but is generally about 1.0e-10. Two floats a and b are considered to be equal if abs(a-b) < epsilon.

The full syntax for float expressions is given below. Detailed explanations are given in the following sub-sections.

FLOAT:
  NUMERIC_TERM [SIGN NUMERIC_TERM]...
SIGN:
  + | -
NUMERIC_TERM:
  NUMERIC_FACTOR [MULT NUMERIC_FACTOR]...
MULT:
  * | /
NUMERIC_FACTOR:
  FLOAT_LITERAL                 |
  FLOAT_IDENTIFIER              |
  SIGN NUMERIC_FACTOR           |
  FLOAT_FUNCTION                |
  FLOAT_BUILT_IN_IDENT          |
  ( FULL_EXPRESSION )           |
  ! NUMERIC_FACTOR              |
  VECTOR DECIMAL_POINT DOT_ITEM |
  FLOAT_FUNCTION_INVOCATION
FLOAT_LITERAL:
  MANTISSA [EXP [SIGN] DIGIT...]
MANTISSA:
  DIGIT... [DECIMAL_POINT [DIGIT...]] |
  DECIMAL_POINT DIGIT...
DIGIT:
  0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
DECIMAL_POINT:
  .
EXP:
  e | E
DOT_ITEM:
  x | y | z | t | u | v | red | green | blue | filter |
  transmit | gray
FLOAT_FUNCTION:
  abs( FLOAT ) | acos( FLOAT ) | acosh( FLOAT ) | asc( STRING ) |
  asin( FLOAT ) | asinh( FLOAT ) | atan( FLOAT) | atanh( FLOAT) |
  atan2( FLOAT , FLOAT ) | bitwise_and( FLOAT, FLOAT, ...) |
  bitwise_or (FLOAT, FLOAT, ...) | bitwise_xor ( FLOAT, FLOAT, ...) |
  ceil( FLOAT ) | cos( FLOAT ) | cosh( FLOAT ) | defined(IDENTIFIER ) |
  degrees( FLOAT ) | dimensions( ARRAY_IDENTIFIER ) |
  dimension_size( ARRAY_IDENTIFIER , FLOAT ) |
  div( FLOAT , FLOAT ) | exp( FLOAT ) | file_exists( STRING ) |
  floor( FLOAT ) | int( FLOAT ) | ln(Float | log( FLOAT ) |
  max( FLOAT , FLOAT, ... ) | min( FLOAT , FLOAT, ... ) |
  mod( FLOAT , FLOAT ) | pow( FLOAT , FLOAT ) |
  radians( FLOAT ) | rand( FLOAT ) | seed( FLOAT ) |
  select( FLOAT, FLOAT, FLOAT [,FLOAT]) | sin( FLOAT ) |
  sinh( FLOAT ) | sqrt( FLOAT ) | strcmp( STRING , STRING ) |
  strlen( STRING ) | tan( FLOAT ) | tanh( FLOAT ) |
  val( STRING ) | vdot( VECTOR , VECTOR ) | vlength( VECTOR ) |
FLOAT_BUILT_IN_IDENT:
  clock | clock_delta | clock_on | false | final_clock |
  final_frame | frame_number | image_height | image_width |
  initial_clock | initial_frame | no | off | on | pi | true |
  version | yes
FULL_EXPRESSION:
  FLOAT |
  LOGICAL_EXPRESSION [? FULL_EXPRESSION : FULL_EXPRESSION]
LOGICAL_EXPRESSION:
  REL_TERM [LOGICAL_OPERATOR REL_TERM]...
LOGICAL_OPERATOR:
  & | | (note: this means an ampersand or a
         vertical bar is a logical operator)
REL_TERM:
  FLOAT [REL_OPERATOR FLOAT]... |
  STRING REL_OPERATOR STRING
REL_OPERATOR:
  < | <= | = | >= | > | !=
INT:
  FLOAT (note: any syntax which requires a
         integer INT will accept a FLOAT
         and it will be truncated to an
         integer internally by POV-Ray).

Note: FLOAT_IDENTIFIERS are identifiers previously declared to have float values. The DOT_ITEM syntax is actually a vector or color operator but it returns a float value. See Vector Operators or Color Operators for details. An ARRAY_IDENTIFIER is just the identifier name of a previously declared array, it does not include the [] braces nor the index. The syntax for STRING is in the section Strings.

3.3.1.5.1 Literals

Float literals are represented by an optional sign ("+" or "-") digits, an optional decimal point and more digits. If the number is an integer you may omit the decimal point and trailing zero. If it is all fractional you may omit the leading zero. POV-Ray supports scientific notation for very large or very small numbers. The following are all valid float literals:

-2.0 -4 34 3.4e6 2e-5 .3 0.6

3.3.1.5.2 Identifiers

Float identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

FLOAT_DECLARATION:
  #declare IDENTIFIER = EXPRESSION;    |
  #local IDENTIFIER = EXPRESSION;

Where IDENTIFIER is the name of the identifier up to 40 characters long and EXPRESSION is any valid expression which evaluates to a float value.

Note: There should be a semi-colon after the expression in a float declaration. If omitted, it generates a warning and some macros may not work properly. See #declare vs. #local for information on identifier scope.

Here are some examples.

#declare Count = 0;
#declare Rows = 5.3;
#declare Cols = 6.15;
#declare Number = Rows*Cols;
#declare Count = Count+1;

As the last example shows, you can re-declare a float identifier and may use previously declared values in that re-declaration. There are several built-in identifiers which POV-Ray declares for you. See Float Expressions: Built-in Variables for details.

3.3.1.5.3 Operators

Arithmetic expressions: Basic math expressions can be created from float literals, identifiers or functions using the following operators in this order of precedence...

( ) | expressions in parentheses first
+A -A !A | unary minus, unary plus and logical not
A*B A/B | multiplication and division
A+B A-B | addition and subtraction

Relational, logical and conditional expressions may also be created. However there is a restriction that these types of expressions must be enclosed in parentheses first. This restriction, which is not imposed by most computer languages, is necessary because POV-Ray allows mixing of float and vector expressions. Without the parentheses there is an ambiguity problem. Parentheses are not required for the unary logical not operator "!" as shown above. The operators and their precedence are shown here.

Relational expressions: The operands are arithmetic expressions and the result is always boolean with 1 for true and 0 for false. All relational operators have the same precedence.

(A < B) | A is less than B
(A <= B) | A is less than or equal to B
(A = B) | A is equal to B (actually abs(A-B)<EPSILON)
(A != B) | A is not equal to B (actually abs(A-B)>=EPSILON)
(A >= B) | A is greater than or equal to B
(A > B) | A is greater than B

Logical expressions: The operands are converted to boolean values of 0 for false and 1 for true. The result is always boolean. All logical operators have the same precedence.

Note: These are not bit-wise operations, they are logical.

(A & B) | true only if both A and B are true, false otherwise
(A | B) | true if either A or B or both are true

Conditional expressions: The operand C is boolean while operands A and B are any expressions. The result is of the same type as A and B.

(C ? A : B) if C then A else B

Assuming the various identifiers have been declared, the following are examples of valid expressions...

1+2+3    2*5     1/3     Row*3    Col*5
(Offset-5)/2      This/That+Other*Thing
((This<That) & (Other>=Thing)?Foo:Bar)

Expressions are evaluated left to right with innermost parentheses evaluated first, then unary +, - or !, then multiply or divide, then add or subtract, then relational, then logical, then conditional.

3.3.1.5.4 Functions

POV-Ray defines a variety of built-in functions for manipulating floats, vectors and strings. Function calls consist of a keyword which specifies the name of the function followed by a parameter list enclosed in parentheses. Parameters are separated by commas. For example:

keyword(param1,param2)

The following are the functions which return float values. They take one or more float, integer, vector, or string parameters. Assume that A and B are any valid expression that evaluates to a float; I is a float which is truncated to integer internally, S, S1, S2 etc. are strings, and V, V1, V2 etc. are any vector expressions.O is an object identifier to a pre-declared object.

abs(A)
Absolute value of A. If A is negative, returns -A otherwise returns A.

acos(A)
Arc-cosine of A. Returns the angle, measured in radians, whose cosine is A.

acosh(A)
Inverse hyperbolic cosine of A.

asc(S)
Returns an integer value in the range 0 to 255 that is the ASCII value of the first character of the string S. For example asc("ABC") is 65 because that is the value of the character "A".

asin(A)
Arc-sine of A. Returns the angle, measured in radians, whose sine is A.

asinh(A)
Inverse hyperbolic sine of A

atan2(A,B)
Arc-tangent of (A/B). Returns the angle, measured in radians, whose tangent is (A/B). Returns appropriate value even if B is zero. Use atan2(A,1) to compute usual atan(A) function.

atanh(A)
Inverse hyperbolic tangent of A

bitwise_and(A,B,...)
Bitwise AND of two or more float values considered as integers.

bitwise_or(A,B,...)
Bitwise OR of two or more float values considered as integers.

bitwise_xor(A,B,...)
Bitwise XOR of two or more float values considered as integers.

Note: For the three bit-wise functions, each parameter is first converted to integer (so fractional part is ignored), and the computation is performed on a classical int. Do not expect to much precision, as conversion from a double precision number (usually with 52 bits mantissa) to an integer and back to a double precision number is not the best way to keep track of every bit.

ceil(A)
Ceiling of A. Returns the smallest integer greater than A. Rounds up to the next higher integer.

cos(A)
Cosine of A. Returns the cosine of the angle A, where A is measured in radians.

cosh(A)
The hyperbolic cosine of A.

defined(IDENTIFIER)
Returns true if the identifier is currently defined, false otherwise. This is especially useful for detecting end-of-file after a #read directive because the file identifier is automatically undefined when end-of-file is reached. See The #read Directive for details.

degrees(A)
Convert radians to degrees. Returns the angle measured in degrees whose value in radians is A. Formula is degrees=A/pi*180.0.

dimensions( ARRAY_IDENTIFIER )
Returns the number of dimensions of a previously declared array identifier. For example if you do #declare MyArray=array[6][10] then dimensions(MyArray) returns the value 2.

dimension_size( ARRAY_IDENTIFIER, FLOAT )
Returns the size of a given dimension of a previously declared array identifier. Dimensions are numbered left-to-right starting with 1. For example if you do #declare MyArray=array[6][10] then dimension_size(MyArray,2) returns the value 10.

div(A,B)
Integer division. The integer part of (A/B).

exp(A)
Exponential of A. Returns the value of e raised to the power A where e is the base of the natural logarithm, i.e. the non-repeating value approximately equal to 2.71828182846.

file_exists(S)
Attempts to open the file specified by the string S. The current directory and all library directories specified by the Library_Path or +L options are also searched. See Library Paths for details. Returns 1 if successful and 0 if unsuccessful.

floor(A)
Floor of A. Returns the largest integer less than A. Rounds down to the next lower integer.

inside(O,V)
It returns either 0.0, when the vector V is outside the object, specified by the object-identifier O, or 1.0 if it is inside.

Note: The inside keyword does not accept object-identifiers to non-solid objects.

int(A)
Integer part of A. Returns the truncated integer part of A. Rounds towards zero.

log(A)
Logarithm of A. Returns the logarithm base 10 of the value A.

ln(A)
Natural logarithm of A. Returns the natural logarithm base e of the value A.

max(A,B,...)
Maximum of two or more float values. Returns A if A larger than B. Otherwise returns B.

min(A,B,...)
Minimum of two or more float values. Returns A if A smaller than B. Otherwise returns B.

mod(A,B)
Value of A modulo B. Returns the remainder after the integer division of A/B. Formula is mod=((A/B)-int(A/B))*B.

pow(A,B)
Exponentiation. Returns the value of A raised to the power B.

Note: For a negative A and a non-integer B the function has no defined return value. The result then may depend on the platform POV-Ray is compiled on.

radians(A)
Convert degrees to radians. Returns the angle measured in radians whose value in degrees is A. Formula is radians=A*pi/180.0.

rand(I)
Returns the next pseudo-random number from the stream specified by the positive integer I. You must call seed() to initialize a random stream before calling rand(). The numbers are uniformly distributed, and have values between 0.0 and 1.0, inclusively. The numbers generated by separate streams are independent random variables.

seed(I)
Initializes a new pseudo-random stream with the initial seed value I. The number corresponding to this random stream is returned. Any number of pseudo-random streams may be used as shown in the example below:

#declare R1 = seed(0);
#declare R2 = seed(12345);
sphere { <rand(R1), rand(R1), rand(R1)>, rand(R2) }

Multiple random generators are very useful in situations where you use rand() to place a group of objects, and then decide to use rand() in another location earlier in the file to set some colors or place another group of objects. Without separate rand() streams, all of your objects would move when you added more calls to rand(). This is very annoying.

select(A, B, C [,D])
It can be used with three or four parameters Select compares the first argument with zero, depending on the outcome it will return B, C or D. A,B,C,D can be floats or funtions.

When used with three parameters, if A < 0 it will return B, else C (A >= 0).

When used with four parameters, if A < 0 it will return B. If A = 0 it will return C. Else it will return D (A > 0).

Example:

If A has the consecutive values -2, -1, 0, 1, and 2 :

                         //    A =  -2 -1 0 1 2
select (A, -1, 0, 1)     //returns  -1 -1 0 1 1
select (A, -1, 1)        //returns  -1 -1 1 1 1

sin(A)
Sine of A. Returns the sine of the angle A, where A is measured in radians.

sinh(A)
The hyperbolic sine of A.

strcmp(S1,S2)
Compare string S1 to S2. Returns a float value zero if the strings are equal, a positive number if S1 comes after S2 in the ASCII collating sequence, else a negative number.

strlen(S)
Length of S. Returns an integer value that is the number of characters in the string S.

sqrt(A)
Square root of A. Returns the value whose square is A.

tan(A)
Tangent of A. Returns the tangent of the angle A, where A is measured in radians.

tanh(A)
The hyperbolic tangent of A.

val(S)
Convert string S to float. Returns a float value that is represented by the text in string S. For example val("123.45") is 123.45 as a float.

vdot(V1,V2)
Dot product of V1 and V2. Returns a float value that is the dot product (sometimes called scalar product) of V1 with V2. It is directly proportional to the length of the two vectors and the cosine of the angle between them. Formula is vdot=V1.x*V2.x + V1.y*V2.y + V1.z*V2.z. See the animated demo scene VECT2.POV for an illustration.

vlength(V)
Length of V. Returns a float value that is the length of vector V. Formula is vlength=sqrt(vdot(A,A)). Can be used to compute the distance between two points. Dist=vlength(V2-V1).

See section Vector Functions and section String Functions for other functions which are somewhat float-related but which return vectors and strings. In addition to the above built-in functions, you may also define your own functions using the function keyword. See the section User-Defined Functions for more details.

3.3.1.5.5 Built-in Constants

Constants are:

FLOAT_BUILT_IN_IDENT:
  false | no | off | on | pi | true | yes

The built-in constants never change value. They are defined as though the following lines were at the start of every scene.

#declare pi = 3.1415926535897932384626;
#declare true = 1;
#declare yes = 1;
#declare on = 1;
#declare false = 0;
#declare no = 0;
#declare off = 0;

The built-in float identifier pi is obviously useful in math expressions involving circles. The built-in float identifiers on, off, yes, no, true, and false are designed for use as boolean constants.

The built-in float constants on, off, yes, no, true, and false are most often used as boolean values with object modifiers or parameters such as sturm, hollow, hierarchy, smooth, media_attenuation, and media_interaction. Whenever you see syntax of the form keyword [Bool], if you simply specify the keyword without the optional boolean then it assumes keyword on. You need not use the boolean but for readability it is a good idea. You must use one of the false booleans or an expression which evaluates to zero to turn it off.

Note: Some of these keywords are on by default, if no keyword is specified.

For example:

object { MyBlob }                // sturm defaults off, but
                                 // hierarchy defaults on
object { MyBlob sturm }          // turn sturm on
object { MyBlob sturm on }       // turn sturm on
object { MyBlob sturm off }      // turn sturm off
object { MyBlob hierarchy }      // does nothing, hierarchy was
                                 // already on
object { MyBlob hierarchy off }  // turn hierarchy off
3.3.1.5.6 Built-in Variables

There are several built-in float variables. You can use them to specify values or to create expressions but you cannot re-declare them to change their values.

Clock-related are:

FLOAT_BUILT-IN_IDENT:
  clock | clock_delta | clock_on | final_clock | final_frame
  frame_number | initial_clock | initial_frame

These keywords allow to use the values of the clock which have been set in the command line switch options (or INI-file). They represent float or integer values, read from the animation options. You cannot re-declare these identifiers.

clock
The built-in float identifier clock is used to control animations in POV-Ray. Unlike some animation packages, the action in POV-Ray animated scenes does not depend upon the integer frame numbers. Rather you should design your scenes based upon the float identifier clock. For non-animated scenes its default value is 0 but you can set it to any float value using the INI file option Clock=n.n or the command-line switch +K n.n to pass a single float value your scene file.

Other INI options and switches may be used to animate scenes by automatically looping through the rendering of frames using various values for clock. By default, the clock value is 0 for the initial frame and 1 for the final frame. All other frames are interpolated between these values.
For example if your object is supposed to rotate one full turn over the course of the animation you could specify rotate 360*clock*y. Then as clock runs from 0 to 1, the object rotates about the y-axis from 0 to 360 degrees.

Although the value of clock will change from frame-to-frame, it will never change throughout the parsing of a scene.

clock_delta
The built-in float identifier clock_delta returns the amount of time between clock values in animations in POV-Ray. While most animations only need the clock value itself, some animation calculations are easier if you know how long since the last frame. Caution must be used when designing such scenes. If you render a scene with too few frames, the results may be different than if you render with more frames in a given time period. On non-animated scenes, clock_delta defaults to 0. See the section Animation Options for more details.

clock_on

With this identifier the status of the clock can be checked: 1 is on, 0 is off.

#if(clock_on=0)
  //stuff for still image
#else
  //some animation
#end

frame_number

If you rather want to define the action in POV-Ray animated scenes depending upon the integer frame numbers, this identifier can be used. It reads the number of the frame currently being rendered.

#if(frame_number=1)
  //stuff for first image or frame
#end
#if(frame_number=2)
  //stuff for second image or frame
#end
#if(frame_number=n)
  //stuff for n th image or frame
#end

initial_clock
This identifier reads the value set through the INI file option Initial_Clock=n.n or the command-line switch +KI n.n.

final_clock
This identifier reads the value set through the INI file option Final_Clock=n.n or the command-line switch +KF n.n.

initial_frame
This identifier reads the value set through the INI file option Initial_Frame=n or the command-line switch +KFI n.

final_frame
This identifier reads the value set through the INI file option Final_Frame=n or the command-line switch +KFF n.

Note: These values are the ones actually used. When the option 'cyclic animation' is set, they could be different from the ones originally set in the options.

Image-size are:

FLOAT_BUILT-IN_IDENT:
  image_width | image_height

image_width
This identifier reads the value set through the INI file option Width=n or the command-line switch +W n.

image_height
This identifier reads the value set through the INI file option Height=n or the command-line switch +H n.

You could use these keywords to set the camera ratio (up and right vectors) correctly. The viewing angle of the camera covers the full width of the rendered image. The camera ratio will always follow the ratio of the image width to height, regardless of the set image size. Use it like this:

up y*image_height
right x*image_width

You could also make some items of the scene dependent on the image size:

#if (image_width < 300) crand 0.1 #else crand 0.5 #end

or:

image_map {
  pattern image_width, image_width {  //make pattern resolution
    gradient x                        //dependent of render width
    color_map { [ 0.0 ... ] [ 1.0 ... ] }
    }
  }

version

FLOAT_BUILT-IN_IDENT:
  version

The built-in float variable version contains the current setting of the version compatibility option. Although this value defaults to the current POV-Ray version number, the initial value of version may be set by the INI file option Version=n.n or by the +MV n.n command-line switch. This tells POV-Ray to parse the scene file using syntax from an earlier version of POV-Ray.

The INI option or switch only affects the initial setting. Unlike other built-in identifiers, you may change the value of version throughout a scene file. You do not use #declare to change it though. The #version language directive is used to change modes. Such changes may occur several times within scene files.

Together with the built-in version identifier the #version directive allows you to save and restore the previous values of this compatibility setting. The new #local identifier option is especially useful here. For example suppose mystuff.inc is in version 1 format. At the top of the file you could put:

#local Temp_Vers = version;  // Save previous value
#version 1.0;                // Change to 1.0 mode
...                          // Version 1.0 stuff goes here...
#version Temp_Vers;          // Restore previous version

Note: There should be a semi-colon after the float expression in a #version directive. If omitted, it generates a warning and some macros may not work properly.

3.3.1.6 Vector Expressions

POV-Ray often requires you to specify a vector. A vector is a set of related float values. Vectors may be specified using literals, identifiers or functions which return vector values. You may also create very complex vector expressions from combinations of any of these using various familiar operators.

POV-Ray vectors may have from two to five components but the vast majority of vectors have three components. Unless specified otherwise, you should assume that the word vector means a three component vector. POV-Ray operates in a 3D x, y, z coordinate system and you will use three component vectors to specify x, y and z values. In some places POV-Ray needs only two coordinates. These are often specified by a 2D vector called an UV vector. Fractal objects use 4D vectors. Color expressions use 5D vectors but allow you to specify 3, 4 or 5 components and use default values for the unspecified components. Unless otherwise noted, all 2, 4 or 5 component vectors work just like 3D vectors but they have a different number of components.

The syntax for combining vector literals into vector expressions is almost identical to the rules for float expressions. In the syntax for vector expressions below, some of the syntax items are defined in the section for float expressions. See Float Expressions for those definitions. Detailed explanations of vector-specific issues are given in the following sub-sections.

VECTOR:
    NUMERIC_TERM [SIGN NUMERIC_TERM]
NUMERIC_TERM:
    NUMERIC_FACTOR [MULT NUMERIC_FACTOR]
NUMERIC_FACTOR:
    VECTOR_LITERAL        |
    VECTOR_IDENTIFIER     |
    SIGN NUMERIC_FACTOR   |
    VECTOR_FUNCTION       |
    VECTOR_BUILT-IN_IDENT |
    ( FULL_EXPRESSION )   |
    ! NUMERIC_FACTOR      |
    FLOAT
VECTOR_LITERAL:
    < FLOAT , FLOAT , FLOAT >
VECTOR_FUNCTION:
    min_extent ( OBJECT_IDENTIFIER )         |
    max_extent ( OBJECT_IDENTIFIER )         |
    trace(OBJECT_IDENTIFIER, VECTOR, VECTOR, [VECTOR_IDENTIFIER] )|
    vaxis_rotate( VECTOR , VECTOR , FLOAT )  |
    vcross( VECTOR , VECTOR )                |
    vrotate( VECTOR , VECTOR )               |
    vnormalize( VECTOR )                     |
    vturbulence(FLOAT, FLOAT, FLOAT, VECTOR)
VECTOR_BUILT-IN_IDENT:
     x | y | z | t | u | v

Note: VECTOR_IDENTIFIERS are identifiers previously declared to have vector values.

3.3.1.6.1 Literals

Vector literals consist of two to five float expressions that are bracketed by angle brackets < and >. The terms are separated by commas. For example here is a typical three component vector:

< 1.0, 3.2, -5.4578 >

The commas between components are necessary to keep the program from thinking that the 2nd term is the single float expression 3.2-5.4578 and that there is no 3rd term. If you see an error message such as "Float expected but '>' found instead" then you probably have missed a comma.

Sometimes POV-Ray requires you to specify floats and vectors side-by-side. The rules for vector expressions allow for mixing of vectors with vectors or vectors with floats so commas are required separators whenever an ambiguity might arise. For example <1,2,3>-4 evaluates as a mixed float and vector expression where 4 is subtracted from each component resulting in <-3,-2,-1>. However the comma in <1,2,3>,-4 means this is a vector followed by a float.

Each component may be a full float expression. For example

<This+3,That/3,5*Other_Thing>

is a valid vector.

3.3.1.6.2 Identifiers

Vector identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

VECTOR_DECLARATION:
  #declare IDENTIFIER = EXPRESSION; |
  #local IDENTIFIER = EXPRESSION;

Where IDENTIFIER is the name of the identifier up to 40 characters long and EXPRESSION is any valid expression which evaluates to a vector value.

Note: There should be a semi-colon after the expression in a vector declaration. If omitted, it generates a warning and some macros may not work properly. See #declare vs. #local for information on identifier scope.

Here are some examples....

#declare Here = <1,2,3>;
#declare There = <3,4,5>;
#declare Jump = <Foo*2,Bar-1,Bob/3>;
#declare Route = There-Here;
#declare Jump = Jump+<1,2,3>;

Note: You invoke a vector identifier by using its name without any angle brackets. As the last example shows, you can re-declare a vector identifier and may use previously declared values in that re-declaration. There are several built-in identifiers which POV-Ray declares for you. See section Built-in Vector Identifiers for details.

3.3.1.6.3 Operators

Vector literals, identifiers and functions may also be combined in expressions the same as float values. Operations are performed on a component-by-component basis. For example <1,2,3> + <4,5,6> evaluates the same as <1+4,2+5,3+6> or <5,7,9>. Other operations are done on a similar component-by-component basis. For example (<1,2,3> = <3,2,1>) evaluates to <0,1,0> because the middle components are equal but the others are not. Admittedly this is not very useful but it is consistent with other vector operations.

Conditional expressions such as (C ? A : B) require that C is a float expression but A and B may be vector expressions. The result is that the entire conditional evaluates as a valid vector. For example if Foo and Bar are floats then (Foo < Bar ? <1,2,3> : <5,6,7>) evaluates as the vector <1,2,3> if Foo is less than Bar and evaluates as <5,6,7> otherwise.

You may use the dot operator to extract a single float component from a vector. Suppose the identifier Spot was previously defined as a vector. Then Spot.x is a float value that is the first component of this x, y, z vector. Similarly Spot.y and Spot.z reference the 2nd and 3rd components. If Spot was a two component UV vector you could use Spot.u and Spot.v to extract the first and second component. For a 4D vector use .x, .y, .z, and .t to extract each float component. The dot operator is also used in color expressions which are covered later.

3.3.1.6.4 Operator Promotion

You may use a lone float expression to define a vector whose components are all the same. POV-Ray knows when it needs a vector of a particular type and will promote a float into a vector if need be. For example the POV-Ray scale statement requires a three component vector. If you specify scale 5 then POV-Ray interprets this as scale <5,5,5> which means you want to scale by 5 in every direction.

Versions of POV-Ray prior to 3.0 only allowed such use of a float as a vector in various limited places such as scale and turbulence. However you may now use this trick anywhere. For example...

box{0,1}     // Same as box{<0,0,0>,<1,1,1>}
sphere{0,1} // Same as sphere{<0,0,0>,1}

When promoting a float into a vector of 2, 3, 4 or 5 components, all components are set to the float value, however when promoting a vector of a lower number of components into a higher order vector, all remaining components are set to zero. For example if POV-Ray expects a 4D vector and you specify 9 the result is <9,9,9,9> but if you specify <7,6> the result is <7,6,0,0>.

3.3.1.6.5 Functions

POV-Ray defines a variety of built-in functions for manipulating floats, vectors and strings. Function calls consist of a keyword which specifies the name of the function followed by a parameter list enclosed in parentheses. Parameters are separated by commas. For example:

keyword(param1,param2)

The following are the functions which return vector values. They take one or more float, integer, vector, or string parameters. Assume that A and B are any valid expression that evaluates to a vector; and F is any float expression.

min_extent(OBJECT_IDENTIFIER), max_extent(OBJECT_IDENTIFIER). The min_extent and max_extent return the minimum and maximum coordinates of a #declared object's bounding box (Corner1 and Corner2), in effect allowing you to find the dimensions and location of the object.

Note: This is not perfect, in some cases (such as CSG intersections and differences or isosurfaces) the bounding box does not represent the actual dimensions of the object.

Example:

#declare Sphere =
sphere {
  <0,0,0>, 1
  pigment { rgb <1,0,0> }
  }

#declare Min = min_extent ( Sphere );
#declare Max = max_extent ( Sphere );

object { Sphere }
box {
  Min, Max
  pigment { rgbf <1,1,1,0.5> }
  }

As of version 3.7 experimental support for reading the pixel resolution of an image map was added. This is done by giving an image map pigment identifier to max_extent(), which will then return the resolution of the image map as the x and y values of the returned vector.

One usage of this feature would be when using an image as a background matte.

Example:

#declare MatteImage =
pigment {
  image_map {
    jpeg "YourImage.jpg"
    once
    }
  };

#declare Resolution = max_extent ( MatteImage );

box { 0, Resolution
  pigment { MatteImage  }
  // avoid the scale by warning (z direction)
  #declare Resolution = Resolution + <0, 0, 1>;
  // some scale factor to fit your needs
  scale Resolution*ScaleFactor
  }

trace(OBJECT_IDENTIFIER, A, B, [VECTOR_IDENTIFIER]). trace helps you finding the exact location of a ray intersecting with an object's surface. It traces a ray beginning at the point A in the direction specified by the vector B. If the ray hits the specified object, this function returns the coordinate where the ray intersected the object. If not, it returns <0,0,0>. If a fourth parameter in the form of a vector identifier is provided, the normal of the object at the intersection point (not including any normal perturbations due to textures) is stored into that vector. If no intersection was found, the normal vector is reset to <0,0,0>.

Note: Checking the normal vector for <0,0,0> is the only reliable way to determine whether an intersection has actually occurred, intersections can and do occur anywhere, including at <0,0,0>.

Example:

#declare MySphere = sphere { <0, 0, 0>, 1 }
#declare Norm = <0, 0, 0>;
#declare Start = <1, 1, 1>;
#declare Inter=
trace ( MySphere, Start, <0, 0, 0>-Start, Norm );

object {
  MySphere
  texture {
    pigment { rgb 1}
    }
  }

#if (vlength(Norm)!=0)
cylinder {
  Inter, Inter+Norm, .1
  texture {
    pigment {color red 1}
    }
  }
#end

vaxis_rotate(A,B,F) Rotate A about B by F. Given the x,y,z coordinates of a point in space designated by the vector A, rotate that point about an arbitrary axis defined by the vector B. Rotate it through an angle specified in degrees by the float value F. The result is a vector containing the new x,y,z coordinates of the point.

vcross(A,B) Cross product of A and B. Returns a vector that is the vector cross product of the two vectors. The resulting vector is perpendicular to the two original vectors and its length is equal to the area of the parallelogram defined by them. Or to put in an other way, the cross product can also be formulated as: AxB = |A| * |B| * sin(angle(A,B)) * perpendicular_unit_vector(A,B) So the length of the resulting vector is proportional to the sine of the angle between A and B. See the animated demo scene VECT2.POV for an illustration.

vnormalize(A) Normalize vector A. Returns a unit length vector that is the same direction as A. Formula is vnormalize(A)=A/vlength(A).

Warning: Using vnormalize(<0,0,0>) will result in an error.

vrotate(A,B) Rotate A about origin by B. Given the x,y,z coordinates of a point in space designated by the vector A, rotate that point about the origin by an amount specified by the vector B. Rotate it about the x-axis by an angle specified in degrees by the float value B.x. Similarly B.y and B.z specify the amount to rotate in degrees about the y-axis and z-axis. The result is a vector containing the new x,y,z coordinates of the point.

vturbulence(Lambda, Omega, Octaves, A) Turbulence vector at A. Given the x,y,z coordinates of a point in space designated by the vector A, return the turbulence vector for that point based on the numbers given for Lambda, Omega and Octaves. For the meaning of the parameters, check out the Lambda, Omega and Octaves sections.
The amount of turbulence can be controlled by multiplying the turbulence vector by a multiple. The frequency at which the turbulence vector changes can be controlled by multiplying A with a multiple. The turbulence vector returned by the function can be added to the original point A to obtain a turbulated version of the point A. Example :
#declare MyVector = MyVector + Amount * vturbulence(2, 0.5, 6, MyVector * Frequency);

See section Float Functions for other functions which are somewhat vector-related but which return floats. In addition to the above built-in functions, you may also define your own functions using the #macro directive. See the section User Defined Macros for more details.

3.3.1.6.6 Built-in Constants

There are several built-in vector identifiers. You can use them to specify values or to create expressions but you cannot re-declare them to change their values. They are:

VECTOR_BUILT-IN_IDENT:
  x | y | z | t | u | v

All built-in vector identifiers never change value. They are defined as though the following lines were at the start of every scene.

#declare x = <1, 0, 0>;
#declare y = <0, 1, 0>;
#declare z = <0, 0, 1>;
#declare t = <0, 0, 0, 1>;
#declare u = <1, 0>;
#declare v = <0, 1>;

The built-in vector identifiers x, y, and z provide much greater readability for your scene files when used in vector expressions. For example....

plane { y, 1}             // The normal vector is obviously "y".
plane { <0,1,0>, 1} // This is harder to read.
translate 5*x             // Move 5 units in the "x" direction.
translate <5,0,0>   // This is less obvious.

An expression like 5*x evaluates to 5*<1,0,0> or <5,0,0>.

Similarly u and v may be used in 2D vectors. When using 4D vectors you should use x, y, z, and t and POV-Ray will promote x, y, and z to 4D when used where 4D is required.

3.3.1.7 Color Expressions

COLOR:
    COLOR_BODY             |
    color COLOR_BODY       | (this means the keyword color or
    colour COLOR_BODY        colour may optionally precede any color specification)
COLOR_BODY:
    COLOR_VECTOR           |
    COLOR_KEYWORD_GROUP    |
    COLOR_IDENTIFIER
COLOR_VECTOR:
    rgb <3_Term_Vector>    |
    rgbf <4_Term_Vector>   |
    rgbt <4_Term_Vector>   |
    [ rgbft ] <5_Term_Vector> |
    srgb <3_Term_Vector>   |
    srgbf <4_Term_Vector>  |
    srgbt <4_Term_Vector>  |
    srgbft <5_Term_Vector>
COLOR_KEYWORD_GROUP:
    [ COLOR_KEYWORD_ITEM ]...
COLOR_KEYWORD_ITEM:
    COLOR_IDENTIFIER       |
    red Red_Amount         |
    blue Blue_Amount       |
    green Green_Amount     |
    filter Filter_Amount   |
    transmit Transmit_Amount

Note: COLOR_IDENTIFIERS are identifiers previously declared to have color values. The 3, 4, and 5 term vectors are usually vector literals but may be vector expressions or floats promoted to vectors. See Operator Promotion and the sections below.

POV-Ray often requires you to specify a color. Colors consist of five values or color components. The first three are called red, green, and blue. They specify the intensity of the primary colors red, green and blue using an additive color system like the one used by the red, green and blue color phosphors on a color monitor.

The 4th component, called filter, specifies the amount of filtered transparency of a substance. Some real-world examples of filtered transparency are stained glass windows or tinted cellophane. The light passing through such objects is tinted by the appropriate color as the material selectively absorbs some frequencies of light while allowing others to pass through. The color of the object is subtracted from the light passing through so this is called subtractive transparency.

The 5th component, called transmit, specifies the amount of non-filtered light that is transmitted through a surface. Some real-world examples of non-filtered transparency are thin see-through cloth, fine mesh netting and dust on a surface. In these examples, all frequencies of light are allowed to pass through tiny holes in the surface. Although the amount of light passing through is diminished, the color of the light passing through is unchanged.

The color of the object and the color transmitted through the object together contribute 100% of the final color. So if transmit is set to 0.9, the transmitted color contributes 90% and the color of the object contributes only 10%. This is also true outside of the 0-1 range, so for example if transmit is set to 1.7, the transmitted color contributes with 170% and the color of the object contributes with minus 70%. Using transmit values outside of the 0-1 range can be used to create interesting special effects, but does not correspond to any phenomena seen in the real world. An example:

camera {location -2.5*z look_at 0 orthographic}

box {
  0,1
  texture {
    pigment {
    gradient y
      colour_map {
        [0, red 1]
        [1, blue 1]
        }
      }
    finish{ambient 1}
    }
  texture {
    pigment {
    gradient x
      colour_map {
        [0, rgb 0.5 transmit -3]
        [1, rgb 0.5 transmit  3]
        }
      }
    finish{ambient 1}
    }
  translate <-0.5,-0.5,0>
  scale <3,2,1>
  }

When using the transmit value for special effects, you can visualize it this way: The transmit value means contrast. 1.0 is no change in contrast, 0.5 is half contrast, 2.0 is double contrast and so on. You could say that transmit scales the colors. The color of the object is the center value. All colors will get closer to the center value if transmit is between 0 and 1, and all colors will spread away from the center value if transmit is greater than 1. If transmit is negative the colors will be inverted around the center value. Rgb 0.5 is common to use as center value, but other values can be used for other effects. The center value really is a color, and non-gray colors can be used for interesting effects. The red, green and blue components are handled separately.

Note: Earlier versions of POV-Ray used the keyword alpha to specify filtered transparency. However that word is often used to describe non-filtered transparency. For this reason alpha is no longer used.

Each of the five components of a color are float values which are normally in the range between 0.0 and 1.0. However any values, even negatives may be used.

Under most circumstances the keyword color is optional and may be omitted. We also support the British or Canadian spelling colour. Colors may be specified using vectors, keywords with floats or identifiers. You may also create very complex color expressions from combinations of any of these using various familiar operators. The syntax for specifying a color has evolved since POV-Ray was first released. We have maintained the original keyword-based syntax and added a short-cut vector notation. Either the old or new syntax is acceptable however the vector syntax is easier to use when creating color expressions.

The syntax for combining color literals into color expressions is almost identical to the rules for vector and float expressions. In the syntax for vector expressions, some of the syntax items are defined in the section for float expressions. See Float Expressions for those definitions. Detailed explanations of color-specific issues are given in the following sub-sections.

3.3.1.7.1 Color Vectors

The syntax for a color vector is...

COLOR_VECTOR:
  rgb <3_Term_Vector>   |
  rgbf <4_Term_Vector>  |
  rgbt <4_Term_Vector>  |
  [ rgbft ] <5_Term_Vector>

...where the vectors are any valid vector expressions of 3, 4 or 5 components. For example

color rgb <1.0, 0.5, 0.2>

This specifies a color whose red component is 1.0 or 100% of full intensity. The green component is 0.5 or 50% of full intensity and the blue component is 0.2 or 20% of full intensity. Although the filter and transmit components are not explicitly specified, they exist and are set to their default values of 0 or no transparency.

The rgbf keyword requires a four component vector. The 4th component is the filter component and the transmit component defaults to zero. Similarly the rgbt keyword requires four components where the 4th value is moved to the 5th component which is transmit and then the filter component is set to zero.

The rgbft keyword allows you to specify all five components. Internally in expressions all five are always used.

Under some circumstances, if the vector expression is a 5 component expression or there is a color identifier in the expression then the rgbft keyword is optional.

3.3.1.7.2 sRGB Colors

While POV-Ray will normally expect colors to be expressed in whatever working gamma space you have set via assumed_gamma, as of version 3.7 the srgb, srgbf, srgbt and srgbft keywords have been added to specify colors encoded according to the sRGB standard (roughly corresponding to a display gamma pre-correction of 2.2). Using these keywords instead of rgb, rgbf, rgbt or rgbft, respectively, instructs POV-Ray to automatically convert the color components to the working gamma space, being approximately equivalent to:

Effective_Red_Amount      = pow ( Red_Amount,   2.2/AssumedGamma )
Effective_Green_Amount    = pow ( Green_Amount, 2.2/AssumedGamma )
Effective_Blue_Amount     = pow ( Blue_Amount,  2.2/AssumedGamma )
Effective_Filter_Amount   = Filter_Amount
Effective_Transmit_Amount = Transmit_Amount

Note: Defining sRGB colors before assumed_gamma has been set will halt parsing and issue a warning.

The syntax is primarily intended for convenience when working with a physically accurate assumed_gamma of 1.0, as many people find this way of specifying colors more intuitive (for instance a value of about srgb 0.5 is commonly perceived as a medium grey, despite having an actual brightness of no more than 21.4%), and most image processing software and tools also use gamma pre-corrected colours in their user interface; while those may use slightly different color spaces, sRGB is a good approximation, and also has the advantage of being the official recommendation for the World Wide Web.

Note: Colors specified this way are not a different flavor of colors, but are rather converted on the fly to linear color values. When interpreting such values as a vector or accessing individual components, you will get the linear values rather than the pre-corrected values you originally specified.

For instance, the following color statements are all fully equivalent (except for rounding errors):

#declare Foo = color srgbt <51,76,102,127>/255;
#debug concat("<",vstr(5,Foo,",",0,3),">\n")
#declare Foo = color srgbt <0.2, 0.3, 0.4, 0.5>;
#debug concat("<",vstr(5,Foo,",",0,3),">\n")
#declare Foo = color srgb <0.2, 0.3, 0.4> transmit 0.5;
#debug concat("<",vstr(5,Foo,",",0,3),">\n")
#declare Foo = color rgbt <0.033,0.073,0.133,0.5>;
#debug concat("<",vstr(5,Foo,",",0,3),">\n")

Note: The srgb, srgbf, srgbt and srgbft keywords do not affect the way filter or transmit components are interpreted; these are always expected to be linear.

3.3.1.7.3 Color Keywords

The older keyword method of specifying a color is still useful and many users prefer it.

COLOR_KEYWORD_GROUP:
  [ COLOR_KEYWORD_ITEM ]...
  COLOR_KEYWORD_ITEM:
  COLOR_IDENTIFIER |
  red Red_Amount | blue Blue_Amount | green Green_Amount |
  filter Filter_Amount | transmit Transmit_Amount

Although the color keyword at the beginning is optional, it is more common to see it in this usage. This is followed by any of five additional keywords red, green, blue, filter, or transmit. Each of these component keywords is followed by a float expression. For example

color red 1.0 green 0.5

This specifies a color whose red component is 1.0 or 100% of full intensity and the green component is 0.5 or 50% of full intensity. Although the blue, filter and transmit components are not explicitly specified, they exist and are set to their default values of 0. The component keywords may be given in any order and if any component is unspecified its value defaults to zero. A COLOR_IDENTIFIER can also be specified but it should always be first in the group. See Common Color Pitfalls for details.

3.3.1.7.4 Color Identifiers

Color identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

COLOR_DECLARATION:
  #declare IDENTIFIER = COLOR; |
  #local IDENTIFIER = COLOR;

Where IDENTIFIER is the name of the identifier up to 40 characters long and COLOR is any valid specification.

Note: There should be a semi-colon at the end of the declaration. If omitted, it generates a warning and some macros may not work properly. See #declare vs. #local for information on identifier scope.

Here are some examples....

#declare White = rgb <1,1,1>;
#declare Cyan = color blue 1.0 green 1.0;
#declare Weird = rgb <Foo*2,Bar-1,Bob/3>;
#declare LightGray = White*0.8;
#declare LightCyan = Cyan red 0.6;

As the LightGray example shows you do not need any color keywords when creating color expressions based on previously declared colors. The last example shows you may use a color identifier with the keyword style syntax. Make sure that the identifier comes first before any other component keywords.

Like floats and vectors, you may re-define colors throughout a scene but the need to do so is rare.

3.3.1.7.5 Color Operators

Color vectors may be combined in expressions the same as float or vector values. Operations are performed on a component by component basis. For example rgb <1.0,0.5,0.2>*0.9 evaluates the same as rgb<1.0,0.5,0.2>*<0.9,0.9,0.9> or rgb<0.9,0.45,0.18>. Other operations are done on a similar component by component basis.

You may use the dot operator to extract a single component from a color. Suppose the identifier Shade was previously defined as a color. Then Shade.red is the float value of the red component of Shade. Similarly Shade.green, Shade.blue, Shade.filter and Shade.transmit extract the float value of the other color components. shade.gray returns the gray value of the color vector.

3.3.1.7.6 Common Color Pitfalls

The variety and complexity of color specification methods can lead to some common mistakes. Here are some things to consider when specifying a color.

When using filter transparency, the colors which come through are multiplied by the primary color components. For example if gray light such as rgb<0.9,0.9,0.9> passes through a filter such as rgbf<1.0,0.5,0.0,1.0> the result is rgb<0.9,0.45,0.0> with the red let through 100%, the green cut in half from 0.9 to 0.45 and the blue totally blocked. Often users mistakenly specify a clear object by

color filter 1.0

but this has implied red, green and blue values of zero. You have just specified a totally black filter so no light passes through. The correct way is either

color red 1.0  green 1.0  blue 1.0  filter 1.0

or

color transmit 1.0

In the 2nd example it does not matter what the rgb values are. All of the light passes through untouched. Another pitfall is the use of color identifiers and expressions with color keywords. For example...

color My_Color red 0.5

this substitutes whatever was the red component of My_Color with a red component of 0.5 however...

color My_Color + red 0.5

adds 0.5 to the red component of My_Color and even less obvious...

color My_Color * red 0.5

that cuts the red component in half as you would expect but it also multiplies the green, blue, filter and transmit components by zero! The part of the expression after the multiply operator evaluates to rgbft<0.5,0,0,0,0> as a full 5 component color.

The following example results in no change to My_Color.

color red 0.5 My_Color

This is because the identifier fully overwrites the previous value. When using identifiers with color keywords, the identifier should be first. Another issue to consider: some POV-Ray syntax allows full color specifications but only uses the rgb part. In these cases it is legal to use a float where a color is needed. For example:

finish { ambient 1 }

The ambient keyword expects a color so the value 1 is promoted to <1,1,1,1,1> which is no problem. However

pigment { color 0.4 }

is legal but it may or may not be what you intended. The 0.4 is promoted to <0.4,0.4,0.4,0.4,0.4> with the filter and transmit set to 0.4 as well. It is more likely you wanted...

pigment { color rgb 0.4 }

in which case a 3 component vector is expected. Therefore the 0.4 is promoted to <0.4,0.4,0.4,0.0,0.0> with default zero for filter and transmit. Finally there is another problem which arises when using color dot operators in #declare or #local directives. Consider the directive:

#declare MyColor = rgb <0.75, 0.5, 0.75>;
#declare RedAmt = MyColor.red;

Now RedAmt should be a float but unfortunately it is a color. POV-Ray looks at the first keyword after the equals to try to guess what type of identifier you want. It sees the color identifier MyColor and assumes you want to declare a color. It then computes the float value as 0.75 then promotes that into rgbft<0.75,0.75,0.75,0.75,0.75>. It would take a major rewrite to fix this problem so we are just warning you about it. Any of the following work-arounds will work properly.

#declare RedAmt = 0.0+MyColor.red;
#declare RedAmt = 1.0*MyColor.red;
#declare RedAmt = (MyColor.red);

3.3.1.8 Function

Some objects allow you to specify functions that will be evaluated while rendering to determine the surface of these objects. In this respect functions are quite different to macros, which are evaluated at parse time but do not otherwise affect rendering. Additionally you may call these functions anywhere a Float Function is allowed, even during parsing. The syntax is identical to Float Expressions, however, only float functions that apply to float values may be used. Excluded are for example strlen or vlength. You find a full list of supported float functions in the syntax definition below.

FLOAT:
  LOGIC_AND [OR LOGIC_AND]
OR:
  |
LOGIC_AND:
  REL_TERM [AND REL_TERM]
AND:
  &REL_TERM:
  TERM [REL_OPERATOR TERM]
REL_OPERATOR:
  < | <= | >= | > | = | !=
TERM:
  FACTOR [SIGN FACTOR]
SIGN:
  + | -
FACTOR:
  MOD_EXPRESSION [MULT MOD_EXPRESSION]
MULT:
  * | /
  EXPRESSION:
  FLOAT_LITERAL         |
  FLOAT_IDENTIFIER      |
  FLOAT_FUNCTION        |
  FLOAT_BUILT-IN_IDENT  |
  FUNCTION_IDENTIFIER   |
  ( FLOAT )             |
  IDENTIFIER            |
  SIGN EXPRESSION
  FLOAT_FUNCTION:
  abs( FLOAT ) | acos( FLOAT ) | acosh( FLOAT ) | asin( FLOAT ) |
  asinh( FLOAT ) | atan( FLOAT) | atanh( FLOAT) |
  atan2( FLOAT , FLOAT ) | ceil( FLOAT ) | cos( FLOAT ) |
  cosh( FLOAT ) | degrees( FLOAT ) | exp( FLOAT ) |
  floor( FLOAT ) | int( FLOAT ) | ln (Float) | log( FLOAT ) |
  max( FLOAT , FLOAT, ... ) | min( FLOAT , FLOAT, ... ) |
  mod( FLOAT , FLOAT ) | pow( FLOAT , FLOAT ) |
  radians( FLOAT ) | sin( FLOAT ) | sinh( FLOAT ) |
  sqrt( FLOAT ) | tan( FLOAT ) | tanh( FLOAT ) |
  select( FLOAT , FLOAT , FLOAT [, FLOAT] )
FUNCTION_IDENTIFIER:
  #local FUNCTION_IDENTIFIER = function { FLOAT }               |
  #declare FUNCTION_IDENTIFIER = function { FLOAT }             |
  #local FUNCTION_IDENTIFIER = function(IDENT_LIST) { FLOAT }   |
  #declare FUNCTION_IDENTIFIER = function(IDENT_LIST) { FLOAT } |
  #local FUNCTION_IDENTIFIER = function{SPECIAL_FLOAT_FUNCTION} |
  #local VECTOR_IDENTIFIER = function{SPECIAL_VECTOR_FUNCTION}  |
  #local COLOR_IDENTIFIER = function { SPECIAL_COLOR_FUNCTION } |
IDENT_LIST:
  IDENT_ITEM [, IDENT_LIST]
IDENT_ITEM:
  x | y | z | u | v | IDENTIFIER
  (Note: x = u and y = v)
SPECIAL_FLOAT_FUNCTION:
  pattern { PATTERN_BLOCK }
SPECIAL_VECTOR_FUNCTION:
  TRANSFORMATION_BLOCK | SPLINE
SPECIAL_COLOR_FUNCTION:
  PIGMENT
PATTERN_BLOCK:
  PATTERN

Note: Only the above mentioned items can be used in user-defined functions. For example the rand() function is not available.

All of the above mentioned float functions are described in the section Float Functions.

3.3.1.8.1 Sum and Product functions
 | sum(i, b, n, a)
The sum function. |

prod(i, b, n, a) |
 | The product function.

For both prod and sum: i is any variable name and a is any expression, usually depending on i. b and n are also any expression.

Note: Even though the following example demonstrates just one usage, both the prod and sum functions require a wrapper before use.

#declare factorial = function(C) { prod(i, 1, C, i) }
#declare A = factorial(5);

The first parameter is the name of the iteration variable. The second is the initial value expression and the third is the final value expression. Those may not depend on the iteration variable but the iteration variable may still be used inside those two expressions (because it happens to already have been defined) but its value is undefined. The last expression is the actual expression which will be iterated through. It may use any variable in scope.

The scope of an iteration variable is the sequence operation function. That is, a iteration variable is only defined when used inside the sum/prod function. Of course sum/prod functions may be nested. However, there is one limit of a maximum of 56 local variable defined simultaneously, which essentially means that in any combination sum/prod functions cannot be nested deeper than 56 levels.

The iteration variable is incremented by one for each step, but its initial and final value may be any value. The iteration will be continued as long as the iteration value is less or equal to the final value.

Note: Because the iteration value is a floating-point variable, adding one will add a certain bias in a long iterations and thus the floating-point precision will be an issue in such a case and needs to be considered by allowing a reasonable error for the final value!

If the expression to be added has a negative sign it will of course in effect be substracted. Thus changing the sign will allow to generate negative values in the sum function. Equally multiplying by 1/expression effectively creates a division when used in the prod function.

Obviously to work in the first place the initial value of the result is the neutral element of the operation. That is, a sum calculation starts with 0 and a product calculation starts with 1 just like it is assumed in the sum and product functions in 'regular' math.

It should be noted that mathematically either sum or product are redundant because:

log10(prod(i, b, n, a)) = sum(i, b, n, log10(a))

which implies a sum can be represented as a product and vice versa, observing the usual mathematical constraints of logarithms, of course. However, as logarithms and their inverse (powers) are slow to compute both are provided...

3.3.1.8.2 Functions and Macros

You can use macros in functions, but the macros will be called only once when the function is defined, not every time the function is called. You cannot pass function variables to the macros.

You can pass functions to macros, how to do this is best explained by an example:

#macro Foo( Bar, X )
#declare Y = Bar(X);
#declare Z = Bar(Y);
#end

#declare FUNC=function(n){n+2}

Foo(FUNC, 1)

#debug str(Y,5,5)
#debug "n"
#debug str(Z,5,5)
#debug "n"
3.3.1.8.3 Declaring User-Defined Float Functions

You declare a user defined function using the #declare or #local directives. By default a function takes three parameters and you do not have to explicitly specify the parameter names. The default three parameters are x, y and z. For example:

#declare foo = function { x + y * z }

If you need fewer or more parameters you have to explicitly specify the parameter list.

Note: The x and u as well as y and v keywords are equivalent so you may not specify both parameter names. You may not specify two or more parameters with the same name either. Doing so may result in a parse error or undefined function results.

The following are valid functions with parameters:

#declare foo2 = function(x, y, z) { x + y * z }
#declare foo3 = function(k1, k2, z, y) { x + y * z + k1 * y + k2 }
#declare foo4 = function(h) { h * h + h }
#declare foo4 = function(u, v) { x + y * v } //=u + v*v
#declare foo4 = function(x, v, z) { u + y * v + z } //=x + v*v + z

Limits:

  • The minimum number of parameters per function is 1.
  • The maximum number of allowed parameters per function is 56.
  • The maximum number of function blocks per scene is 1048575.
  • The maximum number of operators per function is about 200000. Individual limits will be different depending on the types of operators used in the function.
  • The maximum depth for nesting functions is 1024.
  • The maximum number of constants in all functions 1048575.

Note: Redeclaring functions, directly, is not allowed. The way to do this is to undef it first.

There is one special float function type. You may declare a pattern function.

Note: The syntax is identical to that of patterns, however, you may not specify colors. Its result is always a float and not a color vector, as returned by a function containing a pigment.

#declare foo = function {
  pattern {
    checker
    }
  }

Note: The number of parameters of special function types is determined automatically, so you do not need to specify parameter names.

3.3.1.8.4 Declaring User-Defined Vector Functions

Right now you may only declare vector functions using one of the special function types. Supported types are transform and spline functions. For example:

#declare foo = function {
  transform {
    rotate <90, 0, 0>
    scale 4
    }
  }

#declare myvector = foo(4, 3, 7);

#declare foo2 = function {
  spline {
    linear_spline
    0.0, <0,0,0>
    0.5, <1,0,0>
    1.0, <0,0,0>
    }
  }

#declare myvector2 = foo2(0.7);

Function splines take the vector size into account. That is, a function containing a spline with five components will also return a five component vector (aka a color), a function containing a spline with two components will only return a two component vector and so on.

Note: The number of parameters of special function types is determined automatically, so you do not need to specify parameter names.

3.3.1.8.5 Declaring User-Defined Color Functions

Right now you may only declare color functions using one of the special function types. The only supported type is the pigment function. You may use every valid pigment. This is a very simple example:

#declare foo = function {
  pigment {
    color red 1
    }
  }

#declare Vec = foo(1,2,3)

An example using a pattern:

#declare foo = function {
  pigment {
    crackle
    color_map {
      [0.3, color Red]
      [1.0, color Blue]
      }
    }
  }

#declare Val = foo(2,3,4).gray

Note: The number of parameters of special function types is determined automatically, so you do not need to specify parameter names.

3.3.1.8.6 Internal Pre-Defined Functions

Several functions are pre-defined. These internal functions can be accessed through the functions.inc, so it should be included in your scene. The number of required parameters and what they control are also given in the include file. See the functions.inc chapter in the Standard Include File section gives more information.

3.3.1.9 Strings

The POV-Ray language requires you to specify a string of characters to be used as a file name, text for messages or text for a text object. Strings may be specified using literals, identifiers or functions which return string values. See String Functions for details on string functions. Although you cannot build string expressions from symbolic operators such as are used with floats, vectors or colors, you may perform various string operations using string functions. Some applications of strings in POV-Ray allow for non-printing formatting characters such as newline or form-feed.

STRING:
  STRING_FUNCTION   |
  STRING_IDENTIFIER |
  STRING_LITERAL STRING_LITERAL:
  "up to 256 ASCII characters"
STRING_REL_TERM:
  STRING_LITERAL [STRING_REL_OPERATOR STRING_LITERAL]...
  STRING_REL_OPERATOR:
  < | <= | = | >= | > | !=
STRING_FUNCTION:
  str( FLOAT , INT , INT ) |
  concat( STRING , STRING , [STRING ,...]) | chr( INT ) |
  substr( STRING , INT , INT ) | strupr( STRING ) |
  strlwr( STRING ) | vstr( INT, VECTOR, STRING, INT, INT )
3.3.1.9.1 String Literals

String literals begin with a double quote mark '"' which is followed by up to 256 characters and are terminated by another double quote mark. You can change the character set of strings using the global_settings charset option. The following are all valid string literals:

"Here" "There" "myfile.gif" "textures.inc"

Note: If you need to specify a quote mark in a string literal you must precede it with a backslash.

Example

 "Joe said \"Hello\" as he walked in."

is converted to

 Joe said "Hello" as he walked in.

If you need to specify a backslash, you will have to specify two. For example:

 "This is a backslash \\ and this is two \\\\"

Is converted to:

This is a backslash \ and this is two \\

Windows users need to be especially wary about this as the backslash is also the windows path separator. For example, the following code does not produce the intended result:

#declare DisplayFont = "c:\windows\fonts\lucon.ttf"
  text { ttf DisplayFont "Hello", 2,0 translate y*1.50 }

New users might expect this to create a text object using the font c:\windows\fonts\lucon.ttf. Instead, it will give an error message saying that it cannot find the font file c:windowsontslucon.ttf.

The correct form of the above code is as follows:

#declare DisplayFont = "c:\\windows\\fonts\\lucon.ttf"
  text { ttf DisplayFont "Hello", 2,0 translate y*1.50 }

The escaping of backslashes occurs in all POV-Ray string literals. There are also other formatting codes such as \n for new line. See Text Formatting for details.

3.3.1.9.2 String Identifiers

String identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

STRING_DECLARATION:
  #declare IDENTIFIER = STRING |
  #local IDENTIFIER = STRING

Where IDENTIFIER is the name of the identifier up to 40 characters long and STRING is any valid string specification.

Note: Unlike floats, vectors, or colors, there need not be a semi-colon at the end of the declaration. See #declare vs. #local for information on identifier scope.

Here are some examples...

#declare Font_Name = "ariel.ttf"
#declare Inc_File = "myfile.inc"
#declare Name = "John"
#declare Name = concat(Name," Doe")

As the last example shows, you can re-declare a string identifier and may use previously declared values in that re-declaration.

3.3.1.9.3 String Relational Operators

POV-Ray supports the following string relational operators: < <= = >= > != and are subject to standard ASCII collating sequence rules.

Note: These relational operators are nothing more than a shortcut as they are an equivalent to calling the strcmp() function.

For example:

#if (string1 = string2)
  #declare Color = pigment {rgb <0, 1, 0>};
#else
  #declare Color = pigment {rgb <1, 0, 0>};
#end

Is the same as:

#if (strcmp(string1, string2) = 0)
  #declare Color = pigment {rgb <0, 1, 0>};
#else
  #declare Color = pigment {rgb <1, 0, 0>};
#end

This simple example shows just one usage:

// perspective (default) camera
camera {
  location  <0.0, 2.0, -5.0>
  look_at   <0.0, 0.0, 0.0>
  right     x*image_width/image_height
}

// create a regular point light source
light_source {
  0*x                  // light's position (translated below)
  color rgb <1,1,1>    // light's color
  translate <0, 20, -20>
}

background {rgb 1}

#declare TestCase = "ABC";

#if (TestCase < "ABD")
  #declare Color = pigment {rgb <0, 1, 0>};
#else
  #declare Color = pigment {rgb <1, 0, 0>};
#end

sphere {0,1 pigment {Color}}
3.3.1.9.4 String Functions

POV-Ray defines a variety of built-in functions for manipulating floats, vectors and strings. Function calls consist of a keyword which specifies the name of the function followed by a parameter list enclosed in parentheses. Parameters are separated by commas. For example:

keyword(param1,param2)

The following are the functions which return string values. They take one or more float, integer, vector, or string parameters. Assume that A is any valid expression that evaluates to a float; B, L, and P are floats which are truncated to integers internally, S, S1, S2 etc are strings.

chr(B) Character whose character value is B. Returns a single character string. The character value of the character is specified by an integer B which must be in the range 0 to 65535 if you specified charset utf8 in the global_settings and 0 to 127 if you specified charset ascii. Refer to your platform specific documentation if you specified charset sys. For example chr(70) is the string "F". When rendering text objects you should be aware that the characters rendered are dependent on the (TTF) font being used.

concat(S1,S2,...) concatenates strings S1 and S2. Returns a string that is the concatenation of all parameter strings. Must have at least 2 parameters but may have more. For example:

concat("Value is ", str(A,3,1), " inches")

If the float value A was 12.34321 the result is "Value is 12.3 inches", which is a string.

datetime() Can be used to return the date and time. It's syntax is:

datetime(FLOAT [,STRING])

when FLOAT uses the keyword now it will return a string which evaluates to the time elapsed since 2000-01-01, 00:00:00 GMT in days, with a precision of seconds or better. For example:

datetime(now)

The optional STRING parameter should conform to the same formatting as that of the strftime() C function.

The default for the STRING parameter format is %Y-%m-%d %H:%M:%SZ

str(A,L,P) Convert float A to a formatted string. Returns a formatted string representation of float value A. The integer parameter L specifies the minimum length of the string and the type of left padding used if the string's representation is shorter than the minimum. If L is positive then the padding is with blanks. If L is negative then the padding is with zeros. The overall minimum length of the formatted string is abs(L). If the string needs to be longer, it will be made as long as necessary to represent the value.

The integer parameter P specifies the number of digits after the decimal point. If P is negative then a compiler-specific default precision is use. Here are some examples:

str(123.456, 0, 3) "123.456"
str(123.456, 4, 3) "123.456"
str(123.456, 9, 3) "  123.456"
str(123.456,-9, 3) "00123.456"

str(123.456, 0, 2) "123.46"
str(123.456, 0, 0) "123"
str(123.456, 5, 0) "  123"
str(123.000, 7, 2) " 123.00"

str(123.456, 0,-1) "123.456000" (platform specific)

strlwr(S) Lower case of S. Returns a new string in which all upper case letters in the string S1 are converted to lower case. The original string is not affected. For example strlwr("Hello There!") results in "hello there!".

substr(S,P,L) Sub-string from S. Returns a string that is a subset of the characters in parameter S starting at the position specified by the integer value P for a length specified by the integer value L. For example substr("ABCDEFGHI",4,2) evaluates to the string "DE". If P+L-1>strlen(S) an error occurs.

strupr(S) Upper case of S. Returns a new string in which all lower case letters in the string S are converted to upper case. The original string is not affected. For example strupr("Hello There!") results in "HELLO THERE!".

vstr(N,A,S,L,P) Convert vector A to a formatted string. Returns a formatted string representation of vector A where the elements of the vector are separated by the string parameter S. The integer parameter N specifies the amount of dimensions in vector A. N is autoclipped to the range of 2 to 5, without warning. Specifying a vector A with more dimensions than given by N will result in an error.

The integer parameter L specifies the minimum length of the string and the type of left padding used if the string's representation is shorter than the minimum. The integer parameter P specifies the number of digits after the decimal point. If P is negative then a compiler-specific default precision is use. The function of L and P is the same as in str. Here are some examples:

vstr(2, <1,2>, ", ", 0,1)         "1.0, 2.0"
vstr(5, <1,2,3,4,5>, ", ", 0,1)   "1.0, 2.0, 3.0, 4.0, 5.0"
vstr(1, 1, ", ", 0,1)             "1.0, 1.0"
vstr(2, 1, ", ", 0,1)             "1.0, 1.0"
vstr(5, 1, ", ", 0,1)             "1.0, 1.0, 1.0, 1.0, 1.0"
vstr(7, 1, ", ", 0,1)             "1.0, 1.0, 1.0, 1.0, 1.0"
vstr(3, <1,2>, ", ", 0,1)         "1.0, 2.0, 0.0"
vstr(5, <1,2,3>, ", ", 0,1)       "1.0, 2.0, 3.0, 0.0, 0.0"
vstr(3, <1,2,3,4>, ", ", 0,1)     error

See section Float Functions for other functions which are somewhat string-related but which return floats. In addition to the above built-in functions, you may also define your own functions using the #macro directive. See the section User Defined Macros for more details.

3.3.1.9.5 Built-in Variables

At the moment there is only one built-in string variable. You can use it to specify values or to create expressions but you cannot re-declare it to change it's value.

File-related are:

STRING_BUILT-IN_IDENT:
  input_file_name

input_file_name
The name of the scene input file.

3.3.1.10 Array

You may declare arrays of identifiers of up to five dimensions. Any item that can be declared as an identifier can be declared in an array.

3.3.1.10.1 Declaring Arrays

The syntax for declaring an array is as follows:

ARRAY_DECLARATION:
  #declare IDENTIFIER = array[ INT ][[ INT ]]..[ARRAY_INITIALIZER] |
  #local IDENTIFIER = array[ INT ][[ INT ]]..[ARRAY_INITIALIZER]
ARRAY_INITIALIZER:
  {ARRAY_ITEM, [ARRAY_ITEM, ]... }
ARRAY_ITEM:
  RVALUE | ARRAY_INITIALIZER

Where IDENTIFIER is the name of the identifier up to 40 characters long and INT is a valid float expression which is internally truncated to an integer which specifies the size of the array. The optional ARRAY_INITIALIZER is discussed in the next section Array Initializers. Here is an example of a one-dimensional, uninitialized array.

#declare MyArray = array[10]

This declares an uninitialized array of ten elements. The elements are referenced as MyArray[0] through MyArray[9]. As yet, the type of the elements are undetermined. Once you have initialized any element of the array, all other elements can only be defined as that type. An attempt to reference an uninitialized element results in an error. For example:

#declare MyArray = array[10]
#declare MyArray[5] = pigment{White}     //all other elements must
                                         //be pigments too.
#declare MyArray[2] = normal{bumps 0.2}  //generates an error
#declare Thing = MyArray[4]              //error: uninitialized array element

Multi-dimensional arrays up to five dimensions may be declared. For example:

#declare MyGrid = array[4][5]

declares a 20 element array of 4 rows and 5 columns. Elements are referenced from MyGrid[0][0] to MyGrid[3][4]. Although it is permissible to reference an entire array as a whole, you may not reference just one dimension of a multi-dimensional array. For example:

#declare MyArray = array[10]
#declare MyGrid = array[4][5]
#declare YourArray = MyArray  //this is ok
#declare YourGrid = MyGrid    //so is this
#declare OneRow  = MyGrid[2]  //this is illegal

The #ifdef and #ifndef directives can be used to check whether a specific element of an array has been declared. For methods to determine the size of an array look in the float section for dimensions and dimension_size.

Large uninitialized arrays do not take much memory. Internally they are arrays of pointers so they probably use just 4 bytes per element. Once initialized with values, they consume memory depending on what you put in them.

The rules for local vs. global arrays are the same as any other identifier.

Note: This applies to the entire array. You cannot mix local and global elements in the same array. See #declare vs. #local for information on identifier scope.

Any legitimate use of the #declare directive can also be put into an array. In other words, you can also create multidimensional arrays by making an array of arrays.

3.3.1.10.2 Array Initializers

Because it is cumbersome to individually initialize the elements of an array, you may initialize it as it is created using array initializer syntax. For example:

#include "colors.inc"
#declare FlagColors = array[3] {Red,White,Blue}

Multi-dimensional arrays may also be initialized this way. For example:

#declare Digits =
array[4][10] {
  {7,6,7,0,2,1,6,5,5,0},
  {1,2,3,4,5,6,7,8,9,0},
  {0,9,8,7,6,5,4,3,2,1},
  {1,1,2,2,3,3,4,4,5,5}
  }

The commas are required between elements and between dimensions as shown in the example.

3.3.1.11 Spline

Splines give you a way to define 'pathways' through your scenes. You specify a series of points, and POV-Ray interpolates to make a curve connecting them. Every point along the spline has a numerical value. A good example of a spline is the path of a moving object: the spline itself would be the path traced out by the object and the 'parameter' would be time; as time changes the object's position moves along the spline. Therefore, given a time reference you could use this spline to find the position of the object. In fact, splines are very well suited to animation.

The syntax is:

SPLINE_DECLARATION:
  #declare IDENTIFIER =
    spline {
      [SPLINE_IDENTIFIER] |
      [SPLINE_TYPE] |
      [Val_1, <Point_1>[,]
      Val_2, <Point_2>[,]
      ...
      Val_n, <Point_n>]
      }

SPLINE_TYPE:
  linear_spline | quadratic_spline | cubic_spline | natural_spline

SPLINE_USAGE:
  MySpline(Val) | MySpline(Val, SPLINE_TYPE)

The first item gives the type of interpolation. In a linear_spline, straight lines connect each point. In a quadratic_spline, a smooth curve defined by a second-order polynomial connects each point, whereas with cubic_spline and natural_spline, a smooth curve defined by a third-order polynomial connects each point. The default is linear_spline.

Following this are a number of float values each followed by a position vector, all separated by commas. Val_1, Val_2, etc, are the value of the spline parameter at each specific point. The points need not be in order of their parameter values. If two points have the same parameter value, the second point will replace the first. Beyond the range of the lowest and highest parameter values, the spline position is fixed at the endpoints.

Note: Because of the way cubic splines are defined, the first and last points are tangents rather than points on the spline, cubic_spline interpolation is only valid between the second and next-to-last points. For all other spline types, interpolation is valid from the first point to the last point. For t-values outside the valid range, POV-Ray returns the value of the nearest valid point.

To use a spline, you place the spline identifier followed by the parameter (in parentheses) wherever you would normally put a vector, similar to a macro. Splines behave mostly like three-dimensional vectors.

Here is an example:

camera { location <0,2,-2> look_at 0 }
light_source { <-5,30,-10> 1 }

#declare MySpline =
spline {
  cubic_spline
    -.25, <0,0,-1>
    0.00, <1,0,0>
    0.25, <0,0,1>
    0.50, <-1,0,0>
    0.75, <0,0,-1>
    1.00, <1,0,0>
    1.25, <0,0,1>
    }

#declare ctr = 0;
#while (ctr < 1)
  sphere {
    MySpline(ctr),.25
    pigment { rgb <1-ctr,ctr,0> }
    }
  #declare ctr = ctr + 0.01;
#end

You can also have POV-Ray evaluate a spline as if it were a different type of spline by specifying the type of spline after the value to interpolate at, for example:

sphere{ <2,0,2>, .25 pigment{rgb MySpline(clock, linear_spline)}}

Splines are 'intelligent' when it comes to returning vectors. The vector with the most components in the spline determines the size of the returned vector. This allows vectors from two to five components to be returned by splines.

Also, function splines take the vector size into account. That is, a function containing a spline with five components will also return a five component vector (aka a color), a function containing a spline with two components will only return a two component vector and so on.

3.3.1.11.1 Splines and Macros

You can pass functions to macros, how to do this is best explained by an example

#macro Foo( Bar, Val )
  #declare Y = Bar(Val).y;
#end

#declare myspline =
  spline {
    1, <4,5>
    3, <5,5>
    5, <6,5>
    }

Foo(myspline, 2)

#debug str(Y,5,5)
#debug "\n"

3.3.1.12 Transformations

The supported transformations are rotate, scale, and translate. They are used to turn, size and move an object or texture. A transformation matrix may also be used to specify complex transformations directly. Groups of transformations may be merged together and stored in a transformation identifier.

The syntax for transformations is as follows:

TRANSFORMATION:
    rotate <Rotate_Amt> | scale <Scale_Amt> |
    translate <Translate_Amt> | transform TRANSFORM_IDENTIFIER |
    transform { TRANSFORMATION_BLOCK...} |
    matrix <Val00, Val01, Val02,
        Val10, Val11, Val12,
        Val20, Val21, Val22,
        Val30, Val31, Val32>
TRANSFORMATION_BLOCK:
    TRANSFORM_IDENTIFIER | TRANSFORMATION | inverse
TRANSFORM_DECLARATION:
    #declare IDENTIFIER = transform { TRANSFORMATION_BLOCK...} |
    #local IDENTIFIER = transform { TRANSFORMATION_BLOCK...}
3.3.1.12.1 Translate

Items may be moved by adding a translate modifier. It consists of the keyword translate followed by a vector expression. The three terms of the vector specify the number of units to move in each of the x, y and z directions. Translate moves the element relative to its current position.

For example:

 sphere { <10, 10, 10>, 1
  pigment { Green }
  translate <-5, 2, 1>
 }

will move the sphere from the location <10,10,10> to <5,12,11>. It does not move it to the absolute location <-5,2,1>. Translations are always relative to the item's location before the move. Translating by zero will leave the element unchanged on that axis.

For example:

 sphere { <10, 10, 10>, 1
  pigment { Green }
  translate 3*x // evaluates to <3,0,0> so move 3 units
         // in the x direction and none along y or z
 }
3.3.1.12.2 Scale

You may change the size of an object or texture pattern by adding a scale modifier. It consists of the keyword scale followed by a vector expression. The three terms of the vector specify the amount of scaling in each of the x, y and z directions.

Uneven scaling is used to stretch or squish an element. Values larger than one stretch the element on that axis while values smaller than one are used to squish it. Scale is relative to the current element size. If the element has been previously re-sized using scale then scale will size relative to the new size. Multiple scale values may used.

For example:

 sphere { <0,0,0>, 1
  scale <2,1,0.5>
 }

will stretch and smash the sphere into an ellipsoid shape that is twice the original size along the x-direction, remains the same size in the y-direction and is half the original size in the z-direction.

If a lone float expression is specified it is promoted to a three component vector whose terms are all the same. Thus the item is uniformly scaled by the same amount in all directions.

For example:

 object {
  MyObject
  scale 5 // Evaluates as <5,5,5> so uniformly scale
      // by 5 in every direction.
 }

When one of the scaling components is zero, POV-Ray changes this component to 1 since it assumes that 0 means no scaling in this direction. A warning "Illegal Value: Scale X, Y or Z by 0.0. Changed to 1.0." is issued.

3.3.1.12.3 Rotate

You may change the orientation of an object or texture pattern by adding a rotate modifier. It consists of the keyword rotate followed by a vector expression. The three terms of the vector specify the number of degrees to rotate about each of the x-, y- and z-axes.

Note: The order of the rotations does matter. Rotations occur about the x-axis first, then the y-axis, then the z-axis. If you are not sure if this is what you want then you should only rotate on one axis at a time using multiple rotation statements to get a correct rotation.

 rotate <0, 30, 0>  // 30 degrees around Y axis then,
 rotate <-20, 0, 0> // -20 degrees around X axis then,
 rotate <0, 0, 10>  // 10 degrees around Z axis.

Rotation is always performed relative to the axis. Thus if an object is some distance from the axis of rotation it will not only rotate but it will orbit about the axis as though it was swinging around on an invisible string.

POV-Ray uses a left-handed rotation system. Using the famous Computer Graphics Aerobics exercise, you hold up your left hand and point your thumb in the positive direction of the axis of rotation. Your fingers will curl in the positive direction of rotation. Similarly if you point your thumb in the negative direction of the axis your fingers will curl in the negative direction of rotation. See Understanding POV-Ray's Coordinate System for an illustration.

3.3.1.12.4 Matrix

The matrix keyword can be used to explicitly specify the transformation matrix to be used for objects or textures.

Its syntax is:

MATRIX:
    matrix <Val00, Val01, Val02,
        Val10, Val11, Val12,
        Val20, Val21, Val22,
        Val30, Val31, Val32>

Where Val00 through Val32 are float expressions enclosed in angle brackets and separated by commas.

Note: This is not a vector. It is a set of 12 float expressions.

These floats specify the elements of a 4 by 4 matrix with the fourth column implicitly set to <0,0,0,1>. At any given point P, P=<px, py, pz>, is transformed into the point Q, Q=<qx, qy, qz> by

qx = Val00 * px + Val10 * py + Val20 * pz + Val30

qy = Val01 * px + Val11 * py + Val21 * pz + Val31

qz = Val02 * px + Val12 * py + Val22 * pz + Val32

Normally you will not use the matrix keyword because it is less descriptive than the transformation commands and harder to visualize. However the matrix command allows more general transformation effects like shearing. The following matrix causes an object to be sheared along the y-axis.

 object {
  MyObject
  matrix < 1, 1, 0,
       0, 1, 0,
       0, 0, 1,
       0, 0, 0 >
 }

3.3.2 Language Directives

The POV Scene Language contains several statements called language directives which tell the file parser how to do its job. These directives can appear in almost any place in the scene file - even in the middle of some other statements. They are used to include other text files in the stream of commands, to declare identifiers, to define macros, conditional, or looped parsing and to control other important aspects of scene file processing.

Each directive begins with the hash character # (often called a number sign or pound sign). It is followed by a keyword and optionally other parameters.

In versions of POV-Ray prior to 3.0, the use of this # character was optional. Language directives could only be used between objects, camera or light_source statements and could not appear within those statements. The exception was the #include which could appear anywhere. Now that all language directives can be used almost anywhere, the # character is mandatory. The following keywords introduce language directives.

#break
#case
#debug
#declare
#default
#else
#elseif
         #end
#error
#fclose
#fopen
#for
#if
#ifdef
         #ifndef
#include
#local
#macro
#range
#read
#render
         #statistics
#switch
#undef
#version
#warning
#while
#write

Earlier versions of POV-Ray considered the keyword #max_intersections and the keyword #max_trace_level to be language directives but they have been moved to the global_settings statement and should be placed there without the # sign. Their use as a directive still works but it generates a warning and may be discontinued in the future.

3.3.2.1 Include Directive

The language allows include files to be specified by placing the line

#include "filename.inc"

at any point in the input file. The filename may be specified by any valid string expression but it usually is a literal string enclosed in double quotes. It may be up to 40 characters long (or your computer's limit), including the two double-quote characters.

The include file is read in as if it were inserted at that point in the file. Using include is almost the same as cutting and pasting the entire contents of this file into your scene.

Include files may be nested. You may have at most 10 nested include files. There is no limit on un-nested include files.

Generally, include files have data for scenes but are not scenes in themselves. By convention scene files end in .pov and include files end with .inc.

It is legal to specify drive and directory information in the file specification however it is discouraged because it makes scene files less portable between various platforms. Use of full lower case is also recommended but not required.

Note: If you ever intend to distribute any source files you make for POV-Ray, remember that some operating systems have case-sensitive file names).

It is typical to put standard include files in a special sub-directory. POV-Ray can only read files in the current directory or one referenced by the Library_Path option or +L switch. See the section Library Paths.

You may use the #local directive to declare identifiers which are temporary in duration and local to the include file in scope. For details see #declare vs. #local.

3.3.2.2 Declare and Local Directives

Identifiers may be declared and later referenced to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. There are several built-in identifiers which POV-Ray declares for you. See the sections: Built-in Variables and Built-in Vector Identifiers for details.

3.3.2.2.1 Declaring identifiers

An identifier is declared as follows.

DECLARATION:
  #declare [deprecated] IDENTIFIER = RVALUE |
  #local [deprecated] IDENTIFIER = RVALUE
RVALUE:
  FLOAT; | VECTOR; | COLOR; | STRING | OBJECT | TEXTURE |
  PIGMENT | NORMAL | FINISH | INTERIOR | MEDIA | DENSITY |
  COLOR_MAP | PIGMENT_MAP | SLOPE_MAP | NORMAL_MAP |
  DENSITY_MAP | CAMERA | LIGHT_SOURCE | FOG | RAINBOW |
  SKY_SPHERE | TRANSFORM

Note: See the section on Deprecation Support for more information

Where IDENTIFIER is the name of the identifier up to 40 characters long and RVALUE is any of the listed items. They are called that because they are values that can appear to the right of the equals sign. The syntax for each is in the corresponding section of this language reference. Here are some examples.

#declare Rows = 5;
#declare Count = Count+1;
#local  Here = <1,2,3>;
#declare White = rgb <1,1,1>;
#declare Cyan = color blue 1.0 green 1.0;
#declare Font_Name = "ariel.ttf"
#declare Rod = cylinder {-5*x,5*x,1}
#declare Ring = torus {5,1}
#local  Checks = pigment { checker White, Cyan }

object { Rod scale y*5 } // not "cylinder { Rod }"
object {
  Ring
  pigment { Checks scale 0.5 }
  transform Skew
  }

Note: There should be a semi-colon after the expression in all float, vector and color identifier declarations. This semi-colon is introduced in POV-Ray version 3.1. If omitted, it generates a warning and some macros may not work properly. Semicolons after other declarations are optional.

Declarations, like most language directives, can appear almost anywhere in the file - even within other statements. For example:

#declare Here=<1,2,3>;
#declare Count=0;               // initialize Count
  union {
    object { Rod translate Here*Count }
    #declare Count=Count+1;     // re-declare inside union
    object { Rod translate Here*Count }
    #declare Count=Count+1;     // re-declare inside union
    object { Rod translate Here*Count }
    }

As this example shows, you can re-declare an identifier and may use previously declared values in that re-declaration.

Note: Object identifiers use the generic wrapper statement object{ ... }. You do not need to know what kind of object it is.

Declarations may be nested inside each other within limits. In the example in the previous section you could declare the entire union as a object. However for technical reasons there are instances where you may not use any language directive inside the declaration of floats, vectors or color expressions. Although these limits have been loosened somewhat since POV-Ray 3.1, they still exist.

Identifiers declared within #macro ... #end blocks are not created at the time the macro is defined. They are only created at the time the macro is actually invoked. Like all other items inside such a #macro definition, they are ignored when the macro is defined.

3.3.2.2.2 declare vs. local

Identifiers may be declared either global using #declare or local using the #local directive.

Those created by the #declare directive are permanent in duration and global in scope. Once created, they are available throughout the scene and they are not released until all parsing is complete or until they are specifically released using #undef. See Destroying Identifiers.

Those created by the #local directive are temporary in duration and local in scope. They temporarily override any identifiers with the same name. See Identifier Name Collisions.

If #local is used inside a #macro then the identifier is local to that macro. When the macro is invoked and the #local directive is parsed, the identifier is created. It persists until the #end directive of the macro is reached. At the #end directive, the identifier is destroyed. Subsequent invocations of the macro create totally new identifiers.

Use of #local within an include file but not in a macro, also creates a temporary identifier that is local to that include file. When the include file is included and the #local directive is parsed, the identifier is created. It persists until the end of the include file is reached. At the end of file the identifier is destroyed. Subsequent inclusions of the file create totally new identifiers.

Use of #local in the main scene file (not in an include file and not in a macro) is identical to #declare. For clarity sake you should not use #local in a main file except in a macro.

There is currently no way to create permanent, yet local identifiers in POV-Ray.

Local identifiers may be specifically released early using #undef but in general there is no need to do so. See Destroying Identifiers.

3.3.2.2.3 Identifier Name Collisions

Local identifiers may have the same names as previously declared identifiers. In this instance, the most recent, most local identifier takes precedence. Upon entering an include file or invoking a macro, a new symbol table is created. When referencing identifiers, the most recently created symbol table is searched first, then the next most recent and so on back to the global table of the main scene file. As each macro or include file is exited, its table and identifiers are destroyed. Parameters passed by value reside in the same symbol table as the one used for identifiers local to the macro.

The rules for duplicate identifiers may seem complicated when multiple-nested includes and macros are involved, but in actual practice the results are generally what you intended.

Consider this example: You have a main scene file called myscene.pov and it contains

#declare A = 123;
#declare B = rgb<1,2,3>;
#declare C = 0;
#include "myinc.inc"

Inside the include file you invoke a macro called MyMacro(J,K,L). It is not important where MyMacro is defined as long as it is defined before it is invoked. In this example, it is important that the macro is invoked from within myinc.inc.

The identifiers A, B, and C are generally available at all levels. If either myinc.inc or MyMacro contain a line such as #declare C=C+1; then the value C is changed everywhere as you might expect.

Now suppose inside myinc.inc you do...

#local A = 546;

The main version of A is hidden and a new A is created. This new A is also available inside MyMacro because MyMacro is nested inside myinc.inc. Once you exit myinc.inc, the local A is destroyed and the original A with its value of 123 is now in effect. Once you have created the local A inside myinc.inc, there is no way to reference the original global A unless you #undef A or exit the include file. Using #undef always undefines the most local version of an identifier.

Similarly if MyMacro contained...

#local B = box{0,1}

then a new identifier B is created local to the macro only. The original value of B remains hidden but is restored when the macro is finished. The local B need not have the same type as the original.

The complication comes when trying to assign a new value to an identifier at one level that was declared local at an earlier level. Suppose inside myinc.inc you do...

#local D = 789;

If you are inside myinc.inc and you want to increment D by one, you might try to do...

#local D = D + 1;

but if you try to do that inside MyMacro you will create a new D which is local to MyMacro and not the D which is external to MyMacro but local to myinc.inc. Therefore you've said "create a MyMacro D from the value of myinc.inc's D plus one". That's probably not what you wanted. Instead you should do...

#declare D = D + 1;

You might think this creates a new D that is global but it actually increments the myinc.inc version of D. Confusing isn't it? Here are the rules:

  1. When referencing an identifier, you always get the most recent, most local version. By "referencing" we mean using the value of the identifier in a POV-Ray statement or using it on the right of an equals sign in either a #declare or #local.
  2. When declaring an identifier using the #local keyword, the identifier which is created or has a new value assigned, is ALWAYS created at the current nesting level of macros or include files.
  3. When declaring a NEW, NON-EXISTANT identifier using #declare, it is created as fully global. It is put in the symbol table of the main scene file.
  4. When ASSIGNING A VALUE TO AN EXISTING identifier using #declare, it assigns it to the most recent, most local version at the time.

In summary, #local always means "the current level", and #declare means "global" for new identifiers and "most recent" for existing identifiers.

3.3.2.2.4 Destroying Identifiers with undef

Identifiers created with #declare will generally persist until parsing is complete. Identifiers created with #local will persist until the end of the macro or include file in which they were created. You may however un-define an identifier using the #undef directive. For example:

#undef MyValue

If multiple local nested versions of the identifier exist, the most local most recent version is deleted and any identically named identifiers which were created at higher levels will still exist.

See also The #ifdef and #ifndef Directives.

3.3.2.2.5 Deprecation Support

The ability to add a deprecated flag to a #declare has been added. This is to aid in migrating scenes away from old constructs (e.g. old textures). The usage is illustrated below:

#declare deprecated Col_Glass_Old=color rgbf <0.8, 0.9, 0.85, 0.85>;
#declare deprecated once Col_Glass_Old=... etc
#declare deprecated "Some message" Col_Glass_Old=... etc

A deprecated identifier generates no message at the time it is declared, a warning is only issued if it is used.

If the optional once keyword is present it must immediately follow the deprecated keyword and indicates that the warning should only be displayed once per parse.

If the optional message string is present, it will be used as the warning to be displayed if the identifier is used. Otherwise, a message in the form "Identifier Col_Glass_Old was declared deprecated." is used.

An identifier is considered used if it is referenced anywhere (even if in another #declare).

3.3.2.3 File I/O Directives

You may open, read, write, append, and close plain ASCII text files while parsing POV-Ray scenes. This feature is primarily intended to help pass information between frames of an animation. Values such as an object's position can be written while parsing the current frame and read back during the next frame. Clever use of this feature could allow a POV-Ray scene to generate its own include files or write self-modifying scripts. We trust that users will come up with other interesting uses for this feature.

Note: Some platform versions of POV-Ray (e.g. Windows) provide means to restrict the ability of scene files to read and write files.

3.3.2.3.1 The fopen Directive

Users may open a text file using the #fopen directive. The syntax is as follows:

FOPEN_DIRECTIVE:
  #fopen FILE_HANDLE_IDENTIFIER "filename" OPEN_TYPE
OPEN_TYPE:
  read | write | append

Where FILE_HANDLE_IDENTIFIER is an undefined identifier used to reference this file as a file handle, "filename" is any string literal or string expression which specifies the file name. Files opened with the read are open for read only. Those opened with write create a new file with the specified name and it overwrites any existing file with that name. Those opened with append opens a file for writing but appends the text to the end of any existing file.

The file handle identifier created by #fopen is always global and remains in effect (and the file remains open) until the scene parsing is complete or until you #fclose the file. You may use #ifdef FILE_HANDLE_IDENTIFIER to see if a file is open.

3.3.2.3.2 The fclose Directive

Files opened with the #fopen directive are automatically closed when scene parsing completes however you may close a file using the #fclose directive. The syntax is as follows:

FCLOSE_DIRECTIVE:
  #fclose FILE_HANDLE_IDENTIFIER

Where FILE_HANDLE_IDENTIFIER is previously opened file opened with the #fopen directive.

3.3.2.3.3 The read Directive

You may read string, float or vector values from a plain ASCII text file directly into POV-Ray variables using the #read directive. The file must first be opened in read mode using the #fopen directive. The syntax for #read is as follows:

READ_DIRECTIVE:
  #read (FILE_HANDLE_IDENTIFIER, DATA_IDENTIFIER[,DATA_IDENTIFIER]..)
DATA_IDENTIFIER:
  UNDECLARED_IDENTIFIER | FLOAT_IDENTIFIER | VECTOR_IDENTIFIER |
  STRING_IDENTIFIER

Where FILE_HANDLE_IDENTIFIER is the previously opened file. It is followed by one or more DATA_IDENTIFIER(s) separated by commas. The parentheses around the identifier list are required. A DATA_IDENTIFIER is any undeclared identifier or any previously declared string identifier, float identifier, or vector identifier. Undefined identifiers will be turned into global identifiers of the type determined by the data which is read. Previously defined identifiers remain at whatever global/local status they had when originally created. Type checking is performed to insure that the proper type data is read into these identifiers.

The format of the data to be read must be a series of valid string literals, float literals, or vector literals separated by commas. Expressions or identifiers are not permitted in the data file however unary minus signs and exponential notation are permitted on float values.

If you attempt to read past end-of-file, the file is automatically closed and the FILE_HANDLE_IDENTIFIER is deleted from the symbol table. This means that the boolean function defined(FILE_HANDLE_IDENTIFIER) can be used to detect end-of-file.

For example:

#fopen FILE_HANDLE_IDENTIFIER "mydata.txt" read
#while (defined(FILE_HANDLE_IDENTIFIER))
  #read (FILE_HANDLE_IDENTIFIER,Var1,Var2,Var3)
  ...
#end
3.3.2.3.4 The write Directive

You may write string, float or vector values to a plain ASCII text file from POV-Ray variables using the #write directive. Additionally it is now possible to write 8, 16, and 32-bit words to an external file.

These words may be arranged in either little or big-endian fashion. Placing one of the following keywords in the argument list of a #write statement causes the values up to the next comma to be written in binary format, using 2's complement integer representation, rounded to the nearest integer in the representable range:

  uint8              - unsigned byte (0..255)
  sint8              - signed byte (-128..127)
  uint16be, uint16le - unsigned 16-bit word (0..65535)
  sint16be, sint16le - signed 16-bit word (-32768..32767)
  sint32be, sint32le - signed 32-bit word (-2^31..2^31-1)

Note: Currently, unsigned 32-bit words are not supported.

Keywords ending in "be" will cause the values to be written most significant byte first (big endian, aka network byte order) while those ending in "le" will instead write the least significant byte first (little endian, Intel format).

Note: See the sample macro ARRAYS_WriteDF3 in arrays.inc to see how this feature may be used.

As always, the file must first be opened in either write or append mode using the #fopen directive. The syntax for the #write directive is as follows:

WRITE_DIRECTIVE:
  #write (FILE_HANDLE_IDENTIFIER, [BINARY_WORD_TYPE,] DATA_ITEM [,DATA_ITEM]...)
BINARY_WORD_TYPE:
  uint8 | sint8 | uint16be | uint16le | sint16be | sint16le | sint32be | sint32le
DATA_ITEM:
  FLOAT | VECTOR | STRING

Where FILE_HANDLE_IDENTIFIER is the previously opened file. It is followed by one or more DATA_ITEM(s) separated by commas. The parentheses around the identifier list are required. A DATA_ITEM is any valid string expression, float expression, or vector expression. Float expressions are evaluated and written as signed float literals. If you require format control, you should use the str(VALUE,L,P) function to convert it to a formatted string. See String Functions for details on the str function. Vector expressions are evaluated into three signed float constants and are written with angle brackets and commas in standard POV-Ray vector notation. String expressions are evaluated and written as specified.

Note: Data read by the #read directive must have comma delimiters between values and quotes around string data but the #write directive does not automatically output commas or quotes.

For example the following #read directive reads a string, float and vector.

#read (FILE_HANDLE_IDENTIFIER,MyString,MyFloat,MyVect)

It expects to read something like:

"A quote delimited string", -123.45, <1,2,-3>

The POV-Ray code to write this might be:

#declare Val1 = -123.45;
#declare Vect1 = <1,2,-3>;
#write (FILE_HANDLE_IDENTIFIER,"\"A quote delimited string\",",Val1,",",Vect1,"\n")

See String Literals and Text Formatting for details on writing special characters such as quotes, newline, etc.

3.3.2.4 Default Directive

POV-Ray creates a default texture when it begins processing. You may change those defaults as described below. Every time you specify a texture statement, POV-Ray creates a copy of the default texture. Anything you put in the texture statement overrides the default settings. If you attach a pigment, normal, or finish to an object without any texture statement then POV-Ray checks to see if a texture has already been attached. If it has a texture then the pigment, normal or finish will modify the existing texture. If no texture has yet been attached to the object then the default texture is copied and the pigment, normal or finish will modify that texture.

You may change the default texture, pigment, normal or finish using the language directive #default as follows:

DEFAULT_DIRECTIVE:
  #default {DEFAULT_ITEM }
DEFAULT_ITEM:
  TEXTURE | PIGMENT | NORMAL | FINISH

For example:

#default {
  texture {
    pigment { rgb <1,0,0> }
    normal { bumps 0.3 }
    finish { ambient 0.4 }
    }
  }

This means objects will default to red bumps and slightly high ambient finish. You may also change just part of it like this:

#default {
  pigment {rgb <1,0,0>}
  }

This still changes the pigment of the default texture. At any time there is only one default texture made from the default pigment, normal and finish. The example above does not make a separate default for pigments alone.

Note: The special textures tiles and material_map or a texture with a texture_map may not be used as defaults.

You may change the defaults several times throughout a scene as you wish. Subsequent #default statements begin with the defaults that were in effect at the time. If you wish to reset to the original POV-Ray defaults then you should first save them as follows:

//At top of file
#declare Original_Default = texture {}

later after changing defaults you may restore it with...

#default {texture {Original_Default}}

If you do not specify a texture for an object then the default texture is attached when the object appears in the scene. It is not attached when an object is declared.

For example:

#declare My_Object =
sphere{ <0,0,0>, 1 } // Default texture not applied
object{ My_Object }        // Default texture added here

You may force a default texture to be added by using an empty texture statement as follows:

#declare My_Thing =
sphere { <0,0,0>, 1 texture {} } // Default texture applied

The original POV-Ray defaults for all items are given throughout the documentation under each appropriate section.

3.3.2.5 Version Directive

As POV-Ray has evolved from version 1.0 through 3.6 we have made every effort to maintain some amount of backwards compatibility with earlier versions. Some old or obsolete features can be handled directly without any special consideration by the user. Some old or obsolete features can no longer be handled at all. However some old features can still be used if you warn POV-Ray that this is an older scene. The #version directive can be used to switch version compatibility to different setting several times throughout a scene file. The syntax is:

VERSION_DIRECTIVE:
  #version FLOAT;

Note: There should be a semi-colon after the float expression in a #version directive. This semi-colon is introduced in POV-Ray version 3.1. If omitted, it generates a warning and some macros may not work properly.

Additionally you may use the Version=n.n option or the +MV n.n switch to establish the initial setting. See Language Version for details. For example, one feature introduced in 2.0 that was incompatible with any 1.0 scene files is the parsing of float expressions. Using #version 1.0 turns off expression parsing as well as many warning messages so that nearly all 1.0 files will still work. Naturally the default setting for this option is #version 3.5.

Note: Some obsolete or re-designed features are totally unavailable in the current version of POV-Ray REGARDLESS OF THE VERSION SETTING. Details on these features are noted throughout this documentation.

The built-in float identifier version contains the current setting of the version compatibility option. See Float Expressions: Built-in Variables. Together with the built-in version identifier the #version directive allows you to save and restore the previous values of this compatibility setting. The new #local identifier option is especially useful here. For example, suppose mystuff.inc is in version 1 format. At the top of the file you could put:

#local Temp_Vers = version;  // Save previous value
  #version 1.0;              // Change to 1.0 mode
    ... // Version 1.0 stuff goes here...
  #version Temp_Vers;        // Restore previous version

As of version 3.7, there has been a requirement implemented. In order to obtain full version 3.7 functionality, you MUST specify the #version 3.7 directive in your scene file. Prior to a #version directive appearing, the version defaults to 3.62. Additionally, if the first #version appears after any other declaration, or a #version directive does not appear at all, a post-parse warning is issued.

Warning: The version directive and command-line setting no longer provide compatibility with most rendering bugs in versions prior to POV-Ray 3.5. However, compatibility with the scene language is provided for scenes as old as POV-Ray 1.0 just as in all previous versions of POV-Ray. Nevertheless, we strongly recommend you update scenes at least to POV-Ray 3.5 syntax if you plan to use them in future versions of POV-Ray.

3.3.2.6 Conditional Directives

POV-Ray allows a variety of language directives to implement conditional parsing of various sections of your scene file. This is especially useful in describing the motion for animations but it has other uses as well. Also available is a #while loop directive. You may nest conditional directives 200 levels deep.

3.3.2.6.1 The if...else...end Directives

The simplest conditional directive is the traditional #if directive. The syntax is:

IF_DIRECTIVE:
  #if ( Cond ) TOKENS... [ELSE_DIRECTIVE] #end
ELSE_DIRECTIVE:
  #else TOKENS... |
  #elseif ( Cond ) TOKENS... [ELSE_DIRECTIVE]

The TOKENS are any number of POV-Ray keyword, identifiers, or punctuation and ( Cond ) is a float expression that is interpreted as a boolean value. The parentheses and the #end directive are required, an optional #elseif clause is now supported.

A value of 0.0 is false (numbers <= 1e-10 are also considered zero) while other any non-zero value is true.

For example:

#if (Foo)
  #debug "Foo is true\n"
#elseif (Bar)
  #debug "Foo is false, but Bar is true\n"
#else
  #debug "Foo and Bar are both false\n"
#end

Note: Nesting directives in the following manner has been known to cause problems during the parse phase.

#if( #if(yes) yes #end ) #end
3.3.2.6.2 The ifdef and ifndef Directives

The #ifdef and #ifndef directive are similar to the #if directive however they are used to determine if an identifier has been previously declared.

IFDEF_DIRECTIVE:
  #ifdef ( IDENTIFIER ) TOKENS... [ELSE_DIRECTIVE] #end
IFNDEF_DIRECTIVE:
  #ifndef ( IDENTIFIER ) TOKENS... [ELSE_DIRECTIVE] #end
ELSE_DIRECTIVE:
  #else TOKENS... |
  #elseif ( Cond ) TOKENS... [ELSE_DIRECTIVE]

If the IDENTIFIER exists then the first group of tokens is parsed normally and the second set is skipped. If false, the first set is skipped and the second set is parsed. This is especially useful for replacing an undefined item with a default.

For example:

#ifdef (User_Thing)
  // This section is parsed if the
  // identifier "User_Thing" was
  // previously declared
  object{User_Thing} // invoke identifier
#else
  // This section is parsed if the
  // identifier "User_Thing" was not
  // previously declared
  box{<0,0,0>,<1,1,1>} // use a default
#end
// End of conditional part

The #ifndef directive works the opposite. The first group is parsed if the identifier is not defined. As with the #if directive, the #else clause is optional and the #end directive is required.

The #ifdef and #ifndef directives can be used to determine whether a specific element of an array has been assigned.

#declare MyArray=array[10]
//#declare MyArray[0]=7;
#ifdef(MyArray[0])
  #debug "first element is assigned\n"
#else
  #debug "first element is not assigned\n"
#end

Note: Additionally, just like the #if directive, the #ifdef and #ifndef directives now also supports an #elseif clause.

3.3.2.6.3 The for Directive

A new #for loop construct is now available for simple loops incrementing Identifier from Start to End (inclusive) with the given Step size. The default Step size is +1.0.

The syntax is:

#for (Identifier, Start, End [, Step])
  //...
#end

Consider the following example:

#for (i,0,330,30)
  sphere { 0,1 translate <0,0,-10> rotate y*i }
#end

The Identifier (i in this case) starts at 0 and ends at 330 ... an optional step value of 30 was added.

Some additional notes:

  • If Step is negative, comparison will be automatically adjusted to match a countdown pattern.
  • Start, End and Step are evaluated only once.
  • The loop counter is a full-fledged local variable. Any local variable of the same name already defined before the loop will be overwritten without warning (note that in the main scene file, all local variables outside of macros are effectively global); inside the loop, any tampering with the variable is possible for effect, as long as it is defined as a local numeric variable at the end of each iteration.
  • After the loop has terminated, the variable will remain defined, typically holding the value End+Step.
  • The loop counter must not be an array element.

Note: See the end of the next section for more information about #break directive behavior.

3.3.2.6.4 The switch, case, range and break Directives

A more powerful conditional is the #switch directive. The syntax is as follows...

SWITCH_DIRECTIVE:
  #switch ( Switch_Value ) SWITCH_CLAUSE... [#else TOKENS...] #end
SWITCH_CLAUSE:
  #case( Case_Value ) TOKENS... [#break] |
  #range( Low_Value , High_Value ) TOKENS... [#break]

The TOKENS are any number of POV-Ray keyword, identifiers, or punctuation and ( Switch_Value ) is a float expression. The parentheses are required. The #end directive is required. The SWITCH_CLAUSE comes in two varieties. In the #case variety, the float Switch_Value is compared to the float Case_Value. If they are equal, the condition is true.

Note: Values whose difference is less than 1e-10 are considered equal in case of round off errors.

In the #range variety, Low_Value and High_Value are floats separated by a comma and enclosed in parentheses.

If Low_Value <= Switch_Value and Switch_Value <= High_Value then the condition is true.

In either variety, if the clause's condition is true, that clause's tokens are parsed normally and parsing continues until a #break, #else or #end directive is reached. If the condition is false, POV-Ray skips until another #case or #range is found.

There may be any number of #case or #range clauses in any order you want. If a clause evaluates true but no #break is specified, the parsing will fall through to the next #case or #range and that clause conditional is evaluated. Hitting #break while parsing a successful section causes an immediate jump to the #end without processing subsequent sections, even if a subsequent condition would also have been satisfied.

An optional #else clause may be the last clause. It is only executed if the clause before it was a false clause.

Additionally, within the #switch directive, the #else clause acts like a #range directive that encompasses any possible number. To avoid execution of the #else block, the preceding #case or #range directives must be ended with a #break statement.

Note: The above behavior applies only within the #switch directive.

For example:

#switch (VALUE)
  #case (TEST_1)
    // This section is parsed if VALUE=TEST_1
  #break //First case ends
  #case (TEST_2)
    // This section is parsed if VALUE=TEST_2
  #break //Second case ends
  #range (LOW_1,HIGH_1)
    // This section is parsed if (VALUE>=LOW_1)&(VALUE<=HIGH_1)
  #break //Third case ends
  #range (LOW_2,HIGH_2)
    // This section is parsed if (VALUE>=LOW_2)&(VALUE<=HIGH_2)
  #break //Fourth case ends
  #else
    // This section is parsed if no other case or
    // range is true.
#end

Note: As of version 3.7 the #break directive can now be used:

  • anywhere within a #case or #range block, to skip to the end of the #switch directive (previously, #break was only useful right before the next #case, #range or #else directive, to indicate that a slip-through was not desired).
  • anywhere within a loop block (both #while and #for), to terminate the loop.
  • anywhere within a #macro to preliminarily terminate the macro.

Example for the use in a loop:

#local R = seed(4711);
#for (I, 1, 100)
  #if (rand(R) < I/1000)
    #break // terminate loop early
  #end
  #debug concat(str(I,0,0), " iterations and counting\n")
#end

Where multiple #switch, loop and/or #macro blocks are nested, #break will leave only the innermost of these.

3.3.2.6.5 The while...end Directive

The #while directive is a looping feature that makes it easy to place multiple objects in a pattern or other uses.

WHILE_DIRECTIVE:
  #while ( Cond ) TOKENS... #end

The TOKENS are any number of POV-Ray keyword, identifiers, or punctuation marks which are the body of the loop. The #while directive is followed by a float expression that evaluates to a boolean value. A value of 0.0 is false and any non-zero value is true.

Note: Extremely small values of about 1e-10 are considered zero in case of round off errors.

The parentheses around the expression are required. If the condition is true parsing continues normally until an #end directive is reached. At the end, POV-Ray loops back to the #while directive and the condition is re-evaluated. Looping continues until the condition fails. When it fails, parsing continues after the #end directive.

Note: It is possible for the condition to fail the first time and the loop is totally skipped. It is up to the user to insure that something inside the loop changes so that it eventually terminates.

Here is a properly constructed loop example:

#declare Count=0;
#while (Count < 5)
  object { MyObject translate x*3*Count }
  #declare Count=Count+1;
#end

This example places five copies of MyObject in a row spaced three units apart in the x-direction.

Note: See the end of the previous section for more information about #break directive behavior.

3.3.2.7 User Message Directives

With the addition of conditional and loop directives, the POV-Ray language has the potential to be more like an actual programming language. This means that it will be necessary to have some way to see what is going on when trying to debug loops and conditionals. To fulfill this need we have added the ability to print text messages to the screen. You have a choice of five different text streams to use including the ability to generate a fatal error if you find it necessary. Limited formatting is available for strings output by this method.

3.3.2.7.1 Text Message Streams

The syntax for a text message is any of the following:

TEXT_STREAM_DIRECTIVE:
  #debug STRING | #error STRING | #warning STRING

Where STRING is any valid string of text including string identifiers or functions which return strings. For example:

#switch (clock*360)
  #range (0,180)
    #debug "Clock in 0 to 180 range\n"
  #break
  #range (180,360)
    #debug "Clock in 180 to 360 range\n"
  #break
  #else
    #warning "Clock outside expected range\n"
    #warning concat("Value is:",str(clock*360,5,0),"\n")
#end

There are seven distinct text streams that POV-Ray uses for output. You may output only to three of them. On some versions of POV-Ray, each stream is designated by a particular color. Text from these streams are displayed whenever it is appropriate so there is often an intermixing of the text. The distinction is only important if you choose to turn some of the streams off or to direct some of the streams to text files. On some systems you may be able to review the streams separately in their own scroll-back buffer. See Directing Text Streams to Files for details on re-directing the streams to a text file.

Here is a description of how POV-Ray uses each stream. You may use them for whatever purpose you want except note that use of the #error stream causes a fatal error after the text is displayed.

Debug: This stream displays debugging messages. It was primarily designed for developers but this and other streams may also be used by the user to display messages from within their scene files.

Error: This stream displays fatal error messages. After displaying this text, POV-Ray will terminate. When the error is a scene parsing error, you may be shown several lines of scene text that leads up to the error.

Warning: This stream displays warning messages during the parsing of scene files and other warnings. Despite the warning, POV-Ray can continue to render the scene.

The #render and #statistsics could be accessed in previous versions. Their output is now redirected to the #debug stream. The #banner and #status streams can not be accessed by the user.

3.3.2.7.2 Text Formatting

Some escape sequences are available to include non-printing control characters in your text. These sequences are similar to those used in string literals in the C programming language. The sequences are:

"\a" | Bell or alarm, | 0x07
"\b" | Backspace, | 0x08
"\f" | Form feed, | 0x0C
"\n" | New line (line feed) | 0x0A
"\r" | Carriage return | 0x0D
"\t" | Horizontal tab | 0x09
"\uNNNN" | Unicode character code NNNN | 0xNNNN
"\v" | Vertical tab | 0x0B
"\0" | Null | 0x00
"\\" | Backslash | 0x5C
"\'" | Single quote | 0x27
"\"" | Double quote | 0x22

For example:

#debug "This is one line.\nBut this is another\n"

Depending on what platform you are using, they may not be fully supported for console output. However they will appear in any text file if you re-direct a stream to a file.

3.3.2.8 User Defined Macros

POV-Ray 3.1 introduced user defined macros with parameters. This feature, along with the ability to declare #local variables, turned the POV-Ray Language into a fully functional programming language. Consequently, it is now possible to write scene generation tools in POV-Ray's own language that previously required external utilities.

3.3.2.8.1 The macro Directive

The syntax for declaring a macro is:

MACRO_DEFINITION:
  #macro IDENTIFIER ([PARAM_IDENT] [, PARAM_IDENT]... ) TOKENS... #end

Where IDENTIFIER is the name of the macro and PARAM_IDENT is a list of zero or more formal parameter identifiers separated by commas and enclosed by parentheses. The parentheses are required even if no parameters are specified.

The TOKENS are any number of POV-Ray keyword, identifiers, or punctuation marks which are the body of the macro. The body of the macro may contain almost any POV-Ray syntax items you desire. It is terminated by the #end directive.

Note: Any conditional directives such as #if...#end, #while...#end, etc. must be fully nested inside or outside the macro so that the corresponding #end directives pair-up properly.

A macro must be declared before it is invoked. All macro names are global in scope and permanent in duration. You may redefine a macro by another #macro directive with the same name. The previous definition is lost. Macro names respond to #ifdef, #ifndef, and #undef directives. See The #ifdef and #ifndef Directives and Destroying Identifiers with #undef.

3.3.2.8.2 Invoking Macros

You invoke the macro by specifying the macro name followed by a list of zero or more actual parameters enclosed in parentheses and separated by commas. The number of actual parameters must match the number of formal parameters in the definition. The parentheses are required even if no parameters are specified. The syntax is:

MACRO_INVOCATION:
  MACRO_IDENTIFIER ( [ACTUAL_PARAM] [, ACTUAL_PARAM]... )
ACTUAL_PARAM:
  IDENTIFIER | RVALUE

An RVALUE is any value that can legally appear to the right of an equals sign in a #declare or #local declaration. See Declaring identifiers for information on RVALUE. When the macro is invoked, a new local symbol table is created. The actual parameters are assigned to formal parameter identifiers as local, temporary variables. POV-Ray jumps to the body of the macro and continues parsing until the matching #end directive is reached. There, the local variables created by the parameters are destroyed as well as any local identifiers expressly created in the body of the macro. It then resumes parsing at the point where the macro was invoked. It is as though the body of the macro was cut and pasted into the scene at the point where the macro was invoked.

Note: It is possible to invoke a macro that was declared in another file. This is quite normal and in fact is how many plug-ins work (such as the popular Lens Flare macro). However, be aware that calling a macro that was declared in a file different from the one that it is being called from involves more overhead than calling one in the same file.

This is because POV-Ray does not tokenize and store its language. Calling a macro in another file therefore requires that the other file be opened and closed for each call. Normally, this overhead is inconsequential; however, if you are calling the macro many thousands of times, it can cause significant delays. A future version of the POV-Ray language will remove this problem.

Here is a simple macro that creates a window frame object when you specify the inner and outer dimensions.

#macro Make_Frame(OuterWidth,OuterHeight,InnerWidth,
        InnerHeight,Depth)
#local Horz = (OuterHeight-InnerHeight)/2;
#local Vert = (OuterWidth-InnerWidth)/2;
difference {
  box {
    <0,0,0>,<OuterWidth,OuterHeight,Depth>
    }
  box {
    <Vert,Horz,-0.1>,
    <OuterWidth-Vert,OuterHeight-Horz,Depth+0.1>
    }
  }
#end
Make_Frame(8,10,7,9,1) //invoke the macro

In this example, the macro has five float parameters. The actual parameters (the values 8, 10, 7, 9, and 1) are assigned to the five identifiers in the #macro formal parameter list. It is as though you had used the following five lines of code.

#local OuterWidth = 8;
#local OuterHeight = 10;
#local InnerWidth, = 7;
#local InnerHeight = 9;
#local Depth = 1;

These five identifiers are stored in the same symbol table as any other local identifier such as Horz or Vert in this example. The parameters and local variables are all destroyed when the #end statement is reached. See Identifier Name Collisions for a detailed discussion of how local identifiers, parameters, and global identifiers work when a local identifier has the same name as a previously declared identifier.

3.3.2.8.3 Are POV-Ray Macros a Function or a Macro?

POV-Ray macros are a strange mix of macros and functions. In traditional computer programming languages, a macro works entirely by token substitution. The body of the routine is inserted into the invocation point by simply copying the tokens and parsing them as if they had been cut and pasted in place. Such cut-and-paste substitution is often called macro substitution because it is what macros are all about. In this respect, POV-Ray macros are exactly like traditional macros in that they use macro substitution for the body of the macro. However traditional macros also use this cut-and-paste substitution strategy for parameters but POV-Ray does not.

Suppose you have a macro in the C programming language Typical_Cmac(Param) and you invoke it as Typical_Cmac(else A=B). Anywhere that Param appears in the macro body, the four tokens else, A, =, and B are substituted into the program code using a cut-and-paste operation. No type checking is performed because anything is legal. The ability to pass an arbitrary group of tokens via a macro parameter is a powerful (and sadly often abused) feature of traditional macros.

After careful deliberation, we have decided against this type of parameters for our macros. The reason is that POV-Ray uses commas more frequently in its syntax than do most programming languages. Suppose you create a macro that is designed to operate on one vector and two floats. It might be defined OurMac(V,F1,F2). If you allow arbitrary strings of tokens and invoke a macro such as OurMac(<1,2,3>,4,5) then it is impossible to tell if this is a vector and two floats or if its 5 parameters with the two tokens < and 1 as the first parameter. If we design the macro to accept 5 parameters then we cannot invoke it like this... OurMac(MyVector,4,5).

Function parameters in traditional programming languages do not use token substitution to pass values. They create temporary, local variables to store parameters that are either constant values or identifier references which are in effect a pointer to a variable. POV-Ray macros use this function-like system for passing parameters to its macros. In our example OurMac(<1,2,3>,4,5), POV-Ray sees the < and knows it must be the start of a vector. It parses the whole vector expression and assigns it to the first parameter exactly as though you had used the statement #local V=<1,2,3>;.

Although we say that POV-Ray parameters are more like traditional function parameters than macro parameters, there still is one difference. Most languages require you to declare the type of each parameter in the definition before you use it but POV-Ray does not. This should be no surprise because most languages require you to declare the type of any identifier before you use it but POV-Ray does not. This means that if you pass the wrong type value in a POV-Ray macro parameter, it may not generate an error until you reference the identifier in the macro body. No type checking is performed as the parameter is passed. So in this very limited respect, POV-Ray parameters are somewhat macro-like but are mostly function-like.

3.3.2.8.4 Returning a Value Like a Function

POV-Ray macros have a variety of uses. Like most macros, they provide a parameterized way to insert arbitrary code into a scene file. However most POV-Ray macros will be used like functions or procedures in a traditional programming language. Macros are designed to fill all of these roles.

When the body of a macro consists of statements that create an entire item such as an object, texture, etc. then the macro acts like a function which returns a single value. The Make_Frame macro example in the section Invoking Macros above is such a macro which returns a value that is an object. Here are some examples of how you might invoke it.

union {  //make a union of two objects
  object{ Make_Frame(8,10,7,9,1) translate  20*x}
  object{ Make_Frame(8,10,7,9,1) translate -20*x}
  }
#declare BigFrame = object{ Make_Frame(8,10,7,9,1)}
#declare SmallFrame = object{ Make_Frame(5,4,4,3,0.5)}

Because no type checking is performed on parameters and because the expression syntax for floats, vectors, and colors is identical, you can create clever macros which work on all three. See the sample scene MACRO3.POV which includes this macro to interpolate values.

// Define the macro.  Parameters are:
//   T:  Middle value of time
//   T1: Initial time
//   T2: Final time
//   P1: Initial position (may be float, vector or color)
//   P2: Final position (may be float, vector or color)
//   Result is a value between P1 and P2 in the same proportion
//    as T is between T1 and T2.
#macro Interpolate(T,T1,T2,P1,P2)
  (P1+(T1+T/(T2-T1))*(P2-P1))
#end

You might invoke it with P1 and P2 as floats, vectors, or colors as follows.

sphere{
  Interpolate(I,0,15,<2,3,4>,<9,8,7>), //center location is vector
  Interpolate(I,0,15,3.0,5.5)          //radius is float
  pigment {
    color Interpolate(I,0,15,rgb<1,1,0>,rgb<0,1,1>)
    }
  }

As the float value I varies from 0 to 15, the location, radius, and color of the sphere vary accordingly.

There is a danger in using macros as functions. In a traditional programming language function, the result to be returned is actually assigned to a temporary variable and the invoking code treats it as a variable of a given type. However macro substitution may result in invalid or undesired syntax. The definition of the macro Interpolate above has an outermost set of parentheses. If those parentheses are omitted, it will not matter in the examples above, but what if you do this...

#declare Value = Interpolate(I,0,15,3.0,5.5)*15;

The end result is as if you had done...

#declare Value = P1+(T1+T/(T2-T1))*(P2-P1) * 15;

which is syntactically legal but not mathematically correct because the P1 term is not multiplied. The parentheses in the original example solves this problem. The end result is as if you had done...

#declare Value = (P1+(T1+T/(T2-T1))*(P2-P1)) * 15;

which is correct.

3.3.2.8.5 Returning Values Via Parameters

Sometimes it is necessary to have a macro return more than one value or you may simply prefer to return a value via a parameter as is typical in traditional programming language procedures. POV-Ray macros are capable of returning values this way. The syntax for POV-Ray macro parameters says that the actual parameter may be an IDENTIFIER or an RVALUE. Values may only be returned via a parameter if the parameter is an IDENTIFIER. Parameters that are RVALUES are constant values that cannot return information. An RVALUE is anything that legally may appear to the right of an equals sign in a #declare or #local directive. For example consider the following trivial macro which rotates an object about the x-axis.

#macro Turn_Me(Stuff,Degrees)
  #declare Stuff = object{Stuff rotate x*Degrees}
#end

This attempts to re-declare the identifier Stuff as the rotated version of the object. However the macro might be invoked with Turn_Me(box{0,1},30) which uses a box object as an RVALUE parameter. This will not work because the box is not an identifier. You can however do this

#declare MyObject=box{0,1}
Turn_Me(MyObject,30)

The identifier MyObject now contains the rotated box.

See Identifier Name Collisions for a detailed discussion of how local identifiers, parameters, and global identifiers work when a local identifier has the same name as a previously declared identifier.

While it is obvious that MyObject is an identifier and box{0,1} is not, it should be noted that Turn_Me(object{MyObject},30) will not work because object{MyObject} is considered an object statement and is not a pure identifier. This mistake is more likely to be made with float identifiers versus float expressions. Consider these examples.

#declare Value=5.0;
MyMacro(Value)     //MyMacro can change the value of Value but...
MyMacro(+Value)    //This version and the rest are not lone
MyMacro(Value+0.0) // identifiers. They are float expressions
MyMacro(Value*1.0) // which cannot be changed.

Although all four invocations of MyMacro are passed the value 5.0, only the first may modify the value of the identifier.


Reference Section 4

3.4 Scene File Elements

This section details settings, camera types, objects, and textures used in POV-Ray scene files. It is divided into the following sub-sections:

  1. Global Settings
  2. Camera
  3. Atmospheric Effects
  4. LightingTypes
  5. Object
  6. Texture
  7. Pattern
  8. Media
  9. Include Files

3.4.1 Global Settings

The global_settings statement is a catch-all statement that gathers together a number of global parameters. The statement may appear anywhere in a scene as long as it is not inside any other statement. You may have multiple global_settings statements in a scene. Whatever values were specified in the last global_settings statement override any previous settings.

Note: Some items which were language directives in earlier versions of POV-Ray have been moved inside the global_settings statement so that it is more obvious to the user that their effect is global. The old syntax is permitted but generates a warning.

The new syntax is:

GLOBAL_SETTINGS:
  global_settings { [GLOBAL_SETTINGS_ITEMS...] }
GLOBAL_SETTINGS_ITEM:
  adc_bailout Value | ambient_light COLOR | assumed_gamma GAMMA_VALUE |
  hf_gray_16 [Bool] | irid_wavelength COLOR | charset GLOBAL_CHARSET |
  max_intersections Number | max_trace_level Number |
  mm_per_unit Number | number_of_waves Number | noise_generator Number |
  radiosity { RADIOSITY_ITEMS... } | subsurface { SUBSURFACE_ITEMS } |
  photon { PHOTON_ITEMS... }
GLOBAL_CHARSET:
  ascii | utf8 | sys
GAMMA_VALUE:
  Value | srgb

Global setting default values:

charset		   : ascii
adc_bailout	   : 1/255
ambient_light	   : <1,1,1>
assumed_gamma	   : 1.0 (undefined for legacy scenes)
hf_gray_16	   : deprecated
irid_wavelength	   : <0.25,0.18,0.14>
max_trace_level	   : 5
max_intersections  : 64
mm_per_unit        : 10
number_of_waves	   : 10
noise_generator	   : 2

Radiosity:
adc_bailout	   : 0.01
always_sample	   : off
brightness	   : 1.0
count		   : 35  (supports adaptive mode)
error_bound	   : 1.8
gray_threshold	   : 0.0
low_error_factor   : 0.5
max_sample	   : non-positive value
maximum_reuse      : 0.2
minimum_reuse	   : 0.015
nearest_count	   : 5   (max = 20; supports adaptive mode)
normal		   : off
pretrace_start	   : 0.08
pretrace_end	   : 0.04
recursion_limit	   : 2
subsurface 	   : off

Subsurface:
radiosity	   : off
samples		   : 50,50

Each item is optional and may appear in any order. If an item is specified more than once, the last setting overrides previous values. Details on each item are given in the following sections.

3.4.1.1 ADC_Bailout

In scenes with many reflective and transparent surfaces, POV-Ray can get bogged down tracing multiple reflections and refractions that contribute very little to the color of a particular pixel. The program uses a system called Adaptive Depth Control (ADC) to stop computing additional reflected or refracted rays when their contribution is insignificant.

You may use the global setting adc_bailout keyword followed by float value to specify the point at which a ray's contribution is considered insignificant. For example:

global_settings { adc_bailout 0.01 }

The default value is 1/255, or approximately 0.0039, since a change smaller than that could not be visible in a 24 bit image. Generally this setting is perfectly adequate and should be left alone. Setting adc_bailout to 0 will disable ADC, relying completely on max_trace_level to set an upper limit on the number of rays spawned.

See the section Max_Trace_Level for details on how ADC and max_trace_level interact.

3.4.1.2 Ambient_Light

Ambient light is used to simulate the effect of inter-diffuse reflection that is responsible for lighting areas that partially or completely lie in shadow. POV-Ray provides the ambient_light keyword to let you easily change the brightness of the ambient lighting without changing every ambient value in all finish statements. It also lets you create interesting effects by changing the color of the ambient light source. The syntax is:

global_settings { ambient_light COLOR }

The default is a white ambient light source set at rgb <1,1,1>. Only the rgb components are used. The actual ambient used is: Ambient = Finish_Ambient * Global_Ambient.

See the section Ambient for more information.

3.4.1.3 Assumed_Gamma

The assumed_gamma statement specifies a dsiplay gamma for which all color literals in the scene are presumed to be pre-corrected; at the same time it also defines the working gamma space in which POV-Ray will perform all its color computations.

Note: Using any value other than 1.0 will produce physically inaccurate results. Furthermore, if you decide to go for a different value for convenience, it is highly recommended to set this value to the same as your Display_Gamma. Using this parameter for artistic purposes is strongly discouraged.

Note: As of POV-Ray 3.7 this keyword is considered mandatory (except in legacy scenes) and consequently enables the experimental gamma handling feature. Future versions of POV-Ray may treat the absence of this keyword in non-legacy scenes as an error.

See section Gamma Handling for more information about gamma.

3.4.1.4 HF_Gray_16

Grayscale output can be used to generate heightfields for use in other POV-Ray scenes, and may be specified via Grayscale_Output=true as an INI option, or +Fxg (for output type 'x') as a command-line option. For example, +Fng for PNG and +Fpg for PPM (effectively PGM) grayscale output. By default this option is off.

Note: In version 3.7 the hf_gray_16 keyword in the global_settings block has been deprecated. If encountered, it has no effect on the output type and will additionally generate a warning message.

With Grayscale_Output=true, the output file will be in the form of a heightfield, with the height at any point being dependent on the brightness of the pixel. The brightness of a pixel is calculated in the same way that color images are converted to grayscale images: height = 0.3 * red + 0.59 * green + 0.11 * blue.

Setting the Grayscale_Output=true option will cause the preview display, if used, to be grayscale rather than color. This is to allow you to see how the heightfield will look because some file formats store heightfields in a way that is difficult to understand afterwards. See the section Height Field for a description of how POV-Ray heightfields are stored for each file type.

Caveat: Grayscale output implies the maximum bit-depth the format supports is 16, it is not valid to specify bits per color channel with 'g' (e.g. +Fng16 is not allowed, and nor for that matter is +Fn16g). If bits per channel is provided via an INI option, it is ignored.

Currently PNG, and PPM are the only file formats that support grayscale output.

3.4.1.5 Irid_Wavelength

Iridescence calculations depend upon the dominant wavelengths of the primary colors of red, green and blue light. You may adjust the values using the global setting irid_wavelength as follows...

global_settings { irid_wavelength COLOR }

The default value is rgb <0.70,0.52,0.48> and any filter or transmit values are ignored. These values are proportional to the wavelength of light but they represent no real world units.

In general, the default values should prove adequate but we provide this option as a means to experiment with other values.

3.4.1.6 Charset

This allows you to specify the assumed character set of all text strings. If you specify ascii only standard ASCII character codes in the range from 0 to 127 are valid. You can easily find a table of ASCII characters on the internet. The option utf8 is a special Unicode text encoding and it allows you to specify characters of nearly all languages in use today. We suggest you use a text editor with the capability to export text to UTF8 to generate input files. You can find more information, including tables with codes of valid characters on the »Unicode website The last possible option is to use a system specific character set. For details about the sys character set option refer to the platform specific documentation.

3.4.1.7 Max_Trace_Level

In scenes with many reflective and transparent surfaces POV-Ray can get bogged down tracing multiple reflections and refractions that contribute very little to the color of a particular pixel. The global setting max_trace_level defines the integer maximum number of recursive levels that POV-Ray will trace a ray.

global_settings { max_trace_level Level }

This is used when a ray is reflected or is passing through a transparent object and when shadow rays are cast. When a ray hits a reflective surface, it spawns another ray to see what that point reflects. That is trace level one. If it hits another reflective surface another ray is spawned and it goes to trace level two. The maximum level by default is five.

One speed enhancement added to POV-Ray in version 3.0 is Adaptive Depth Control (ADC). Each time a new ray is spawned as a result of reflection or refraction its contribution to the overall color of the pixel is reduced by the amount of reflection or the filter value of the refractive surface. At some point this contribution can be considered to be insignificant and there is no point in tracing any more rays. Adaptive depth control is what tracks this contribution and makes the decision of when to bail out. On scenes that use a lot of partially reflective or refractive surfaces this can result in a considerable reduction in the number of rays fired and makes it safer to use much higher max_trace_level values.

This reduction in color contribution is a result of scaling by the reflection amount and/or the filter values of each surface, so a perfect mirror or perfectly clear surface will not be optimizable by ADC. You can see the results of ADC by watching the Rays Saved and Highest Trace Level displays on the statistics screen.

The point at which a ray's contribution is considered insignificant is controlled by the adc_bailout value. The default is 1/255 or approximately 0.0039 since a change smaller than that could not be visible in a 24 bit image. Generally this setting is perfectly adequate and should be left alone. Setting adc_bailout to 0 will disable ADC, relying completely on max_trace_level to set an upper limit on the number of rays spawned.

If max_trace_level is reached before a non-reflecting surface is found and if ADC has not allowed an early exit from the ray tree the color is returned as black. Raise max_trace_level if you see black areas in a reflective surface where there should be a color.

The other symptom you could see is with transparent objects. For instance, try making a union of concentric spheres with a clear texture on them. Make ten of them in the union with radius's from 1 to 10 and render the scene. The image will show the first few spheres correctly, then black. This is because a new level is used every time you pass through a transparent surface. Raise max_trace_level to fix this problem.

Note: Raising max_trace_level will use more memory and time and it could cause the program to crash with a stack overflow error, although ADC will alleviate this to a large extent.

Values for max_trace_level can be set up to a maximum of 256. If there is no max_trace_level set and during rendering the default value is reached, a warning is issued.

3.4.1.8 Max_Intersections

POV-Ray uses a set of internal stacks to collect ray/object intersection points. The usual maximum number of entries in these I-Stacks is 64. Complex scenes may cause these stacks to overflow. POV-Ray does not stop but it may incorrectly render your scene. When POV-Ray finishes rendering, a number of statistics are displayed. If you see I-Stack overflows reported in the statistics you should increase the stack size. Add a global setting to your scene as follows:

global_settings { max_intersections Integer }

If the I-Stack Overflows remain increase this value until they stop.

3.4.1.9 Mm_Per_Unit

See the section Subsurface Light Transport for more information about the role of mm_per_unit in the global settings block.

3.4.1.10 Number_Of_Waves

The waves and ripples patterns are generated by summing a series of waves, each with a slightly different center and size. By default, ten waves are summed but this amount can be globally controlled by changing the number_of_waves setting.

global_settings { number_of_waves Integer }

Changing this value affects both waves and ripples alike on all patterns in the scene.

3.4.1.11 Noise_generator

There are three noise generators implemented.

  • noise_generator 1 the noise that was used in POV_Ray 3.1
  • noise_generator 2 'range corrected' version of the old noise, it does not show the plateaus seen with noise_generator 1
  • noise_generator 3 generates Perlin noise

The default is noise_generator 2

Note: The noise_generators can also be used within the pigment/normal/etc. statement.

3.4.1.12 Subsurface

See the section Subsurface Light Transport for more information about the role of subsurface in the global settings block.

3.4.2 Camera

The camera definition describes the position, projection type and properties of the camera viewing the scene. Its syntax is:

CAMERA:
  camera{ [CAMERA_ITEMS...] }
CAMERA_ITEMS:
  CAMERA_TYPE | CAMERA_VECTOR | CAMERA_MODIFIER |
  CAMERA_IDENTIFIER
CAMERA_TYPE:
  perspective | orthographic | mesh_camera{MESHCAM_MODIFIERS} | fisheye | ultra_wide_angle |
  omnimax | panoramic | cylinder CylinderType | spherical
CAMERA_VECTOR:
  location <Location> | right <Right> | up <Up> |
  direction <Direction> | sky <Sky>
CAMERA_MODIFIER:
  angle HORIZONTAL [VERTICAL] | look_at <Look_At> |
  blur_samples [MIN_SAMPLES,] MAX_SAMPLES | aperture Size |
  focal_point <Point> | confidence Blur_Confidence |
  variance Blur_Variance | [bokeh{pigment{BOKEH}}] |
  NORMAL | TRANSFORMATION | [MESHCAM_SMOOTH]
MESHCAM_MODIFIERS:
  rays per pixel & distribution type & [max distance] & MESH_OBJECT & [MESH_OBJECT...]
BOKEH:
  a COLOR_VECTOR in the range of <0,0,0> ... <1,1,0>
MESHCAM_SMOOTH:
  optional smooth modifier valid only when using mesh_camera

Camera default values:

DEFAULT CAMERA:
camera {
  perspective
  location <0,0,0>
  direction <0,0,1>
  right 1.33*x
  up y
  sky <0,1,0>
  }

CAMERA TYPE: perspective
  angle      : ~67.380 ( direction_length=0.5*
             right_length/tan(angle/2) )
  confidence : 0.9 (90%)
  direction  : <0,0,1>
  focal_point: <0,0,0>
  location   : <0,0,0>
  look_at    : z
  right      : 1.33*x
  sky        : <0,1,0>
  up         : y
  variance   : 1/128

Depending on the projection type zero or more of the parameters are required:

  • If no camera is specified the default camera is used.
  • If no projection type is given the perspective camera will be used (pinhole camera).
  • The CAMERA_TYPE has to be the first item in the camera statement.
  • Other CAMERA_ITEMs may legally appear in any order.
  • For other than the perspective camera, the minimum that has to be specified is the CAMERA_TYPE, the cylindrical camera also requires the CAMERA_TYPE to be followed by a float.
  • The Orthographic camera has two 'modes'. For the pure orthographic projection up or right have to be specified. For an orthographic camera, with the same area of view as a perspective camera at the plane which goes through the look_at point, the angle keyword has to be use. A value for the angle is optional.
  • All other CAMERA_ITEMs are taken from the default camera, unless they are specified differently.

3.4.2.1 Placing the Camera

The POV-Ray camera has 9 different models and they are as follows:

  1. perspective
  2. orthographic
  3. mesh
  4. fisheye
  5. ultra-wide angle
  6. onmimax
  7. panoramic
  8. cylindrical
  9. spherical

Each of which uses a different projection method to project the scene onto your screen. Regardless of the projection type all cameras use location, right, up, direction, and other keywords to determine the location and orientation of the camera. The type keywords and these four vectors fully define the camera. All other camera modifiers adjust how the camera does its job. The meaning of these vectors and other modifiers differ with the projection type used. A more detailed explanation of the camera types follows later. In the sub-sections which follows, we explain how to place and orient the camera by the use of these four vectors and the sky and look_at modifiers. You may wish to refer to the illustration of the perspective camera below as you read about these vectors.

Basic (default) camera geometry
3.4.2.1.1 Location and Look_At

Under many circumstances just two vectors in the camera statement are all you need to position the camera: location and look_at vectors. For example:

camera {
  location <3,5,-10>
  look_at <0,2,1>
  }

The location is simply the x, y, z coordinates of the camera. The camera can be located anywhere in the ray-tracing universe. The default location is <0,0,0>. The look_at vector tells POV-Ray to pan and tilt the camera until it is looking at the specified x, y, z coordinates. By default the camera looks at a point one unit in the z-direction from the location.

The look_at modifier should almost always be the last item in the camera statement. If other camera items are placed after the look_at vector then the camera may not continue to look at the specified point.

3.4.2.1.2 The Sky Vector

Normally POV-Ray pans left or right by rotating about the y-axis until it lines up with the look_at point and then tilts straight up or down until the point is met exactly. However you may want to slant the camera sideways like an airplane making a banked turn. You may change the tilt of the camera using the sky vector. For example:

camera {
  location <3,5,-10>
  sky   <1,1,0>
  look_at <0,2,1>
  }

This tells POV-Ray to roll the camera until the top of the camera is in line with the sky vector. Imagine that the sky vector is an antenna pointing out of the top of the camera. Then it uses the sky vector as the axis of rotation left or right and then to tilt up or down in line with the sky until pointing at the look_at point. In effect you are telling POV-Ray to assume that the sky isn't straight up.

The sky vector does nothing on its own. It only modifies the way the look_at vector turns the camera. The default value is sky<0,1,0>.

3.4.2.1.3 Angles

The angle keyword followed by a float expression specifies the (horizontal) viewing angle in degrees of the camera used. Even though it is possible to use the direction vector to determine the viewing angle for the perspective camera it is much easier to use the angle keyword.

When you specify the angle, POV-Ray adjusts the length of the direction vector accordingly. The formula used is direction_length = 0.5 * right_length / tan(angle / 2) where right_length is the length of the right vector. You should therefore specify the direction and right vectors before the angle keyword. The right vector is explained in the next section.

There is no limitation to the viewing angle except for the perspective projection. If you choose viewing angles larger than 360 degrees you will see repeated images of the scene (the way the repetition takes place depends on the camera). This might be useful for special effects.

The spherical camera has the option to also specify a vertical angle. If not specified it defaults to the horizontal angle/2

For example if you render an image with a 2:1 aspect ratio and map it to a sphere using spherical mapping, it will recreate the scene. Another use is to map it onto an object and if you specify transformations for the object before the texture, say in an animation, it will look like reflections of the environment (sometimes called environment mapping).

3.4.2.1.4 The Direction Vector

You will probably not need to explicitly specify or change the camera direction vector but it is described here in case you do. It tells POV-Ray the initial direction to point the camera before moving it with the look_at or rotate vectors (the default value is direction<0,0,1>). It may also be used to control the (horizontal) field of view with some types of projection. The length of the vector determines the distance of the viewing plane from the camera's location. A shorter direction vector gives a wider view while a longer vector zooms in for close-ups. In early versions of POV-Ray, this was the only way to adjust field of view. However zooming should now be done using the easier to use angle keyword.

If you are using the ultra_wide_angle, panoramic, or cylindrical projection you should use a unit length direction vector to avoid strange results. The length of the direction vector does not matter when using the orthographic, fisheye, or omnimax projection types.

3.4.2.1.5 Up and Right Vectors

The primary purpose of the up and right vectors is to tell POV-Ray the relative height and width of the view screen. The default values are:

right 4/3*x
up y

In the default perspective camera, these two vectors also define the initial plane of the view screen before moving it with the look_at or rotate vectors. The length of the right vector (together with the direction vector) may also be used to control the (horizontal) field of view with some types of projection. The look_at modifier changes both the up and right vectors. The angle calculation depends on the right vector.

Most camera types treat the up and right vectors the same as the perspective type. However several make special use of them. In the orthographic projection: The lengths of the up and right vectors set the size of the viewing window regardless of the direction vector length, which is not used by the orthographic camera.

When using cylindrical projection: types 1 and 3, the axis of the cylinder lies along the up vector and the width is determined by the length of right vector or it may be overridden with the angle vector. In type 3 the up vector determines how many units high the image is. For example if you have up 4*y on a camera at the origin. Only points from y=2 to y=-2 are visible. All viewing rays are perpendicular to the y-axis. For type 2 and 4, the cylinder lies along the right vector. Viewing rays for type 4 are perpendicular to the right vector.

Note: The up, right, and direction vectors should always remain perpendicular to each other or the image will be distorted. If this is not the case a warning message will be printed. The vista buffer will not work for non-perpendicular camera vectors.

3.4.2.1.6 Aspect Ratio

Together the up and right vectors define the aspect ratio (height to width ratio) of the resulting image. The default values up<0,1,0> and right<1.33,0,0> result in an aspect ratio of 4 to 3. This is the aspect ratio of a typical computer monitor. If you wanted a tall skinny image or a short wide panoramic image or a perfectly square image you should adjust the up and right vectors to the appropriate proportions.

Most computer video modes and graphics printers use perfectly square pixels. For example Macintosh displays and IBM SVGA modes 640x480, 800x600 and 1024x768 all use square pixels. When your intended viewing method uses square pixels then the width and height you set with the Width and Height options or +W or +H switches should also have the same ratio as the up and right vectors.

Note: 640/480 = 4/3 so the ratio is proper for this square pixel mode.

Not all display modes use square pixels however. For example IBM VGA mode 320x200 and Amiga 320x400 modes do not use square pixels. These two modes still produce a 4/3 aspect ratio image. Therefore images intended to be viewed on such hardware should still use 4/3 ratio on their up and right vectors but the pixel settings will not be 4/3.

For example:

camera {
  location <3,5,-10>
  up    <0,1,0>
  right  <1,0,0>
  look_at <0,2,1>
  }

This specifies a perfectly square image. On a square pixel display like SVGA you would use pixel settings such as +W480 +H480 or +W600 +H600. However on the non-square pixel Amiga 320x400 mode you would want to use values of +W240 +H400 to render a square image.

The bottom line issue is this: the up and right vectors should specify the artist's intended aspect ratio for the image and the pixel settings should be adjusted to that same ratio for square pixels and to an adjusted pixel resolution for non-square pixels. The up and right vectors should not be adjusted based on non-square pixels.

3.4.2.1.7 Handedness

The right vector also describes the direction to the right of the camera. It tells POV-Ray where the right side of your screen is. The sign of the right vector can be used to determine the handedness of the coordinate system in use. The default value is: right<1.33,0,0>. This means that the +x-direction is to the right. It is called a left-handed system because you can use your left hand to keep track of the axes. Hold out your left hand with your palm facing to your right. Stick your thumb up. Point straight ahead with your index finger. Point your other fingers to the right. Your bent fingers are pointing to the +x-direction. Your thumb now points into +y-direction. Your index finger points into the +z-direction.

To use a right-handed coordinate system, as is popular in some CAD programs and other ray-tracers, make the same shape using your right hand. Your thumb still points up in the +y-direction and your index finger still points forward in the +z-direction but your other fingers now say the +x-direction is to the left. That means that the right side of your screen is now in the -x-direction. To tell POV-Ray to act like this you can use a negative x value in the right vector such as: right<-1.33,0,0>. Since having x values increasing to the left does not make much sense on a 2D screen you now rotate the whole thing 180 degrees around by using a positive z value in your camera's location. You end up with something like this.

camera {
  location <0,0,10>
  up    <0,1,0>
  right  <-1.33,0,0>
  look_at <0,0,0>
  }

Now when you do your ray-tracer's aerobics, as explained in the section Understanding POV-Ray's Coordinate System, you use your right hand to determine the direction of rotations.

In a two dimensional grid, x is always to the right and y is up. The two versions of handedness arise from the question of whether z points into the screen or out of it and which axis in your computer model relates to up in the real world.

Architectural CAD systems, like AutoCAD, tend to use the God's Eye orientation that the z-axis is the elevation and is the model's up direction. This approach makes sense if you are an architect looking at a building blueprint on a computer screen. z means up, and it increases towards you, with x and y still across and up the screen. This is the basic right handed system.

Stand alone rendering systems, like POV-Ray, tend to consider you as a participant. You are looking at the screen as if you were a photographer standing in the scene. The up direction in the model is now y, the same as up in the real world and x is still to the right, so z must be depth, which increases away from you into the screen. This is the basic left handed system.

3.4.2.1.8 Transforming the Camera

The various transformations such as translate and rotate modifiers can re-position the camera once you have defined it. For example:

camera {
  location < 0, 0, 0>
  direction < 0, 0, 1>
  up    < 0, 1, 0>
  right   < 1, 0, 0>
  rotate  <30, 60, 30>
  translate < 5, 3, 4>
  }

In this example, the camera is created, then rotated by 30 degrees about the x-axis, 60 degrees about the y-axis and 30 degrees about the z-axis, then translated to another point in space.

3.4.2.2 Types of Projection

 | The following sections explain the different projection types that can be used with the scene camera. The most common types are the perspective and orthographic projections. The CAMERA_TYPE should be the first item in a camera statement. If none is specified, the perspective camera is the default.
The camera sample scene global view |

Note: The vista buffer feature can only be used with the perspective and orthographic camera.

3.4.2.2.1 Perspective projection

The perspective keyword specifies the default perspective camera which simulates the classic pinhole camera. The horizontal viewing angle is either determined by the ratio between the length of the direction vector and the length of the right vector or by the optional keyword angle, which is the preferred way. The viewing angle has to be larger than 0 degrees and smaller than 180 degrees.

The perspective projection diagram | A perspective camera sample image

Note: The angle keyword can be used as long as less than 180 degrees. It recomputes the length of right and up vectors using direction. The proper aspect ratio between the up and right vectors is maintained.

3.4.2.2.2 Orthographic projection

The orthographic camera offers two modes of operation:

The pure orthographic projection. This projection uses parallel camera rays to create an image of the scene. The area of view is determined by the lengths of the right and up vectors. One of these has to be specified, they are not taken from the default camera. If omitted the second method of the camera is used.

If, in a perspective camera, you replace the perspective keyword by orthographic and leave all other parameters the same, you will get an orthographic view with the same image area, i.e. the size of the image is the same. The same can be achieved by adding the angle keyword to an orthographic camera. A value for the angle is optional. So this second mode is active if no up and right are within the camera statement, or when the angle keyword is within the camera statement.

You should be aware though that the visible parts of the scene change when switching from perspective to orthographic view. As long as all objects of interest are near the look_at point they will be still visible if the orthographic camera is used. Objects farther away may get out of view while nearer objects will stay in view.

If objects are too close to the camera location they may disappear. Too close here means, behind the orthographic camera projection plane (the plane that goes through the location point).

The orthographic projection diagram | An orthographic camera sample image

Note: The length of direction is irrelevant unless angle is used. The lengths of up and right define the dimensions of the view. The angle keyword can be used, as long as less than 180. It will override the length of the right and up vectors (the aspect ratio between up and right will be kept nevertheless) with a scope of a perspective camera having the same direction and angle.

3.4.2.2.3 Mesh projection

The mesh projection is a special camera type that allows complete control of the ray origin and direction for each pixel of the output image. The basic concept is to associate pixels with faces defined within a previously declared mesh or mesh2 object. The MESH_OBJECT_IDENTIFIER need not be instantiated in the scene, though it can be, and doing so can lead to some interesting uses, such as texture baking or illumination calculations.

In its simplest form, each pixel of the output image is assigned to a face of the mesh according to (width * (int) y) + (int) x, however, more complex mapping is possible via multiple meshes and multiple rays per pixel. The type of mapping in use is determined by the distribution type parameter in the camera declaration. Except for mapping #3, the ray origin will be set to the centroid of the face, and the direction will be that of the face's normal. For mapping #3, barycentric co-ordinates are determined from the UV co-ordinates of the first face to match the X and Y position, and those are then converted to a position on the face which will serve as the ray origin. Support is provided to move the origin off the face along the normal, and to reverse the ray direction.

For most of the distribution methods, any POV feature that causes sub-pixel positioning to be used for shooting rays (e.g. anti-aliasing or jitter) will not do anything useful, because X and Y are converted to integers for indexing purposes. At this time, no warning is issued if anti-aliasing or jitter is requested when rendering a non-applicable distribution; this may be added later.

The syntax for the mesh camera is as follows:

camera {
  mesh_camera {
    rays per pixel
    distribution type
    [max distance]
    mesh {
      MESH_OBJECT_IDENTIFIER
      [TRANSFORMATIONS]
    }
    [mesh ...]
  }
  [location]
  [direction]
  [smooth]
  }

Note: The mesh camera is an experimental feature introduced in version 3.7 beta 39 and its syntax is likely to change. Additionally, many of the normal camera concepts presented in this section (such as location and direction) either do not work as they do for other cameras or do not work at all (for example, the concept of 'up' simply does not apply to a mesh camera). It should also be kept in mind that the camera has not yet been tested with many of POV-Ray's advanced features such as photons and radiosity, and more work in that area is likely to be needed.

3.4.2.2.3.1 Rays Per Pixel

This float parameter controls the number of rays that will be shot for each pixel in the output image. Each distribution allows different values, but the minimum is always 1.

3.4.2.2.3.2 Distribution Type

This float parameter controls how pixels are assigned to faces as documented below:

  • distribution #0

This method allows single or multiple rays per pixel, with the ray number for that pixel allocated to each mesh in turn. The index into the meshes is the ray number, where rays per pixel is greater than one, and the index into the selected mesh is the pixel number within the output image. If there is no face at that pixel position, the resulting output pixel is unaffected.

You must supply at least as many meshes as rays per pixel. Each pixel is shot rays per pixel times, and the results averaged. Any ray that does not correspond with a face (i.e. the pixel number is greater than or equal to the face count) does not affect the resulting pixel color. Generally, it would be expected that the number of faces in each mesh is the same, but this is not a requirement. Keep in mind that a ray that is not associated with a face is not the same thing as a ray that is but that, when shot, hits nothing. The latter will return a pixel (even if it is transparent or the background color), whereas the former causes the ray to not be shot in the first place; hence, it is not included in the calculation of the average for the pixel.

Using multiple rays per pixel is useful for generating anti-aliasing (since standard AA won't work) or for special effects such as focal blur, motion blur, and so forth, with each additional mesh specified in the camera representing a slightly different camera position.

Note: It is legal to use transformations on meshes specified in the camera body, hence it's possible to obtain basic anti-aliasing by using a single mesh multiple times, with subsequent ones jittered slightly from the first combined with a suitable rays per pixel count.

  • distribution #1

This method allows both multiple rays per pixel and summing of meshes, in other words the faces of all the supplied meshes are logically summed together as if they were one single mesh. In this mode, if you specify more than one ray per pixel, the second ray for a given pixel will go to the face at (width * height * ray_number) + pixel_number, where ray_number is the count of rays shot into a specific pixel. If the calculated face index exceeds the total number of faces for all the meshes, no ray is shot.

The primary use for this summing method is convenience in generation of the meshes, as some modelers slow down to an irritating extent with very large meshes. Using distribution #1 allows these to be split up.

  • distribution #2

Distribution method 2 is a horizontal array of sub-cameras, one per mesh (i.e. like method #0, it does not sum meshes). The image is divided horizontally into #num_meshes blocks, with the first mesh listed being the left-most camera, and the last being the right-most. The most obvious use of this would be with two meshes to generate a stereo camera arrangement.

In this mode, you can (currently) only have a single ray per pixel.

  • distribution #3

This method will reverse-map the face from the UV co-ordinates. Currently, only a single ray per pixel is supported, however, unlike the preceding methods, standard AA and jitter will work. This method is particularly useful for texture baking and resolution-independent mesh cameras, but requires that the mesh have a UV map supplied with it.

You can use the smooth modifier to allow interpolation of the normals at the vertices. This allows for use of UV mapped meshes as cameras with the benefit of not being resolution dependent, unlike the other distributions. The interpolation is identical to that used for smooth_triangles.

If used for texture baking, the generated image may have visible seams when applied back to the mesh, this can be mitigated. Also, depending on the way the original UV map was set up, using AA may produce incorrect pixels on the outside edge of the generated maps.

3.4.2.2.3.3 Max Distance
This is an optional floating-point value which, if greater than EPSILON (a very small value used internally for comparisons with 0), will be used as the limit for the length of any rays cast. Objects at a distance greater than this from the ray origin will not be intersected by the ray. The primary use for this parameter is to allow a mesh camera to 'probe' a scene in order to determine whether or not a given location contains a visible object. Two examples would be a camera that divides the scene into slices for use in 3d printing or to generate an STL file, and a camera that divides the scene into cubes to generate voxel information. In both cases, some external means of processing the generated image into a useful form would be required. It should be kept in mind that this method of determining spatial information is not guaranteed to generate an accurate result, as it is entirely possible for a ray to miss an object that is within its section of the scene, should that object have features that are smaller than the resolution of the mesh being used. In other words, it is (literally) hit and miss. This issue is conceptually similar to aliasing in a normal render. It is left as an exercise for the reader to come up with means of generating pixel information that carries useful information, given the lack of light sources within the interior of an opaque object (hint: try ambient).
3.4.2.2.3.4 Mesh Object

One or more mesh or mesh2 objects to be used for the camera. These will be treated differently depending on the distribution method, as explained above. Transformations on the meshes can be used here, and will reflect on the resulting image as it would be expected for a regular camera.

3.4.2.2.3.5 About the Location Vector

With this special camera, location doesn't affect where the camera is placed per se (that information is on the mesh object itself), but is used to move the origin of the ray off the face, along the normal of that face. This would typically be done for texture baking or illumination calculation scenes where the camera mesh is also instantiated into the scene, usually only a tiny amount of displacement is needed. The X and Y for location is not currently used, and the Z always refers to the normal of the face, rather than the real Z direction in the scene.

3.4.2.2.3.6 About the Direction Vector

Like location, this doesn't correspond to the real direction vector of the camera. It serves only to reverse the normal of all the faces, if necessary. If the Z component is less than -EPSILON, then the rays will be shot in the opposite direction than they would otherwise have been. X and Y are not used.

3.4.2.2.3.7 The Smooth Modifier

This optional parameter is only useful with distribution #3, and will cause the ray direction to be interpolated according to the same rules as are applied to smooth triangles. For this to work, the mesh must have provided a normal for each vertex.

Note: See the sample scene files located in ~scenes/camera/mesh_camera/ for additional usages and other samples of mesh cameras. There are also some useful macros to assist in generating and processing meshes for use as cameras.

3.4.2.2.4 Fisheye projection

This is a spherical projection. The viewing angle is specified by the angle keyword. An angle of 180 degrees creates the "standard" fisheye while an angle of 360 degrees creates a super-fisheye or "I-see-everything-view". If you use this projection you should get a circular image. If this is not the case, i.e. you get an elliptical image, you should read Aspect Ratio.

The fisheye projection diagram | A fisheye camera sample image

Note: The length of the direction, up and right vectors are irrelevant. The angle keyword is the important setting.

3.4.2.2.5 Ultra wide angle projection

The ultra wide angle projection is somewhat similar to the fisheye, but it projects the image onto a rectangle instead of a circle. The viewing angle can be specified by using the angle keyword. The aspect ratio of the lengths of the up/right vectors are used to provide the vertical angle from the horizontal angle, so that the ratio of vertical angle on horizontal angle is identical to the ratio of the length of up on length of right. When the ratio is one, a square is wrapped on a quartic surface defined as follows:

x2+y2+z2 = x2y2 + 1

The section where z=0 is a square, the section where x=0 or y=0 is a circle, and the sections parallel to x=0 or y=0 are ellipses. When the ratio is not one, the bigger angle obviously gets wrapped further. When the angle reaches 180, the border meets the square section. The angle can be greater than 180, in that case, when both (vertical and horizontal) angles are greater than 180, the parts around the corners of the square section will be wrapped more than once. The classical usage (using an angle of 360) but with a up/right ratio of 1/2 up 10*y and right 20*x will keep the top of the image as the zenith, and the bottom of the image as the nadir, avoiding perception issues and giving a full 360 degree view.

The ultra wide angle projection diagram | An ultra wide angle sample image
3.4.2.2.6 Omnimax projection

The omnimax projection is a 180 degrees fisheye that has a reduced viewing angle in the vertical direction. In reality this projection is used to make movies that can be viewed in the dome-like Omnimax theaters. The image will look somewhat elliptical.

The omnimax projection diagram | An omnimax camera sample image

Note: The use of the angle keyword is irrelevant, the relative length of up and right vectors are what is important.

3.4.2.2.7 Panoramic projection

This projection is called "cylindrical equirectangular projection". It overcomes the degeneration problem of the perspective projection if the viewing angle approaches 180 degrees. It uses a type of cylindrical projection to be able to use viewing angles larger than 180 degrees with a tolerable lateral-stretching distortion. The angle keyword is used to determine the viewing angle.

The panoramic projection diagram | A panoramic camera sample image

Note: The angle keyword is irrelevant. The relative length of direction, up and right vectors are important as they define the lengths of the 3 axis of the ellipsoid. With identical length and orthogonal vectors (both strongly recommended, unless used on purpose), it's identical to a spherical camera with angle 180,90.

3.4.2.2.8 Cylindrical projection

Using this projection the scene is projected onto a cylinder. There are four different types of cylindrical projections depending on the orientation of the cylinder and the position of the viewpoint. An integer value in the range 1 to 4 must follow the cylinder keyword. The viewing angle and the length of the up or right vector determine the dimensions of the camera and the visible image. The characteristics of different types are as follows:

  1. vertical cylinder, fixed viewpoint
  2. horizontal cylinder, fixed viewpoint
  3. vertical cylinder, viewpoint moves along the cylinder's axis
  4. horizontal cylinder, viewpoint moves along the cylinder's axis
The type 1 cylindrical projection diagram | A type 1 cylindrical camera sample image

The type 2 cylindrical projection diagram | A type 2 cylindrical camera sample image
The type 3 cylindrical projection diagram | A type 3 cylindrical camera sample image

The type 4 cylindrical projection diagram | A type 4 cylindrical camera sample image
3.4.2.2.9 Spherical projection

Using this projection the scene is projected onto a sphere.

The syntax is:

camera {
  spherical
  [angle HORIZONTAL [VERTICAL]]
  [CAMERA_ITEMS...]
  }

The first value after angle sets the horizontal viewing angle of the camera. With the optional second value, the vertical viewing angle is set: both in degrees. If the vertical angle is not specified, it defaults to half the horizontal angle.

The spherical projection is similar to the fisheye projection, in that the scene is projected on a sphere. But unlike the fisheye camera, it uses rectangular coordinates instead of polar coordinates; in this it works the same way as spherical mapping (map_type 1).

This has a number of uses. Firstly, it allows an image rendered with the spherical camera to be mapped on a sphere without distortion (with the fisheye camera, you first have to convert the image from polar to rectangular coordinates in some image editor). Also, it allows effects such as "environment mapping", often used for simulating reflections in scanline renderers.

The spherical projection diagram | A spherical camera sample image

Note: The lengths of the direction, up and right vectors are irrelevant. Angle is the important setting, and it gets two values separated by a comma: the first is the horizontal angle, the second is the vertical angle. Both values can reach 360. If the second value is missing, it is set to half the value of the first.

3.4.2.3 Focal Blur

POV-Ray can simulate focal depth-of-field by shooting a number of sample rays from jittered points within each pixel and averaging the results.

To turn on focal blur, you must specify the aperture keyword followed by a float value which determines the depth of the sharpness zone. Large apertures give a lot of blurring, while narrow apertures will give a wide zone of sharpness.

Note: While this behaves as a real camera does, the values for aperture are purely arbitrary and are not related to f-stops.

You must also specify the blur_samples keyword followed by an integer value specifying the maximum number of rays to use for each pixel. More rays give a smoother appearance but is slower. By default no focal blur is used, i. e. the default aperture is 0 and the default number of samples is 0.

The center of the zone of sharpness is specified by the focal_point vector. The zone of sharpness is a plane through the focal_point and is parallel to the camera. Objects close to this plane of focus are in focus and those farther from that plane are more blurred. The default value is focal_point<0,0,0>.

Although blur_samples specifies the maximum number of samples, there is an adaptive mechanism that stops shooting rays when a certain degree of confidence has been reached. At that point, shooting more rays would not result in a significant change.

Extra samples are generated in a circular rather than square pattern when blur_samples is not set to either 4, 7, 19 or 37, leading to a circular rather than square bokeh. The extra samples are generated from a Halton sequence rather than a random stream. You can also optionally specify a minimum number of samples to be taken before testing against the confidence and variance settings. The default is 4, if the blur_samples maximum is less than 7, otherwise the default is 7, to provide a means to get rid of stray non-blurred pixels.

The syntax is:

blur_samples [ MIN_SAMPLES, ] MAX_SAMPLES

The confidence and variance keywords are followed by float values to control the adaptive function. The confidence value is used to determine when the samples seem to be close enough to the correct color. The variance value specifies an acceptable tolerance on the variance of the samples taken so far. In other words, the process of shooting sample rays is terminated when the estimated color value is very likely (as controlled by the confidence probability) near the real color value.

Since the confidence is a probability its values can range from 0 to less than 1 (the default is 0.9, i. e. 90%). The value for the variance should be in the range of the smallest displayable color difference (the default is 1/128). If 1 is used POV-Ray will issue a warning and then use the default instead.

Rendering with the default settings can result in quite grainy images. This can be improved by using a lower variance. A value of 1/10000 gives a fairly good result (with default confidence and blur_samples set to something like 100) without being unacceptably slow.

Larger confidence values will lead to more samples, slower traces and better images. The same holds for smaller variance thresholds.

Focal blur can also support a user-defined bokeh using the following syntax:

camera {
  // ... focal blur camera definition
  bokeh {
    pigment { ... }
    }
  }

If bokeh is specified, focal blur will use a custom sampling sequence based on the specified pigment's brightness in the range <0,0,0> to <1,1,0> i.e. the unit square in the XY plane.

3.4.2.4 Camera Ray Perturbation

The optional normal may be used to assign a normal pattern to the camera. For example:

camera{
  location Here
  look_at There
  normal { bumps 0.5 }
  }

All camera rays will be perturbed using this pattern. The image will be distorted as though you were looking through bumpy glass or seeing a reflection off of a bumpy surface. This lets you create special effects. See the animated scene camera2.pov for an example. See Normal for information on normal patterns.

3.4.2.5 Camera Identifiers

Camera identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. You may declare several camera identifiers if you wish. This makes it easy to quickly change cameras. An identifier is declared as follows.

CAMERA_DECLARATION:
  #declare IDENTIFIER = CAMERA |
  #local IDENTIFIER = CAMERA

Where IDENTIFIER is the name of the identifier up to 40 characters long and CAMERA is any valid camera statement. See #declare vs. #local for information on identifier scope. Here is an example...

#declare Long_Lens =
camera {
  location -z*100
  look_at <0,0,0>
  angle 3
  }

#declare Short_Lens =
camera {
  location -z*50
  look_at <0,0,0>
  angle 15
  }

camera {
  Long_Lens  // edit this line to change lenses
  translate <33,2,0>
  }

Note: Only camera transformations can be added to an already declared camera. Camera behaviour changing keywords are not allowed, as they are needed in an earlier stage for resolving the keyword order dependencies.

3.4.3 Atmospheric Effects

Atmospheric effects are a loosely-knit group of features that affect the background and/or the atmosphere enclosing the scene. POV-Ray includes the ability to render a number of atmospheric effects, such as fog, haze, mist, rainbows and skies.

3.4.3.1 Atmospheric Media

Atmospheric effects such as fog, dust, haze, or visible gas may be simulated by a media statement specified in the scene but not attached to any object. All areas not inside a non-hollow object in the entire scene. A very simple approach to add fog to a scene is explained in the section Fog however this kind of fog does not interact with any light sources like media does. It will not show light beams or other effects and is therefore not very realistic.

The atmosphere media effect overcomes some of the fog's limitations by calculating the interaction between light and the particles in the atmosphere using volume sampling. Thus shafts of light beams will become visible and objects will cast shadows onto smoke or fog.

Note: POV-Ray cannot sample media along an infinitely long ray. The ray must be finite in order to be possible to sample. This means that sampling media is only possible for rays that hit an object, so no atmospheric media will show up against the background or sky_sphere. Another way of being able to sample media is using spotlights, because in this case the ray is not infinite, as it is sampled only inside the spotlight cone.

With spotlights you will be able to create the best results because their cone of light will become visible. Pointlights can be used to create effects like street lights in fog. Lights can be made to not interact with the atmosphere by adding media_interaction off to the light source. They can be used to increase the overall light level of the scene to make it look more realistic.

Complete details on media are given in the section Media. Earlier versions of POV-Ray used an atmosphere statement for atmospheric effects but that system was incompatible with the old object halo system. So atmosphere has been eliminated and replaced with a simpler and more powerful media feature. The user now only has to learn one media system for either atmospheric or object use.

If you only want media effects in a particular area, you should use object media rather than only relying upon the media pattern. In general it will be faster and more accurate because it only calculates inside the constraining object.

Note: The atmosphere feature will not work if the camera is inside a non-hollow object (see the section Empty and Solid Objects for a detailed explanation).

3.4.3.2 Background

A background color can be specified if desired. Any ray that does not hit an object will be colored with this color. The default background is black. The syntax for background is:

BACKGROUND:
 background {COLOR}

Note: As of version 3.7 some changes have been made to the way alpha is handled when +ua is activated.

  • In previous versions, specifying a background with the background keyword would by default supply a background with transmit set to 1.0 (i.e. fully transparent provided that +ua is being used). This is no longer the case. While the default background is transparent, any background specified in a scene file (unless 3.6 or earlier compatibility is being used) will now be opaque unless transmit is explicitly given. In other words, use rgbft<> rather than rgb<> in the background statement if you want the old behavior.
  • The way that objects are blended with the background has changed. Previously the color of the background was not taken into account when calculating effects of transmission through translucent objects when +ua is in effect (i.e. where the background could otherwise have been seen through the object). Now, however, the background color is taken into account, even if it is not otherwise visible. Blending is performed in the same way regardless of the presence of background transparency.

Note: When using Output_Alpha=on or +ua with legacy scenes (the #version directive set to less than 3.7) the background will be suppressed, except in reflections.

3.4.3.3 Fog

If it is not necessary for light beams to interact with atmospheric media, then fog may be a faster way to simulate haze or fog. This feature artificially adds color to every pixel based on the distance the ray has traveled. The syntax for fog is:

FOG:
  fog { [FOG_IDENTIFIER] [FOG_ITEMS...] }
FOG_ITEMS:
  fog_type Fog_Type | distance Distance | COLOR |
  turbulence <Turbulence> | turb_depth Turb_Depth |
  omega Omega | lambda Lambda | octaves Octaves |
  fog_offset Fog_Offset | fog_alt Fog_Alt |
  up <Fog_Up> | TRANSFORMATION

Fog default values:

lambda     : 2.0
fog_type   : 1
fog_offset : 0.0
fog_alt    : 0.0
octaves    : 6
omega      : 0.5
turbulence : <0,0,0>
turb_depth : 0.5
up         : <0,1,0>

Currently there are two fog types, the default fog_type 1 is a constant fog and fog_type 2 is ground fog. The constant fog has a constant density everywhere while the ground fog has a constant density for all heights below a given point on the up axis and thins out along this axis.

The color of a pixel with an intersection depth d is calculated by

PIXEL_COLOR = exp(-d/D) * OBJECT_COLOR + (1-exp(-d/D)) * FOG_COLOR

where D is the specified value of the required fog distance keyword. At depth 0 the final color is the object's color. If the intersection depth equals the fog distance the final color consists of 64% of the object's color and 36% of the fog's color.

Note: For this equation, a distance of zero is undefined. In practice, povray will treat this value as "fog is off". To use an extremely thick fog, use a small nonzero number such as 1e-6 or 1e-10.

For ground fog, the height below which the fog has constant density is specified by the fog_offset keyword. The fog_alt keyword is used to specify the rate by which the fog fades away. The default values for both are 0.0 so be sure to specify them if ground fog is used. At an altitude of Fog_Offset+Fog_Alt the fog has a density of 25%. The density of the fog at height less than or equal to Fog_Offset is 1.0 and for height larger than than Fog_Offset is calculated by:

1/(1 + (y - Fog_Offset) / Fog_Alt) ^2

The total density along a ray is calculated by integrating from the height of the starting point to the height of the end point.

The optional up vector specifies a direction pointing up, generally the same as the camera's up vector. All calculations done during the ground fog evaluation are done relative to this up vector, i. e. the actual heights are calculated along this vector. The up vector can also be modified using any of the known transformations described in Transformations. Though it may not be a good idea to scale the up vector - the results are hardly predictable - it is quite useful to be able to rotate it. You should also note that translations do not affect the up direction (and thus do not affect the fog).

The required fog color has three purposes. First it defines the color to be used in blending the fog and the background. Second it is used to specify a translucency threshold. By using a transmittance larger than zero one can make sure that at least that amount of light will be seen through the fog. With a transmittance of 0.3 you will see at least 30% of the background. Third it can be used to make a filtering fog. With a filter value larger than zero the amount of background light given by the filter value will be multiplied with the fog color. A filter value of 0.7 will lead to a fog that filters 70% of the background light and leaves 30% unfiltered.

Fogs may be layered. That is, you can apply as many layers of fog as you like. Generally this is most effective if each layer is a ground fog of different color, altitude and with different turbulence values. To use multiple layers of fogs, just add all of them to the scene.

You may optionally stir up the fog by adding turbulence. The turbulence keyword may be followed by a float or vector to specify an amount of turbulence to be used. The omega, lambda and octaves turbulence parameters may also be specified. See the section Turbulence Warp for details on all of these turbulence parameters.

Additionally the fog turbulence may be scaled along the direction of the viewing ray using the turb_depth amount. Typical values are from 0.0 to 1.0 or more. The default value is 0.5 but any float value may be used.

Note: The fog feature will not work if the camera is inside a non-hollow object (see the section Empty and Solid Objects for a detailed explanation).

3.4.3.4 Sky Sphere

The sky sphere is used create a realistic sky background without the need of an additional sphere to simulate the sky. Its syntax is:

SKY_SPHERE:
  sky_sphere { [SKY_SPHERE_IDENTIFIER] [SKY_SPHERE_ITEMS...] }
SKY_SPHERE_ITEM:
  PIGMENT | TRANSFORMATION | [emission]

Note: When using Output_Alpha=on or +ua with legacy scenes (the #version directive set to less than 3.7) the sky_sphere will be suppressed, except in reflections.

The sky sphere can contain several pigment layers with the last pigment being at the top, i. e. it is evaluated last, and the first pigment being at the bottom, i. e. it is evaluated first. If the upper layers contain filtering and/or transmitting components lower layers will shine through. If not lower layers will be invisible.

Note: Version 3.7 changed the effect of filter in a layered-pigment sky_sphere to match the behavior of a corresponding layered-texture large regular sphere. The old behavior, though probably having been unintentional, is automatically re-activated for backward compatibility when a #version of less than 3.7 is specified.

The sky sphere is calculated by using the direction vector as the parameter for evaluating the pigment patterns. This leads to results independent from the view point, which fairly accurately models a real sky, where the distance to the sky is much larger than the distances between visible objects.

Optionally adding the emission keyword allows for brightness tuning of image-mapped sky sphere's. The default is rgb <1,1,1> with higher values increasing the brightness, and lower values correspondingly decrease it. Although primarily intended for easy tuning of light probe skies, the parameter also works with procedural sky pigments.

If you want to add a nice color blend to your background you can easily do this by using the following example.

sky_sphere {
  pigment {
    gradient y
      color_map {
        [ 0.5  color CornflowerBlue ]
        [ 1.0  color MidnightBlue ]
        }
    scale 2
    translate -1
    }
  emission rgb <0.8,0.8,1>
  }

This gives a soft blend from CornflowerBlue at the horizon to MidnightBlue at the zenith. The scale and translate operations are used to map the direction vector values, which lie in the range from <-1, -1, -1> to <1, 1, 1>, onto the range from <0, 0, 0> to <1, 1, 1>. Thus a repetition of the color blend is avoided for parts of the sky below the horizon.

In order to easily animate a sky sphere you can transform it using the usual transformations described in Transformations. Though it may not be a good idea to translate or scale a sky sphere - the results are hardly predictable - it is quite useful to be able to rotate it. In an animation the color blendings of the sky can be made to follow the rising sun for example.

Note: Only one sky sphere can be used in any scene. It also will not work as you might expect if you use camera types like the orthographic or cylindrical camera. The orthographic camera uses parallel rays and thus you will only see a very small part of the sky sphere (you will get one color skies in most cases). Reflections in curved surface will work though, e. g. you will clearly see the sky in a mirrored ball.

3.4.3.5 Rainbow

Rainbows are implemented using fog-like, circular arcs. Their syntax is:

RAINBOW:
  rainbow { [RAINBOW_IDENTIFIER] [RAINBOW_ITEMS...] }
RAINBOW_ITEM:
  direction <Dir> | angle Angle | width Width |
  distance Distance | COLOR_MAP | jitter Jitter | up <Up> |
  arc_angle Arc_Angle | falloff_angle Falloff_Angle

Rainbow default values:

arc_angle     : 180.0
falloff_angle : 180.0
jitter        : 0.0
up            : y

The required direction vector determines the direction of the (virtual) light that is responsible for the rainbow. Ideally this is an infinitely far away light source like the sun that emits parallel light rays. The position and size of the rainbow are specified by the required angle and width keywords. To understand how they work you should first know how the rainbow is calculated.

For each ray the angle between the rainbow's direction vector and the ray's direction vector is calculated. If this angle lies in the interval from Angle-Width/2 to Angle+Width/2 the rainbow is hit by the ray. The color is then determined by using the angle as an index into the rainbow's color_map. After the color has been determined it will be mixed with the background color in the same way like it is done for fogs.

Thus the angle and width parameters determine the angles under which the rainbow will be seen. The optional jitter keyword can be used to add random noise to the index. This adds some irregularity to the rainbow that makes it look more realistic.

The required distance keyword is the same like the one used with fogs. Since the rainbow is a fog-like effect it is possible that the rainbow is noticeable on objects. If this effect is not wanted it can be avoided by using a large distance value. By default a sufficiently large value is used to make sure that this effect does not occur.

The color_map statement is used to assign a color map that will be mapped onto the rainbow. To be able to create realistic rainbows it is important to know that the index into the color map increases with the angle between the ray's and rainbow's direction vector. The index is zero at the innermost ring and one at the outermost ring. The filter and transmittance values of the colors in the color map have the same meaning as the ones used with fogs (see the section Fog).

The default rainbow is a 360 degree arc that looks like a circle. This is no problem as long as you have a ground plane that hides the lower, non-visible part of the rainbow. If this is not the case or if you do not want the full arc to be visible you can use the optional keywords up, arc_angle and falloff_angle to specify a smaller arc.

The arc_angle keyword determines the size of the arc in degrees (from 0 to 360 degrees). A value smaller than 360 degrees results in an arc that abruptly vanishes. Since this does not look nice you can use the falloff_angle keyword to specify a region in which the rainbow will smoothly blend into the background making it vanish softly. The falloff angle has to be smaller or equal to the arc angle.

The up keyword determines were the zero angle position is. By changing this vector you can rotate the rainbow about its direction. You should note that the arc goes from -Arc_Angle/2 to +Arc_Angle/2. The soft regions go from -Arc_Angle/2 to -Falloff_Angle/2 and from +Falloff_Angle/2 to +Arc_Angle/2.

The following example generates a 120 degrees rainbow arc that has a falloff region of 30 degrees at both ends:

rainbow {
  direction <0, 0, 1>
  angle 42.5
  width 5
  distance 1000
  jitter 0.01
  color_map { Rainbow_Color_Map }
  up <0, 1, 0>
  arc_angle 120
  falloff_angle 30
  }

It is possible to use any number of rainbows and to combine them with other atmospheric effects.

3.4.4 Lighting Types

POV-Ray supports several lighting types. The most basic being a highly configurable conventional light source. Scenes can have more than one light source, and light sources can be grouped together with other objects and/or light sources. POV-Ray also supports more sophisticated lighting models such as: global illumination or radiosity and photon mapping.

3.4.4.1 Light Source

The light_source is not really an object. Light sources have no visible shape of their own. They are just points or areas which emit light. They are categorized as objects so that they can be combined with regular objects using union.

Note: Due to a hard-coded limit the number of light sources should not exceed 127. Since the class of the variable that governs this limit is not exclusive to light sources, a value had to be chosen that provides the best balance between performance, memory use and flexibility. See the following »news-group discussion for more details and information about ways to overcome this limitation.

The syntax is as follows:

LIGHT_SOURCE:
  light_source {
    <Location>, COLOR
    [LIGHT_MODIFIERS...]
    }
LIGHT_MODIFIER:
  LIGHT_TYPE | SPOTLIGHT_ITEM | AREA_LIGHT_ITEMS |
  GENERAL_LIGHT_MODIFIERS
LIGHT_TYPE:
  spotlight | shadowless | cylinder | parallel
SPOTLIGHT_ITEM:
  radius Radius | falloff Falloff | tightness Tightness |
  point_at <Spot>
PARALLEL_ITEM:
  point_at <Spot>
AREA_LIGHT_ITEM:
  area_light <Axis_1>, <Axis_2>, Size_1, Size_2 |
  adaptive Adaptive | area_illumination [Bool] |
  jitter | circular | orient
GENERAL_LIGHT_MODIFIERS:
  looks_like { OBJECT } |
  TRANSFORMATION fade_distance Fade_Distance |
  fade_power Fade_Power | media_attenuation [Bool] |
  media_interaction [Bool] | projected_through

Light source default values:

LIGHT_TYPE        : pointlight
falloff           : 70
media_interaction : on
media_attenuation : off
point_at          : <0,0,0>
radius            : 70
tightness         : 10

The different types of light sources and the optional modifiers are described in the following sections.

The first two items are common to all light sources. The <Location> vector gives the location of the light. The COLOR gives the color of the light. Only the red, green, and blue components are significant. Any transmit or filter values are ignored.

Note: You vary the intensity of the light as well as the color using this parameter. A color such as rgb <0.5,0.5,0.5> gives a white light that is half the normal intensity.

All of the keywords or items in the syntax specification above may appear in any order. Some keywords only have effect if specified with other keywords. The keywords are grouped into functional categories to make it clear which keywords work together. The GENERAL_LIGHT_MODIFIERS work with all types of lights and all options.

Note: TRANSFORMATIONS such as translate, rotate etc. may be applied but no other OBJECT_MODIFIERS may be used.

There are three mutually exclusive light types. If no LIGHT_TYPE is specified it is a point light. The other choices are spotlight and cylinder.

3.4.4.1.1 Point Lights

The simplest kind of light is a point light. A point light source sends light of the specified color uniformly in all directions. The default light type is a point source. The <Location> and COLOR is all that is required. For example:

light_source {
  <1000,1000,-1000>, rgb <1,0.75,0> //an orange light
  }
3.4.4.1.2 Spotlights

Normally light radiates outward equally in all directions from the source. However the spotlight keyword can be used to create a cone of light that is bright in the center and falls of to darkness in a soft fringe effect at the edge.

Although the cone of light fades to soft edges, objects illuminated by spotlights still cast hard shadows. The syntax is:

SPOTLIGHT_SOURCE:
  light_source {
    <Location>, COLOR spotlight
    [LIGHT_MODIFIERS...]
    }
LIGHT_MODIFIER:
  SPOTLIGHT_ITEM | AREA_LIGHT_ITEMS | GENERAL_LIGHT_MODIFIERS
SPOTLIGHT_ITEM:
  radius Radius | falloff Falloff | tightness Tightness |
  point_at <Spot>

Default values:

radius:    30 degrees
falloff:   45 degrees
tightness:  0

The point_at keyword tells the spotlight to point at a particular 3D coordinate. A line from the location of the spotlight to the point_at coordinate forms the center line of the cone of light. The following illustration will be helpful in understanding how these values relate to each other.

The geometry of a spotlight.

The falloff, radius, and tightness keywords control the way that light tapers off at the edges of the cone. These four keywords apply only when the spotlight or cylinder keywords are used.

The falloff keyword specifies the overall size of the cone of light. This is the point where the light falls off to zero intensity. The float value you specify is the angle, in degrees, between the edge of the cone and center line. The radius keyword specifies the size of the hot-spot at the center of the cone of light. The hot-spot is a brighter cone of light inside the spotlight cone and has the same center line. The radius value specifies the angle, in degrees, between the edge of this bright, inner cone and the center line. The light inside the inner cone is of uniform intensity. The light between the inner and outer cones tapers off to zero.

For example, assuming a tightness 0, with radius 10 and falloff 20 the light from the center line out to 10 degrees is full intensity. From 10 to 20 degrees from the center line the light falls off to zero intensity. At 20 degrees or greater there is no light.

Note: If the radius and falloff values are close or equal the light intensity drops rapidly and the spotlight has a sharp edge.

The values for the radius, and tightness parameters are half the opening angles of the corresponding cones, both angles have to be smaller than 90 degrees. The light smoothly falls off between the radius and the falloff angle like shown in the figures below (as long as the radius angle is not negative).

Intensity multiplier curve with a fixed falloff angle of 45 degrees.

Intensity multiplier curve with a fixed radius angle of 45 degrees.

The tightness keyword is used to specify an additional exponential softening of the edges. A value other than 0, will affect light within the radius cone as well as light in the falloff cone. The intensity of light at an angle from the center line is given by: intensity * cos(angle)tightness. The default value for tightness is 0. Lower tightness values will make the spotlight brighter, making the spot wider and the edges sharper. Higher values will dim the spotlight, making the spot tighter and the edges softer. Values from 0 to 100 are acceptable.

Intensity multiplier curve with fixed angle and falloff angles of 30 and 60 degrees respectively and different tightness values.

You should note from the figures that the radius and falloff angles interact with the tightness parameter. To give the tightness value full control over the spotlight's appearance use radius 0 falloff 90. As you can see from the figure below. In that case the falloff angle has no effect and the lit area is only determined by the tightness parameter.

Intensity multiplier curve with a negative radius angle and different tightness values.

Spotlights may be used any place that a normal light source is used. Like any light sources, they are invisible. They may also be used in conjunction with area lights.

3.4.4.1.3 Cylindrical Lights

The cylinder keyword specifies a cylindrical light source that is great for simulating laser beams. Cylindrical light sources work pretty much like spotlights except that the light rays are constrained by a cylinder and not a cone. The syntax is:

CYLINDER_LIGHT_SOURCE:
  light_source {
    <Location>, COLOR cylinder
    [LIGHT_MODIFIERS...]
    }
LIGHT_MODIFIER:
  SPOTLIGHT_ITEM | AREA_LIGHT_ITEMS | GENERAL_LIGHT_MODIFIERS
SPOTLIGHT_ITEM:
  radius Radius | falloff Falloff | tightness Tightness |
  point_at <Spot>

Default values:

radius:     0.75 degrees
falloff:    1    degrees
tightness:  0

The point_at, radius, falloff and tightness keywords control the same features as with the spotlight. See Spotlights for details.

You should keep in mind that the cylindrical light source is still a point light source. The rays are emitted from one point and are only constraint by a cylinder. The light rays are not parallel.

3.4.4.1.4 Parallel Lights
syntax:

light_source {
  LOCATION_VECTOR, COLOR
  [LIGHT_SOURCE_ITEMS...]
  parallel
  point_at VECTOR
  }

The parallel keyword can be used with any type of light source.

Note: For normal point lights, point_at must come after parallel.

Parallel lights are useful for simulating very distant light sources, such as sunlight. As the name suggests, it makes the light rays parallel.

Technically this is done by shooting rays from the closest point on a plane to the object intersection point. The plane is determined by a perpendicular defined by the light location and the point_at vector.

Two things must be considered when choosing the light location (specifically, its distance):

  1. Any parts of an object above the light plane still get illuminated according to the light direction, but they will not cast or receive shadows.
  2. fade_distance and fade_power use the light location to determine distance for light attenuation, so the attenuation still looks like that of a point source.
    Area light also uses the light location in its calculations.
3.4.4.1.5 Area Lights

Area light sources occupy a finite, one or two-dimensional area of space. They can cast soft shadows because an object can partially block their light. Point sources are either totally blocked or not blocked.

The area_light keyword in POV-Ray creates sources that are rectangular in shape, sort of like a flat panel light. Rather than performing the complex calculations that would be required to model a true area light, it is approximated as an array of point light sources spread out over the area occupied by the light. The array-effect applies to shadows only, however with the addition of the area_illumination keyword, full area light diffuse and specular illumination can be achieved. The object's illumination is still that of a point source. The intensity of each individual point light in the array is dimmed so that the total amount of light emitted by the light is equal to the light color specified in the declaration. The syntax is:

AREA_LIGHT_SOURCE:
  light_source {
    LOCATION_VECTOR, COLOR
    area_light
    AXIS_1_VECTOR, AXIS_2_VECTOR, Size_1, Size_2
    [ adaptive Adaptive ] [ area_illumination on/off ]
    [ jitter ] [ circular ] [ orient ]
    [ [LIGHT_MODIFIERS...]
    }

Any type of light source may be an area light.

The area_light keyword defines the location, the size and orientation of the area light as well as the number of lights in the light source array. The location vector is the centre of a rectangle defined by the two vectors <Axis_1> and <Axis_2>. These specify the lengths and directions of the edges of the light.

4x4 Area light, location and vectors.

Since the area lights are rectangular in shape these vectors should be perpendicular to each other. The larger the size of the light the thicker the soft part of shadows will be. The integers Size_1 and Size_2 specify the number of rows and columns of point sources of the. The more lights you use the smoother the shadows, but render time will increase.

Note: It is possible to specify spotlight parameters along with the area light parameters to create area spotlights. Using area spotlights is a good way to speed up scenes that use area lights since you can confine the lengthy soft shadow calculations to only the parts of your scene that need them.

An interesting effect can be created using a linear light source. Rather than having a rectangular shape, a linear light stretches along a line sort of like a thin fluorescent tube. To create a linear light just create an area light with one of the array dimensions set to 1.

Note: In version 3.7 experimental support for full area light diffuse and specular illumination was added.

This feature is off by default, so area lights will work as previously expected, and can be turned on by specifying the area_illumination keyword, followed by the optional on/off keyword, in the light source definition. As with area lights, the Size_1 and Size_2 parameters determine the quality of the lighting, as well as the quality of the shadows.

The jitter keyword is optional. When used it causes the positions of the point lights in the array to be randomly jittered to eliminate any shadow banding that may occur. The jittering is completely random from render to render and should not be used when generating animations.

The adaptive keyword is used to enable adaptive sampling of the light source. By default POV-Ray calculates the amount of light that reaches a surface from an area light by shooting a test ray at every point light within the array. As you can imagine this is very slow. Adaptive sampling on the other hand attempts to approximate the same calculation by using a minimum number of test rays. The number specified after the keyword controls how much adaptive sampling is used. The higher the number the more accurate your shadows will be but the longer they will take to render. If you are not sure what value to use a good starting point is adaptive 1. The adaptive keyword only accepts integer values and cannot be set lower than 0.

When performing adaptive sampling POV-Ray starts by shooting a test ray at each of the four corners of the area light. If the amount of light received from all four corners is approximately the same then the area light is assumed to be either fully in view or fully blocked. The light intensity is then calculated as the average intensity of the light received from the four corners. However, if the light intensity from the four corners differs significantly then the area light is partially blocked. The area light is split into four quarters and each section is sampled as described above. This allows POV-Ray to rapidly approximate how much of the area light is in view without having to shoot a test ray at every light in the array. Visually the sampling goes like shown below.

Area light adaptive samples.

While the adaptive sampling method is fast (relatively speaking) it can sometimes produce inaccurate shadows. The solution is to reduce the amount of adaptive sampling without completely turning it off. The number after the adaptive keyword adjusts the number of times that the area light will be split before the adaptive phase begins. For example if you use adaptive 0 a minimum of 4 rays will be shot at the light. If you use adaptive 1 a minimum of 9 rays will be shot (adaptive 2 gives 25 rays, adaptive 3 gives 81 rays, etc). Obviously the more shadow rays you shoot the slower the rendering will be so you should use the lowest value that gives acceptable results.

The number of rays never exceeds the values you specify for rows and columns of points. For example area_light x,y,4,4 specifies a 4 by 4 array of lights. If you specify adaptive 3 it would mean that you should start with a 9 by 9 array. In this case no adaptive sampling is done. The 4 by 4 array is used.

The circular keyword has been added to area lights in order to better create circular soft shadows. With ordinary area lights the pseudo-lights are arranged in a rectangular grid and thus project partly rectangular shadows around all objects, including circular objects. By including the circular tag in an area light, the light is stretched and squashed so that it looks like a circle: this way, circular or spherical light sources are better simulated.

A few things to remember:

  • Circular area lights can be ellipses: the AXIS_1_VECTOR and AXIS_2_VECTOR define the shape and orientation of the circle; if the vectors are not equal, the light source is elliptical in shape.
  • Rectangular artefacts may still show up with very large area grids.
  • There is no point in using circular with linear area lights or area lights which have a 2x2 size.
  • The area of a circular light is roughly 78.5 per cent of a similar size rectangular area light. Increase your axis vectors accordingly if you wish to keep the light source area constant.

The orient keyword has been added to area lights in order to better create soft shadows. Without this modifier, you have to take care when choosing the axis vectors of an area_light, since they define both its area and orientation. Area lights are two dimensional: shadows facing the area light receive light from a larger surface area than shadows at the sides of the area light.

Area light facing object.

Actually, the area from which light is emitted at the sides of the area light is reduced to a single line, only casting soft shadows in one direction.

Area light not facing object.

Between these two extremes the surface area emitting light progresses gradually. By including the orient modifier in an area light, the light is rotated so that for every shadow test, it always faces the point being tested. The initial orientation is no longer important, so you only have to consider the desired dimensions (area) of the light source when specifying the axis vectors. In effect, this makes the area light source appear 3-dimensional (e.g. an area_light with perpendicular axis vectors of the same size and dimensions using circular and orient simulates a spherical light source).

Orient has a few restrictions:

  1. It can be used with circular lights only.
  2. The two axes of the area light must be of equal length.
  3. The two axes of the area light should use an equal number of samples, and that number should be greater than one

These three rules exist because without them, you can get unpredictable results from the orient feature.

If one of the first two rules is broken, POV-Ray will issue a warning and correct the problem. If the third rule is broken, you will only get the error message, and POV-Ray will not automatically correct the problem.

3.4.4.1.6 Shadowless Lights

Using the shadowless keyword you can stop a light source from casting shadows. These lights are sometimes called fill lights. They are another way to simulate ambient light however shadowless lights have a definite source. The syntax is:

SHADOWLESS_LIGHT_SOURCE:
  light_source {
    <Location>, COLOR shadowless
    [LIGHT_MODIFIERS...]
    }
LIGHT_MODIFIER:
  AREA_LIGHT_ITEMS | GENERAL_LIGHT_MODIFIERS

shadowless may be used with all types of light sources. The only restriction is that shadowless should be before or after all spotlight or cylinder option keywords. Do not mix or you get the message Keyword 'the one following shadowless' cannot be used with standard light source. Also note that shadowless lights will not cause highlights on the illuminated objects.

3.4.4.1.7 Looks_like

Normally the light source itself has no visible shape. The light simply radiates from an invisible point or area. You may give a light source any shape by adding a looks_like { OBJECT } statement.

There is an implied no_shadow attached to the looks_like object so that light is not blocked by the object. Without the automatic no_shadow the light inside the object would not escape. The object would, in effect, cast a shadow over everything.

If you want the attached object to block light then you should attach it with a union and not a looks_like as follows:

union {
  light_source { <100, 200, -300> color White }
  object { My_Lamp_Shape }
  }

Presumably parts of the lamp shade are transparent to let some light out.

3.4.4.1.8 Projected_Through

Syntax:

light_source {
  LOCATION_VECTOR, COLOR
  [LIGHT_SOURCE_ITEMS...]
  projected_through { OBJECT }
  }

Projected_through can be used with any type of light source. Any object can be used, provided it has been declared before.
Projecting a light through an object can be thought of as the opposite of shadowing: only the light rays that hit the projected_through object will contribute to the scene.
This also works with area_lights, producing spots of light with soft edges.
Any objects between the light and the projected through object will not cast shadows for this light. Also any surface within the projected through object will not cast shadows.
Any textures or interiors on the object will be stripped and the object will not show up in the scene.

3.4.4.1.9 Light Fading

By default POV-Ray does not diminish light from any light source as it travels through space. In order to get a more realistic effect fade_distance and fade_power keywords followed by float values can be used to model the distance based falloff in light intensity.

The fade_distance is used to specify the distance at which the full light intensity arrives, i.e.: the intensity which was given by the color attribute. The actual attenuation is described by the fade_power keyword, which determines the falloff rate. For example linear or quadratic falloff can be used by setting the fade_power to 1 or 2 respectively.

The complete formula to calculate the factor by which the light is attenuated is:

The attenuation of light fading formula

Where d is the distance the light has traveled.

Light fading functions for different fading powers

With any given value for fade_distance, either larger OR smaller than one, the light intensity at distances smaller than that given value actually increases. The internal calculation used to determine the attenuation factor is set up in a way so that one could set the fade distance and know that for any given fade distance, the light value would equal the set intensity. Lastly, only light coming directly from light sources is attenuated, and that reflected or refracted light is not attenuated by distance.

However, further investigation does reveal certain short comings with this method, as it doesn't follow a very good inverse-squared relationship over the fade distance and somewhat beyond. In other words, the function does break down to be very close to inverse squared as the distance from the given value for fade_distance gets significantly larger.

To that end consider the following:

A value for the light source intensity can be easily calculated when you take into account the distance from the light source to the scene center, or the object to be illuminated, and you set a relatively small value for fade_distance e.g.: the size of the light itself, relative to the scene dimensions.

The following example, that takes the inverse of the above formula that was used to calculate the factor by which the light is attenuated.

// setup the function
#declare Intensity_Factor = function (LD,FD,FP) {pow(1+(LD/FD),FP)/2};

// the translated position of the light source
#declare Light_Position = <0,0,-2400>;

// determine the light distance
#declare Light_Distance = vlength(Light_Position-<0,0,0>);

// scaled size of the light source
#declare Fade_Distance = 4.5;

// linear (1) or quadratic (2) falloff
#declare Fade_Power = 2;

Note: The above example calculates Light_Distance to the scene center, but you could have just as easily used the location of an object.

Now all you have to do is setup the light source. The #debug statements make it easy to see whats going on while tuning the light source.

#debug concat ("\nFade Distance: ", str(Fade_Distance,2,4))
#debug concat ("\nLight Distance: ", str(Light_Distance,5,4)," \n")
#debug concat ("Intensity Factor: ", str(Intensity_Factor (Light_Distance, Fade_Distance, Fade_Power),6,4)
#debug concat ("\n\n")

light_source {
  0, rgb <0.9,0.9,1> * Intensity_Factor (Light_Distance, Fade_Distance, Fade_Power)
  fade_distance Fade_Distance
  fade_power Fade_Power
  translate Light_Position
  }

At first glance this may seem counter-intuitive but it works out well given the small value used for Fade_Distance. You should be aware that this method is meant to give a light strength value of ONE at the point of interest ONLY. In other words, the point represented by the calculated value Light_Distance in the above example. Naturally objects closer to the light source will get a stronger illumination, while objects further away will receive less.

3.4.4.1.10 Atmospheric Media Interaction

By default light sources will interact with an atmosphere added to the scene. This behavior can be switched off by using media_interaction off inside the light source statement.

Note: In POV-Ray 3.0 this feature was turned off and on with the atmosphere keyword.

3.4.4.1.11 Atmospheric Attenuation

Normally light coming from light sources is not influenced by fog or atmospheric media. This can be changed by turning the media_attenuation on for a given light source on. All light coming from this light source will now be diminished as it travels through the fog or media. This results in an distance-based, exponential intensity falloff ruled by the used fog or media. If there is no fog or media no change will be seen.

Note: In POV-Ray 3.0 this feature was turned off and on with the atmospheric_attenuation keyword.

3.4.4.2 Light Group

Light groups make it possible to create a union of light sources and objects, where the objects in the group are illuminated by the lights in the group or, if so desired, by the global light sources as well. The light sources in the group can only illuminate the objects that are in the group, this also applies to scattering media, and it must be included in the light group as well. Keep in mind that if the scattering media also has an absorption component, it will be affected by light sources that are not in the light group definition.

Light groups are for example useful when creating scenes in which some objects turn out to be too dark but the average light is exactly how it should be, as the light sources in the group do not contribute to the global lighting.

Syntax :

light_group {
  LIGHT_GROUP LIGHT  |
  LIGHT_GROUP OBJECT |
  LIGHT_GROUP
  [LIGHT_GROUP MODIFIER]
  }

LIGHT_GROUP LIGHT:
  light_source | light_source IDENTIFIER
LIGHT_GROUP OBJECT:
  OBJECT | OBJECT IDENTIFIER
LIGHT_GROUP MODIFIER:
  global_lights BOOL | TRANSFORMATION
  • To illuminate objects in the group with the light from global light sources, add global_lights on to the light group definition.
  • Light groups may be nested. In this case light groups inherit the light sources of the light group in which they are contained.
  • Light groups can be seen as a union of an object with a light_source and can be used with CSG.

Some examples of a simple light group:

#declare RedLight =
light_source {
  <-500,500,-500>
  rgb <1,0,0>
  }

light_group {
  light_source {RedLight}
  sphere {0,1 pigment {rgb 1}}
  global_lights off
  }

A nested light group:

#declare L1 =
light_group {
  light_source {<10,10,0>, rgb <1,0,0>}
  light_source {<0,0,-100>, rgb <0,0,1>}
  sphere {0,1 pigment {rgb 1}}
  }

light_group {
  light_source {<0,100,0>, rgb 0.5}
  light_group {L1}
  }

Light groups with CSG:

difference {
  light_group {
    sphere {0,1 pigment {rgb 1}}
    light_source {<-100,0,-100> rgb <1,0,0>}
    global_lights off
    }
  light_group {
    sphere {<0,1,0>,1 pigment {rgb 1}}
    light_source {<100,100,0> rgb <0,0,1>}
    global_lights off
    }
  rotate <-45,0,0>
  }

In the last example the result will be a sphere illuminated red, where the part that is differenced away is illuminated blue. The end result is comparable to the difference between two spheres with a different pigment.

3.4.4.3 Radiosity

3.4.4.3.1 Radiosity Basics

Radiosity is an extra calculation that more realistically computes the diffuse inter-reflection of light. This diffuse inter-reflection can be seen if you place a white chair in a room full of blue carpet, blue walls and blue curtains. The chair will pick up a blue tint from light reflecting off of other parts of the room. Also notice that the shadowed areas of your surroundings are not totally dark even if no light source shines directly on the surface. Diffuse light reflecting off of other objects fills in the shadows. Typically ray-tracing uses a trick called ambient light to simulate such effects but it is not very accurate.

Radiosity calculations are only made when a radiosity{} block is used inside the global_settings{} block.

The following sections describes how radiosity works, how to control it with various global settings and tips on trading quality vs. speed.

3.4.4.3.2 How Radiosity Works

The problem of ray-tracing is to figure out what the light level is at each point that you can see in a scene. Traditionally, in ray tracing, this is broken into the sum of these components:

Diffuse
the effect that makes the side of things facing the light brighter;
Specular
the effect that makes shiny things have dings or sparkles on them;
Reflection
the effect that mirrors give; and
Ambient
the general all-over light level that any scene has, which keeps things in shadow from being pure black.

POV-Ray's radiosity system, based on a method by Greg Ward, provides a way to replace the last term - the constant ambient light value - with a light level which is based on what surfaces are nearby and how bright in turn they are.

The first thing you might notice about this definition is that it is circular: the brightness and color of everything is dependent on everything else and vice versa. This is true in real life but in the world of ray-tracing, we can make an approximation. The approximation that is used is: the objects you are looking at have their ambient values calculated for you by checking the other objects nearby. When those objects are checked during this process, however, their diffuse term is used. The brightness of radiosity in POV-Ray is based on two things:

  1. the amount of light gathered
  2. the diffuse property of the surface finish

Note: The following is an important behavior change!

Previously an object could have both radiosity and an ambient term. This is no longer the case, as when radiosity is used an objects ambient term is effectively set to zero. See the emission keyword that has been added to the finish block if the intent is to model a glowing object.

How does POV-Ray calculate the ambient term for each point? By sending out more rays, in many different directions, and averaging the results. A typical point might use 200 or more rays to calculate its ambient light level correctly.

Now this sounds like it would make the ray-tracer 200 times slower. This is true, except that the software takes advantage of the fact that ambient light levels change quite slowly (remember, shadows are calculated separately, so sharp shadow edges are not a problem). Therefore, these extra rays are sent out only once in a while (about 1 time in 50), then these calculated values are saved and reused for nearby pixels in the image when possible.

This process of saving and reusing values is what causes the need for a variety of tuning parameters, so you can get the scene to look just the way you want.

3.4.4.3.3 Adjusting Radiosity

As described earlier, radiosity is turned on by using the radiosity{} block in global_setting. Radiosity has many parameters that are specified as follows:

global_settings { radiosity { [RADIOSITY_ITEMS...] } }
RADIOSITY_ITEMS:
  adc_bailout Float | always_sample Bool | brightness Float |
  count Integer [,Integer] | error_bound Float | gray_threshold Float |
  low_error_factor Float | max_sample Float | media Bool |
  maximum_reuse Float | minimum_reuse Float | nearest_count Integer [,Integer] |
  normal Bool | pretrace_start Float |
  pretrace_end Float | recursion_limit Integer | subsurface Bool

Each item is optional and may appear in any order. If an item is specified more than once the last setting overrides previous values. Details on each item is given in the following sections.

Note: Considerable changes have been made to the way radiosity works in POV-Ray 3.7 compared to previous versions. Old scenes will not render with exactly the same results. It is not possible to use the #version directive to get backward compatibility for radiosity.

3.4.4.3.3.1 adc_bailout

You can specify an adc_bailout for radiosity rays. Usually the default of 0.01 will give good results, but for scenes with bright emissive objects it should be set to adc_bailout = 0.01 / brightest_emissive_object.

3.4.4.3.3.2 always_sample

Since always_sample off is the default, POV-Ray will only use the data from the pretrace step and not gather any new samples during the final radiosity pass. This produces higher quality results, and quicker renders. It may also reduce the splotchy appearance of the radiosity samples, and can be very useful when reusing previously saved radiosity data. If you find the need to override the behavior, you can do so by specifying always_sample on.

3.4.4.3.3.3 brightness

The brightness keyword specifies a float value that is the degree to which objects are brightened before being returned upwards to the rest of the system. Ideally brightness should be set to the default value of 1.0. If the overall brightness doesn't seem to fit, the diffuse color of objects and/or the overall brightness of light sources (including emission > 0 objects) should be adjusted.

As an example, a typical problem encountered in radiosity scenes is, when setting pigment {rgb 1} and diffuse 1.0, then tweaking the light source(s) and ambient_light setting to make the image look right. It just doesn't work properly in radiosity scenes, as it will give too strong inter-reflections. While you can compensate for this by reducing radiosity brightness, it's generally discouraged. In this case the surface properties should be fixed (e.g. diffuse set to something around 0.7, which is much more realistic).

An exception, calling for the adjustment of radiosity brightness, would be to compensate for a low recursion_limit setting (e.g recursion_limit 1). In such a case, increasing brightness will help maintain a realistic overall brightness.

3.4.4.3.3.4 count

The integer number of rays that are sent out whenever a new radiosity value has to be calculated is given by count. The default value is 35, if the value exceeds 1600, POV-Ray will use a Halton sequence instead of the default built-in sequence. When this value is too low, the light level will tend to look a little bit blotchy, as if the surfaces you are looking at were slightly warped. If this is not important to your scene (as in the case that you have a bump map or if you have a strong texture) then by all means use a lower number.

By default, POV-Ray uses the same set of directions for each new radiosity value to calculate. In order to cover more directions in total without increasing the number of rays to trace, count accepts an optional second parameter which specifies the total number of directions from which to choose. POV-Ray will then draw directions from this pool in a round-robin fashion.

3.4.4.3.3.5 error_bound

The error_bound float value is one of the two main speed/quality tuning values (the other is of course the number of rays shot). In an ideal world, this would be the only value needed. It is intended to mean the fraction of error tolerated. For example, if it were set to 1 the algorithm would not calculate a new value until the error on the last one was estimated at as high as 100%. Ignoring the error introduced by rotation for the moment, on flat surfaces this is equal to the fraction of the reuse distance, which in turn is the distance to the closest item hit. If you have an old sample on the floor 10 inches from a wall, an error bound of 0.5 will get you a new sample at a distance of about 5 inches from the wall.

The default value of 1.8 is good for a smooth general lighting effect. Using lower values is more accurate, but it will strongly increase the danger of artifacts and therefore require higher count. You can use values even lower than 0.1 but both render time and memory use can become extremely high.

3.4.4.3.3.6 gray_threshold

Diffusely inter-reflected light is a function of the objects around the point in question. Since this is recursively defined to millions of levels of recursion, in any real life scene, every point is illuminated at least in part by every other part of the scene. Since we cannot afford to compute this, if we only do one bounce, the calculated ambient light is very strongly affected by the colors of the objects near it. This is known as color bleed and it really happens but not as much as this calculation method would have you believe. The gray_threshold float value grays it down a little, to make your scene more believable. A value of .6 means to calculate the ambient value as 60% of the equivalent gray value calculated, plus 40% of the actual value calculated. At 0%, this feature does nothing. At 100%, you always get white/gray ambient light, with no hue.

Note: This does not change the lightness/darkness, only the strength of hue/grayness (in HLS terms, it changes S only). The default value is 0.0

3.4.4.3.3.7 low_error_factor

If you calculate just enough samples, but no more, you will get an image which has slightly blotchy lighting. What you want is just a few extra interspersed, so that the blending will be nice and smooth. The solution to this is the mosaic preview, controlled by pretrace, it goes over the image one or more times beforehand, calculating radiosity values. To ensure that you get a few extra, the radiosity algorithm lowers the error bound during the pre-final passes, then sets it back just before the final pass. The low_error_factor is a float tuning value which sets the amount that the error bound is dropped during the preliminary image passes. If your low error factor is 0.8 and your error bound is set to 0.4 it will really use an error bound of 0.32 during the first passes and 0.4 on the final pass. The default value is 0.5.

3.4.4.3.3.8 max_sample

Sometimes there can be splotchy patches that are caused by objects that are very bright. This can be sometimes avoided by using the max_sample keyword. max_sample takes a float parameter which specifies the brightest that any gathered sample is allowed to be. Any samples brighter than this will have their brightness decreased (without affecting color). Note however that this mechanism will somewhat darken the overall brightness in an unrealistic way. Specifying a non-positive value for max_sample will allow any brightness of samples (which is the default).

3.4.4.3.3.9 maximum_reuse

The maximum_reuse parameter works in conjunction with, and is similar to that of minimum_reuse, the only difference being that it is an upper bound rather than a lower one. The default value is 0.200.

Note: If you choose to adjust either the minimum_reuse or maximum_reuse settings they are subject to the criteria listed below:

  • If minimum_reuse > maximum_reuse/2 with only one value is specified, a warning is issued and the unspecified value is adjusted.
  • If minimum_reuse > maximum_reuse/2 with both values specified, a warning is issued and neither value is modified.
  • If minimum_reuse >= maximum_reuse, an error is generated.
3.4.4.3.3.10 minimum_reuse

The minimum effective radius ratio is set by minimum_reuse float value. This is the fraction of the screen width which sets the minimum radius of reuse for each sample point (actually, it is the fraction of the distance from the eye but the two are roughly equal for normal camera angles). For example, if the value is 0.02, the radius of maximum reuse for every sample is set to whatever ground distance corresponds to 2% of the width of the screen. Imagine you sent a ray off to the horizon and it hits the ground at a distance of 100 miles from your eye point. The reuse distance for that sample will be set to 2 miles. At a resolution of 300*400 this will correspond to (very roughly) 8 pixels. The theory is that you do not want to calculate values for every pixel into every crevice everywhere in the scene, it will take too long. This sets a minimum bound for the reuse. If this value is too low, (which it should be in theory) rendering gets slow, and inside corners can get a little grainy. If it is set too high, you do not get the natural darkening of illumination near inside edges, since it reuses. At values higher than 2% you start getting more just plain errors, like reusing the illumination of the open table underneath the apple. Remember that this is a unit less ratio. The default value is 0.015.

3.4.4.3.3.11 nearest_count

The nearest_count integer value is the minimum number of old radiosity values blended together to create a new interpolated value. There is no upper limit on the number of samples blended, all available samples are blended that match the error_bound and maximum_reuse settings. When an optional second parameter (adaptive radiosity pretrace) is specified after the nearest_count keyword, pretrace will stop re-iterating over areas where, on average, that many average-quality samples are already present per ray. (The actual number of samples required to satisfy the nearest_count settings is influenced by sample quality, with high-quality samples reducing the effective number of samples required, down to 1/4 of the parameter value in extreme cases, and low-quality samples increasing the number.) With a setting lower than 4, things can get pretty patchy, this can be useful for debugging. Conversely, the nearest_count upper limit setting is 20, since values greater than 20 are not very useful in practice, and that is currently the size of the array allocated. The default value is 5.

3.4.4.3.3.12 pretrace_start and pretrace_end

To control the radiosity pre-trace gathering step, use the keywords pretrace_start and pretrace_end. Each of these is followed by a decimal value between 0.0 and 1.0 which specifies the size of the blocks in the mosaic preview as a percentage of the image size. The defaults are 0.08 for pretrace_start and 0.04 for pretrace_end.

3.4.4.3.3.13 recursion_limit

The recursion_limit is an integer value which determines how many recursion levels are used to calculate the diffuse inter-reflection. The default value is 2, the upper limit is 20. In practice, values greater than 3 are seldom useful.

3.4.4.3.4 Configuring Radiosity

The following parameters deal with configuring radiosity and how it interacts with other features. See also these additional command line options for more control.

3.4.4.3.4.1 Importance

If you have some comparatively small yet bright objects in your scene, radiosity will tend to produce bright splotchy artifacts unless you use a pretty high number of rays, which in turn will tremendously increase rendering time. To somewhat mitigate this issue, full ray computations are performed only for a certain portion of sample rays, depending on the ''importance'' of the first object each ray encounters. Importance can be assigned on a per-object basis using the following syntax:

sphere { ... radiosity { importance IMPORTANCE } }

Where IMPORTANCE is a value in the range of greater than 0.0 to less than or equal to 1.0 specifying the percentage of rays to actually compute on average. A particular ray will only be fully computed if it is within the first COUNT*IMPORTANCE rays of the sampling sequence; due to the low-discrepancy sub-random nature of the sequence, this is mostly equivalent to a per-ray weighted random choice, while maintaining a low-discrepancy uniform distribution on a per-object basis. Rays actually computed are weighted to compensate for those not computed.

Objects derived from previously defined objects will default to the inherited importance. CSG components without an explicit importance value set will default to their parent object's importance. Other objects will normally default to importance 1.0, however this can be changed in a default{} block:

default { radiosity { importance DEFAULT_IMPORTANCE } }
3.4.4.3.4.2 Media and Radiosity

Radiosity estimation can be affected by media. To enable this feature, add media on to the radiosity{} block. The default is off

3.4.4.3.4.3 No Radiosity

Specifying no_radiosity in an object block makes that object invisible to radiosity rays, in the same way as no_image, no_reflection and no_shadow make an object invisible to primary, reflected and shadow test rays, respectively.

3.4.4.3.4.4 Normal and Radiosity

Radiosity estimation can be affected by normals. To enable this feature, add normal on to the radiosity{} block. The default is off

3.4.4.3.4.5 Save and Load Radiosity Data

In general, it is not a good idea to save and load radiosity data if scene objects are moving. Even after the data is loaded, more samples may be taken during the final rendering phase, particularly if you've specified always_sample on.

Note: The method to load and save radiosity data has been changed to a command line option. See section radiosity load and save for more details.

3.4.4.3.4.6 Subsurface and Radiosity

To specify whether radiosity sampling should honor subsurface light transport, you should place the following in the global settings radiosity block:

  global_settings {
    radiosity { subsurface BOOL }
    }

If this setting is off, the default, radiosity based diffuse illumination is computed as if the surrounding objects had subsurface light transport turned off. Setting this to on may improve realism especially in the presence of materials with high translucency, but at some cost in rendering time.

See the section Subsurface Light Transport for more information about the role of subsurface in the global settings block.

3.4.4.3.5 Tips on Radiosity

Have a look at the Radiosity Tutorial to get a feel for what the visual result of changing radiosity parameters is.

If you want to see where your values are being calculated set radiosity count down to about 20, set radiosity nearest_count to 1 and set gray_threshold to 0. This will make everything maximally patchy, so you will be able to see the borders between patches. There will have been a radiosity calculation at the center of most patches. As a bonus, this is quick to run. You can then change the error_bound up and down to see how it changes things. Likewise modify minimum_reuse.

One way to get extra smooth results: crank up the sample count (we have gone as high as 1300) and drop the low_error_factor to something small like 0.6. Bump up the nearest_count to 7 or 8. This will get better values, and more of them, then interpolate among more of them on the last pass. This is not for people with a lack of patience since it is like a squared function. If your blotchiness is only in certain corners or near certain objects try tuning the error bound instead. Never drop it by more than a little at a time, since the run time will get very long.

Sometimes extra samples are taken during the final rendering pass, if you've specified always_sample on. These newer samples can cause discontinuities in the radiosity in some scenes. To decrease these artifacts, use a pretrace_end of 0.04 (or even 0.02 if you are really patient and picky). This will cause the majority of the samples to be taken during the preview passes, and decrease the artifacts created during the final rendering pass. Be sure to force POV-Ray to only use the data from the pretrace step and not gather any new samples during the final radiosity pass, by removing always_sample on from within the global_settings radiosity block.

If your scene uses ambient objects (especially small ambient objects) as light sources, you should probably use a higher count (100-150 and higher). For such scenes, an error_bound of 1.0 is usually good. A higher value causes too much error, but lower causes very slow rendering. It is important to adjust adc_bailout.

3.4.4.4 Photons

With photons it is possible to render true reflective and refractive caustics. The photon map was first introduced by Henrik Wann Jensen (see Suggested Reading).

Photon mapping is a technique which uses a forward ray-tracing pre-processing step to render refractive and reflective caustics realistically. This means that mirrors can reflect light rays and lenses can focus light.

Photon mapping works by shooting packets of light (photons) from light sources into the scene. The photons are directed towards specific objects. When a photon hits an object after passing through (or bouncing off of) the target object, the ray intersection is stored in memory. This data is later used to estimate the amount of light contributed by reflective and refractive caustics.

3.4.4.4.1 Examples
This image shows refractive caustics from a sphere and a cylinder. Both use an index of refraction of 1.2. Also visible is a small amount of reflective caustics from the metal sphere, and also from the clear cylinder and sphere. |
 | Reflective caustics
 | Here we have three lenses and three light sources. The middle lens has photon mapping turned off. You can also see some reflective caustics from the brass box (some light reflects and hits the blue box, other light bounces through the nearest lens and is focused in the lower left corner of the image).
Photons used for lenses and caustics |
3.4.4.4.2 Using Photon Mapping in Your Scene

When designing a scene with photons, it helps to think of the scene objects in two categories. Objects in the first category will show photon caustics when hit by photons. Objects in the second category cause photon caustics by reflecting or refracting photons. Some objects may be in both categories, and some objects may be in neither category.

Category 1 - Objects that show photon caustics

By default, all objects are in the first category. Whenever a photon hits an object, the photon is stored and will later be used to render caustics on that object. This means that, by default, caustics from photons can appear on any surface. To speed up rendering, you can take objects out of this category. You do this with the line: photons{collect off}. If you use this syntax, caustics from photons will not appear on the object. This will save both memory and computational time during rendering.

Category 2 - Objects that cause photon caustics

By default, there are no objects in the second category. If you want your object to cause caustics, you need to do two things. First, make your object into a "target." You do this with the target keyword. This enables light sources to shoot photons at your object. Second, you need to specify if your object reflects photons, refracts photons, or both. This is done with the reflection on and refraction on keywords. To allow an object to reflect and refract photons, you would use the following lines of code inside the object:

photons{
  target
  reflection on
  refraction on
  }

Generally speaking, you do not want an object to be in both categories. Most objects that cause photon caustics do not themselves have much color or brightness. Usually they simply refract or reflect their surroundings. For this reason, it is usually a waste of time to display photon caustics on such surfaces. Even if computed, the effects from the caustics would be so dim that they would go unnoticed.

Sometimes, you may also wish to add photons{collect off} to other clear or reflective objects, even if they are not photon targets. Again, this is done to prevent unnecessary computation of caustic lighting.

Finally, you may wish to enable photon reflection and refraction for a surface, even if it is not a target. This allows indirect photons (photons that have already hit a target and been reflected or refracted) to continue their journey after hitting this object.

3.4.4.4.3 Photon Global Settings
global_photon_block:

photons {
  spacing <photon_spacing> | count <photons_to_shoot>
  [gather <min_gather>, <max_gather>]
  [media <max_steps> [,<factor>]]
  [jitter <jitter_amount>]
  [max_trace_level <photon_trace_level>]
  [adc_bailout <photon_adc_bailout>]
  [save_file "filename" | load_file "filename"]
  [autostop <autostop_fraction>]
  [expand_thresholds <percent_increase>, <expand_min>]
  [radius <gather_radius>, <multiplier>, <gather_radius_media>,<multiplier>]
  }

All photons default values:

Global :
expand_min    : 40
gather        : 20, 100
jitter        : 0.4
media         : 0

Object :
collect       : on
refraction    : off
reflection    : off
split_union   : on
target        : 1.0

Light_source:
area_light    : off
refraction    : off
reflection    : off

To specify photon gathering and storage options you need to add a photons block to the global_settings section of your scene.

For example:

global_settings {
  photons {
    count 20000
    autostop 0
    jitter .4
    }
  }

The number of photons generated can be set using either the spacing or count keywords:

  • If spacing is used, it specifies approximately the average distance between photons on surfaces. If you cut the spacing in half, you will get four times as many surface photons, and eight times as many media photons.
  • If count is used, POV-Ray will shoot the approximately number of photons specified. The actual number of photons that result from this will almost always be at least slightly different from the number specified. Still, if you double the photons_to_shoot value, then twice as many photons will be shot. If you cut the value in half, then half the number of photons will be shot.
    • It may be less, because POV shoots photons at a target object's bounding box, which means that some photons will miss the target object.
    • On the other hand, may be more, because each time one object hits an object that has both reflection and refraction, two photons are created (one for reflection and one for refraction).
    • POV will attempt to compensate for these two factors, but it can only estimate how many photons will actually be generated. Sometimes this estimation is rather poor, but the feature is still usable.

The keyword gather allows you to specify how many photons are gathered at each point during the regular rendering step. The first number (default 20) is the minimum number to gather, while the second number (default 100) is the maximum number to gather. These are good values and you should only use different ones if you know what you are doing.

The keyword media turns on media photons. The parameter max_steps specifies the maximum number of photons to deposit over an interval. The optional parameter factor specifies the difference in media spacing compared to surface spacing. You can increase factor and decrease max_steps if too many photons are being deposited in media.

The keyword jitter specifies the amount of jitter used in the sampling of light rays in the pre-processing step. The default value is good and usually does not need to be changed.

The keywords max_trace_level and adc_bailout allow you to specify these attributes for the photon-tracing step. If you do not specify these, the values for the primary ray-tracing step will be used.

The keywords save_file and load_file allow you to save and load photon maps. If you load a photon map, no photons will be shot. The photon map file contains all surface (caustic) and media photons.

radius is used for gathering photons. The larger the radius, the longer it takes to gather photons. But if you use too small of a radius, you might not get enough photons to get a good estimate. Therefore, choosing a good radius is important. Normally POV-Ray looks through the photon map and uses some ad-hoc statistical analysis to determine a reasonable radius. Sometimes it does a good job, sometimes it does not. The radius keyword lets you override or adjust POV-Ray's guess.

radius parameters (all are optional):

  1. Manually set the gather radius for surface photons. If this is either zero or if you leave it out, POV-Ray will analyze and guess.
  2. Adjust the radius for surface photons by setting a multiplier. If POV-Ray, for example, is picking a radius that you think is too big (render is too slow), you can use radius ,0.5 to lower the radius (multiply by 0.5) and speed up the render at the cost of quality.
  3. Manually set the gather radius for media photons.
  4. Adjust the radius for media photons by setting a multiplier.

The keywords autostop and expand_thresholds will be explained later.

3.4.4.4.4 Shooting Photons at an Object
object_photon_block:
photons {
  [target [Float]]
  [refraction on|off]
  [reflection on|off]
  [collect on|off]
  [pass_through]
  }

To shoot photons at an object, you need to tell POV that the object receives photons. To do this, create a photons { } block within the object. For example:

object {
  MyObject
  photons {
    target
    refraction on
    reflection on
    collect off
    }
  }

In this example, the object both reflects and refracts photons. Either of these options could be turned off (by specifying reflection off, for example). By using this, you can have an object with a reflective finish which does not reflect photons for speed and memory reasons.

The keyword target makes this object a target.

The density of the photons can be adjusted by specifying a spacing multiplier in the form of an optional value after the target keyword. If, for example, you specify a spacing multiplier of 0.5, then the spacing for photons hitting this object will be 1/2 of the distance of the spacing for other objects.

Note: This means four times as many surface photons, and eight times as many media photons.

The keyword collect off causes the object to ignore photons. Photons are neither deposited nor gathered on that object.

The keyword pass_through causes photons to pass through the object unaffected on their way to a target object. Once a photon hits the target object, it will ignore the pass_through flag. This is basically a photon version of the no_shadow keyword, with the exception that media within the object will still be affected by the photons (unless that media specifies collect off). If you use the no_shadow keyword, the object will be tagged as pass_through automatically. You can then turn off pass_through if necessary by simply using photons { pass_through off }.

Note: Photons will not be shot at an object unless you specify the target keyword. Simply turning refraction on will not suffice.

When shooting photons at a CSG-union, it may sometimes be of advantage to use split_union off inside the union. POV-Ray will be forced to shoot at the whole object, instead of splitting it up and shooting photons at its compound parts.

3.4.4.4.5 Photons and Light Sources
light_photon_block:
photons {
  [refraction on | off]
  [reflection on | off]
  [area_light]
  }

Example:

light_source {
  MyLight
  photons {
    refraction on
    reflection on
    }
  }

Sometimes, you want photons to be shot from one light source and not another. In that case, you can turn photons on for an object, but specify photons {reflection off refraction off } in the light source's definition. You can also turn off only reflection or only refraction for any light source.

Note: The photon shooting performance has been improved with the addition of multiple-thread support. To take advantage of this at the moment, your scene will need multiple light sources.

3.4.4.4.6 Photons and Media
global_settings {
  photons {
    count 10000
    media 100
    }
  }

Photons also interact fully with media. This means that volumetric photons are stored in scattering media. This is enabled by using the keyword media within the photons block.

To store photons in media, POV deposits photons as it steps through the media during the photon-tracing phase of the render. It will deposit these photons as it traces caustic photons, so the number of media photons is dependent on the number of caustic photons. As a light ray passes through a section of media, the photons are deposited, separated by approximately the same distance that separates surface photons.

You can specify a factor as a second optional parameter to the media keyword. If, for example, factor is set to 2.0, then photons will be spaced twice as far apart as they would otherwise have been spaced.

Sometimes, however, if a section of media is very large, using these settings could create a large number of photons very fast and overload memory. Therefore, following the media keyword, you must specify the maximum number of photons that are deposited for each ray that travels through each section of media. A setting of 100 should probably work in most cases.

You can put collect off into media to make that media ignore photons. Photons will neither be deposited nor gathered in a media that is ignoring them. Photons will also not be gathered nor deposited in non-scattering media. However, if multiple medias exist in the same space, and at least one does not ignore photons and is scattering, then photons will be deposited in that interval and will be gathered for use with all media in that interval.

3.4.4.4.7 Photons FAQ

I made an object with IOR 1.0 and the shadows look weird.

If the borders of your shadows look odd when using photon mapping, do not be alarmed. This is an unfortunate side-effect of the method. If you increase the density of photons (by decreasing spacing and gather radius) you will notice the problem diminish. We suggest not using photons if your object does not cause much refraction (such as with a window pane or other flat piece of glass or any objects with an IOR very close to 1.0).

My scene takes forever to render.

When POV-Ray builds the photon maps, it continually displays in the status bar the number of photons that have been shot. Is POV-Ray stuck in this step and does it keep shooting lots and lots of photons?

yes

If you are shooting photons at an infinite object (like a plane), then you should expect this. Either be patient or do not shoot photons at infinite objects.

Are you shooting photons at a CSG difference? Sometimes POV-Ray does a bad job creating bounding boxes for these objects. And since photons are shot at the bounding box, you could get bad results. Try manually bounding the object. You can also try the autostop feature (try autostop 0). See the docs for more info on autostop.

no

Does your scene have lots of glass (or other clear objects)? Glass is slow and you need to be patient.

My scene has polka dots but renders really quickly. Why?

You should increase the number of photons (or decrease the spacing).

The photons in my scene show up only as small, bright dots. How can I fix this?

The automatic calculation of the gather radius is probably not working correctly, most likely because there are many photons not visible in your scene which are affecting the statistical analysis.

You can fix this by either reducing the number of photons that are in your scene but not visible to the camera (which confuse the auto-computation), or by specifying the initial gather radius manually by using the keyword radius. If you must manually specify a gather radius, it is usually best to also use spacing instead of count, and then set radius and spacing to a 5:1 (radius:spacing) ratio.

Adding photons slowed down my scene a lot, and I see polka dots.

This is usually caused by having both high- and low-density photons in the same scene. The low density ones cause polka dots, while the high density ones slow down the scene. It is usually best if the all photons are on the same order of magnitude for spacing and brightness. Be careful if you are shooting photons objects close to and far from a light source. There is an optional parameter to the target keyword which allows you to adjust the spacing of photons at the target object. You may need to adjust this factor for objects very close to or surrounding the light source.

I added photons, but I do not see any caustics.

When POV-Ray builds the photon maps, it continually displays in the status bar the number of photons that have been shot. Did it show any photons being shot?

no

Try avoiding autostop, or you might want to bound your object manually.

Try increasing the number of photons (or decreasing the spacing).

yes

Were any photons stored (the number after total in the rendering message as POV-Ray shoots photons)?

no

It is possible that the photons are not hitting the target object (because another object is between the light source and the other object).

yes

The photons may be diverging more than you expect. They are probably there, but you cannot see them since they are spread out too much

The base of my glass object is really bright.

Use collect off with that object.

Will area lights work with photon mapping?

Photons do work with area lights. However, normally photon mapping ignores all area light options and treats all light sources as point lights. If you would like photon mapping to use your area light options, you must specify the "area_light" keyword within the photons { } block in your light source's code. Doing this will not increase the number of photons shot by the light source, but it might cause regular patterns to show up in the rendered caustics (possibly splotchy).

What do the stats mean?

In the stats, photons shot means how many light rays were shot from the light sources. photons stored means how many photons are deposited on surfaces in the scene. If you turn on reflection and refraction, you could get more photons stored than photons shot, since the each ray can get split into two.

3.4.4.4.8 Photon Tips
  • Use collect off in objects that photons do not hit. Just put photons { collect off } in the object's definition.
  • Use collect off in glass objects.
  • Use autostop unless it causes problems.
  • A big tip is to make sure that all of the final densities of photons are of the same general magnitude. You do not want spots with really high density photons and another area with really low density photons. You will always have some variation (which is a good thing), but having really big differences in photon density is what causes some scenes to take many hours to render.
3.4.4.4.9 Advanced Techniques
3.4.4.4.9.1 Autostop
To understand the autostop option, you need to understand the way photons are shot from light sources. Photons are shot in a spiral pattern with uniform angular density. Imagine a sphere with a spiral starting at one of the poles and spiraling out in ever-increasing circles to the equator. Two angles are involved here. The first, phi, is the how far progress has been made in the current circle of the spiral. The second, theta, is how far we are from the pole to the equator. Now, imagine this sphere centered at the light source with the pole where the spiral starts pointed towards the center of the object receiving photons. Now, photons are shot out of the light in this spiral pattern. |
 | Example of the photon autostop option

Normally, POV does not stop shooting photons until the target object's entire bounding box has been thoroughly covered. Sometimes, however, an object is much smaller than its bounding box. At these times, we want to stop shooting if we do a complete circle in the spiral without hitting the object. Unfortunately, some objects (such as copper rings), have holes in the middle. Since we start shooting at the middle of the object, the photons just go through the hole in the middle, thus fooling the system into thinking that it is done. To avoid this, the autostop keyword lets you specify how far the system must go before this auto-stopping feature kicks in. The value specified is a fraction of the object's bounding box. Valid values are 0.0 through 1.0 (0% through 100%). POV will continue to shoot photons until the spiral has exceeded this value or the bounding box is completely covered. If a complete circle of photons fails to hit the target object after the spiral has passed the autostop threshold, POV will then stop shooting photons.

The autostop feature will also not kick in until at least one photon has hit the object. This allows you to use autostop 0 even with objects that have holes in the middle.

Note: If the light source is within the object's bounding box, the photons are shot in all directions from the light source.

3.4.4.4.9.2 Adaptive Search Radius

Unless photons are interacting with media, POV-Ray uses an adaptive search radius while gathering photons. If the minimum number of photons is not found in the original search radius, the radius is expanded and searched again. Using this adaptive search radius can both decrease the amount of time it takes to render the image, and sharpen the borders in the caustic patterns.

Sometimes this adaptive search technique can create unwanted artifacts at borders. To remove these artifacts, a few thresholds are used, which can be specified by expand_thresholds. For example, if expanding the radius increases the estimated density of photons by too much (threshold is percent_increase, default is 20%, or 0.2), the expanded search is discarded and the old search is used instead. However, if too few photons are gathered in the expanded search (expand_min, default is 40), the new search will be used always, even if it means more than a 20% increase in photon density.

3.4.4.4.9.3 Photons and Dispersion

When dispersion is specified for interior of a transparent object, photons will make use of that and show "colored" caustics.

3.4.4.4.9.4 Saving and Loading Photon Maps

It is possible to save and load photon maps to speed up rendering. The photon map itself is view-independent, so if you want to animate a scene that contains photons and you know the photon map will not change during the animation, you can save it on the first frame and then load it for all subsequent frames.

To save the photon map, put the line

save_file "myfile.ph"

into the photons { } block inside the global_settings section.

Loading the photon map is the same, but with load_file instead of save_file. You cannot both load and save a photon map in the POV file. If you load the photon map, it will load all of the photons. No photons will be shot if the map is loaded from a file. All other options (such as gather radius) must still be specified in the POV scene file and are not loaded with the photon map.

When can you safely re-use a saved photon map?

  • Moving the camera is always safe.
  • Moving lights that do not cast photons is always safe.
  • Moving objects that do not have photons shot at them, that do not receive photons, and would not receive photons in the new location is always safe.
  • Moving an object that receives photons to a new location where it does not receive photons is sometimes safe.
  • Moving an object to a location where it receives photons is not safe
  • Moving an object that has photons shot at it is not safe
  • Moving a light that casts photons is not safe.
  • Changing the texture of an object that receives photons is safe.
  • Changing the texture of an object that has photons shot at it produces results that are not realistic, but can be useful sometimes.

In general, changes to the scene geometry require photons to be re-shot. Changing the camera parameters or changing the image resolution does not.

3.4.5 Object

Objects are the building blocks of your scene. There are a lot of different types of objects supported by POV-Ray. In the following sections, we describe Finite Solid Primitives, Finite Patch Primitives and Infinite Solid Primitives. These primitive shapes may be combined into complex shapes using Constructive Solid Geometry (also known as CSG).

The basic syntax of an object is a keyword describing its type, some floats, vectors or other parameters which further define its location and/or shape and some optional object modifiers such as texture, interior_texture, pigment, normal, finish, interior, bounding, clipping or transformations. Specifically the syntax is:

OBJECT:
  FINITE_SOLID_OBJECT | FINITE_PATCH_OBJECT |
  INFINITE_SOLID_OBJECT | CSG_OBJECT | LIGHT_SOURCE |
  object { OBJECT_IDENTIFIER [OBJECT_MODIFIERS...] }
FINITE_SOLID_OBJECT:
  BLOB | BOX | CONE | CYLINDER | HEIGHT_FIELD | ISOSURFACE | JULIA_FRACTAL |
  LATHE | OVUS | PARAMETRIC | PRISM | SPHERE | SPHERE_SWEEP | SUPERELLIPSOID |
  SOR | TEXT | TORUS
FINITE_PATCH_OBJECT:
  BICUBIC_PATCH | DISC | MESH | MESH2 | POLYGON | TRIANGLE |
  SMOOTH_TRIANGLE
  INFINITE_SOLID_OBJECT:
  PLANE | POLY | CUBIC | QUARTIC | QUADRIC
CSG_OBJECT:
  UNION | INTERSECTION | DIFFERENCE | MERGE

Object identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

OBJECT_DECLARATION:
  #declare IDENTIFIER = OBJECT |
  #local IDENTIFIER = OBJECT

Where IDENTIFIER is the name of the identifier up to 40 characters long and OBJECT is any valid object. To invoke an object identifier, you wrap it in an object{...} statement. You use the object statement regardless of what type of object it originally was. Although early versions of POV-Ray required this object wrapper all of the time, now it is only used with OBJECT_IDENTIFIERS.

Object modifiers are covered in detail later. However here is a brief overview.

The texture describes the surface properties of the object. Complete details are in textures. Textures are combinations of pigments, normals, and finishes. In the section pigment you will learn how to specify the color or pattern of colors inherent in the material. In normal, we describe a method of simulating various patterns of bumps, dents, ripples or waves by modifying the surface normal vector. The section on finish describes the reflective properties of the surface. The Interior is a feature introduced in POV-Ray 3.1. It contains information about the interior of the object which was formerly contained in the finish and halo parts of a texture. Interior items are no longer part of the texture. Instead, they attach directly to the objects. The halo feature has been discontinued and replaced with a new feature called Media which replaces both halo and atmosphere.

Bounding shapes are finite, invisible shapes which wrap around complex, slow rendering shapes in order to speed up rendering time. Clipping shapes are used to cut away parts of shapes to expose a hollow interior. Transformations tell the ray-tracer how to move, size or rotate the shape and/or the texture in the scene.

3.4.5.1 Finite Solid Primitives

There are seventeen different solid finite primitive shapes: blob, box, cone, cylinder, height field, isosurface, Julia fractal, lathe, ovus, parametric, prism, sphere, sphere_sweep, superellipsoid, surface of revolution, text and torus. These have a well-defined inside and can be used in CSG: see Constructive Solid Geometry. They are finite and respond to automatic bounding. You may specify an interior for these objects.

3.4.5.1.1 Blob

Blobs are an interesting and flexible object type. Mathematically they are iso-surfaces of scalar fields, i.e. their surface is defined by the strength of the field in each point. If this strength is equal to a threshold value you are on the surface otherwise you are not.

Picture each blob component as an object floating in space. This object is filled with a field that has its maximum at the center of the object and drops off to zero at the object's surface. The field strength of all those components are added together to form the field of the blob. Now POV-Ray looks for points where this field has a given value, the threshold value. All these points form the surface of the blob object. Points with a greater field value than the threshold value are considered to be inside while points with a smaller field value are outside.

There's another, simpler way of looking at blobs. They can be seen as a union of flexible components that attract or repel each other to form a blobby organic looking shape. The components' surfaces actually stretch out smoothly and connect as if they were made of honey or something similar.

The syntax for blob is defined as follows:

BLOB:
  blob { BLOB_ITEM... [BLOB_MODIFIERS...]}
BLOB_ITEM:
  sphere{<Center>, Radius,
    [ strength ] Strength[COMPONENT_MODIFIER...] } |
  cylinder{<End1>, <End2>, Radius,
    [ strength ] Strength [COMPONENT_MODIFIER...] } |
  component Strength, Radius, <Center> |
  threshold Amount
COMPONENT_MODIFIER:
  TEXTURE | PIGMENT | NORMAL | FINISH | TRANSFORMATION
BLOB_MODIFIER:
  hierarchy [Boolean] | sturm [Boolean] | OBJECT_MODIFIER

Blob default values:

hierarchy : on
sturm     : off
threshold : 1.0

The threshold keyword is followed by a float value which determines the total field strength value that POV-Ray is looking for. The default value if none is specified is threshold 1.0. By following the ray out into space and looking at how each blob component affects the ray, POV-Ray will find the points in space where the field strength is equal to the threshold value. The following list shows some things you should know about the threshold value.

  1. The threshold value must be positive.
  2. A component disappears if the threshold value is greater than its strength.
  3. As the threshold value gets larger, the surface you see gets closer to the centers of the components.
  4. As the threshold value gets smaller, the surface you see gets closer to the surface of the components.

Cylindrical components are specified by a cylinder statement. The center of the end-caps of the cylinder is defined by the vectors <End1> and <End2>. Next is the float value of the Radius followed by the float Strength. These vectors and floats are required and should be separated by commas. The keyword strength may optionally precede the strength value. The cylinder has hemispherical caps at each end.

Spherical components are specified by a sphere statement. The location is defined by the vector <Center>. Next is the float value of the Radius followed by the float Strength. These vector and float values are required and should be separated by commas. The keyword strength may optionally precede the strength value.

You usually will apply a single texture to the entire blob object, and you typically use transformations to change its size, location, and orientation. However both the cylinder and sphere statements may have individual texture, pigment, normal, finish, and transformations applied to them. You may not apply separate interior statements to the components but you may specify one for the entire blob.

Note: By unevenly scaling a spherical component you can create ellipsoidal components. The tutorial section on Blob Object illustrates individually textured blob components and many other blob examples.

The component keyword is an obsolete method for specifying a spherical component and is only used for compatibility with earlier POV-Ray versions. It may not have textures or transformations individually applied to it.

The strength parameter of either type of blob component is a float value specifying the field strength at the center of the object. The strength may be positive or negative. A positive value will make that component attract other components while a negative value will make it repel other components. Components in different, separate blob shapes do not affect each other.

You should keep the following things in mind.

  1. The strength value may be positive or negative. Zero is a bad value, as the net result is that no field was added -- you might just as well have not used this component.
  2. If strength is positive, then POV-Ray will add the component's field to the space around the center of the component. If this adds enough field strength to be greater than the threshold value you will see a surface.
  3. If the strength value is negative, then POV-Ray will subtract the component's field from the space around the center of the component. This will only do something if there happen to be positive components nearby. The surface around any nearby positive components will be dented away from the center of the negative component.

After all components and the optional threshold value have been specified you may specify zero or more blob modifiers. A blob modifier is any regular object modifier or the hierarchy or sturm keywords.

The components of each blob object are internally bounded by a spherical bounding hierarchy to speed up blob intersection tests and other operations. Using the optional keyword hierarchy followed by an optional boolean float value will turn it off or on. By default it is on.

The calculations for blobs must be very accurate. If this shape renders improperly you may add the keyword sturm followed by an optional boolean float value to turn off or on POV-Ray's slower-yet-more-accurate Sturmian root solver. By default it is off.

An example of a three component blob is:

BLOB:
  blob {
    threshold 0.6
      sphere { <.75, 0, 0>, 1, 1 }
      sphere { <-.375, .64952, 0>, 1, 1 }
      sphere { <-.375, -.64952, 0>, 1, 1 }
    scale 2
    }

If you have a single blob component then the surface you see will just look like the object used, i.e. a sphere or a cylinder, with the surface being somewhere inside the surface specified for the component. The exact surface location can be determined from the blob equation listed below (you will probably never need to know this, blobs are more for visual appeal than for exact modeling).

For the more mathematically minded, here's the formula used internally by POV-Ray to create blobs. You do not need to understand this to use blobs. The density of the blob field of a single component is:

Blob Density

where distance is the distance of a given point from the spherical blob's center or cylinder blob's axis. This formula has the nice property that it is exactly equal to the strength parameter at the center of the component and drops off to exactly 0 at a distance from the center of the component that is equal to the radius value. The density formula for more than one blob component is just the sum of the individual component densities.

3.4.5.1.2 Box

A simple box can be defined by listing two corners of the box using the following syntax for a box statement:

BOX:
  box {
    <Corner_1>, <Corner_2>
    [OBJECT_MODIFIERS...]
    }

The geometry of a box.

Where <Corner_1> and <Corner_2> are vectors defining the x, y, z coordinates of the opposite corners of the box.

Note: All boxes are defined with their faces parallel to the coordinate axes. They may later be rotated to any orientation using the rotate keyword.

Boxes are calculated efficiently and make good bounding shapes (if manually bounding seems to be necessary).

3.4.5.1.3 Cone

The cone statement creates a finite length cone or a frustum (a cone with the point cut off). The syntax is:

CONE:
  cone {
    <Base_Point>, Base_Radius, <Cap_Point>, Cap_Radius
    [ open ][OBJECT_MODIFIERS...]
    }

The geometry of a cone.

Where <Base_Point> and < Cap_Point> are vectors defining the x, y, z coordinates of the center of the cone's base and cap and Base_Radius and Cap_Radius are float values for the corresponding radii.

Normally the ends of a cone are closed by flat discs that are parallel to each other and perpendicular to the length of the cone. Adding the optional keyword open after Cap_Radius will remove the end caps and results in a tapered hollow tube like a megaphone or funnel.

3.4.5.1.4 Cylinder

The cylinder statement creates a finite length cylinder with parallel end caps The syntax is:

CYLINDER:
  cylinder {
    <Base_Point>, <Cap_Point>, Radius
    [ open ][OBJECT_MODIFIERS...]
    }

The geometry of a cylinder.

Where <Base_Point> and <Cap_Point> are vectors defining the x, y, z coordinates of the cylinder's base and cap and Radius is a float value for the radius.

Normally the ends of a cylinder are closed by flat discs that are parallel to each other and perpendicular to the length of the cylinder. Adding the optional keyword open after the radius will remove the end caps and results in a hollow tube.

3.4.5.1.5 Height Field

Height fields are fast, efficient objects that are generally used to create mountains or other raised surfaces out of hundreds of triangles in a mesh. The height_field statement syntax is:

HEIGHT_FIELD:
  height_field {
    [HF_TYPE] "filename" [gamma GAMMA] [premultiplied BOOL] | [HF_FUNCTION]
    [HF_MODIFIER...]
    [OBJECT_MODIFIER...]
    }
HF_TYPE:
  exr | gif | hdr | iff | jpeg | pgm | png | pot | ppm | sys | tga | tiff
HF_FUNCTION:
  function FieldResolution_X, FieldResolution_Y { UserDefined_Function }
HF_MODIFIER:
  smooth & water_level Level
OBJECT_MODIFIER:
  hierarchy [Boolean]

Height_field default values:

hierarchy   : on
smooth      : off
water_level : 0.0

A height field is essentially a one unit wide by one unit long square with a mountainous surface on top. The height of the mountain at each point is taken from the color number or palette index of the pixels in a graphic image file. The maximum height is one, which corresponds to the maximum possible color or palette index value in the image file.

The size and orientation of an unscaled height field.

The mesh of triangles corresponds directly to the pixels in the image file. Each square formed by four neighboring pixels is divided into two triangles. An image with a resolution of N*M pixels has (N-1)*(M-1) squares that are divided into 2*(N-1)*(M-1) triangles.

Relationship of pixels and triangles in a height field.

The resolution of the height field is influenced by two factors: the resolution of the image and the resolution of the color/index values. The size of the image determines the resolution in the x- and z-direction. A larger image uses more triangles and looks smoother. The resolution of the color/index value determines the resolution along the y-axis. A height field made from an 8-bit image can have 256 different height levels while one made from a 16-bit image can have up to 65536 different height levels. Thus the second height field will look much smoother in the y-direction if the height field is created appropriately.

The size/resolution of the image does not affect the size of the height field. The unscaled height field size will always be 1 by 1 by 1. Higher resolution image files will create smaller triangles, not larger height fields.

The image file type used to create a height field is specified by one of the keywords listed above. Specifying the file type is optional. If it is not defined the same file type will be assumed as the one that is set as the output file type. This is useful when the source for the height_field is also generated with POV-Ray.

The GIF, PNG, PGM, TIFF and possibly SYS format files are the only ones that can be created using a standard paint program. Though there are paint programs for creating TGA image files they will not be of much use for creating the special 16 bit TGA files used by POV-Ray (see below and HF_Gray_16 for more details).

In an image file that uses a color palette, like GIF, the color number is the palette index at a given pixel. Use a paint program to look at the palette of a GIF image. The first color is palette index zero, the second is index one, the third is index two and so on. The last palette entry is index 255. Portions of the image that use low palette entries will result in lower parts of the height field. Portions of the image that use higher palette entries will result in higher parts of the height field.

Height fields created from GIF files can only have 256 different height levels because the maximum number of colors in a GIF file is 256.

The color of the palette entry does not affect the height of the pixel. Color entry 0 could be red, blue, black or orange but the height of any pixel that uses color entry 0 will always be 0. Color entry 255 could be indigo, hot pink, white or sky blue but the height of any pixel that uses color entry 255 will always be 1.

You can create height field GIF images with a paint program or a fractal program like Fractint.

A POT file is essentially a GIF file with a 16 bit palette. The maximum number of colors in a POT file is 65536. This means a POT height field can have up to 65536 possible height values. This makes it possible to have much smoother height fields.

Note: The maximum height of the field is still 1 even though more intermediate values are possible.

At the time of this writing the only program that created POT files was a freeware MS-Dos/Windows program called Fractint. POT files generated with this fractal program create fantastic landscapes.

The TGA and PPM file formats may be used as a storage device for 16 bit numbers rather than an image file. These formats use the red and green bytes of each pixel to store the high and low bytes of a height value. These files are as smooth as POT files but they must be generated with special custom-made programs. Several programs can create TGA heightfields in the format POV uses, such as Gforge and Terrain Maker.

PNG format heightfields are usually stored in the form of a grayscale image with black corresponding to lower and white to higher parts of the height field. Because PNG files can store up to 16 bits in grayscale images they will be as smooth as TGA and PPM images. Since they are grayscale images you will be able to view them with a regular image viewer. Gforge can create 16-bit heightfields in PNG format. Color PNG images will be used in the same way as TGA and PPM images.

SYS format is a platform specific file format. See your platform specific documentation for details.

In addition to all the usual object modifiers, there are three additional height field modifiers available.

The optional water_level parameter may be added after the file name. It consists of the keyword water_level followed by a float value telling the program to ignore parts of the height field below that value. The default value is zero and legal values are between zero and one. For example water_level 0.5 tells POV-Ray to only render the top half of the height field. The other half is below the water and could not be seen anyway. Using water_level renders faster than cutting off the lower part using CSG or clipping. This term comes from the popular use of height fields to render landscapes. A height field would be used to create islands and another shape would be used to simulate water around the islands. A large portion of the height field would be obscured by the water so the water_level parameter was introduced to allow the ray-tracer to ignore the unseen parts of the height field. water_level is also used to cut away unwanted lower values in a height field. For example if you have an image of a fractal on a solid colored background, where the background color is palette entry 0, you can remove the background in the height field by specifying, water_level 0.001.

Normally height fields have a rough, jagged look because they are made of lots of flat triangles. Adding the keyword smooth causes POV-Ray to modify the surface normal vectors of the triangles in such a way that the lighting and shading of the triangles will give a smooth look. This may allow you to use a lower resolution file for your height field than would otherwise be needed. However, smooth triangles will take longer to render. The default value is off.

In order to speed up the intersection tests a one-level bounding hierarchy is available. By default it is always used but it can be switched off using hierarchy off to improve the rendering speed for small height fields (i.e. low resolution images). You may optionally use a boolean value such as hierarchy on or hierarchy off.

While POV-Ray will normally interpret the height field input file as a container of linear data irregardless of file type, this can be overridden for any individual height field input file by specifying gamma GAMMA immediately after the file name. For example:

height field {
  jpeg "foobar.jpg" gamma 1.8
  }

This will cause POV-Ray to perform gamma adjustment or -decoding on the input file data before building the height field. Alternatively to a numerical value, srgb may be specified to denote that the file format is pre-corrected or encoded using the ''sRGB transfer function'' instead of a power-law gamma function. See the section Gamma Handling for more information.

The height field object also allows for substituting a user defined function instead of specifying an image. That function can either be in it's literal form, or it can be a call to a function that you have predeclared. The user supplied parameters FieldResolution_X and FieldResolution_Y are integer values that affect the resolution of the color/index values, not size of the unscaled height field.

3.4.5.1.6 Isosurface

Details about many of the things that can be done with the isosurface object are discussed in the isosurface tutorial section. Below you will only find the syntax basics:

isosurface {
  function { FUNCTION_ITEMS }
  [contained_by { SPHERE | BOX }]
  [threshold FLOAT_VALUE]
  [accuracy FLOAT_VALUE]
  [max_gradient FLOAT_VALUE]
  [evaluate P0, P1, P2]
  [open]
  [max_trace INTEGER] | [all_intersections]
  [OBJECT_MODIFIERS...]
  }

Isosurface default values:

contained_by : box{-1,1}
threshold    : 0.0
accuracy     : 0.001
max_gradient : 1.1

function { ... } This must be specified and be the first item of the isosurface statement. Here you place all the mathematical functions that will describe the surface.

contained_by { ... } The contained_by object limits the area where POV-Ray samples for the surface of the function. This container can either be a sphere or a box, both of which use the standard POV-Ray syntax. If not specified a box {<-1,-1,-1>, <1,1,1>} will be used as default.

contained_by { sphere { CENTER, RADIUS } }
contained_by { box { CORNER1, CORNER2 } }

threshold This specifies how much strength, or substance to give the isosurface. The surface appears where the function value equals the threshold value. The default threshold is 0.

function = threshold

accuracy The isosurface finding method is a recursive subdivision method. This subdivision goes on until the length of the interval where POV-Ray finds a surface point is less than the specified accuracy. The default value is 0.001.
Smaller values produces more accurate surfaces, but it takes longer to render.

max_gradient POV-Ray can find the first intersecting point between a ray and the isosurface of any continuous function if the maximum gradient of the function is known. Therefore you can specify a max_gradient for the function. The default value is 1.1. When the max_gradient used to find the intersecting point is too high, the render slows down considerably. When it is too low, artifacts or holes may appear on the isosurface. When it is way too low, the surface does not show at all. While rendering the isosurface POV-Ray records the found gradient values and prints a warning if these values are higher or much lower than the specified max_gradient:

Warning: The maximum gradient found was 5.257, but max_gradient of
the isosurface was set to 5.000. The isosurface may contain holes!
Adjust max_gradient to get a proper rendering of the isosurface.

Warning: The maximum gradient found was 5.257, but max_gradient of
the isosurface was set to 7.000. Adjust max_gradient to
get a faster rendering of the isosurface.

For best performance you should specify a value close to the real maximum gradient.

evaluate POV-Ray can also dynamically adapt the used max_gradient. To activate this technique you have to specify the evaluate keyword followed by three parameters:

  • P0: the minimum max_gradient in the estimation process,
  • P1: an over-estimating factor. This means that the max_gradient is multiplied by the P1 parameter.
  • P2: an attenuation parameter (1 or less)

In this case POV-Ray starts with the max_gradient value P0 and dynamically changes it during the render using P1 and P2. In the evaluation process, the P1 and P2 parameters are used in quadratic functions. This means that over-estimation increases more rapidly with higher values and attenuation more rapidly with lower values. Also with dynamic max_gradient, there can be artifacts and holes.

If you are unsure what values to use, start a render without evaluate to get a value for max_gradient. Now you can use it with evaluate like this:

  • P0 : found max_gradient * min_factor
    min_factor being a float between 0 and 1 to reduce the max_gradient to a minimum max_gradient. The ideal value for P0 would be the average of the found max_gradients, but we do not have access to that information.
    A good starting point is 0.6 for the min_factor
  • P1 : sqrt(found max_gradient/(found max_gradient * min_factor))
    min_factor being the same as used in P0 this will give an over-estimation factor of more than 1, based on your minimum max_gradient and the found max_gradient.
  • P2 : 1 or less
    0.7 is a good starting point.

When there are artifacts / holes in the isosurface, increase the min_factor and / or P2 a bit. Example: when the first run gives a found max_gradient of 356, start with

#declare Min_factor= 0.6;
isosurface {
  ...
  evaluate 356*Min_factor,  sqrt(356/(356*Min_factor)),  0.7
  //evaluate 213.6, 1.29, 0.7
  ...
  }

This method is only an approximation of what happens internally, but it gives faster rendering speeds with the majority of isosurfaces.

open When the isosurface is not fully contained within the contained_by object, there will be a cross section. Where this happens, you will see the surface of the container. With the open keyword, these cross section surfaces are removed. The inside of the isosurface becomes visible.

Note: Using open slows down the render speed, and it is not recommended to use it with CSG operations.

max_trace Isosurfaces can be used in CSG shapes since they are solid finite objects - if not finite by themselves, they are through the cross section with the container.
By default POV-Ray searches only for the first surface which the ray intersects. But when using an isosurface in CSG operations, the other surfaces must also be found. Therefore, the keyword max_trace must be added to the isosurface statement. It must be followed by an integer value. To check for all surfaces, use the keyword all_intersections instead.
With all_intersections POV-Ray keeps looking until all surfaces are found. With a max_trace it only checks until that number is reached.

3.4.5.1.7 Julia Fractal

A julia fractal object is a 3-D slice of a 4-D object created by generalizing the process used to create the classic Julia sets. You can make a wide variety of strange objects using the julia_fractal statement including some that look like bizarre blobs of twisted taffy. The julia_fractal syntax is:

JULIA_FRACTAL:
  julia_fractal {
    <4D_Julia_Parameter>
    [JF_ITEM...] [OBJECT_MODIFIER...]
    }
JF_ITEM:
  ALGEBRA_TYPE | FUNCTION_TYPE | max_iteration Count |
  precision Amt | slice <4D_Normal>, Distance
ALGEBRA_TYPE:
  quaternion | hypercomplex
FUNCTION_TYPE:
  QUATERNATION:
    sqr | cube
  HYPERCOMPLEX:
    sqr | cube | exp | reciprocal | sin | asin | sinh |
    asinh | cos | acos | cosh | acosh | tan | atan |tanh |
    atanh | ln | pwr( X_Val, Y_Val )

Julia Fractal default values:

ALGEBRA_TYPE    : quaternion
FUNCTION_TYPE   : sqr
max_iteration   : 20
precision       : 20
slice, DISTANCE : <0,0,0,1>, 0.0

The required 4-D vector <4D_Julia_Parameter> is the classic Julia parameter p in the iterated formula f(h) + p. The julia fractal object is calculated by using an algorithm that determines whether an arbitrary point h(0) in 4-D space is inside or outside the object. The algorithm requires generating the sequence of vectors h(0), h(1), ... by iterating the formula h(n+1) = f(h(n)) + p (n = 0, 1, ..., max_iteration-1) where p is the fixed 4-D vector parameter of the julia fractal and f() is one of the functions sqr, cube, ... specified by the presence of the corresponding keyword. The point h(0) that begins the sequence is considered inside the julia fractal object if none of the vectors in the sequence escapes a hypersphere of radius 4 about the origin before the iteration number reaches the integer max_iteration value. As you increase max_iteration, some points escape that did not previously escape, forming the julia fractal. Depending on the <4D_Julia_Parameter>, the julia fractal object is not necessarily connected; it may be scattered fractal dust. Using a low max_iteration can fuse together the dust to make a solid object. A high max_iteration is more accurate but slows rendering. Even though it is not accurate, the solid shapes you get with a low max_iteration value can be quite interesting. If none is specified, the default is max_iteration 20.

Since the mathematical object described by this algorithm is four-dimensional and POV-Ray renders three dimensional objects, there must be a way to reduce the number of dimensions of the object from four dimensions to three. This is accomplished by intersecting the 4-D fractal with a 3-D plane defined by the slice modifier and then projecting the intersection to 3-D space. The keyword is followed by 4-D vector and a float separated by a comma. The slice plane is the 3-D space that is perpendicular to <4D_Normal> and is Distance units from the origin. Zero length <4D_Normal> vectors or a <4D_Normal> vector with a zero fourth component are illegal. If none is specified, the default is slice <0,0,0,1>,0.

You can get a good feel for the four dimensional nature of a julia fractal by using POV-Ray's animation feature to vary a slice's Distance parameter. You can make the julia fractal appear from nothing, grow, then shrink to nothing as Distance changes, much as the cross section of a 3-D object changes as it passes through a plane.

The precision parameter is a tolerance used in the determination of whether points are inside or outside the fractal object. Larger values give more accurate results but slower rendering. Use as low a value as you can without visibly degrading the fractal object's appearance but note values less than 1.0 are clipped at 1.0. The default if none is specified is precision 20.

The presence of the keywords quaternion or hypercomplex determine which 4-D algebra is used to calculate the fractal. The default is quaternion. Both are 4-D generalizations of the complex numbers but neither satisfies all the field properties (all the properties of real and complex numbers that many of us slept through in high school). Quaternions have non-commutative multiplication and hypercomplex numbers can fail to have a multiplicative inverse for some non-zero elements (it has been proved that you cannot successfully generalize complex numbers to four dimensions with all the field properties intact, so something has to break). Both of these algebras were discovered in the 19th century. Of the two, the quaternions are much better known, but one can argue that hypercomplex numbers are more useful for our purposes, since complex valued functions such as sin, cos, etc. can be generalized to work for hypercomplex numbers in a uniform way.

For the mathematically curious, the algebraic properties of these two algebras can be derived from the multiplication properties of the unit basis vectors 1 = <1,0,0,0>, i=< 0,1,0,0>, j=<0,0,1,0> and k=< 0,0,0,1>. In both algebras 1 x = x 1 = x for any x (1 is the multiplicative identity). The basis vectors 1 and i behave exactly like the familiar complex numbers 1 and i in both algebras.

ij = k | jk = i | ki = j
ji = -k | kj = -i | ik = -j
ii = jj = kk = -1 | ijk = -1 |
ij = k | jk = -i | ki = -j
ji = k | kj = -i | ik = -j
ii = jj = kk = -1 | ijk = 1 |

A distance estimation calculation is used with the quaternion calculations to speed them up. The proof that this distance estimation formula works does not generalize from two to four dimensions but the formula seems to work well anyway, the absence of proof notwithstanding!

The presence of one of the function keywords sqr, cube, etc. determines which function is used for f(h) in the iteration formula h(n+1) = f(h(n)) + p. The default is sqr. Most of the function keywords work only if the hypercomplex keyword is present. Only sqr and cube work with quaternion. The functions are all familiar complex functions generalized to four dimensions. Function Keyword Maps 4-D value h to:

sqr | h*h
cube | h*h*h
exp | e raised to the power h
reciprocal | 1/h
sin | sine of h
asin | arcsine of h
sinh | hyperbolic sine of h
asinh | inverse hyperbolic sine of h
cos | cosine of h
acos | arccosine of h
cosh | hyperbolic cos of h
acosh | inverse hyperbolic cosine of h
tan | tangent of h
atan | arctangent of h
tanh | hyperbolic tangent of h
atanh | inverse hyperbolic tangent of h
ln | natural logarithm of h
pwr(x,y) | h raised to the complex power x+iy

A simple example of a julia fractal object is:

julia_fractal {
  <-0.083,0.0,-0.83,-0.025>
  quaternion
  sqr
  max_iteration 8
  precision 15
  }

The first renderings of julia fractals using quaternions were done by Alan Norton and later by John Hart in the '80's. This POV-Ray implementation follows Fractint in pushing beyond what is known in the literature by using hypercomplex numbers and by generalizing the iterating formula to use a variety of transcendental functions instead of just the classic Mandelbrot z2 + c formula. With an extra two dimensions and eighteen functions to work with, intrepid explorers should be able to locate some new fractal beasts in hyperspace, so have at it!

3.4.5.1.8 Lathe

The lathe is an object generated from rotating a two-dimensional curve about an axis. This curve is defined by a set of points which are connected by linear, quadratic, cubic or bezier spline curves. The syntax is:

LATHE:
  lathe {
    [SPLINE_TYPE] Number_Of_Points, <Point_1>
    <Point_2>... <Point_n>
    [LATHE_MODIFIER...]
    }
SPLINE_TYPE:
  linear_spline | quadratic_spline | cubic_spline | bezier_spline
LATHE_MODIFIER:
  sturm | OBJECT_MODIFIER

Lathe default values:

SPLINE_TYPE   : linear_spline
sturm         : off

The first item is a keyword specifying the type of spline. The default if none is specified is linear_spline. The required integer value Number_Of_Points specifies how many two-dimensional points are used to define the curve. The points follow and are specified by 2-D vectors. The curve is not automatically closed, i.e. the first and last points are not automatically connected. You will have to do this yourself if you want a closed curve. The curve thus defined is rotated about the y-axis to form the lathe object, centered at the origin.

The following examples creates a simple lathe object that looks like a thick cylinder, i.e. a cylinder with a thick wall:

lathe {
  linear_spline
  5,
  <2, 0>, <3, 0>, <3, 5>, <2, 5>, <2, 0>
  pigment {Red}
  }

The cylinder has an inner radius of 2 and an outer radius of 3, giving a wall width of 1. It's height is 5 and it's located at the origin pointing up, i.e. the rotation axis is the y-axis.

Note: The first and last point are equal to get a closed curve.

The splines that are used by the lathe and prism objects are a little bit difficult to understand. The basic concept of splines is to draw a curve through a given set of points in a determined way. The default linear_spline is the simplest spline because it's nothing more than connecting consecutive points with a line. This means the curve that is drawn between two points only depends on those two points. No additional information is taken into account. The other splines are different in that they do take other points into account when connecting two points. This creates a smooth curve and, in the case of the cubic spline, produces smoother transitions at each point.

The quadratic_spline keyword creates splines that are made of quadratic curves. Each of them connects two consecutive points. Since those two points (call them second and third point) are not sufficient to describe a quadratic curve, the predecessor of the second point is taken into account when the curve is drawn. Mathematically, the relationship (their relative locations on the 2-D plane) between the first and second point determines the slope of the curve at the second point. The slope of the curve at the third point is out of control. Thus quadratic splines look much smoother than linear splines but the transitions at each point are generally not smooth because the slopes on both sides of the point are different.

The cubic_spline keyword creates splines which overcome the transition problem of quadratic splines because they also take a fourth point into account when drawing the curve between the second and third point. The slope at the fourth point is under control now and allows a smooth transition at each point. Thus cubic splines produce the most flexible and smooth curves.

The bezier_spline is an alternate kind of cubic spline. Points 1 and 4 specify the end points of a segment and points 2 and 3 are control points which specify the slope at the endpoints. Points 2 and 3 do not actually lie on the spline. They adjust the slope of the spline. If you draw an imaginary line between point 1 and 2, it represents the slope at point 1. It is a line tangent to the curve at point 1. The greater the distance between 1 and 2, the flatter the curve. With a short tangent the spline can bend more. The same holds true for control point 3 and endpoint 4. If you want the spline to be smooth between segments, points 3 and 4 on one segment and points 1 and 2 on the next segment must form a straight line and point 4 of one segment must be the same as point 1 on the next segment.

You should note that the number of spline segments, i. e. curves between two points, depends on the spline type used. For linear splines you get n-1 segments connecting the points P[i], i=1,...,n. A quadratic spline gives you n-2 segments because the last point is only used for determining the slope, as explained above (thus you will need at least three points to define a quadratic spline). The same holds for cubic splines where you get n-3 segments with the first and last point used only for slope calculations (thus needing at least four points). The bezier spline requires 4 points per segment, creating n/4 segments.

If you want to get a closed quadratic and cubic spline with smooth transitions at the end points you have to make sure that in the cubic case P[n-1] = P[2] (to get a closed curve), P[n] = P[3] and P[n-2] = P[1] (to smooth the transition). In the quadratic case P[n-1] = P[1] (to close the curve) and P[n] = P[2].

The sturm keyword can be used to specify that the slower, but more accurate, Sturmian root solver should be used. Use it, if the shape does not render properly. Since a quadratic polynomial has to be solved for the linear spline lathe, the Sturmian root solver is not needed.

3.4.5.1.9 Ovus

An ovus is a shape that looks like an egg. The syntax of the ovus object is:

OVUS:
  ovus {
    Bottom_radius, Top_radius
    [OBJECT_MODIFIERS...]
    }

Where Bottom_radius is a float value giving the radius of the bottom sphere and Top_radius is a float specifying the radius of the top sphere. The top sphere and the bottom sphere are connected together with a suitably truncated citrus (lemon), that is automatically computed so as to provide the needed continuity to the shape.
  • The center of the top sphere lies on the top of the bottom sphere.
  • The bottom sphere of the ovus is centered at the origin.
  • The top sphere of the ovus lies on the y-axis.

An ovus 2D section

The ovus and it's constituent 3D shapes

Whenever the top radius is bigger than twice the bottom radius, the ovus degenerates into a sphere with an offset center. There are a lot of variations in the shape of the ovus.

Note: According to the ratio of the radius, the pointy part is the smallest radius, but is not always on top!

Evolution of ratio from 0 to 1.95 in 0.15 steps.

Note: See the following MathWorld references for more information about the math behind how the ovus object is constructed.

  • »Torus
  • »Lemon
  • »SpindleTorus
3.4.5.1.10 Parametric

Where the isosurface object uses implicit surface functions, F(x,y,z)=0, the parametric object is a set of equations for a surface expressed in the form of the parameters that locate points on the surface, x(u,v), y(u,v), z(u,v). Each pair of values for u and v gives a single point <x,y,z> in 3d space.

The parametric object is not a solid object it is hollow, like a thin shell.

Syntax:

parametric {
  function { FUNCTION_ITEMS },
  function { FUNCTION_ITEMS },
  function { FUNCTION_ITEMS }

  <u1,v1>, <u2,v2>
  [contained_by { SPHERE | BOX }]
  [max_gradient FLOAT_VALUE]
  [accuracy FLOAT_VALUE]
  [precompute DEPTH, VarList]
  }

Parametric default values:

accuracy     : 0.001

The first function calculates the x value of the surface, the second y and the third the z value. Allowed is any function that results in a float.

<u1,v1>,<u2,v2> boundaries of the (u,v) space, in which the surface has to be calculated

contained_by { ... } The contained_by 'object' limits the area where POV-Ray samples for the surface of the function. This container can either be a sphere or a box, both of which use the standard POV-Ray syntax. If not specified a box {<-1,-1,-1>, <1,1,1>} will be used as default.

max_gradient, It is not really the maximum gradient. It's the maximum magnitude of all six partial derivatives over the specified ranges of u and v. That is, if you take dx/du, dx/dv, dy/du, dy/dv, dz/du, and dz/dv and calculate them over the entire range, the max_gradient is the maximum of the absolute values of all of those values.

accuracy The default value is 0.001. Smaller values produces more accurate surfaces, but take longer to render.

precompute can speedup rendering of parametric surfaces. It simply divides parametric surfaces into small ones (2^depth) and precomputes ranges of the variables(x,y,z) which you specify after depth. The maximum depth is 20. High values of depth can produce arrays that use a lot of memory, take longer to parse and render faster. If you declare a parametric surface with the precompute keyword and then use it twice, all arrays are in memory only once.

Example, a unit sphere:

parametric {
  function { sin(u)*cos(v) }
  function { sin(u)*sin(v) }
  function { cos(u) }

  <0,0>, <2*pi,pi>
  contained_by { sphere{0, 1.1} }
  max_gradient ??
  accuracy 0.0001
  precompute 10 x,y,z
  pigment {rgb 1}
  }
3.4.5.1.11 Prism

The prism is an object generated by specifying one or more two-dimensional, closed curves in the x-z plane and sweeping them along y axis. These curves are defined by a set of points which are connected by linear, quadratic, cubic or bezier splines. The syntax for the prism is:

PRISM:
  prism {
    [PRISM_ITEMS...] Height_1, Height_2, Number_Of_Points,
    <Point_1>, <Point_2>, ... <Point_n>
    [ open ] [PRISM_MODIFIERS...]
    }
PRISM_ITEM:
  linear_spline | quadratic_spline | cubic_spline |
  bezier_spline | linear_sweep | conic_sweep
PRISM_MODIFIER:
  sturm | OBJECT_MODIFIER

Prism default values:

SPLINE_TYPE   : linear_spline
SWEEP_TYPE    : linear_sweep
sturm         : off

The first items specify the spline type and sweep type. The defaults if none is specified is linear_spline and linear_sweep. This is followed by two float values Height_1 and Height_2 which are the y coordinates of the top and bottom of the prism. This is followed by a float value specifying the number of 2-D points you will use to define the prism. (This includes all control points needed for quadratic, cubic and bezier splines). This is followed by the specified number of 2-D vectors which define the shape in the x-z plane.

The interpretation of the points depends on the spline type. The prism object allows you to use any number of sub-prisms inside one prism statement (they are of the same spline and sweep type). Wherever an even number of sub-prisms overlaps a hole appears.

Note: You need not have multiple sub-prisms and they need not overlap as these examples do.

In the linear_spline the first point specified is the start of the first sub-prism. The following points are connected by straight lines. If you specify a value identical to the first point, this closes the sub-prism and next point starts a new one. When you specify the value of that sub-prism's start, then it is closed. Each of the sub-prisms has to be closed by repeating the first point of a sub-prism at the end of the sub-prism's point sequence. In this example, there are two rectangular sub-prisms nested inside each other to create a frame.

prism {
  linear_spline
  0, 1, 10,
  <0,0>, <6,0>, <6,8>, <0,8>, <0,0>,  //outer rim
  <1,1>, <5,1>, <5,7>, <1,7>, <1,1>   //inner rim
  }

The last sub-prism of a linear spline prism is automatically closed - just like the last sub-polygon in the polygon statement - if the first and last point of the sub-polygon's point sequence are not the same. This make it very easy to convert between polygons and prisms. Quadratic, cubic and bezier splines are never automatically closed.

In the quadratic_spline, each sub-prism needs an additional control point at the beginning of each sub-prisms' point sequence to determine the slope at the start of the curve. The first point specified is the control point which is not actually part of the spline. The second point is the start of the spline. The sub-prism ends when this second point is duplicated. The next point is the control point of the next sub-prism. The point after that is the first point of the second sub-prism. Here is an example:

prism {
  quadratic_spline
  0, 1, 12,
  <1,-1>, <0,0>, <6,0>, //outer rim; <1,-1> is control point and
  <6,8>, <0,8>, <0,0>,  //<0,0> is first & last point
  <2,0>, <1,1>, <5,1>,  //inner rim; <2,0> is control point and
  <5,7>, <1,7>, <1,1>   //<1,1> is first & last point
  }

In the cubic_spline, each sub-prism needs two additional control points -- one at the beginning of each sub-prisms' point sequence to determine the slope at the start of the curve and one at the end. The first point specified is the control point which is not actually part of the spline. The second point is the start of the spline. The sub-prism ends when this second point is duplicated. The next point is the control point of the end of the first sub-prism. Next is the beginning control point of the next sub-prism. The point after that is the first point of the second sub-prism.

Here is an example:

prism {
  cubic_spline
  0, 1, 14,
  <1,-1>, <0,0>, <6,0>, //outer rim; First control is <1,-1> and
  <6,8>, <0,8>, <0,0>,  //<0,0> is first & last point.
  <-1,1>,                           //Last control of first spline is <-1,1>
  <2,0>, <1,1>, <5,1>,  //inner rim; First control is <2,0> and
  <5,7>, <1,7>, <1,1>,  //<1,1> is first & last point
  <0,2>                             //Last control of first spline is <0,2>
  }

The bezier_spline is an alternate kind of cubic spline. Points 1 and 4 specify the end points of a segment and points 2 and 3 are control points which specify the slope at the endpoints. Points 2 and 3 do not actually lie on the spline. They adjust the slope of the spline. If you draw an imaginary line between point 1 and 2, it represents the slope at point 1. It is a line tangent to the curve at point 1. The greater the distance between 1 and 2, the flatter the curve. With a short tangent the spline can bend more. The same holds true for control point 3 and endpoint 4. If you want the spline to be smooth between segments, point 3 and 4 on one segment and point 1 and 2 on the next segment must form a straight line and point 4 of one segment must be the same as point one on the next segment.

By default linear sweeping is used to create the prism, i.e. the prism's walls are perpendicular to the x-z-plane (the size of the curve does not change during the sweep). You can also use conic_sweep that leads to a prism with cone-like walls by scaling the curve down during the sweep.

Like cylinders the prism is normally closed. You can remove the caps on the prism by using the open keyword. If you do so you should not use it with CSG because the results may get wrong.

For an explanation of the spline concept read the description of the Lathe object. Also see the tutorials on Lathe and Prism objects.

The sturm keyword specifies the slower but more accurate Sturmian root solver which may be used with the cubic or bezier spline prisms if the shape does not render properly. The linear and quadratic spline prisms do not need the Sturmian root solver.

3.4.5.1.12 Sphere

The syntax of the sphere object is:

SPHERE:
  sphere {
    <Center>, Radius
    [OBJECT_MODIFIERS...]
    }

The geometry of a sphere.

Where <Center> is a vector specifying the x, y, z coordinates of the center of the sphere and Radius is a float value specifying the radius. Spheres may be scaled unevenly giving an ellipsoid shape.

Because spheres are highly optimized they make good bounding shapes (if manual bounding seems to be necessary).

3.4.5.1.13 Sphere Sweep

The syntax of the sphere_sweep object is:

SPHERE_SWEEP:
  sphere_sweep {
    linear_spline | b_spline | cubic_spline
    NUM_OF_SPHERES,

    CENTER, RADIUS,
    CENTER, RADIUS,
    ...
    CENTER, RADIUS
    [tolerance DEPTH_TOLERANCE]
    [OBJECT_MODIFIERS]
    }

Sphere_sweep default values:

tolerance : 1.0e-6 (0.000001)

A Sphere Sweep is the envelope of a moving sphere with varying radius, or, in other words, the space a sphere occupies during its movement along a spline.
Sphere Sweeps are modeled by specifying a list of single spheres which are then interpolated.
Three kinds of interpolation are supported:

  • linear_spline : Interpolating the input data with a linear function, which means that the single spheres are connected by straight tubes.
  • b_spline : Approximating the input data using a cubic b-spline function, which results in a curved object.
  • cubic_spline : Approximating the input data using a cubic spline, which results in a curved object.

The sphere list (center and radius of each sphere) can take as many spheres as you like to describe the object, but you will need at least two spheres for a linear_spline, and four spheres for b_spline or cubic_spline.

Optional: The depth tolerance that should be used for the intersection calculations. This is done by adding the tolerance keyword and the desired value: the default distance is 1.0e-6 (0.000001) and should do for most sphere sweep objects.
You should change this when you see dark spots on the surface of the object. These are probably caused by an effect called self-shading. This means that the object casts shadows onto itself at some points because of calculation errors. A ray tracing program usually defines the minimal distance a ray must travel before it actually hits another (or the same) object to avoid this effect. If this distance is chosen too small, self-shading may occur.
If so, specify tolerance 1.0e-4 or higher.

Note: If these dark spots remain after raising the tolerance, you might get rid of these spots by using adaptive super-sampling (method 2) for anti-aliasing. Images look better with anti-aliasing anyway.

Note: The merge CSG operation is not recommended with Sphere Sweeps: there could be a small gap between the merged objects!

3.4.5.1.14 Superquadric Ellipsoid

The superellipsoid object creates a shape known as a superquadric ellipsoid object. It is an extension of the quadric ellipsoid. It can be used to create boxes and cylinders with round edges and other interesting shapes. Mathematically it is given by the equation:

Superquadric Ellipsoid Formula

The values of e and n, called the east-west and north-south exponent, determine the shape of the superquadric ellipsoid. Both have to be greater than zero. The sphere is given by e = 1 and n = 1.

The syntax of the superquadric ellipsoid is:

SUPERELLIPSOID:
  superellipsoid {
    <Value_E, Value_N>
    [OBJECT_MODIFIERS...]
    }

The 2-D vector specifies the e and n values in the equation above. The object sits at the origin and occupies a space about the size of a box{<-1,-1,-1>,<1,1,1>}.

Two useful objects are the rounded box and the rounded cylinder. These are declared in the following way.

#declare Rounded_Box = superellipsoid { <Round, Round> }
#declare Rounded_Cylinder = superellipsoid { <1, Round> }

The roundedness value Round determines the roundedness of the edges and has to be greater than zero and smaller than one. The smaller you choose the values, the smaller and sharper the edges will get.

Very small values of e and n might cause problems with the root solver (the Sturmian root solver cannot be used).

3.4.5.1.15 Surface of Revolution

The sor object is a surface of revolution generated by rotating the graph of a function about the y-axis. This function describes the dependence of the radius from the position on the rotation axis. The syntax is:

SOR:
  sor {
    Number_Of_Points, <Point_1>, <Point_2>, ... <Point_n>
    [ open ] [SOR_MODIFIERS...]
    }
SOR_MODIFIER:
  sturm | OBJECT_MODIFIER

SOR default values:

sturm : off

The float value Number_Of_Points specifies the number of 2-D vectors which follow. The points <Point_1> through <Point_n> are two-dimensional vectors consisting of the radius and the corresponding height, i.e. the position on the rotation axis. These points are smoothly connected (the curve is passing through the specified points) and rotated about the y-axis to form the SOR object. The first and last points are only used to determine the slopes of the function at the start and end point. They do not actually lie on the curve. The function used for the SOR object is similar to the splines used for the lathe object. The difference is that the SOR object is less flexible because it underlies the restrictions of any mathematical function, i.e. to any given point y on the rotation axis belongs at most one function value, i.e. one radius value. You cannot rotate closed curves with the SOR object. Also, make sure that the curve does not cross zero (y-axis) as this can result in 'less than perfect' bounding cylinders. POV-Ray will very likely fail to render large chunks of the part of the spline contained in such an interval.

The optional keyword open allows you to remove the caps on the SOR object. If you do this you should not use it with CSG because the results may be wrong.

The SOR object is useful for creating bottles, vases, and things like that. A simple vase could look like this:

#declare Vase = sor {
  7,
  <0.000000, 0.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>
  open
  }

One might ask why there is any need for a SOR object if there is already a lathe object which is much more flexible. The reason is quite simple. The intersection test with a SOR object involves solving a cubic polynomial while the test with a lathe object requires to solve a 6th order polynomial (you need a cubic spline for the same smoothness). Since most SOR and lathe objects will have several segments this will make a great difference in speed. The roots of the 3rd order polynomial will also be more accurate and easier to find.

The sturm keyword may be added to specify the slower but more accurate Sturmian root solver. It may be used with the surface of revolution object if the shape does not render properly.

The following explanations are for the mathematically interested reader who wants to know how the surface of revolution is calculated. Though it is not necessary to read on it might help in understanding the SOR object.

The function that is rotated about the y-axis to get the final SOR object is given by

Surface of Revolution Formula

with radius r and height h. Since this is a cubic function in h it has enough flexibility to allow smooth curves.

The curve itself is defined by a set of n points P(i), i=0...n-1, which are interpolated using one function for every segment of the curve. A segment j, j=1...n-3, goes from point P(j) to point P(j+1) and uses points P(j-1) and P(j+2) to determine the slopes at the endpoints. If there are n points we will have n-3 segments. This means that we need at least four points to get a proper curve. The coefficients A(j), B(j), C(j) and D(j) are calculated for every segment using the equation

Curve Math

where r(j) is the radius and h(j) is the height of point P(j).

The figure below shows the configuration of the points P(i), the location of segment j, and the curve that is defined by this segment.

Points on a surface of revolution.
3.4.5.1.16 Text

A text object creates 3-D text as an extruded block letter. Currently only TrueType fonts (ttf) and TrueType Collections (ttc) are supported but the syntax allows for other font types to be added in the future. If TrueType Collections are used, the first font found in the collection will be used. The syntax is:

TEXT_OBECT:
  text {
    ttf "fontname.ttf/ttc" "String_of_Text"
    Thickness, <Offset>
    [OBJECT_MODIFIERS...]
    }

Where fontname.ttf or fontname.ttc is the name of the TrueType font file. It is a quoted string literal or string expression. The string expression which follows is the actual text of the string object. It too may be a quoted string literal or string expression. See section Strings for more on string expressions.

In version 3.7 several fonts are now built-in. It should be noted that this is only a preliminary solution so the benchmark program will run without installing POV-Ray. Future versions may lack this mechanism, so in scene files (other than the built-in benchmark) you should continue to reference the external font files as before. Consequently, the following alternate syntax is available:

TEXT_OBECT:
  text {
    internal Font_Number "String_of_Text"
    Thickness, <Offset>
    [OBJECT_MODIFIERS] }
    }

Where Font_Number is one of the integer values from the list below:

  1. povlogo.ttf
  2. timrom.ttf
  3. cyrvetic.ttf
  4. crystal.ttf

Note: An out of range Font_Number value will default to 0.

The text will start with the origin at the lower left, front of the first character and will extend in the +x-direction. The baseline of the text follows the x-axis and descender drop into the -y-direction. The front of the character sits in the x-y-plane and the text is extruded in the +z-direction. The front-to-back thickness is specified by the required value Thickness.

Characters are generally sized so that 1 unit of vertical spacing is correct. The characters are about 0.5 to 0.75 units tall.

The horizontal spacing is handled by POV-Ray internally including any kerning information stored in the font. The required vector <Offset> defines any extra translation between each character. Normally you should specify a zero for this value. Specifying 0.1*x would put additional 0.1 units of space between each character. Here is an example:

text {
  ttf "timrom.ttf" "POV-Ray" 1, 0
  pigment { Red }
  }

Only printable characters are allowed in text objects. Characters such as return, line feed, tabs, backspace etc. are not supported.

For easy access to your fonts, set the Library_Path to the directory that contains your font collection.

3.4.5.1.17 Torus

A torus is a 4th order quartic polynomial shape that looks like a donut or inner tube. Because this shape is so useful and quartics are difficult to define, POV-Ray lets you take a short-cut and define a torus by:

TORUS:
  torus {
    Major, Minor
    [TORUS_MODIFIER...]
    }
TORUS_MODIFIER:
  sturm | OBJECT_MODIFIER

Torus default values:

sturm : off

where Major is a float value giving the major radius and Minor is a float specifying the minor radius. The major radius extends from the center of the hole to the mid-line of the rim while the minor radius is the radius of the cross-section of the rim. The torus is centered at the origin and lies in the x-z-plane with the y-axis sticking through the hole.

Major and minor radius of a torus.

The torus is internally bounded by two cylinders and two rings forming a thick cylinder. With this bounding cylinder the performance of the torus intersection test is vastly increased. The test for a valid torus intersection, i.e. solving a 4th order polynomial, is only performed if the bounding cylinder is hit. Thus a lot of slow root solving calculations are avoided.

Calculations for all higher order polynomials must be very accurate. If the torus renders improperly you may add the keyword sturm to use POV-Ray's slower-yet-more-accurate Sturmian root solver.

3.4.5.2 Finite Patch Primitives

There are six totally thin, finite objects which have no well-defined inside. They are bicubic patch, disc, smooth triangle, triangle, polygon, mesh, and mesh2. They may be combined in CSG union, but cannot be used inside a clipped_by statement.

Note: Patch objects may give unexpected results when used in differences and intersections.

These conditions apply:

  1. Solids may be differenced from bicubic patches with the expected results.
  2. Differencing a bicubic patch from a solid may give unexpected results.
    • Especially if the inverse keyword is used!
  3. Intersecting a solid and a bicubic patch will give the expected results.
    • The parts of the patch that intersect the solid object will be visible.
  4. Merging a solid and a bicubic patch will remove the parts of the bicubic patch that intersect the solid.

Because these types are finite POV-Ray can use automatic bounding on them to speed up rendering time. As with all shapes they can be translated, rotated and scaled.

3.4.5.2.1 Bicubic Patch

A bicubic_patch is a 3D curved surface created from a mesh of triangles. POV-Ray supports a type of bicubic patch called a Bezier patch. A bicubic patch is defined as follows:

BICUBIC_PATCH:
  bicubic_patch {
    PATCH_ITEMS...
    <Point_1>,<Point_2>,<Point_3>,<Point_4>,
    <Point_5>,<Point_6>,<Point_7>,<Point_8>,
    <Point_9>,<Point_10>,<Point_11>,<Point_12>,
    <Point_13>,<Point_14>,<Point_15>,<Point_16>
    [OBJECT_MODIFIERS...]
    }
PATCH_ITEMS:
  type Patch_Type | u_steps Num_U_Steps | v_steps Num_V_Steps |
  flatness Flatness

Bicubic patch default values:

flatness : 0.0
u_steps  : 0
v_steps  : 0

The keyword type is followed by a float Patch_Type which currently must be either 0 or 1. For type 0 only the control points are retained within POV-Ray. This means that a minimal amount of memory is needed but POV-Ray will need to perform many extra calculations when trying to render the patch. Type 1 preprocesses the patch into many subpatches. This results in a significant speedup in rendering at the cost of memory.

The four parameters type, flatness, u_steps and v_steps may appear in any order. Only type is required. They are followed by 16 vectors (4 rows of 4) that define the x, y, z coordinates of the 16 control points which define the patch. The patch touches the four corner points <Point_1>, <Point_4>, <Point_13> and <Point_16> while the other 12 points pull and stretch the patch into shape. The Bezier surface is enclosed by the convex hull formed by the 16 control points, this is known as the convex hull property.

The keywords u_steps and v_steps are each followed by integer values which tell how many rows and columns of triangles are the minimum to use to create the surface, both default to 0. The maximum number of individual pieces of the patch that are tested by POV-Ray can be calculated from the following: pieces = 2^u_steps * 2^v_steps.

This means that you really should keep u_steps and v_steps under 4. Most patches look just fine with u_steps 3 and v_steps 3, which translates to 64 sub-patches (128 smooth triangles).

As POV-Ray processes the Bezier patch it makes a test of the current piece of the patch to see if it is flat enough to just pretend it is a rectangle. The statement that controls this test is specified with the flatness keyword followed by a float. Typical flatness values range from 0 to 1 (the lower the slower). The default if none is specified is 0.0.

If the value for flatness is 0 POV-Ray will always subdivide the patch to the extend specified by u_steps and v_steps. If flatness is greater than 0 then every time the patch is split, POV-Ray will check to see if there is any need to split further.

There are both advantages and disadvantages to using a non-zero flatness. The advantages include:

- If the patch is not very curved, then this will be detected and POV-Ray will not waste a lot of time looking at the wrong pieces.

- If the patch is only highly curved in a couple of places, POV-Ray will keep subdividing there and concentrate its efforts on the hard part.

The biggest disadvantage is that if POV-Ray stops subdividing at a particular level on one part of the patch and at a different level on an adjacent part of the patch there is the potential for cracking. This is typically visible as spots within the patch where you can see through. How bad this appears depends very highly on the angle at which you are viewing the patch.

Like triangles, the bicubic patch is not meant to be generated by hand. These shapes should be created by a special utility. You may be able to acquire utilities to generate these shapes from the same source from which you obtained POV-Ray. Here is an example:

bicubic_patch {
  type 0
  flatness 0.01
  u_steps 4
  v_steps 4
  <0, 0, 2>, <1, 0, 0>, <2, 0, 0>, <3, 0,-2>,
  <0, 1  0>, <1, 1, 0>, <2, 1, 0>, <3, 1, 0>,
  <0, 2, 0>, <1, 2, 0>, <2, 2, 0>, <3, 2, 0>,
  <0, 3, 2>, <1, 3, 0>, <2, 3, 0>, <3, 3, -2>
  }

The triangles in a POV-Ray bicubic_patch are automatically smoothed using normal interpolation but it is up to the user (or the user's utility program) to create control points which smoothly stitch together groups of patches.

3.4.5.2.2 Disc

Another flat, finite object available with POV-Ray is the disc. The disc is infinitely thin, it has no thickness. If you want a disc with true thickness you should use a very short cylinder. A disc shape may be defined by:

DISC:
  disc {
    <Center>, <Normal>, Radius [, Hole_Radius]
    [OBJECT_MODIFIERS...]
    }

Disc default values:

HOLE RADIUS : 0.0

The vector <Center> defines the x, y, z coordinates of the center of the disc. The <Normal> vector describes its orientation by describing its surface normal vector. This is followed by a float specifying the Radius. This may be optionally followed by another float specifying the radius of a hole to be cut from the center of the disc.

Note: The inside of a disc is the inside of the plane that contains the disc. Also note that it is not constrained by the radius of the disc.

3.4.5.2.3 Mesh

The mesh object can be used to efficiently store large numbers of triangles. Its syntax is:

MESH:
  mesh {
    MESH_TRIANGLE...
    [MESH_MODIFIER...]
    }
MESH_TRIANGLE:
  triangle {
    <Corner_1>, <Corner_2>, <Corner_3>
    [uv_vectors <uv_Corner_1>, <uv_Corner_2>, <uv_Corner_3>]
    [MESH_TEXTURE]
    } |

  smooth_triangle {
    <Corner_1>, <Normal_1>,
    <Corner_2>, <Normal_2>,
    <Corner_3>, <Normal_3>
    [uv_vectors <uv_Corner_1>, <uv_Corner_2>, <uv_Corner_3>]
    [MESH_TEXTURE]
    }
MESH_TEXTURE:
  texture { TEXTURE_IDENTIFIER }
  texture_list {
    TEXTURE_IDENTIFIER TEXTURE_IDENTIFIER TEXTURE_IDENTIFIER
    }

MESH_MODIFIER:
  inside_vector <direction> | hierarchy [ Boolean ] |
  OBJECT_MODIFIER

Mesh default values:

hierarchy : on

Any number of triangle and/or smooth_triangle statements can be used and each of those triangles can be individually textured by assigning a texture identifier to it. The texture has to be declared before the mesh is parsed. It is not possible to use texture definitions inside the triangle or smooth triangle statements. This is a restriction that is necessary for an efficient storage of the assigned textures. See Triangle and Smooth Triangle for more information on triangles.

The mesh object can support uv_mapping. For this, per triangle the keyword uv_vectors has to be given, together with three 2D uv-vectors. Each vector specifies a location in the xy-plane from which the texture has to be mapped to the matching points of the triangle. Also see the section uv_mapping.

The mesh's components are internally bounded by a bounding box hierarchy to speed up intersection testing. The bounding hierarchy can be turned off with the hierarchy off keyword. This should only be done if memory is short or the mesh consists of only a few triangles. The default is hierarchy on.

Copies of a mesh object refer to the same triangle data and thus consume very little memory. You can easily trace a hundred copies of a 10000 triangle mesh without running out of memory (assuming the first mesh fits into memory). The mesh object has two advantages over a union of triangles: it needs less memory and it is transformed faster. The memory requirements are reduced by efficiently storing the triangles vertices and normals. The parsing time for transformed meshes is reduced because only the mesh object has to be transformed and not every single triangle as it is necessary for unions.

The mesh object can currently only include triangle and smooth triangle components. That restriction may change, allowing polygonal components, at some point in the future.

3.4.5.2.3.1 Solid Mesh

The triangle mesh objects mesh (and mesh2) can be used in CSG objects such as difference and intersect. Adding the inside_vector they do have a defined inside. This will only work for well-behaved meshes, which are completely closed volumes. If meshes have any holes in them, this might work, but the results are not guaranteed.

To determine if a point is inside a triangle mesh, POV-Ray shoots a ray from the point in some arbitrary direction. If this vector intersects an odd number of triangles, the point is inside the mesh. If it intersects an even number of triangles, the point is outside of the mesh. You can specify the direction of this vector. For example, to use +z as the direction, you would add the following line to the triangle mesh description (following all other mesh data, but before the object modifiers).

inside_vector <0, 0, 1>

This change does not have any effect on unions of triangles, these will still be always hollow.

3.4.5.2.4 Mesh2

The new mesh syntax is designed for use in conversion from other file formats.

MESH2 :
  mesh2{
    VECTORS...
    LISTS...   |
    INDICES... |
    MESH_MODIFIERS
    }
VECTORS :
  vertex_vectors {
  number_of_vertices,
  <vertex1>, <vertex2>, ...
  }|
  normal_vectors {
    number_of_normals,
    <normal1>, <normal2>, ...
    }|
  uv_vectors {
    number_of_uv_vectors,
    <uv_vect1>, <uv_vect2>, ...
    }
LISTS :
  texture_list {
    number_of_textures,
    texture { Texture1 },
    texture { Texture2 }, ...
    }|
INDICES :
  face_indices {
    number_of_faces,
      <index_a, index_b, index_c> [,texture_index [,
    texture_index, texture_index]],
      <index_d, index_e, index_f> [,texture_index [,
      texture_index, texture_index]],
      ...
      }|
  normal_indices {
    number_of_faces,
      <index_a, index_b, index_c>,
      <index_d, index_e, index_f>,
      ...
      }|
  uv_indices {
    number_of_faces,
      <index_a, index_b, index_c>,
      <index_d, index_e, index_f>,
      ...
      }
MESH_MODIFIER :
  inside_vector <direction> | OBJECT_MODIFIERS

The mesh2 object definition MUST be specified in the following order:

  • VECTORS
  • LISTS
  • INDICES

The normal_vectors, uv_vectors, and texture_list sections are optional. If the number of normals equals the number of vertices then the normal_indices section is optional and the indexes from the face_indices section are used instead. Likewise for the uv_indices section.

Note: The texture_list section is optional only if face_indices doesn't contain any texture index values.

For example:

face_indices {
  number_of_faces,
  <index_a, index_b, index_c>,
  <index_d, index_e, index_f>,
  ...
  }

Note: The numbers of uv_indices must equal number of faces.

The indexes are zero based, so the first item in each list has an index of zero.

3.4.5.2.4.1 Smooth and Flat triangles in the same mesh

You can specify both flat and smooth triangles in the same mesh. To do this, specify the smooth triangles first in the face_indices section, followed by the flat triangles. Then, specify normal indices (in the normal_indices section) for only the smooth triangles. Any remaining triangles that do not have normal indices associated with them will be assumed to be flat triangles.

3.4.5.2.4.2 Mesh Triangle Textures

To specify a texture for an individual mesh triangle, specify a single integer texture index following the face-index vector for that triangle.

To specify three textures for vertex-texture interpolation, specify three integer texture indices (separated by commas) following the face-index vector for that triangle.

Vertex-texture interpolation and textures for an individual triangle can be mixed in the same mesh.

3.4.5.2.5 Polygon

The polygon object is useful for creating rectangles, squares and other planar shapes with more than three edges. Their syntax is:

POLYGON:
  polygon {
    Number_Of_Points, <Point_1> <Point_2>... <Point_n>
    [OBJECT_MODIFIER...]
    }

The float Number_Of_Points tells how many points are used to define the polygon. The points <Point_1> through <Point_n> describe the polygon or polygons. A polygon can contain any number of sub-polygons, either overlapping or not. In places where an even number of polygons overlaps a hole appears. When you repeat the first point of a sub-polygon, it closes it and starts a new sub-polygon's point sequence. This means that all points of a sub-polygon are different.

If the last sub-polygon is not closed a warning is issued and the program automatically closes the polygon. This is useful because polygons imported from other programs may not be closed, i.e. their first and last point are not the same.

All points of a polygon are three-dimensional vectors that have to lay on the same plane. If this is not the case an error occurs. It is common to use two-dimensional vectors to describe the polygon. POV-Ray assumes that the z value is zero in this case.

A square polygon that matches the default planar image map is simply:

polygon {
  4,
  <0, 0>, <0, 1>, <1, 1>, <1, 0>
  texture {
    finish { ambient 1 diffuse 0 }
    pigment { image_map { gif "test.gif"  } }
    }
  //scale and rotate as needed here
  }

The sub-polygon feature can be used to generate complex shapes like the letter "P", where a hole is cut into another polygon:

#declare P = polygon {
  12,
  <0, 0>, <0, 6>, <4, 6>, <4, 3>, <1, 3>, <1,0>, <0, 0>,
  <1, 4>, <1, 5>, <3, 5>, <3, 4>, <1, 4>
  }

The first sub-polygon (on the first line) describes the outer shape of the letter "P". The second sub-polygon (on the second line) describes the rectangular hole that is cut in the top of the letter "P". Both rectangles are closed, i.e. their first and last points are the same.

The feature of cutting holes into a polygon is based on the polygon inside/outside test used. A point is considered to be inside a polygon if a straight line drawn from this point in an arbitrary direction crosses an odd number of edges, this is known as Jordan's curve theorem.

Another very complex example showing one large triangle with three small holes and three separate, small triangles is given below:

polygon {
  28,
  <0, 0> <1, 0> <0, 1> <0, 0>          // large outer triangle
  <.3, .7> <.4, .7> <.3, .8> <.3, .7>  // small outer triangle #1
  <.5, .5> <.6, .5> <.5, .6> <.5, .5>  // small outer triangle #2
  <.7, .3> <.8, .3> <.7, .4> <.7, .3>  // small outer triangle #3
  <.5, .2> <.6, .2> <.5, .3> <.5, .2>  // inner triangle #1
  <.2, .5> <.3, .5> <.2, .6> <.2, .5>  // inner triangle #2
  <.1, .1> <.2, .1> <.1, .2> <.1, .1>  // inner triangle #3
  }
3.4.5.2.6 Triangle

The triangle primitive is available in order to make more complex objects than the built-in shapes will permit. Triangles are usually not created by hand but are converted from other files or generated by utilities. A triangle is defined by

TRIANGLE:
  triangle {
    <Corner_1>, <Corner_2>, <Corner_3>
    [OBJECT_MODIFIER...]
    }

where <Corner_n> is a vector defining the x, y, z coordinates of each corner of the triangle.

Because triangles are perfectly flat surfaces it would require extremely large numbers of very small triangles to approximate a smooth, curved surface. However much of our perception of smooth surfaces is dependent upon the way light and shading is done. By artificially modifying the surface normals we can simulate a smooth surface and hide the sharp-edged seams between individual triangles.

3.4.5.2.7 Smooth Triangle

The smooth_triangle primitive is used for just such purposes. The smooth triangles use a formula called Phong normal interpolation to calculate the surface normal for any point on the triangle based on normal vectors which you define for the three corners. This makes the triangle appear to be a smooth curved surface. A smooth triangle is defined by

SMOOTH_TRIANGLE:
  smooth_triangle {
  <Corner_1>, <Normal_1>, <Corner_2>,
  <Normal_2>, <Corner_3>, <Normal_3>
  [OBJECT_MODIFIER...]
  }

where the corners are defined as in regular triangles and <Normal_n> is a vector describing the direction of the surface normal at each corner.

These normal vectors are prohibitively difficult to compute by hand. Therefore smooth triangles are almost always generated by utility programs. To achieve smooth results, any triangles which share a common vertex should have the same normal vector at that vertex. Generally the smoothed normal should be the average of all the actual normals of the triangles which share that point.

The mesh object is a way to combine many triangle and smooth_triangle objects together in a very efficient way. See Mesh for details.

3.4.5.3 Infinite Solid Primitives

There are six polynomial primitive shapes that are possibly infinite and do not respond to automatic bounding. They are plane, cubic, poly, quartic, polynomial, and quadric. They do have a well defined inside and may be used in CSG and inside a clipped_by statement. As with all shapes they can be translated, rotated and scaled.

3.4.5.3.1 Plane

The plane primitive is a simple way to define an infinite flat surface. The plane is not a thin boundary or can be compared to a sheet of paper. A plane is a solid object of infinite size that divides POV-space in two parts, inside and outside the plane. The plane is specified as follows:

PLANE:
  plane {
    <Normal>, Distance
    [OBJECT_MODIFIERS...]
    }

The <Normal> vector defines the surface normal of the plane. A surface normal is a vector which points up from the surface at a 90 degree angle. This is followed by a float value that gives the distance along the normal that the plane is from the origin (that is only true if the normal vector has unit length; see below). For example:

plane { <0, 1, 0>, 4 }

This is a plane where straight up is defined in the positive y-direction. The plane is 4 units in that direction away from the origin. Because most planes are defined with surface normals in the direction of an axis you will often see planes defined using the x, y or z built-in vector identifiers. The example above could be specified as:

plane { y, 4 }

The plane extends infinitely in the x- and z-directions. It effectively divides the world into two pieces. By definition the normal vector points to the outside of the plane while any points away from the vector are defined as inside. This inside/outside distinction is important when using planes in CSG and clipped_by. It is also important when using fog or atmospheric media. If you place a camera on the "inside" half of the world, then the fog or media will not appear. Such issues arise in any solid object but it is more common with planes. Users typically know when they have accidentally placed a camera inside a sphere or box but "inside a plane" is an unusual concept. In general you can reverse the inside/outside properties of an object by adding the object modifier inverse. See Inverse and Empty and Solid Objects for details.

A plane is called a polynomial shape because it is defined by a first order polynomial equation. Given a plane:

plane { <A, B, C>, D }

it can be represented by the equation A*x + B*y + C*z - D*sqrt(A^2 + B^2 + C^2) = 0.

Therefore our example plane{y,4} is actually the polynomial equation y=4. You can think of this as a set of all x, y, z points where all have y values equal to 4, regardless of the x or z values.

This equation is a first order polynomial because each term contains only single powers of x, y or z. A second order equation has terms like x^2, y^2, z^2, xy, xz and yz. Another name for a 2nd order equation is a quadric equation. Third order polys are called cubics. A 4th order equation is a quartic. Such shapes are described in the sections below.

3.4.5.3.2 Poly

Higher order polynomial surfaces may be defined by the use of a poly shape. The syntax is

POLY:
  poly {
    Order, <A1, A2, A3,... An>
    [POLY_MODIFIERS...]
    }
POLY_MODIFIERS:
  sturm | OBJECT_MODIFIER

Poly default values:

sturm : off

where Order is an integer number from 2 to 35 inclusively that specifies the order of the equation. A1, A2, ... An are float values for the coefficients of the equation. There are n such terms where n = ((Order+1)*(Order+2)*(Order+3))/6.

3.4.5.3.3 Cubic

The cubic object is an alternate way to specify 3rd order polys. Its syntax is:

CUBIC:
  cubic {
    <A1, A2, A3,... A20>
    [POLY_MODIFIERS...]
    }
3.4.5.3.4 Quartic

Also 4th order equations may be specified with the quartic object. Its syntax is:

QUARTIC:
  quartic {
    <A1, A2, A3,... A35>
    [POLY_MODIFIERS...]
    }
3.4.5.3.5 Polynomial

Poly, cubic and quartics are just like quadrics in that you do not have to understand one to use one. The file shapesq.inc has plenty of pre-defined quartics for you to play with.

For convenience an alternate syntax is available as polynomial. It doesn't care about the order of the coefficients, as long as you do not define them more than once, otherwise only the value of the last definition is kept. Additionally the default with all coefficients is 0, which can be especially useful typing shortcut.

See the tutorial section for more examples of the simplified syntax.

POLYNOMIAL:
  polynomial {
    Order, [COEFFICIENTS...]
    [POLY_MODIFIERS...]
    }
COEFFICIENTS:
  xyz(<x_power>,<y_power>,<z_power>):<value>[,]
POLY_MODIFIERS:
  sturm | OBJECT_MODIFIER

Same as the torus above, but with the polynomial syntax:

// Torus having major radius sqrt(40), minor radius sqrt(12)
polynomial { 4,
  xyz(4,0,0):1,
  xyz(2,2,0):2,
  xyz(2,0,2):2,
  xyz(2,0,0):-104,
  xyz(0,4,0):1,
  xyz(0,2,2):2,
  xyz(0,2,0):56,
  xyz(0,0,4):1,
  xyz(0,0,2):-104,
  xyz(0,0,0):784
  sturm
  }

The following table shows which polynomial terms correspond to which x,y,z factors for the orders 2 to 7. Remember cubic is actually a 3rd order polynomial and quartic is 4th order.

 | 2nd | 3rd | 4th | 5th | 6th | 7th |  | 5th | 6th | 7th |  | 6th | 7th
A1 | x2 | x3 | x4 | x5 | x6 | x7 | A41 | y3 | xy3 | x2y3 | A81 | z3 | xz3
A2 | xy | x2y | x3y | x4y | x5y | x6y | A42 | y2z3 | xy2z3 | x2y2z3 | A82 | z2 | xz2
A3 | xz | x2z | x3z | x4z | x5z | x6z | A43 | y2z2 | xy2z2 | x2y2z2 | A83 | z | xz
A4 | x | x2 | x3 | x4 | x5 | x6 | A44 | y2z | xy2z | x2y2z | A84 | 1 | x
A5 | y2 | xy2 | x2y2 | x3y2 | x4y2 | x5y2 | A45 | y2 | xy2 | x2y2 | A85 |  | y7
A6 | yz | xyz | x2yz | x3yz | x4yz | x5yz | A46 | yz4 | xyz4 | x2yz4 | A86 |  | y6z
A7 | y | xy | x2y | x3y | x4y | x5y | A47 | yz3 | xyz3 | x2yz3 | A87 |  | y6
A8 | z2 | xz2 | x2z2 | x3z2 | x4z2 | x5z2 | A48 | yz2 | xyz2 | x2yz2 | A88 |  | y5z2
A9 | z | xz | x2z | x3z | x4z | x5z | A49 | yz | xyz | x2yz | A89 |  | y5z
A10 | 1 | x | x2 | x3 | x4 | x5 | A50 | y | xy | x2y | A90 |  | y5
A11 |  | y3 | xy3 | x2y3 | x3y3 | x4y3 | A51 | z5 | xz5 | x2z5 | A91 |  | y4z3
A12 |  | y2z | xy2z | x2y2z | x3y2z | x4y2z | A52 | z4 | xz4 | x2z4 | A92 |  | y4z2
A13 |  | y2 | xy2 | x2y2 | x3y2 | x4y2 | A53 | z3 | xz3 | x2z3 | A93 |  | y4z
A14 |  | yz2 | xyz2 | x2yz2 | x3yz2 | x4yz2 | A54 | z2 | xz2 | x2z2 | A94 |  | y4
A15 |  | yz | xyz | x2yz | x3yz | x4yz | A55 | z | xz | x2z | A95 |  | y3z4
A16 |  | y | xy | x2y | x3y | x4y | A56 | 1 | x | x2 | A96 |  | y3z3
A17 |  | z3 | xz3 | x2z3 | x3z3 | x4z3 | A57 |  | y6 | xy6 | A97 |  | y3z2
A18 |  | z2 | xz2 | x2z2 | x3z2 | x4z2 | A58 |  | y5z | xy5z | A98 |  | y3z
A19 |  | z | xz | x2z | x3z | x4z | A59 |  | y5 | xy5 | A99 |  | y3
A20 |  | 1 | x | x2 | x3 | x4 | A60 |  | y4z2 | xy4z2 | A100 |  | y2z5
A21 |  |  | y4 | xy4 | x2y4 | x3y4 | A61 |  | y4z | xy4z | A101 |  | y2z4
A22 |  |  | y3z | xy3z | x2y3z | x3y3z | A62 |  | y4 | xy4 | A102 |  | y2z3
A23 |  |  | y3 | xy3 | x2y3 | x3y3 | A63 |  | y3z3 | xy3z3 | A103 |  | y2z2
A24 |  |  | y2z2 | xy2z2 | x2y2z2 | x3y2z2 | A64 |  | y3z2 | xy3z2 | A104 |  | y2z
A25 |  |  | y2z | xy2z | x2y2z | x3y2z | A65 |  | y3z | xy3z | A105 |  | y2
A26 |  |  | y2 | xy2 | x2y2 | x3y2 | A66 |  | y3 | xy3 | A106 |  | yz6
A27 |  |  | yz3 | xyz3 | x2yz3 | x3yz3 | A67 |  | y2z4 | xy2z4 | A107 |  | yz5
A28 |  |  | yz2 | xyz2 | x2yz2 | x3yz2 | A68 |  | y2z3 | xy2z3 | A108 |  | yz4
A29 |  |  | yz | xyz | x2yz | x3yz | A69 |  | y2z2 | xy2z2 | A109 |  | yz3
A30 |  |  | y | xy | x2y | x3y | A70 |  | y2z | xy2z | A110 |  | yz2
A31 |  |  | z4 | xz4 | x2z4 | x3z4 | A71 |  | y2 | xy2 | A111 |  | yz
A32 |  |  | z3 | xz3 | x2z3 | x3z3 | A72 |  | yz5 | xyz5 | A112 |  | y
A33 |  |  | z2 | xz2 | x2z2 | x3z2 | A73 |  | yz4 | xyz4 | A113 |  | z7
A34 |  |  | z | xz | x2z | x3z | A74 |  | yz3 | xyz3 | A114 |  | z6
A35 |  |  | 1 | x | x2 | x3 | A75 |  | yz2 | xyz2 | A115 |  | z5
A36 |  |  |  | y5 | xy5 | x2y5 | A76 |  | yz | xyz | A116 |  | z4
A37 |  |  |  | y4z | xy4z | x2y4z | A77 |  | y | xy | A117 |  | z3
A38 |  |  |  | y4 | xy4 | x2y4 | A78 |  | z6 | xz6 | A118 |  | z2
A39 |  |  |  | y3z2 | xy3z2 | x2y3z2 | A79 |  | z5 | xz5 | A119 |  | z
A40 |  |  |  | y3z | xy3z | x2y3z | A80 |  | z4 | xz4 | A120 |  | 1

Polynomial shapes can be used to describe a large class of shapes including the torus, the lemniscate, etc. For example, to declare a quartic surface requires that each of the coefficients (A1 ... A35) be placed in order into a single long vector of 35 terms. As an example let's define a torus the hard way. A Torus can be represented by the equation: x4 + y4 + z4 + 2 x2 y2 + 2 x2 z2 + 2 y2 z2 - 2 (r_02 + r_12) x2 + 2 (r_02 - r_12) y2 - 2 (r_02 + r_12) z2 + (r_02 - r_12)2 = 0

Where r_0 is the major radius of the torus, the distance from the hole of the donut to the middle of the ring of the donut, and r_1 is the minor radius of the torus, the distance from the middle of the ring of the donut to the outer surface. The following object declaration is for a torus having major radius 6.3 minor radius 3.5 (Making the maximum width just under 20).

// Torus having major radius sqrt(40), minor radius sqrt(12)
quartic {
  < 1,   0,   0,   0,   2,   0,   0,   2,   0,
  -104,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   1,   0,   0,   2,   0,  56,   0,
  0,   0,   0,   1,   0, -104,  0, 784 >
  sturm
  }

Polynomial surfaces use highly complex computations and will not always render perfectly. If the surface is not smooth, has dropouts, or extra random pixels, try using the optional keyword sturm in the definition. This will cause a slower but more accurate calculation method to be used. Usually, but not always, this will solve the problem. If sturm does not work, try rotating or translating the shape by some small amount.

There are really so many different polynomial shapes, we cannot even begin to list or describe them all. We suggest you find a good reference or text book if you want to investigate the subject further.

3.4.5.3.6 Quadric

The quadric object can produce shapes like paraboloids (dish shapes) and hyperboloids (saddle or hourglass shapes). It can also produce ellipsoids, spheres, cones, and cylinders but you should use the sphere, cone, and cylinder objects built into POV-Ray because they are faster than the quadric version.

Note: Do not confuse "quaDRic" with "quaRTic". A quadric is a 2nd order polynomial while a quartic is 4th order.

Quadrics render much faster and are less error-prone but produce less complex objects. The syntax is:

QUADRIC:
  quadric {
    <A,B,C>,<D,E,F>,<G,H,I>,J
    [OBJECT_MODIFIERS...]
    }

Although the syntax actually will parse 3 vector expressions followed by a float, we traditionally have written the syntax as above where A through J are float expressions. These 10 float that define a surface of x, y, z points which satisfy the equation A x2 + B y2 + C z2 + D xy + E xz + F yz + G x + H y + I z + J = 0

Different values of A, B, C, ... J will give different shapes. If you take any three dimensional point and use its x, y and z coordinates in the above equation the answer will be 0 if the point is on the surface of the object. The answer will be negative if the point is inside the object and positive if the point is outside the object. Here are some examples:

X2 + Y2 + Z2 - 1 = 0 | Sphere
X2 + Y2 - 1 = 0 | Infinite cylinder along the Z axis
X2 + Y2 - Z2 = 0 | Infinite cone along the Z axis

The easiest way to use these shapes is to include the standard file shapes.inc into your program. It contains several pre-defined quadrics and you can transform these pre-defined shapes (using translate, rotate and scale) into the ones you want. For a complete list, see the file shapes.inc.

3.4.5.4 Constructive Solid Geometry

In addition to all of the primitive shapes POV-Ray supports, you can also combine multiple simple shapes into complex shapes using Constructive Solid Geometry (CSG). There are four basic types of CSG operations: union, intersection, difference, and merge. CSG objects can be composed of primitives or other CSG objects to create more, and more complex shapes.

3.4.5.4.1 Inside and Outside

Most shape primitives, like spheres, boxes and blobs divide the world into two regions. One region is inside the object and one is outside. Given any point in space you can say it is either inside or outside any particular primitive object. Well, it could be exactly on the surface but this case is rather hard to determine due to numerical problems.

Even planes have an inside and an outside. By definition, the surface normal of the plane points towards the outside of the plane. You should note that triangles cannot be used as solid objects in CSG since they have no well defined inside and outside. Triangle-based shapes (mesh and mesh2) can only be used in CSG when they are closed objects and have an inside vector specified.

Note: Although the triangle, the bicubic_patch and some other shapes have no well defined inside and outside, they have a front- and backside which makes it possible to use a texture on the front side and an interior_texture on the back side.

CSG uses the concepts of inside and outside to combine shapes together as explained in the following sections.

Imagine you have two objects that partially overlap like shown in the figure below. Four different areas of points can be distinguished: points that are neither in object A nor in object B, points that are in object A but not in object B, points that are not in object A but in object B and last not least points that are in object A and object B.

Two overlapping objects.

Keeping this in mind it will be quite easy to understand how the CSG operations work.

When using CSG it is often useful to invert an object so that it will be inside-out. The appearance of the object is not changed, just the way that POV-Ray perceives it. When the inverse keyword is used the inside of the shape is flipped to become the outside and vice versa.

The inside/outside distinction is not important for a union, but is important for intersection, difference, and merge. Therefore any objects may be combined using union but only solid objects, i.e. objects that have a well-defined interior can be used in the other kinds of CSG. The objects described in Finite Patch Primitives have no well defined inside/outside. All objects described in the sections Finite Solid Primitives and Infinite Solid Primitives.

3.4.5.4.2 Union

The union of two objects.

The simplest kind of CSG is the union. The syntax is:

UNION:
  union {
    OBJECTS...
    [OBJECT_MODIFIERS...]
    }

Unions are simply glue used to bind two or more shapes into a single entity that can be manipulated as a single object. The image above shows the union of A and B. The new object created by the union operation can be scaled, translated and rotated as a single shape. The entire union can share a single texture but each object contained in the union may also have its own texture, which will override any texture statements in the parent object.

You should be aware that the surfaces inside the union will not be removed. As you can see from the figure this may be a problem for transparent unions. If you want those surfaces to be removed you will have to use the merge operations explained in a later section.

The following union will contain a box and a sphere.

union {
  box { <-1.5, -1, -1>, <0.5, 1, 1> }
  cylinder { <0.5, 0, -1>, <0.5, 0, 1>, 1 }
  }

Earlier versions of POV-Ray placed restrictions on unions so you often had to combine objects with composite statements. Those earlier restrictions have been lifted so composite is no longer needed. It is still supported for backwards compatibility.

3.4.5.4.2.1 Split_Union

split_union is a boolean keyword that can be added to a union. It has two states on/off, its default is on.

split_union is used when photons are shot at the CSG-object. The object is split up in its compound parts, photons are shot at each part separately. This is to prevent photons from being shot at 'empty spaces' in the object, for example the holes in a grid. With compact objects, without 'empty spaces' split_union off can improve photon gathering.

union {
  object {...}
  object {...}
  split_union off
  }
3.4.5.4.3 Intersection

The intersection object creates a shape containing only those areas where all components overlap. A point is part of an intersection if it is inside both objects, A and B, as show in the figure below.

The intersection of two objects.

The syntax is:

INTERSECTION:
  intersection {
    SOLID_OBJECTS...
    [OBJECT_MODIFIERS...]
    }

The component objects must have well defined inside/outside properties. Patch objects are not allowed.

Note: If all components do not overlap, the intersection object disappears.

Here is an example that overlaps:

intersection {
  box { <-1.5, -1, -1>, <0.5, 1, 1> }
  cylinder { <0.5, 0, -1>, <0.5, 0, 1>, 1 }
  }
3.4.5.4.4 Difference

The CSG difference operation takes the intersection between the first object and the inverse of all subsequent objects. Thus only points inside object A and outside object B belong to the difference of both objects.

The result is a subtraction of the 2nd shape from the first shape as shown in the figure below.

The difference between two objects.

The syntax is:

DIFFERENCE:
  difference {
    SOLID_OBJECTS...
    [OBJECT_MODIFIERS...]
    }

The component objects must have well defined inside/outside properties. Patch objects are not allowed.

Note: If the first object is entirely inside the subtracted objects, the difference object disappears.

Here is an example of a properly formed difference:

difference {
  box { <-1.5, -1, -1>, <0.5, 1, 1> }
  cylinder { <0.5, 0, -1>, <0.5, 0, 1>, 1 }
  }

Note: Internally, POV-Ray simply adds the inverse keyword to the second (and subsequent) objects and then performs an intersection.

The example above is equivalent to:

intersection {
  box { <-1.5, -1, -1>, <0.5, 1, 1> }
  cylinder { <0.5, 0, -1>, <0.5, 0, 1>, 1 inverse }
  }
3.4.5.4.5 Merge

The union operation just glues objects together, it does not remove the objects' surfaces inside the union. Under most circumstances this does not matter. However if a transparent union is used, those interior surfaces will be visible. The merge operations can be used to avoid this problem. It works just like union but it eliminates the inner surfaces like shown in the figure below.

Merge removes inner surfaces.

The syntax is:

MERGE:
  merge {
    SOLID_OBJECTS...
    [OBJECT_MODIFIERS...]
    }

The component objects must have well defined inside/outside properties. Patch objects are not allowed.

Note: In general merge is slower rendering than union when used with non transparent objects. A small test may be needed to determine what is the optimal solution regarding speed and visual result.

3.4.5.5 Object Modifiers

A variety of modifiers may be attached to objects. The following items may be applied to any object:

OBJECT_MODIFIER:
  clipped_by { UNTEXTURED_SOLID_OBJECT... } |
  clipped_by { bounded_by }                 |
  bounded_by { UNTEXTURED_SOLID_OBJECT... } |
  bounded_by { clipped_by }                 |
  no_shadow                  |
  no_image [ Bool ]          |
  no_radiosity [ Bool ]      |
  no_reflection [ Bool ]     |
  inverse                    |
  sturm [ Bool ]             |
  hierarchy [ Bool ]         |
  double_illuminate [ Bool ] |
  hollow  [ Bool ]           |
  interior { INTERIOR_ITEMS... }                        |
  material { [MATERIAL_IDENTIFIER][MATERIAL_ITEMS...] } |
  texture { TEXTURE_BODY }   |
  interior_texture { TEXTURE_BODY } |
  pigment { PIGMENT_BODY }   |
  normal { NORMAL_BODY }     |
  finish { FINISH_ITEMS... } |
  photons { PHOTON_ITEMS...}
  radiosity { RADIOSITY_ITEMS...}
  TRANSFORMATION

Transformations such as translate, rotate and scale have already been discussed. The modifiers Textures and its parts Pigment, Normal, and Finish as well as Interior, and Media (which is part of interior) are each in major chapters of their own below. In the sub-sections below we cover several other important modifiers: clipped_by, bounded_by, material, inverse, hollow, no_shadow, no_image, no_reflection, double_illuminate, no_radiosity and sturm. Although the examples below use object statements and object identifiers, these modifiers may be used on any type of object such as sphere, box etc.

3.4.5.5.1 Clipped By Object Modifier

The clipped_by statement is technically an object modifier but it provides a type of CSG similar to CSG intersection. The syntax is:

CLIPPED_BY:
  clipped_by { UNTEXTURED_SOLID_OBJECT... } |
  clipped_by { bounded_by }

Where UNTEXTURED_SOLID_OBJECT is one or more solid objects which have had no texture applied. For example:

object {
  My_Thing
  clipped_by{plane{y,0}}
  }

Every part of the object My_Thing that is inside the plane is retained while the remaining part is clipped off and discarded. In an intersection object the hole is closed off. With clipped_by it leaves an opening. For example the following figure shows object A being clipped by object B.

An object clipped by another object.

You may use clipped_by to slice off portions of any shape. In many cases it will also result in faster rendering times than other methods of altering a shape. Occasionally you will want to use the clipped_by and bounded_by options with the same object. The following shortcut saves typing and uses less memory.

object {
  My_Thing
  bounded_by { box { <0,0,0>, <1,1,1> } }
  clipped_by { bounded_by }
  }

This tells POV-Ray to use the same box as a clip that was used as a bound.

3.4.5.5.2 Bounded By Object Modifier

The calculations necessary to test if a ray hits an object can be quite time consuming. Each ray has to be tested against every object in the scene. POV-Ray attempts to speed up the process by building a set of invisible boxes, called bounding boxes, which cluster the objects together. This way a ray that travels in one part of the scene does not have to be tested against objects in another, far away part of the scene. When a large number of objects are present the boxes are nested inside each other. POV-Ray can use bounding boxes on any finite object and even some clipped or bounded quadrics. However infinite objects (such as a planes, quartic, cubic and poly) cannot be automatically bound. CSG objects are automatically bound if they contain finite (and in some cases even infinite) objects. This works by applying the CSG set operations to the bounding boxes of all objects used inside the CSG object. For difference and intersection operations this will hardly ever lead to an optimal bounding box. It is sometimes better (depending on the complexity of the CSG object) to have you place a bounding shape yourself using a bounded_by statement.

Normally bounding shapes are not necessary but there are cases where they can be used to speed up the rendering of complex objects. Bounding shapes tell the ray-tracer that the object is totally enclosed by a simple shape. When tracing rays, the ray is first tested against the simple bounding shape. If it strikes the bounding shape the ray is further tested against the more complicated object inside. Otherwise the entire complex shape is skipped, which greatly speeds rendering. The syntax is:

BOUNDED_BY:
  bounded_by { UNTEXTURED_SOLID_OBJECT... } |
  bounded_by { clipped_by }

Where UNTEXTURED_SOLID_OBJECT is one or more solid objects which have had no texture applied. For example:

intersection {
  sphere { <0,0,0>, 2 }
  plane  { <0,1,0>, 0 }
  plane  { <1,0,0>, 0 }
  bounded_by { sphere { <0,0,0>, 2 } }
  }

The best bounding shape is a sphere or a box since these shapes are highly optimized, although, any shape may be used. If the bounding shape is itself a finite shape which responds to bounding slabs then the object which it encloses will also be used in the slab system.

While it may a good idea to manually add a bounded_by to intersection, difference and merge, it is best to never bound a union. If a union has no bounded_by POV-Ray can internally split apart the components of a union and apply automatic bounding slabs to any of its finite parts. Note that some utilities such as raw2pov may be able to generate bounds more efficiently than POV-Ray's current system. However most unions you create yourself can be easily bounded by the automatic system. For technical reasons POV-Ray cannot split a merge object. It is maybe best to hand bound a merge, especially if it is very complex.

Note: If bounding shape is too small or positioned incorrectly it may clip the object in undefined ways or the object may not appear at all. To do true clipping, use clipped_by as explained in the previous section. Occasionally you will want to use the clipped_by and bounded_by options with the same object. The following shortcut saves typing and uses less memory.

object {
  My_Thing
  clipped_by{ box { <0,0,0>,<1,1,1 > }}
  bounded_by{ clipped_by }
  }

This tells POV-Ray to use the same box as a bound that was used as a clip.

3.4.5.5.3 Material

One of the changes in POV-Ray 3.1 was the removal of several items from texture { finish{...} } and to move them to the new interior statement. The halo statement, formerly part of texture, is now renamed media and made a part of the interior.

This split was deliberate and purposeful (see Why are Interior and Media Necessary?) however beta testers pointed out that it made it difficult to entirely describe the surface properties and interior of an object in one statement that can be referenced by a single identifier in a texture library.

The result is that we created a wrapper around texture and interior which we call material.

The syntax is:

MATERIAL:
  material { [MATERIAL_IDENTIFIER][MATERIAL_ITEMS...] }
MATERIAL_ITEMS:
  TEXTURE | INTERIOR_TEXTURE | INTERIOR | TRANSFORMATIONS

For example:

#declare MyGlass=material{ texture{ Glass_T } interior{ Glass_I }}
object { MyObject material{ MyGlass}}

Internally, the material is not attached to the object. The material is just a container that brings the texture and interior to the object. It is the texture and interior itself that is attached to the object. Users should still consider texture and interior as separate items attached to the object.

The material is just a bucket to carry them. If the object already has a texture, then the material texture is layered over it. If the object already has an interior, the material interior fully replaces it and the old interior is destroyed. Transformations inside the material affect only the textures and interiors which are inside the material{} wrapper and only those textures or interiors specified are affected. For example:

object {
  MyObject
    material {
      texture { MyTexture }
      scale 4         //affects texture but not object or interior
      interior { MyInterior }
      translate 5*x   //affects texture and interior, not object
      }
  }

Note: The material statement has nothing to do with the material_map statement. A material_map is not a way to create patterned material. See Material Maps for explanation of this unrelated, yet similarly named, older feature.

3.4.5.5.4 Hollow Object Modifier

POV-Ray by default assumes that objects are made of a solid material that completely fills the interior of an object. By adding the hollow keyword to the object you can make it hollow, also see the Empty and Solid Objects chapter. That is very useful if you want atmospheric effects to exist inside an object. It is even required for objects containing an interior media. The keyword may optionally be followed by a float expression which is interpreted as a boolean value. For example hollow off may be used to force it off. When the keyword is specified alone, it is the same as hollow on. By default hollow is off when not specified.

In order to get a hollow CSG object you just have to make the top level object hollow. All children will assume the same hollow state except when their state is explicitly set. The following example will set both spheres inside the union hollow

union {
  sphere { -0.5*x, 1 }
  sphere {  0.5*x, 1 }
  hollow
  }

while the next example will only set the second sphere hollow because the first sphere was explicitly set to be not hollow.

union {
  sphere { -0.5*x, 1 hollow off }
  sphere {  0.5*x, 1 }
  hollow on
  }
3.4.5.5.5 Inverse Object Modifier

When using CSG it is often useful to invert an object so that it will be inside-out. The appearance of the object is not changed, just the way that POV-Ray perceives it. When the inverse keyword is used the inside of the shape is flipped to become the outside and vice versa. For example:

object { MyObject inverse }

The inside/outside distinction is also important when attaching interior to an object especially if media is also used. Atmospheric media and fog also do not work as expected if your camera is inside an object. Using inverse is useful to correct that problem.

3.4.5.5.6 No Shadow Object Modifier

You may specify the no_shadow keyword in an object to make that object cast no shadow. This is useful for special effects and for creating the illusion that a light source actually is visible. This keyword was necessary in earlier versions of POV-Ray which did not have the looks_like statement. Now it is useful for creating things like laser beams or other unreal effects. During test rendering it speeds things up if no_shadow is applied.

Simply attach the keyword as follows:

object {
  My_Thing
  no_shadow
  }
3.4.5.5.7 No Image Object Modifier

Syntax:

OBJECT {
  [OBJECT_ITEMS...]
  no_image
  }

This keyword is very similar in usage and function to the no_shadow keyword, and control an object's visibility.
You can use any combination of no_image, no_reflection and no_shadow with your object.

When no_image is used, the object will not be seen by the camera, either directly or through transparent/refractive objects. However, it will still cast shadows, and show up in reflections (unless no_reflection and/or no_shadow is used also).

Using these three keywords you can produce interesting effects like a sphere casting a rectangular shadow, a cube that shows up as a cone in mirrors, etc.

3.4.5.5.8 No Reflection Object Modifier

Syntax:

OBJECT {
  [OBJECT_ITEMS...]
  no_reflection
  }

This keyword is very similar in usage and function to the no_shadow keyword, and control an object's visibility.
You can use any combination of no_reflection, no_image and no_shadow with your object.

When no_reflection is used, the object will not show up in reflections. It will be seen by the camera (and through transparent/refractive objects) and cast shadows, unless no_image and/or no_shadow is used.

3.4.5.5.9 Double Illuminate Object Modifier

Syntax:

OBJECT {
  [OBJECT_ITEMS...]
  double_illuminate
  }

A surface has two sides; usually, only the side facing the light source is illuminated, the other side remains in shadow. When double_illuminate is used, the other side is also illuminated.
This is useful for simulating effects like translucency (as in a lamp shade, sheet of paper, etc).

Note: Using double_illuminate only illuminates both sides of the same surface, so on a sphere, for example, you will not see the effect unless the sphere is either partially transparent, or if the camera is inside and the light source outside of the sphere (or vise versa).

3.4.5.5.10 No Radiosity Object Modifier

Specifying no_radiosity in an object block makes that object invisible to radiosity rays, in the same way as no_image, no_reflection and no_shadow make an object invisible to primary, reflected and shadow test rays, respectively.

3.4.5.5.11 Sturm Object Modifier

Some of POV-Ray's objects allow you to choose between a fast but sometimes inaccurate root solver and a slower but more accurate one. This is the case for all objects that involve the solution of a cubic or quartic polynomial. There are analytic mathematical solutions for those polynomials that can be used.

Lower order polynomials are trivial to solve while higher order polynomials require iterative algorithms to solve them. One of those algorithms is the Sturmian root solver. For example:

blob {
  threshold .65
  sphere { <.5,0,0>, .8, 1 }
  sphere { <-.5,0,0>,.8, 1 }
  sturm
  }

The keyword may optionally be followed by a float expression which is interpreted as a boolean value. For example sturm off may be used to force it off. When the keyword is specified alone, it is the same as sturm on. By default sturm is off when not specified.

The following list shows all objects for which the Sturmian root solver can be used.

  • blob
  • cubic
  • lathe (only with quadratic splines)
  • poly
  • prism (only with cubic splines)
  • quartic
  • sor
  • torus

3.4.6 Texture

The texture statement is an object modifier which describes what the surface of an object looks like, i.e. its material. Textures are combinations of pigments, normals, and finishes. Pigment is the color or pattern of colors inherent in the material. Normal is a method of simulating various patterns of bumps, dents, ripples or waves by modifying the surface normal vector. Finish describes the reflective properties of a material.

Note: In previous versions of POV-Ray, the texture also contained information about the interior of an object. This information has been moved to a separate object modifier called interior. See Interior for details.

There are three basic kinds of textures: plain, patterned, and layered. A plain texture consists of a single pigment, an optional normal, and a single finish. A patterned texture combines two or more textures using a block pattern or blending function pattern. Patterned textures may be made quite complex by nesting patterns within patterns. At the innermost levels however, they are made up from plain textures. A layered texture consists of two or more semi-transparent textures layered on top of one another.

Note: Although we call a plain texture plain it may be a very complex texture with patterned pigments and normals. The term plain only means that it has a single pigment, normal, and finish.

The syntax for texture is as follows:

TEXTURE:
  PLAIN_TEXTURE | PATTERNED_TEXTURE | LAYERED_TEXTURE
PLAIN_TEXTURE:
  texture {
    [TEXTURE_IDENTIFIER]
    [PNF_IDENTIFIER...]
    [PNF_ITEMS...]
    }
PNF_IDENTIFIER:
  PIGMENT_IDENTIFIER | NORMAL_IDENTIFIER | FINISH_IDENTIFIER
PNF_ITEMS:
  PIGMENT | NORMAL | FINISH | TRANSFORMATION
LAYERED_TEXTURE:
  NON_PATTERNED_TEXTURE...
PATTERNED_TEXTURE:
  texture {
    [PATTERNED_TEXTURE_ID]
    [TRANSFORMATIONS...]
    } |
  texture {
    PATTERN_TYPE
    [TEXTURE_PATTERN_MODIFIERS...]
    } |
  texture {
    tiles TEXTURE tile2 TEXTURE
    [TRANSFORMATIONS...]
    } |
  texture {
    material_map {
      BITMAP_TYPE "bitmap.ext"
      [MATERIAL_MODS...] TEXTURE... [TRANSFORMATIONS...]
      }
    }
TEXTURE_PATTERN_MODIFIER:
  PATTERN_MODIFIER | TEXTURE_LIST |
  texture_map { TEXTURE_MAP_BODY }

In the PLAIN_TEXTURE, each of the items are optional but if they are present the TEXTURE_IDENTIFIER must be first. If no texture identifier is given, then POV-Ray creates a copy of the default texture.

Next are optional pigment, normal, and/or finish identifiers which fully override any pigment, normal and finish already specified in the previous texture identifier or default texture. Typically this is used for backward compatibility to allow things like:

texture { MyPigment }

where MyPigment is a pigment identifier.

Finally we have optional pigment, normal or finish statements which modify any pigment, normal and finish already specified in the identifier. If no texture identifier is specified the pigment, normal and finish statements modify the current default values. This is the typical plain texture:

texture {
  pigment { MyPigment }
  normal { MyNormal }
  finish { MyFinish }
  scale SoBig
  rotate SoMuch
  translate SoFar
  }

The TRANSFORMATIONS may be interspersed between the pigment, normal and finish statements but are generally specified last. If they are interspersed, then they modify only those parts of the texture already specified. For example:

texture {
  pigment { MyPigment }
  scale SoBig      //affects pigment only
  normal { MyNormal }
  rotate SoMuch    //affects pigment and normal
  finish { MyFinish }
  translate SoFar  //finish is never transformable no matter what.
                   //Therefore affects pigment and normal only
  }

Texture identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

TEXTURE_DECLARATION:
  #declare IDENTIFIER = TEXTURE |
  #local IDENTIFIER = TEXTURE

Where IDENTIFIER is the name of the identifier up to 40 characters long and TEXTURE is any valid texture statement. See #declare vs. #local for information on identifier scope.

The sections below describe all of the options available for Pigment, Normal, and Finish. They are the main part of plain textures. There are also separate sections for Patterned Textures and Layered Textures which are made up of plain textures.

Note: The tiles and material_map versions of patterned textures are obsolete and are only supported for backwards compatibility.

3.4.6.1 Pigment

The color or pattern of colors for an object is defined by a pigment statement. All plain textures must have a pigment. If you do not specify one the default pigment is used. The color you define is the way you want the object to look if fully illuminated. You pick the basic color inherent in the object and POV-Ray brightens or darkens it depending on the lighting in the scene. The parameter is called pigment because we are defining the basic color the object actually is rather than how it looks.

The syntax for pigment is:

PIGMENT:
  pigment {
    [PIGMENT_IDENTIFIER]
    [PIGMENT_TYPE]
    [PIGMENT_MODIFIER...]
    }
PIGMENT_TYPE:
  PATTERN_TYPE | COLOR |
  image_map {
    BITMAP_TYPE "bitmap.ext" [IMAGE_MAP_MODS...]
    }
PIGMENT_MODIFIER:
  PATTERN_MODIFIER | COLOR_LIST | PIGMENT_LIST |
  color_map { COLOR_MAP_BODY } | colour_map { COLOR_MAP_BODY } |
  pigment_map { PIGMENT_MAP_BODY } | quick_color COLOR |
  quick_colour COLOR

Each of the items in a pigment are optional but if they are present, they must be in the order shown. Any items after the PIGMENT_IDENTIFIER modify or override settings given in the identifier. If no identifier is specified then the items modify the pigment values in the current default texture. The PIGMENT_TYPE fall into roughly four categories. Each category is discussed the sub-sections which follow. The four categories are solid color and image_map patterns which are specific to pigment statements or color list patterns, color mapped patterns which use POV-Ray's wide selection of general patterns. See Patterns for details about specific patterns.

The pattern type is optionally followed by one or more pigment modifiers. In addition to general pattern modifiers such as transformations, turbulence, and warp modifiers, pigments may also have a COLOR_LIST, PIGMENT_LIST, color_map, pigment_map, and quick_color which are specific to pigments. See Pattern Modifiers for information on general modifiers. The pigment-specific modifiers are described in sub-sections which follow. Pigment modifiers of any kind apply only to the pigment and not to other parts of the texture. Modifiers must be specified last.

A pigment statement is part of a texture specification. However it can be tedious to use a texture statement just to add a color to an object. Therefore you may attach a pigment directly to an object without explicitly specifying that it as part of a texture. For example instead of this:

object { My_Object texture {pigment { color Red } } }

you may shorten it to:

object { My_Object pigment {color Red } }

Doing so creates an entire texture structure with default normal and finish statements just as if you had explicitly typed the full texture {...} around it.

Note: an explicit texture statement is required, if you want to layer pigments.

Pigment identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

PIGMENT_DECLARATION:
  #declare IDENTIFIER = PIGMENT |
  #local IDENTIFIER = PIGMENT

Where IDENTIFIER is the name of the identifier up to 40 characters long and PIGMENT is any valid pigment statement. See #declare vs. #local for information on identifier scope.

3.4.6.1.1 Solid Color Pigments

The simplest type of pigment is a solid color. To specify a solid color you simply put a color specification inside a pigment statement. For example:

pigment { color Orange }

A color specification consists of the optional keyword color followed by a color identifier or by a specification of the amount of red, green, blue, filtered and unfiltered transparency in the surface. See section Specifying Colors for more details about colors. Any pattern modifiers used with a solid color are ignored because there is no pattern to modify.

3.4.6.1.4 Color List Pigments

There are four color list patterns: checker, hexagon, brick and object. The result is a pattern of solid colors with distinct edges rather than a blending of colors as with color mapped patterns. Each of these patterns is covered in more detail in a later section. The syntax is:

COLOR_LIST_PIGMENT:
  pigment {brick [COLOR_1, [COLOR_2]] [PIGMENT_MODIFIERS...] }|
  pigment {checker [COLOR_1, [COLOR_2]] [PIGMENT_MODIFIERS...]}|
  pigment {
    hexagon [COLOR_1, [COLOR_2, [COLOR_3]]] [PIGMENT_MODIFIERS...]
    }|
  pigment {object OBJECT_IDENTIFIER | OBJECT {} [COLOR_1, COLOR_2]}

Each COLOR_n is any valid color specification. There should be a comma between each color or the color keyword should be used as a separator so that POV-Ray can determine where each color specification starts and ends. The brick and checker pattern expects two colors and hexagon expects three. If an insufficient number of colors is specified then default colors are used.

3.4.6.1.5 Quick Color

When developing POV-Ray scenes it is often useful to do low quality test runs that render faster. The +Q command line switch or Quality INI option can be used to turn off some time consuming color pattern and lighting calculations to speed things up. See Quality Settings for details. However all settings of +Q5 or Quality=5 or lower turns off pigment calculations and creates gray objects.

By adding a quick_color to a pigment you tell POV-Ray what solid color to use for quick renders instead of a patterned pigment. For example:

pigment {
  gradient x
  color_map {
    [0.0 color Yellow]
    [0.3 color Cyan]
    [0.6 color Magenta]
    [1.0 color Cyan]
    }
  turbulence 0.5
  lambda 1.5
  omega 0.75
  octaves 8
  quick_color Neon_Pink
  }

This tells POV-Ray to use solid Neon_Pink for test runs at quality +Q5 or lower but to use the turbulent gradient pattern for rendering at +Q6 and higher. Solid color pigments such as

pigment {color Magenta}

automatically set the quick_color to that value. You may override this if you want. Suppose you have 10 spheres on the screen and all are yellow. If you want to identify them individually you could give each a different quick_color. Foe example:

sphere {
  <1,2,3>,4
  pigment { color Yellow  quick_color Red }
  }

sphere {
  <-1,-2,-3>,4
  pigment { color Yellow  quick_color Blue }
  }

and so on. At +Q6 or higher they will all be yellow but at +Q5 or lower each would be different colors so you could identify them.

The alternate spelling quick_colour is also supported.

3.4.6.1.2 Color Map

Most of the color patterns do not use abrupt color changes of just two or three colors like those in the brick, checker or hexagon patterns. They instead use smooth transitions of many colors that gradually change from one point to the next. The colors are defined in a pigment modifier called a color_map that describes how the pattern blends from one color to the next.

Each of the various pattern types available is in fact a mathematical function that takes any x, y, z location and turns it into a number between 0.0 and 1.0 inclusive. That number is used to specify what mix of colors to use from the color map.

The syntax for color_map is as follows:

COLOR_MAP:
  color_map { COLOR_MAP_BODY } | colour_map { COLOR_MAP_BODY }
COLOR_MAP_BODY:
  COLOR_MAP_IDENTIFIER | COLOR_MAP_ENTRY...
COLOR_MAP_ENTRY:
  [ Value COLOR ] |
  [ Value_1, Value_2 color COLOR_1 color COLOR_2 ]

Where each Value_n is a float values between 0.0 and 1.0 inclusive and each COLOR_n, is color specifications.

Note: The [] brackets are part of the actual COLOR_MAP_ENTRY. They are not notational symbols denoting optional parts. The brackets surround each entry in the color map.

There may be from 2 to 256 entries in the map. The alternate spelling colour_map may be used.

Here is an example:

sphere {
  <0,1,2>, 2
  pigment {
    gradient x       //this is the PATTERN_TYPE
    color_map {
      [0.1  color Red]
      [0.3  color Yellow]
      [0.6  color Blue]
      [0.6  color Green]
      [0.8  color Cyan]
      }
    }
  }

The pattern function gradient x is evaluated and the result is a value from 0.0 to 1.0. If the value is less than the first entry (in this case 0.1) then the first color (red) is used. Values from 0.1 to 0.3 use a blend of red and yellow using linear interpolation of the two colors. Similarly values from 0.3 to 0.6 blend from yellow to blue.

The 3rd and 4th entries both have values of 0.6. This causes an immediate abrupt shift of color from blue to green. Specifically a value that is less than 0.6 will be blue but exactly equal to 0.6 will be green. Moving along, values from 0.6 to 0.8 will be a blend of green and cyan. Finally any value greater than or equal to 0.8 will be cyan.

If you want areas of unchanging color you simply specify the same color for two adjacent entries. For example:

color_map {
  [0.1  color Red]
  [0.3  color Yellow]
  [0.6  color Yellow]
  [0.8  color Green]
  }

In this case any value from 0.3 to 0.6 will be pure yellow.

The first syntax version of COLOR_MAP_ENTRY with one float and one color is the current standard. The other double entry version is obsolete and should be avoided. The previous example would look as follows using the old syntax.

color_map {
  [0.0 0.1  color Red color Red]
  [0.1 0.3  color Red color Yellow]
  [0.3 0.6  color Yellow color Yellow]
  [0.6.0.8  color Yellow color Green]
  [0.8 1.0  color Green color Green]
  }

You may use color_map with any patterns except brick, checker, hexagon, object and image_map. You may declare and use color_map identifiers. For example:

#declare Rainbow_Colors=
color_map {
  [0.0   color Magenta]
  [0.33  color Yellow]
  [0.67  color Cyan]
  [1.0   color Magenta]
  }
object {
  My_Object
  pigment {
    gradient x
    color_map { Rainbow_Colors }
    }
  }
3.4.6.1.3 Pigment Map

In addition to specifying blended colors with a color map you may create a blend of pigments using a pigment_map. The syntax for a pigment map is identical to a color map except you specify a pigment in each map entry (and not a color).

The syntax for pigment_map is as follows:

PIGMENT_MAP:
  pigment_map { PIGMENT_MAP_BODY }
PIGMENT_MAP_BODY:
  PIGMENT_MAP_IDENTIFIER | PIGMENT_MAP_ENTRY...
PIGMENT_MAP_ENTRY:
  [ Value PIGMENT_BODY ]

Where Value is a float value between 0.0 and 1.0 inclusive and each PIGMENT_BODY is anything which can be inside a pigment{...} statement. The pigment keyword and {} braces need not be specified.

Note: The [] brackets are part of the actual PIGMENT_MAP_ENTRY. They are not notational symbols denoting optional parts. The brackets surround each entry in the pigment map.

There may be from 2 to 256 entries in the map.

For example:

sphere {
  <0,1,2>, 2
  pigment {
    gradient x       //this is the PATTERN_TYPE
    pigment_map {
      [0.3 wood scale 0.2]
      [0.3 Jade]     //this is a pigment identifier
      [0.6 Jade]
      [0.9 marble turbulence 1]
      }
    }
  }

When the gradient x function returns values from 0.0 to 0.3 the scaled wood pigment is used. From 0.3 to 0.6 the pigment identifier Jade is used. From 0.6 up to 0.9 a blend of Jade and a turbulent marble is used. From 0.9 on up only the turbulent marble is used.

Pigment maps may be nested to any level of complexity you desire. The pigments in a map may have color maps or pigment maps or any type of pigment you want. Any entry of a pigment map may be a solid color however if all entries are solid colors you should use a color_map which will render slightly faster.

Entire pigments may also be used with the block patterns such as checker, hexagon and brick. For example:

pigment {
  checker
    pigment { Jade scale .8 }
    pigment { White_Marble scale .5 }
    }

Note: In the case of block patterns the pigment wrapping is required around the pigment information.

A pigment map is also used with the average pigment type. See Average for details.

You may not use pigment_map or individual pigments with an image_map. See section Texture Maps for an alternative way to do this.

You may declare and use pigment map identifiers but the only way to declare a pigment block pattern list is to declare a pigment identifier for the entire pigment.

3.4.6.2 Normal

Ray-tracing is known for the dramatic way it depicts reflection, refraction and lighting effects. Much of our perception depends on the reflective properties of an object. Ray tracing can exploit this by playing tricks on our perception to make us see complex details that are not really there.

Suppose you wanted a very bumpy surface on the object. It would be very difficult to mathematically model lots of bumps. We can however simulate the way bumps look by altering the way light reflects off of the surface. Reflection calculations depend on a vector called a surface normal vector. This is a vector which points away from the surface and is perpendicular to it. By artificially modifying (or perturbing) this normal vector you can simulate bumps. This is done by adding an optional normal statement.

Note: Attaching a normal pattern does not really modify the surface. It only affects the way light reflects or refracts at the surface so that it looks bumpy.

The syntax is:

NORMAL:
  normal { [NORMAL_IDENTIFIER] [NORMAL_TYPE] [NORMAL_MODIFIER...] }
NORMAL_TYPE:
  PATTERN_TYPE Amount |
  bump_map { BITMAP_TYPE "bitmap.ext" [BUMP_MAP_MODS...]}
NORMAL_MODIFIER:
  PATTERN_MODIFIER | NORMAL_LIST | normal_map { NORMAL_MAP_BODY } |
  slope_map{ SLOPE_MAP_BODY } | bump_size Amount |
  no_bump_scale Bool | accuracy Float

Each of the items in a normal are optional but if they are present, they must be in the order shown. Any items after the NORMAL_IDENTIFIER modify or override settings given in the identifier. If no identifier is specified then the items modify the normal values in the current default texture. The PATTERN_TYPE may optionally be followed by a float value that controls the apparent depth of the bumps. Typical values range from 0.0 to 1.0 but any value may be used. Negative values invert the pattern. The default value if none is specified is 0.5.

There are four basic types of NORMAL_TYPEs. They are block pattern normals, continuous pattern normals, specialized normals and bump maps. They differ in the types of modifiers you may use with them. The pattern type is optionally followed by one or more normal modifiers. In addition to general pattern modifiers such as transformations, turbulence, and warp modifiers, normals may also have a NORMAL_LIST, slope_map, normal_map, and bump_size which are specific to normals. See Pattern Modifiers for information on general modifiers. The normal-specific modifiers are described in sub-sections which follow. Normal modifiers of any kind apply only to the normal and not to other parts of the texture. Modifiers must be specified last.

Originally POV-Ray had some patterns which were exclusively used for pigments while others were exclusively used for normals. Since POV-Ray 3.0 you can use any pattern for either pigments or normals. For example it is now valid to use ripples as a pigment or wood as a normal type. The patterns bumps, dents, ripples, waves, wrinkles, and bump_map were once exclusively normal patterns which could not be used as pigments. Because these six types use specialized normal modification calculations they cannot have slope_map, normal_map or wave shape modifiers. All other normal pattern types may use them. Because block patterns checker, hexagon, object and brick do not return a continuous series of values, they cannot use these modifiers either. See Patterns for details about specific patterns.

A normal statement is part of a texture specification. However it can be tedious to use a texture statement just to add bumps to an object. Therefore you may attach a normal directly to an object without explicitly specifying that it as part of a texture. For example instead of this:

object  {My_Object texture { normal { bumps 0.5 } } }

you may shorten it to:

object { My_Object normal { bumps 0.5 } }

Doing so creates an entire texture structure with default pigment and finish statements just as if you had explicitly typed the full texture {...} around it. Normal identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

NORMAL_DECLARATION:
  #declare IDENTIFIER = NORMAL |
  #local IDENTIFIER = NORMAL

Where IDENTIFIER is the name of the identifier up to 40 characters long and NORMAL is any valid normal statement. See #declare vs. #local for information on identifier scope.

3.4.6.2.4 Scaling normals

When scaling a normal, or when scaling an object after a normal is applied to it, the depth of the normal is affected by the scaling. This is not always wanted. If you want to turn off bump scaling for a texture or normal, you can do this by adding the keyword no_bump_scale to the texture's or normal's modifiers. This modifier will get passed on to all textures or normals contained in that texture or normal. Think of this like the way no_shadow gets passed on to objects contained in a CSG.

It is also important to note that if you add no_bump_scale to a normal or texture that is contained within another pattern (such as within a texture_map or normal_map), then the only scaling that will be ignored is the scaling of that texture or normal. Scaling of the parent texture or normal or of the object will affect the depth of the bumps, unless no_bump_scale is specified at the top-level of the texture (or normal, if the normal is not wrapped in a texture).

Note: See the section Using the Alpha Channel for some important information regarding the use of bump_map.

3.4.6.2.1 Normal Map

Most of the time you will apply single normal pattern to an entire surface but you may also create a pattern or blend of normals using a normal_map. The syntax for a normal_map is identical to a pigment_map except you specify a normal in each map entry. The syntax for normal_map is as follows:

NORMAL_MAP:
  normal_map { NORMAL_MAP_BODY }
NORMAL_MAP_BODY:
  NORMAL_MAP_IDENTIFIER | NORMAL_MAP_ENTRY...
NORMAL_MAP_ENTRY:
  [ Value NORMAL_BODY ]

Where Value is a float value between 0.0 and 1.0 inclusive and each NORMAL_BODY is anything which can be inside a normal{...} statement. The normal keyword and {} braces need not be specified.

Note: The [] brackets are part of the actual NORMAL_MAP_ENTRY. They are not notational symbols denoting optional parts. The brackets surround each entry in the normal map.

There may be from 2 to 256 entries in the map.

For example:

normal {
  gradient x       //this is the PATTERN_TYPE
  normal_map {
    [0.3  bumps scale 2]
    [0.3  dents]
    [0.6  dents]
    [0.9  marble turbulence 1]
    }
  }

When the gradient x function returns values from 0.0 to 0.3 then the scaled bumps normal is used. From 0.3 to 0.6 dents pattern is used. From 0.6 up to 0.9 a blend of dents and a turbulent marble is used. From 0.9 on up only the turbulent marble is used.

Normal maps may be nested to any level of complexity you desire. The normals in a map may have slope maps or normal maps or any type of normal you want.

A normal map is also used with the average normal type. See Average for details.

Entire normals in a normal list may also be used with the block patterns such as checker, hexagon and brick. For example:

normal {
  checker
  normal { gradient x scale .2 }
  normal { gradient y scale .2 }
  }

Note: In the case of block patterns the normal wrapping is required around the normal information.

You may not use normal_map or individual normals with a bump_map. See section Texture Maps for an alternative way to do this.

You may declare and use normal map identifiers but the only way to declare a normal block pattern list is to declare a normal identifier for the entire normal.

3.4.6.2.2 Slope Map

A slope_map is a normal pattern modifier which gives the user a great deal of control over the exact shape of the bumpy features. Each of the various pattern types available is in fact a mathematical function that takes any x, y, z location and turns it into a number between 0.0 and 1.0 inclusive. That number is used to specify where the various high and low spots are. The slope_map lets you further shape the contours. It is best illustrated with a gradient normal pattern. For example:

plane{ z, 0
  pigment{ White }
  normal { gradient x }
  }

Gives a ramp wave pattern that looks like small linear ramps that climb from the points at x=0 to x=1 and then abruptly drops to 0 again to repeat the ramp from x=1 to x=2. A slope map turns this simple linear ramp into almost any wave shape you want. The syntax is as follows:

SLOPE_MAP:
  slope_map { SLOPE_MAP_BODY }
SLOPE_MAP_BODY:
  SLOPE_MAP_IDENTIFIER | SLOPE_MAP_ENTRY...
SLOPE_MAP_ENTRY:
  [ Value, <Height, Slope> ]

Note: The [] brackets are part of the actual SLOPE_MAP_ENTRY. They are not notational symbols denoting optional parts. The brackets surround each entry in the slope map.

There may be from 2 to 256 entries in the map.

Each Value is a float value between 0.0 and 1.0 inclusive and each <Height, Slope> is a 2 component vector such as <0,1> where the first value represents the apparent height of the wave and the second value represents the slope of the wave at that point. The height should range between 0.0 and 1.0 but any value could be used.

The slope value is the change in height per unit of distance. For example a slope of zero means flat, a slope of 1.0 means slope upwards at a 45 degree angle and a slope of -1 means slope down at 45 degrees. Theoretically a slope straight up would have infinite slope. In practice, slope values should be kept in the range -3.0 to +3.0. Keep in mind that this is only the visually apparent slope. A normal does not actually change the surface.

For example here is how to make the ramp slope up for the first half and back down on the second half creating a triangle wave with a sharp peak in the center.

normal {
  gradient x             // this is the PATTERN_TYPE
  slope_map {
    [0   <0, 1>]   // start at bottom and slope up
    [0.5 <1, 1>]   // halfway through reach top still climbing
    [0.5 <1,-1>]   // abruptly slope down
    [1   <0,-1>]   // finish on down slope at bottom
    }
}

The pattern function is evaluated and the result is a value from 0.0 to 1.0. The first entry says that at x=0 the apparent height is 0 and the slope is 1. At x=0.5 we are at height 1 and slope is still up at 1. The third entry also specifies that at x=0.5 (actually at some tiny fraction above 0.5) we have height 1 but slope -1 which is downwards. Finally at x=1 we are at height 0 again and still sloping down with slope -1.

Although this example connects the points using straight lines the shape is actually a cubic spline. This example creates a smooth sine wave.

normal {
  gradient x                // this is the PATTERN_TYPE
  slope_map {
    [0    <0.5, 1>]   // start in middle and slope up
    [0.25 <1.0, 0>]   // flat slope at top of wave
    [0.5  <0.5,-1>]   // slope down at mid point
    [0.75 <0.0, 0>]   // flat slope at bottom
    [1    <0.5, 1>]   // finish in middle and slope up
    }
}

This example starts at height 0.5 sloping up at slope 1. At a fourth of the way through we are at the top of the curve at height 1 with slope 0 which is flat. The space between these two is a gentle curve because the start and end slopes are different. At half way we are at half height sloping down to bottom out at 3/4ths. By the end we are climbing at slope 1 again to complete the cycle. There are more examples in slopemap.pov in the sample scenes.

A slope_map may be used with any pattern except brick, checker, object, hexagon, bumps, dents, ripples, waves, wrinkles and bump_map.

You may declare and use slope map identifiers. For example:

#declare Fancy_Wave =
slope_map {             // Now let's get fancy
  [0.0  <0, 1>]   // Do tiny triangle here
  [0.2  <1, 1>]   //  down
  [0.2  <1,-1>]   //     to
  [0.4  <0,-1>]   //       here.
  [0.4  <0, 0>]   // Flat area
  [0.5  <0, 0>]   //   through here.
  [0.5  <1, 0>]   // Square wave leading edge
  [0.6  <1, 0>]   //   trailing edge
  [0.6  <0, 0>]   // Flat again
  [0.7  <0, 0>]   //   through here.
  [0.7  <0, 3>]   // Start scallop
  [0.8  <1, 0>]   //   flat on top
  [0.9  <0,-3>]   //     finish here.
  [0.9  <0, 0>]   // Flat remaining through 1.0
  }

object{ My_Object
  pigment { White }
  normal {
    wood
    slope_map { Fancy_Wave }
    }
  }
3.4.6.2.2.1 Normals, Accuracy

Surface normals that use patterns that were not designed for use with normals (anything other than bumps, dents, waves, ripples, and wrinkles) uses a slope_map whether you specify one or not. To create a perturbed normal from a pattern, POV-Ray samples the pattern at four points in a pyramid surrounding the desired point to determine the gradient of the pattern at the center of the pyramid. The distance that these points are from the center point determines the accuracy of the approximation. Using points too close together causes floating-point inaccuracies. However, using points too far apart can lead to artefacts as well as smoothing out features that should not be smooth.

Usually, points very close together are desired. POV-Ray currently uses a delta or accuracy distance of 0.02. Sometimes it is necessary to decrease this value to get better accuracy if you are viewing a close-up of the texture. Other times, it is nice to increase this value to smooth out sharp edges in the normal (for example, when using a 'solid' crackle pattern). For this reason, a new property, accuracy, has been added to normals. It only makes a difference if the normal uses a slope_map (either specified or implied).

You can specify the value of this accuracy (which is the distance between the sample points when determining the gradient of the pattern for slope_map) by adding accuracy <float> to your normal. For all patterns, the default is 0.02.

For more on slope_map see the Slope Map Tutorial

3.4.6.2.3 Bump Map

When all else fails and none of the normal pattern types meets your needs you can use a bump_map to wrap a 2-D bit-mapped bump pattern around your 3-D objects.

Instead of placing the color of the image on the shape like an image_map a bump_map perturbs the surface normal based on the color of the image at that point. The result looks like the image has been embossed into the surface. By default, a bump map uses the brightness of the actual color of the pixel. Colors are converted to gray scale internally before calculating height. Black is a low spot, white is a high spot. The image's index values may be used instead. See the sections Use_Index and Use_Color below.

3.4.6.2.3.1 Specifying a Bump Map

The syntax for a bump_map is:

BUMP_MAP:
  normal {
    bump_map {
      BITMAP_TYPE "bitmap.ext" [gamma GAMMA] [premultiplied BOOL]
      [BUMP_MAP_MODS...]
      }
  [NORMAL_MODFIERS...]
  }
BITMAP_TYPE:
  exr | gif | hdr | iff | jpeg | pgm | png | ppm | sys | tga | tiff
BUMP_MAP_MOD:
  map_type Type | once | interpolate Type | use_color |
  use_colour | bump_size Value

After the required BITMAP_TYPE keyword is a string expression containing the name of a bitmapped bump file of the specified type. Several optional modifiers may follow the file specification. The modifiers are described below.

Note: Earlier versions of POV-Ray allowed some modifiers before the BITMAP_TYPE but that syntax is being phased out in favor of the syntax described here.

Filenames specified in the bump_map statements will be searched for in the home (current) directory first and, if not found, will then be searched for in directories specified by any +L or Library_Path options active. This would facilitate keeping all your bump maps files in a separate subdirectory and giving a Library_Path option to specify where your library of bump maps are. See Library Paths for details.

By default, the bump pattern is mapped onto the x-y-plane. The bump pattern is projected onto the object as though there were a slide projector somewhere in the -z-direction. The pattern exactly fills the square area from (x,y) coordinates (0,0) to (1,1) regardless of the pattern's original size in pixels. If you would like to change this default you may translate, rotate or scale the pigment or texture to map it onto the object's surface as desired. If you would like to change this default orientation you may translate, rotate or scale the pigment or texture to map it onto the object's surface as desired.

While POV-Ray will normally interpret the bump map input file as a container of linear data irregardless of file type, this can be overridden for any individual bump map input file by specifying gamma GAMMA immediately after the file name. For example:

bump_map {
  jpeg "foobar.jpg" gamma 1.8
  }

This will cause POV-Ray to perform gamma adjustment or -decoding on the input file data before building the bump map. Alternatively to a numerical value, srgb may be specified to denote that the file is pre-corrected or encoded using the sRGB transfer function instead of a power-law gamma function. See section Gamma Handling for more information on gamma.

The file name is optionally followed by one or more BITMAP_MODIFIERS. The bump_size, use_color and use_index modifiers are specific to bump maps and are discussed in the following sections. See the section Bitmap Modifiers where the generic bitmap modifiers map_type, once and interpolate are described.

3.4.6.2.3.2 Bump_Size

The relative bump size can be scaled using the bump_size modifier. The bump size number can be any number other than 0 but typical values are from about 0.1 to as high as 4.0 or 5.0.

normal {
  bump_map {
    gif "stuff.gif"
    bump_size 5.0
    }
  }

Originally bump_size could only be used inside a bump map but it can now be used with any normal. Typically it is used to override a previously defined size. For example:

normal {
  My_Normal   //this is a previously defined normal identifier
  bump_size 2.0
  }
3.4.6.2.3.3 Use_Index and Use_Color

Usually the bump map converts the color of the pixel in the map to a gray scale intensity value in the range 0.0 to 1.0 and calculates the bumps based on that value. If you specify use_index, the bump map uses the color's palette number to compute as the height of the bump at that point. So, color number 0 would be low and color number 255 would be high (if the image has 256 palette entries). The actual color of the pixels doesn't matter when using the index. This option is only available on palette based formats. The use_color keyword may be specified to explicitly note that the color methods should be used instead. The alternate spelling use_colour is also valid. These modifiers may only be used inside the bump_map statement.

3.4.6.3 Finish

The finish properties of a surface can greatly affect its appearance. How does light reflect? What happens in shadows? What kind of highlights are visible. To answer these questions you need a finish.

The syntax for finish is as follows:

FINISH:
  finish { [FINISH_IDENTIFIER] [FINISH_ITEMS...] }
FINISH_ITEMS:
  ambient COLOR | diffuse [albedo] Amount [, Amount] | emission COLOR |
  brilliance Amount | phong [albedo] Amount | phong_size Amount | specular [albedo] Amount |
  roughness Amount | metallic [Amount] | reflection COLOR |
  crand Amount | conserve_energy BOOL_ON_OFF |
  reflection { Color_Reflecting_Min [REFLECTION_ITEMS...] } |
  subsurface { translucency COLOR } |
  irid { Irid_Amount [IRID_ITEMS...] }
REFLECTION_ITEMS:
  COLOR_REFLECTION_MAX | fresnel BOOL_ON_OFF |
  falloff FLOAT_FALLOFF | exponent FLOAT_EXPONENT |
  metallic FLOAT_METALLIC
IRID_ITEMS:
  thickness Amount | turbulence Amount

The FINISH_IDENTIFIER is optional but should proceed all other items. Any items after the FINISH_IDENTIFIER modify or override settings given in the FINISH_IDENTIFIER. If no identifier is specified then the items modify the finish values in the current default texture.

Note: Transformations are not allowed inside a finish because finish items cover the entire surface uniformly. Each of the FINISH_ITEMS listed above is described in sub-sections below.

In earlier versions of POV-Ray, the refraction, ior, and caustics keywords were part of the finish statement but they are now part of the interior statement. They are still supported under finish for backward compatibility but the results may not be 100% identical to previous versions. See Why are Interior and Media Necessary? for more details.

A finish statement is part of a texture specification. However it can be tedious to use a texture statement just to add a highlights or other lighting properties to an object. Therefore you may attach a finish directly to an object without explicitly specifying that it as part of a texture. For example instead of this:

object { My_Object texture { finish { phong 0.5 } } }

you may shorten it to:

object { My_Object finish { phong 0.5 } }

Doing so creates an entire texture structure with default pigment and normal statements just as if you had explicitly typed the full texture {...} around it.

Finish identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

FINISH_DECLARATION:
  #declare IDENTIFIER = FINISH |
  #local IDENTIFIER = FINISH

Where IDENTIFIER is the name of the identifier up to 40 characters long and FINISH is any valid finish statement. See #declare vs. #local for information on identifier scope.

3.4.6.3.1 Ambient

The light you see in dark shadowed areas comes from diffuse reflection off of other objects. This light cannot be modeled directly using ray-tracing, however, the radiosity feature can do a realistic approximation at the cost of higher render times. For most scenes, especially in-door scenes, this is will greatly improve the end result.

The classic way to simulate ambient lighting in shadowed areas is to assume that light is scattered everywhere in the room equally, so the effect can simply be calculated by adding a small amount of light to each texture, whether or not a light is actually shining on that texture. This renders very fast, but has the disadvantage that shadowed areas look flat.

Note: Without radiosity, ambient light does not account for the color of surrounding objects. If you walk into a room that has red walls, floor and ceiling then your white clothing will look pink from the reflected light. POV-Ray's ambient shortcut does not account for this.

The ambient keyword controls the amount of ambient light used for each object. In some situations the ambient light might also be tinted, for this a color value can be specified. For example:

finish { ambient rgb <0.3,0.1,0.1> } //a pink ambient
However, if all color components are equal, a single float value may be used. For example the single float value of 0.3 is treated as <0.3,0.3,0.3>. The default value is 0.1, which gives very little ambient light. As with light sources, physically meaningful values are greater than 0, but negative values actually work too, and the value may be arbitrarily high to simulate bright light.

You may also specify the overall ambient light level used when calculating the ambient lighting of an object using the global ambient_light setting. The total light is given by Ambient = Finish_Ambient * Global_Ambient_Light_Source. See the section Ambient Light for more details.

Ambient light affects both shadowed and non-shadowed areas, so if you turn up the ambient value, you may want to turn down the diffuse and reflection values. Specifying a high ambient value for an object effectively gives it an intrinsic glow, however, if the intent is to actually have it glowing (as opposed to simulating background light), the emission keyword should be used instead. The difference is that actual glowing objects light up their surroundings in radiosity scenes, while the ambient term is effectively set to zero.

Note: Specular reflected indirect illumination such as the flashlight shining in a mirror is not modeled by either ambient light or radiosity. For this, you need photons.

3.4.6.3.2 Emission

As of version 3.7, you can now add the emission keyword to the finish block. The intention is to simplify the use of materials designed for non-radiosity scenes in scenes with radiosity, or the design of scenes that can be rendered with or without radiosity.

The syntax and effect are virtually identical to ambient, except that emission is unaffected by the global ambient_light parameter. An objects ambient term is now effectively set to 0 if radiosity is active, the exception being, in legacy scenes where the #version is set to less than 3.7

3.4.6.3.3 Diffuse Reflection Items

When light reflects off of a surface the laws of physics say that it should leave the surface at the exact same angle it came in. This is similar to the way a billiard ball bounces off a bumper of a pool table. This perfect reflection is called specular reflection. However only very smooth polished surfaces reflect light in this way. Most of the time, light reflects and is scattered in all directions by the roughness of the surface. This scattering is called diffuse reflection because the light diffuses or spreads in a variety of directions. It accounts for the majority of the reflected light we see.

3.4.6.3.3.1 Diffuse

The keyword diffuse is used in a finish statement to control how much of the light coming directly from any light sources is reflected via diffuse reflection. The optional keyword albedo can be used right after diffuse to specify that the parameter is to be taken as the total diffuse/specular reflectance, rather than peak reflectance.

Note: When brilliance is equal to 1 albedo will have no effect on the diffuse parameter.

For example:

finish { diffuse albedo 0.7 }

Means that 70% of the light seen comes from direct illumination from light sources. The default value for diffuse is 0.6.

To model thin, diffusely-translucent objects (e.g. paper, curtains, leaves etc.), an optional 2nd float parameter has been added to the diffuse finish statement to control the effect of illumination from the back of the surface. The default value is 0.0, i.e. no diffuse backside illumination. For realistic results, the sum of both parameters should be between 0.0 and 1.0, and the 2nd parameter should be the smaller of the two.

Note: This feature is currently experimental and may be subject to change. In particular, the syntax as well as inter-operation with double_illuminate, multi-layered textures or conserve_energy are still under investigation.

A new sample scene, ~scenes/advanced/diffuse_back.pov, has been provided to illustrate this new feature.

3.4.6.3.3.2 Brilliance

The amount of direct light that diffuses from an object depends upon the angle at which it hits the surface. When light hits at a shallow angle it illuminates less. When it is directly above a surface it illuminates more. The brilliance keyword can be used in a finish statement to vary the way light falls off depending upon the angle of incidence. This controls the tightness of the basic diffuse illumination on objects and slightly adjusts the appearance of surface shininess. Objects may appear more metallic by increasing their brilliance. The default value is 1.0. Higher values from 5.0 to about 10.0 cause the light to fall off less at medium to low angles. There are no limits to the brilliance value. Experiment to see what works best for a particular situation. This is best used in concert with highlighting.

3.4.6.3.3.3 Crand Graininess

Very rough surfaces, such as concrete or sand, exhibit a dark graininess in their apparent color. This is caused by the shadows of the pits or holes in the surface. The crand keyword can be added to a finish to cause a minor random darkening in the diffuse reflection of direct illumination. Typical values range from crand 0.01 to crand 0.5 or higher. The default value is 0. For example:

finish { crand 0.05 }

The grain or noise introduced by this feature is applied on a pixel-by-pixel basis. This means that it will look the same on far away objects as on close objects. The effect also looks different depending upon the resolution you are using for the rendering.

Note: The crand should not be used when rendering animations. This is the one of a few truly random features in POV-Ray and will produce an annoying flicker of flying pixels on any textures animated with a crand value. For these reasons it is not a very accurate way to model the rough surface effect.

3.4.6.3.3.4 Subsurface Light Transport

The subsurface light transport feature, also know as subsurface scattering, is enabled ONLY when a global_settings subsurface block is present. For example, to enable SSLT and use it's default settings, you can specify an empty block.

  global_settings {
    subsurface {}
    }

To activate SSLT for a particular object you will also need to add the following statement to its finish block.

  material {
    texture {
      pigment { PIGMENT }
      finish {
        ...
        subsurface { translucency COLOR }
        }
      }
    interior { ior FLOAT }
    }

The pigment determines the SSLT material's overall appearance when applied to an object with sufficiently large structures. The translucency color, which can alternatively be a float, determines the strength of the subsurface light transport effect. The material's index of refraction also affects the appearance, and is essential for SSLT materials, but doesn't generate a warning at parse time if omitted.

Note: The effect doesn't scale with the object, and values may be greater than 1.0

To adjust materials to the dimensions of your scene, you should use the mm_per_unit setting in the global settings block. The algorithm is designed to give realistic results at a scale of 10 mm per POV-Ray unit by default. For other scales, you can place the following statement in the global_settings block:

  mm_per_unit INT

Hint: Using these scaling examples as a guide you can easily come up with a suitable setting.

  • 1 cm per unit, set it to 10 (the default)
  • 1 inch per unit, set it to 25.4
  • 1 m per unit, set it to 1000

To tune the algorithm for quality or performance, the number of samples for the diffuse scattering and single-scattering approximation, respectively, can be specified by placing the following statement in the global_settings section. Both values default is 50.

  subsurface { samples INT, INT }

See the sample SSLT scene in ~scenes/subsurface/subsurface.pov for more information. See also this PDF document, »A Practical Model for Subsurface Light Transport, for more in depth information about SSLT, including some sample values to use when defining new materials.

To specify whether subsurface light transport effects should be applied to incoming radiosity based diffuse illumination, you should place the following in the global settings subsurface block:

  global_settings {
    subsurface { radiosity BOOL }
    }

If this setting is off, the default, subsurface light transport effects will only be applied to direct illumination from classic light sources. Setting this feature to on will improve realism especially for materials with high translucency, but at a significant cost in rendering time.

See the section Subsurface and Radiosity for additional configuration information.

Note: Subsurface scattering is disabled in all quality levels except +Q9 or higher.

Warning: Be advised that the subsurface scattering feature is still experimental. These conditions, and possibly others, can apply. Usage and syntax is also subject to change!

  1. Incorrect use may result in hard crashes instead of parse warnings.
  2. Pigments having any zero color components currently doesn't play nice with SSLT. For example use rgb <1,0.01,0.01> instead of rgb <1,0,0> as color literals or when declaring pigment identifiers.
  3. A diffuse finish attribute of zero can also cause povray to throw an assertion failure.
  4. Unions of overlapping objects will probably give unexpected results, however merge should work.
  5. Mesh objects need to be closed (not perfectly) for realism.
  6. To avoid seams between objects, they currently must share a common interior. It's not sufficient to have interiors with identical parameters, or even instances of the same defined interior. The only way to overcome this is to specify the interior in the parent CSG rather than the individual primitives. For the desired results:
    • REMOVE any interior statements from the material.
    • ADD the interior statement to the union or merge.
    • For each part that needs a different ior (e.g. eyelashes or teeth) add an individual interior statement.
3.4.6.3.4 Highlights

Highlights are the bright spots that appear when a light source reflects off of a smooth object. They are a blend of specular reflection and diffuse reflection. They are specular-like because they depend upon viewing angle and illumination angle. However they are diffuse-like because some scattering occurs. In order to exactly model a highlight you would have to calculate specular reflection off of thousands of microscopic bumps called micro facets. The more that micro facets are facing the viewer the shinier the object appears and the tighter the highlights become. POV-Ray uses two different models to simulate highlights without calculating micro facets. They are the specular and Phong models.

Note: Specular and phong highlights are not mutually exclusive. It is possible to specify both and they will both take effect. Normally, however, you will only specify one or the other.

3.4.6.3.4.1 Phong Highlights

The phong keyword in the finish statement controls the amount of phong highlighting on the object. It causes bright shiny spots on the object that are the color of the light source being reflected.

The phong method measures the average of the facets facing in the mirror direction from the light sources to the viewer.

Phong's value is typically from 0.0 to 1.0, where 1.0 causes complete saturation to the light source's color at the brightest area (center) of the highlight. The default value is 0.0 and gives no highlight.

The size of the highlight spot is defined by the phong_size value. The larger the phong size the tighter, or smaller, the highlight and the shinier the appearance. The smaller the phong size the looser, or larger, the highlight and the less glossy the appearance.

Typical values range from 1.0 (very dull) to 250 (highly polished) though any values may be used. The default value is 40 (plastic) if phong_size is not specified.

The optional keyword albedo can be used right after phong to specify that the parameter is to be taken as the total diffuse/specular reflectance, rather than peak reflectance.

For example:

finish { phong albedo 0.9 phong_size 60 }

If phong is not specified phong_size has no effect.

3.4.6.3.4.2 Specular Highlight

The specular keyword in a finish statement produces a highlight which is very similar to phong highlighting but it uses slightly different model. The specular model more closely resembles real specular reflection and provides a more credible spreading of the highlights occurring near the object horizons.

The specular value is typically from 0.0 to 1.0, where 1.0 causes complete saturation to the light source's color at the brightest area (center) of the highlight. The default value is 0.0 and gives no highlight.

The size of the spot is defined by the value given the roughness keyword. Typical values range from 1.0 (very rough - large highlight) to 0.0005 (very smooth - small highlight). The default value, if roughness is not specified, is 0.05 (plastic).

It is possible to specify wrong values for roughness that will generate an error. Do not use 0! If you get errors, check to see if you are using a very, very small roughness value that may be causing the error.

The optional keyword albedo can be used right after specular to specify that the parameter is to be taken as the total diffuse/specular reflectance, rather than peak reflectance.

For example:

finish { specular albedo 0.9 roughness 0.02 }

If specular is not specified roughness has no effect.

Note: When light is reflected by a surface such as a mirror, it is called specular reflection however such reflection is not controlled by the specular keyword. The reflection keyword controls mirror-like specular reflection.

3.4.6.3.4.3 Metallic Highlight Modifier

The keyword metallic may be used with phong or specular highlights. This keyword indicates that the color of the highlights will be calculated by an empirical function that models the reflectivity of metallic surfaces.

Normally highlights are the color of the light source. Adding this keyword filters the highlight so that white light reflected from a metallic surface takes the color specified by the pigment

The metallic keyword may optionally be follow by a numeric value to specify the influence the amount of the effect. If no keyword is specified, the default value is zero. If the keyword is specified without a value, the default value is 1.

For example:

finish {
  phong 0.9
  phong_size 60
  metallic
  }

If phong or specular keywords are not specified then metallic has no effect.

3.4.6.3.5 Specular Reflection

When light does not diffuse and it does reflect at the same angle as it hits an object, it is called specular reflection. Such mirror-like reflection is controlled by the reflection {...} block in a finish statement.

Syntax:

finish {
  reflection {
    [COLOR_REFLECTION_MIN,] COLOR_REFLECTION_MAX
    [fresnel BOOL_ON_OFF]
    [falloff FLOAT_FALLOFF]
    [exponent FLOAT_EXPONENT]
    [metallic FLOAT_METALLIC]
    }
  }

[interior { ior IOR }]

The simplest use would be a perfect mirror:

finish { reflection {1.0} ambient 0 diffuse 0 }

This gives the object a mirrored finish. It will reflect all other elements in the scene. Usually a single float value is specified after the keyword even though the syntax calls for a color. For example a float value of 0.3 gets promoted to the full color vector <0.3,0.3,0.3,0.3,0.3> which is acceptable because only the red, green and blue parts are used.

The value can range from 0.0 to 1.0. By default there is no reflection.

Note: You should be aware that:

  • Adding reflection to a texture makes it take longer to render because additional rays must be traced.
  • The reflected light may be tinted by specifying a color rather than a float. For example, finish { reflection rgb <1,0,0> } gives a red mirror that only reflects red light.
  • Although such reflection is called specular it is not controlled by the specular keyword. That keyword controls a specular highlight.
  • The old syntax for simple reflection: reflection COLOR and reflection_exponent FLOAT (without braces) is still supported for backward compatibility.

falloff sets a falloff exponent in the variable reflection. This is the exponent telling how fast the reflectivity will fall off, i.e. linear, squared, cubed, etc.

The metallic keyword is similar in function to the metallic keyword used for highlights in finishes: it simulates the reflective properties of metallic surfaces, where reflected light takes on the colour of the surface. When metallic is used, the reflection color is multiplied by the pigment color at each point. You can specify an optional float value, which is the amount of influence the metallic keyword has on the reflected color. metallic uses the Fresnel equation so that the color of the light is reflected at glancing angles, and the color of the metal is reflected for angles close to the surface's normal.

exponent
POV-Ray uses a limited light model that cannot distinguish between objects which are simply brightly colored and objects which are extremely bright. A white piece of paper, a light bulb, the sun, and a supernova, all would be modeled as rgb<1,1,1> and slightly off-white objects would be only slightly darker. It is especially difficult to model partially reflective surfaces in a realistic way. Middle and lower brightness objects typically look too bright when reflected. If you reduce the reflection value, it tends to darken the bright objects too much. Therefore the optional exponent keyword has been added. It produces non-linear reflection intensities. The default value of 1.0 produces a linear curve. Lower values darken middle and low intensities and keeps high intensity reflections bright. This is a somewhat experimental feature designed for artistic use. It does not directly correspond to any real world reflective properties.

Variable reflection
Many materials, such as water, ceramic glaze, and linoleum are more reflective when viewed at shallow angles. This can be simulated by also specifying a minimum reflection in the reflection {...} statement.
For example:

finish { reflection { 0.03, 1 }}

uses the same function as the standard reflection, but the first parameter sets the minimum reflectivity. It could be a color vector or a float (which is automatically promoted to a gray vector). This minimum value is how reflective the surface will be when viewed from a direction parallel to its normal.
The second parameter sets the maximum reflectivity, which could also be a color vector or a float (which is automatically promoted to a gray vector). This maximum parameter is how reflective the surface will be when viewed at a 90-degree angle to its normal.

Note: You can make maximum reflection less than minimum reflection if you want, although the result is something that does not occur in nature.

When adding the fresnel keyword, the Fresnel reflectivity function is used instead of standard reflection. It calculates reflectivity using the finish's IOR. So with a fresnel reflection_type an interior { ior IOR } statement is required, even with opaque pigments. Remember that in real life many opaque objects have a thin layer of transparent glaze on their surface, and it is the glaze (which -does- have an IOR) that is reflective.

3.4.6.3.6 Conserve Energy for Reflection

One of the features in POV-Ray is variable reflection, including realistic Fresnel reflection (see the section on Variable Reflection). Unfortunately, when this is coupled with constant transmittance, the texture can look unrealistic. This unreal-ism is caused by the scene breaking the law of conservation of energy. As the amount of light reflected changes, the amount of light transmitted should also change (in a give-and-take relationship).

This can be achieved by adding the conserve_energy keyword to the object's finish {}.
When conserve_energy is enabled, POV-Ray will multiply the amount filtered and transmitted by what is left over from reflection (for example, if reflection is 80%, filter/transmit will be multiplied by 20%).

3.4.6.3.7 Iridescence

Iridescence, or Newton's thin film interference, simulates the effect of light on surfaces with a microscopic transparent film overlay. The effect is like an oil slick on a puddle of water or the rainbow hues of a soap bubble. This effect is controlled by the irid statement specified inside a finish statement.

This parameter modifies the surface color as a function of the angle between the light source and the surface. Since the effect works in conjunction with the position and angle of the light sources to the surface it does not behave in the same ways as a procedural pigment pattern.

The syntax is:

IRID:
  irid { Irid_Amount [IRID_ITEMS...] }
IRID_ITEMS:
  thickness Amount | turbulence Amount

The required Irid_Amount parameter is the contribution of the iridescence effect to the overall surface color. As a rule of thumb keep to around 0.25 (25% contribution) or less, but experiment. If the surface is coming out too white, try lowering the diffuse and possibly the ambient values of the surface.

The thickness keyword represents the film's thickness. This is an awkward parameter to set, since the thickness value has no relationship to the object's scale. Changing it affects the scale or busy-ness of the effect. A very thin film will have a high frequency of color changes while a thick film will have large areas of color. The default value is zero.

The thickness of the film can be varied with the turbulence keyword. You can only specify the amount of turbulence with iridescence. The octaves, lambda, and omega values are internally set and are not adjustable by the user at this time. This parameter varies only a single value: the thickness. Therefore the value must be a single float value. It cannot be a vector as in other uses of the turbulence keyword.

In addition, perturbing the object's surface normal through the use of bump patterns will affect iridescence.

For the curious, thin film interference occurs because, when the ray hits the surface of the film, part of the light is reflected from that surface, while a portion is transmitted into the film. This subsurface ray travels through the film and eventually reflects off the opaque substrate. The light emerges from the film slightly out of phase with the ray that was reflected from the surface.

This phase shift creates interference, which varies with the wavelength of the component colors, resulting in some wavelengths being reinforced, while others are cancelled out. When these components are recombined, the result is iridescence. See also the global setting Irid_Wavelength for additional information.

Note: The version 3.7 iridescence feature has had a major overhaul. The syntax remains the same, however, both the thickness and amount values are now specified in microns. Consequently, iridescence effects will vary from previous versions.

The concept used for this feature came from the book Fundamentals of Three-Dimensional Computer Graphics by Alan Watt (Addison-Wesley).

3.4.6.4 Halo

Earlier versions of POV-Ray used a feature called halo to simulate fine particles such as smoke, steam, fog, or flames. The halo statement was part of the texture statement. This feature has been discontinued and replaced by the interior and media statements which are object modifiers outside the texture statement.

See Why are Interior and Media Necessary? for a detailed explanation on the reasons for the change. See also Media for details on media.

3.4.6.5 Patterned Textures

Patterned textures are complex textures made up of multiple textures. The component textures may be plain textures or may be made up of patterned textures. A plain texture has just one pigment, normal and finish statement. Even a pigment with a pigment map is still one pigment and thus considered a plain texture as are normals with normal map statements.

Patterned textures use either a texture_map statement to specify a blend or pattern of textures or they use block textures such as checker with a texture list or a bitmap similar to an image map called a material map specified with a material_map statement.

The syntax is...

PATTERNED_TEXTURE:
  texture {
    [PATTERNED_TEXTURE_ID]
    [TRANSFORMATIONS...]
    } |
  texture {
    PATTERN_TYPE
    [TEXTURE_PATTERN_MODIFIERS...]
    } |
  texture {
    tiles TEXTURE tile2 TEXTURE
    [TRANSFORMATIONS...]
    } |
  texture {
    material_map {
      BITMAP_TYPE "bitmap.ext"
      [BITMAP_MODS...] TEXTURE... [TRANSFORMATIONS...]
      }
    }

TEXTURE_PATTERN_MODIFIER:
  PATTERN_MODIFIER | TEXTURE_LIST |
  texture_map {
    TEXTURE_MAP_BODY
    }

There are restrictions on using patterned textures. A patterned texture may not be used as a default texture, see the section: The #default Directive. A patterned texture cannot be used as a layer in a layered texture however you may use layered textures as any of the textures contained within a patterned texture.

3.4.6.5.1 Texture Maps

In addition to specifying blended color with a color map or a pigment map you may create a blend of textures using texture_map. The syntax for a texture map is identical to the pigment map except you specify a texture in each map entry.

The syntax for texture_map is as follows:

TEXTURE_MAP:
  texture_map { TEXTURE_MAP_BODY }
TEXTURE_MAP_BODY:
  TEXTURE_MAP_IDENTIFIER | TEXTURE_MAP_ENTRY...
TEXTURE_MAP_ENTRY:
  [ Value TEXTURE_BODY ]

Where Value is a float value between 0.0 and 1.0 inclusive and each TEXTURE_BODY is anything which can be inside a texture{...} statement. The texture keyword and {} braces need not be specified.

Note: The [] brackets are part of the actual TEXTURE_MAP_ENTRY. They are not notational symbols denoting optional parts. The brackets surround each entry in the texture map.

There may be from 2 to 256 entries in the map.

For example:

texture {
  gradient x           //this is the PATTERN_TYPE
  texture_map {
    [0.3  pigment{Red} finish{phong 1}]
    [0.3  T_Wood11]    //this is a texture identifier
    [0.6  T_Wood11]
    [0.9  pigment{DMFWood4} finish{Shiny}]
    }
  }

When the gradient x function returns values from 0.0 to 0.3 the red highlighted texture is used. From 0.3 to 0.6 the texture identifier T_Wood11 is used. From 0.6 up to 0.9 a blend of T_Wood11 and a shiny DMFWood4 is used. From 0.9 on up only the shiny wood is used.

Texture maps may be nested to any level of complexity you desire. The textures in a map may have color maps or texture maps or any type of texture you want.

The blended area of a texture map works by fully calculating both contributing textures in their entirety and then linearly interpolating the apparent colors. This means that reflection, refraction and lighting calculations are done twice for every point. This is in contrast to using a pigment map and a normal map in a plain texture, where the pigment is computed, then the normal, then reflection, refraction and lighting are calculated once for that point.

Entire textures may also be used with the block patterns such as checker, hexagon and brick. For example...

texture {
  checker
    texture { T_Wood12 scale .8 }
    texture {
      pigment { White_Marble }
      finish { Shiny }
      scale .5
      }
    }
  }

Note: In the case of block patterns the texture wrapping is required around the texture information. Also note that this syntax prohibits the use of a layered texture however you can work around this by declaring a texture identifier for the layered texture and referencing the identifier.

A texture map is also used with the average texture type. See Average for more details.

You may declare and use texture map identifiers but the only way to declare a texture block pattern list is to declare a texture identifier for the entire texture.

3.4.6.5.2 Tiles

Earlier versions of POV-Ray had a patterned texture called a tiles texture. It used the tiles and tile2 keywords to create a checkered pattern of textures.

TILES_TEXTURE:
  texture {
    tiles TEXTURE tile2 TEXTURE
    [TRANSFORMATIONS...]
    }

Although it is still supported for backwards compatibility you should use a checker block texture pattern described in the Texture Maps section rather than tiles textures.

3.4.6.5.3 Material Maps

The material_map patterned texture extends the concept of image maps to apply to entire textures rather than solid colors. A material map allows you to wrap a 2-D bit-mapped texture pattern around your 3-D objects.

Instead of placing a solid color of the image on the shape like an image map, an entire texture is specified based on the index or color of the image at that point. You must specify a list of textures to be used like a texture palette rather than the usual color palette.

When used with mapped file types such as GIF, and some PNG and TGA images, the index of the pixel is used as an index into the list of textures you supply. For unmapped file types such as some PNG and TGA images the 8 bit value of the red component in the range 0-255 is used as an index.

If the index of a pixel is greater than the number of textures in your list then the index is taken modulo N where N is the length of your list of textures.

Note: The material_map statement has nothing to do with the material statement. A material_map is not a way to create patterned material. See Material for an explanation of this unrelated, yet similarly named, older feature.

3.4.6.5.3.1 Specifying a Material Map

The syntax for a material_map is:

MATERIAL_MAP:
  texture {
    material_map {
      BITMAP_TYPE "bitmap.ext"
      [BITMAP_MODS...] TEXTURE... [TRANSFORMATIONS...]
      }
    }
BITMAP_TYPE:
  exr | gif | hdr | iff | jpeg | pgm | png | ppm | sys | tga | tiff
BITMAP_MOD:
  map_type Type | once | interpolate Type

After the required BITMAP_TYPE keyword is a string expression containing the name of a bitmapped material file of the specified type. Several optional modifiers may follow the file specification. The modifiers are described below.

Note: Earlier versions of POV-Ray allowed some modifiers before the BITMAP_TYPE but that syntax is being phased out in favor of the syntax described here.

Filenames specified in the material_map statements will be searched for in the home (current) directory first and, if not found, will then be searched for in directories specified by any +L or Library_Path options active. This would facilitate keeping all your material maps files in a separate subdirectory and giving a Library_Path option to specify where your library of material maps are. See the section Library Paths for details.

By default, the material is mapped onto the x-y-plane. The material is projected onto the object as though there were a slide projector somewhere in the -z-direction. The material exactly fills the square area from (x,y) coordinates (0,0) to (1,1) regardless of the material's original size in pixels. If you would like to change this default you may translate, rotate or scale the texture to map it onto the object's surface as desired.

The file name is optionally followed by one or more BITMAP_MODIFIERS. There are no modifiers which are unique to a material_map. It only uses the generic bitmap modifiers map_type, once and interpolate described in BITMAP_MODIFIERS.

Although interpolate is legal in material maps, the color index is interpolated before the texture is chosen. It does not interpolate the final color as you might hope it would. In general, interpolation of material maps serves no useful purpose but this may be fixed in future versions.

Next is one or more texture statements. Each texture in the list corresponds to an index in the bitmap file. For example:

texture {
  material_map {
    png "povmap.png"
      texture {  //used with index 0
        pigment {color red 0.3 green 0.1 blue 1}
        normal  {ripples 0.85 frequency 10 }
        finish  {specular 0.75}
        scale 5
        }
      texture {  //used with index 1
        pigment {White}
        finish {
        ambient 0 diffuse 0
        reflection 0.9 specular 0.75
        }
      }
      // used with index 2
      texture {pigment{NeonPink} finish{Luminous}}
      texture {  //used with index 3
        pigment {
          gradient y
          color_map {
            [0.00 rgb < 1 , 0 , 0>]
            [0.33 rgb < 0 , 0 , 1>]
            [0.66 rgb < 0 , 1 , 0>]
            [1.00 rgb < 1 , 0 , 0>]
            }
          }
        finish{specular 0.75}
        scale 8
        }
    }
  scale 30
  translate <-15, -15, 0>
  }

After a material_map statement but still inside the texture statement you may apply any legal texture modifiers.

Note: No other pigment, normal, or finish statements may be added to the texture outside the material map.

The following is illegal:

texture {
  material_map {
    gif "matmap.gif"
    texture {T1}
    texture {T2}
    texture {T3}
    }
  finish {phong 1.0}
  }

The finish must be individually added to each texture. Earlier versions of POV-Ray allowed such specifications but they were ignored. The above restrictions on syntax were necessary for various bug fixes. This means some POV-Ray 1.0 scenes using material maps many need minor modifications that cannot be done automatically with the version compatibility mode.

If particular index values are not used in an image then it may be necessary to supply dummy textures. It may be necessary to use a paint program or other utility to examine the map file's palette to determine how to arrange the texture list.

The textures within a material map texture may be layered but material map textures do not work as part of a layered texture. To use a layered texture inside a material map you must declare it as a texture identifier and invoke it in the texture list.

3.4.6.6 Layered Textures

It is possible to create a variety of special effects using layered textures. A layered texture consists of several textures that are partially transparent and are laid one on top of the other to create a more complex texture. The different texture layers show through the transparent portions to create the appearance of one texture that is a combination of several textures.

You create layered textures by listing two or more textures one right after the other. The last texture listed will be the top layer, the first one listed will be the bottom layer. All textures in a layered texture other than the bottom layer should have some transparency. For example:

object {
  My_Object
  texture {T1}  // the bottom layer
  texture {T2}  // a semi-transparent layer
  texture {T3}  // the top semi-transparent layer
  }

In this example T2 shows only where T3 is transparent and T1 shows only where T2 and T3 are transparent.

The color of underlying layers is filtered by upper layers but the results do not look exactly like a series of transparent surfaces. If you had a stack of surfaces with the textures applied to each, the light would be filtered twice: once on the way in as the lower layers are illuminated by filtered light and once on the way out. Layered textures do not filter the illumination on the way in. Other parts of the lighting calculations work differently as well. The results look great and allow for fantastic looking textures but they are simply different from multiple surfaces. See stones.inc in the standard include files directory for some magnificent layered textures.

Note: In versions predating POV-Ray 3.5, filter used to work the same as transmit in layered textures. It has been changed to work as filter should. This can change the appearance of "pre 3.5" textures a lot. The #version directive can be used to get the "pre 3.5" behavior.

Note: Layered textures must use the texture wrapped around any pigment, normal or finish statements. Do not use multiple pigment, normal or finish statements without putting them inside the texture statement.

Layered textures may be declared. For example

#declare Layered_Examp =
  texture {T1}
  texture {T2}
  texture {T3}

may be invoked as follows:

object {
  My_Object
  texture {
    Layer_Examp
    // Any pigment, normal or finish here
    // modifies the bottom layer only.
    }
  }

Note: No macros are allowed in layered textures. The problem is that if a macro would contain a declare the parser could no longer guess that two or more texture identifiers are supposed to belong to the layered texture and not some other declare.

If you wish to use a layered texture in a block pattern, such as checker, hexagon, or brick, or in a material_map, you must declare it first and then reference it inside a single texture statement. A patterned texture cannot be used as a layer in a layered texture however you may use layered textures as any of the textures contained within a patterned texture.

3.4.6.7 UV Mapping

All textures in POV-Ray are defined in 3 dimensions. Even planar image mapping is done this way. However, it is sometimes more desirable to have the texture defined for the surface of the object. This is especially true for bicubic_patch objects and mesh objects, that can be stretched and compressed. When the object is stretched or compressed, it would be nice for the texture to be glued to the object's surface and follow the object's deformations.

When uv_mapping is used, then that object's texture will be mapped to it using surface coordinates (u and v) instead of spatial coordinates (x, y, and z). This is done by taking a slice of the object's regular 3D texture from the XY plane (Z=0) and wrapping it around the surface of the object, following the object's surface coordinates.

Note: Some textures should be rotated to fit the slice in the XY plane.

Syntax:

texture {
  uv_mapping pigment{PIGMENT_BODY} | pigment{uv_mapping PIGMENT_BODY}
  uv_mapping normal {NORMAL_BODY } | normal {uv_mapping NORMAL_BODY }
  uv_mapping texture{TEXTURE_BODY} | texture{uv_mapping TEXTURE_BODY)
  }
3.4.6.7.1 Supported Objects

Surface mapping is currently defined for the following objects:

  • bicubic_patch : UV coordinates are based on the patch's parametric coordinates. They stretch with the control points. The default range is (0..1) and can be changed.
  • box : the image is wrapped around the box, as shown below.
  • lathe, sor : modified spherical mapping... the u coordinate (0..1) wraps around the y axis, while the v coordinate is linked to the object's control points (also ranging 0..1). Surface of Revolution also has special disc mapping on the end caps if the object is not 'open'.
  • mesh, mesh2 : UV coordinates are defined for each vertex and interpolated between.
  • ovus : spherical mapping centered near the center of mass of the ovus (moving from one sphere to another as the ratio of radius progresses).
  • parametric : In this case the map is not taken from a fixed set of coordinates but the map is taken from the area defined by the boundaries of the uv-space, in which the parametric surface has to be calculated.
  • sphere : boring spherical mapping.
  • torus : The map is taken from the area <0,0><1,1> where the u-coordinate is wrapped around the major radius and the the v-coordinate is wrapped around the minor radius.

UV Boxmap
3.4.6.7.2 UV Vectors

With the keyword uv_vectors, the UV coordinates of the corners can be controlled for bicubic patches and standard triangle mesh.

For bicubic patches the UV coordinates can be specified for each of the four corners of the patch. This goes right before the control points.
The syntax is:

  uv_vectors <corner1>,<corner2>,<corner3>, <corner4>
with default
  uv_vectors <0,0>,<1,0>,<1,1>,<0,1>

For standard triangle meshes (not mesh2) you can specify the UV coordinates for each of the three vertices uv_vectors <uv1>,<uv2>,<uv3> inside each mesh triangle. This goes right after the coordinates (or coordinates & normals with smooth triangles) and right before the texture.
Example:

mesh {
  triangle {
    <0,0,0>, <0.5,0,0>, <0.5,0.5,0>
    uv_vectors <0,0>, <1,0>, <1,1>
    }
  triangle {
    <0,0,0>, <0.5,0.5,0>, <0,0.5,0>
    uv_vectors <0,0>, <1,1>, <0,1>
    }
  texture {
    uv_mapping
    pigment {
      image_map {
      sys "SomeImage"
      map_type 0
      interpolate 0
      }
    }
  }
}

3.4.6.8 Triangle Texture Interpolation

This feature is utilized in a number of visualization approaches: triangles with individual textures for each vertex, which are interpolated during rendering.

Syntax:

MESH_TRIANGLE:
triangle {
  <Corner_1>,
  <Corner_2>,
  <Corner_3>
  [MESH_TEXTURE]
  }   |
smooth_triangle {
  <Corner_1>, <Normal_1>,
  <Corner_2>, <Normal_2>,
  <Corner_3>, <Normal_3>
  [MESH_TEXTURE]
  }

MESH_TEXTURE:
  texture { TEXTURE_IDENTIFIER } |
  texture_list {
    TEXTURE_IDENTIFIER TEXTURE_IDENTIFIER TEXTURE_IDENTIFIER
    }

To specify three vertex textures for the triangle, simply use texture_list instead of texture.

3.4.6.9 Interior Texture

Syntax:

object {
  texture { TEXTURE_ITEMS... }
  interior_texture { TEXTURE_ITEMS...}
  }

All surfaces have an exterior and interior surface. The interior_texture simply allows to specify a separate texture for the interior surface of the object. For objects with no well defined inside/outside (bicubic_patch, triangle, ...) the interior_texture is applied to the backside of the surface. Interior surface textures use exactly the same syntax and should work in exactly the same way as regular surface textures, except that they use the keyword interior_texture instead of texture.

Note: Do not confuse interior_texture {} with interior {}: the first one specifies surface properties, the second one specifies volume properties.

3.4.6.10 Cutaway Textures

Syntax:

difference | intersection {
  OBJECT_1_WITH_TEXTURES
  OBJECT_2_WITH_NO_TEXTURE
  cutaway_textures
  }

When using a CSG difference or intersection to cut away parts of an object, it is sometimes desirable to allow the object to retain its original texture. Generally, however, the texture of the surface that was used to do the cutting will be displayed.
Also, if the cutting object was not given a texture by the user, the default texture is assigned to it.

By using the cutaway_textures keyword in a CSG difference or intersection, you specify that you do not want the default texture on the intersected surface, but instead, the textures of the parent objects in the CSG should be used.
POV-Ray will determine which texture(s) to use by doing insidedness tests on the objects in the difference or intersection. If the intersection point is inside an object, that object's texture will be used (and evaluated at the interior point).
If the parent object is a CSG of objects with different textures, then the textures on overlapping parts will be averaged together.

3.4.7 Pattern

POV-Ray uses a method called three-dimensional solid texturing to define the color, bumpiness and other properties of an object. You specify the way that the texture varies over a surface by specifying a pattern. Patterns are used in pigments, normals and texture maps as well as media density.

All patterns in POV-Ray are three dimensional. For every point in space, each pattern has a unique value. Patterns do not wrap around a surface like putting wallpaper on an object. The patterns exist in 3d and the objects are carved from them like carving an object from a solid block of wood or stone.

Consider a block of wood. It contains light and dark bands that are concentric cylinders being the growth rings of the wood. On the end of the block you see these concentric circles. Along its length you see lines that are the veins. However the pattern exists throughout the entire block. If you cut or carve the wood it reveals the pattern inside. Similarly an onion consists of concentric spheres that are visible only when you slice it. Marble stone consists of wavy layers of colored sediments that harden into rock.

These solid patterns can be simulated using mathematical functions. Other random patterns such as granite or bumps and dents can be generated using a random number system and a noise function.

In each case, the x, y, z coordinate of a point on a surface is used to compute some mathematical function that returns a float value. When used with color maps or pigment maps, that value looks up the color of the pigment to be used. In normal statements the pattern function result modifies or perturbs the surface normal vector to give a bumpy appearance. Used with a texture map, the function result determines which combinations of entire textures to be used. When used with media density it specifies the density of the particles or gasses.

The following sections describe each pattern. See the sections Pigment, Normal, Patterned Textures and Density for more details on how to use patterns. Unless mentioned otherwise, all patterns use the ramp_wave wave type by default but may use any wave type and may be used with color_map, pigment_map, normal_map, slope_map, texture_map, density, and density_map.

Note: Some patterns have a built in default color_map that does not result in a grey-scale pattern. This may lead to unexpected results when one of these patterns is used without a user specified color_map, for example in functions or media.

These patterns are:

  • agate
  • bozo
  • brick
  • checker
  • hexagon
  • mandel
  • marble
  • radial
  • square
  • triangular
  • wood

See the following sections for more pattern and pattern related topics:

  • General Patterns
  • Discontinuous Patterns
  • Normal-Dependent Patterns
  • Special Patterns
  • Pattern Modifiers

3.4.7.1 General Patterns

Many patterns can be used in textures, normals and media. These patterns are agate, boxed, bozo, brick, bumps, cubic, cylindrical, density_file, dents, facets, fractal, function, gradient, granite, hexagon, leopard, marble, onion, pavement, pigment_pattern, planar, quilted, radial, ripples, spherical, spiral1, spiral2, spotted, square, tiling, waves, wood, and wrinkles.

3.4.7.1.1 Agate Pattern

The agate pattern is a banded pattern similar to marble but it uses a specialized built-in turbulence function that is different from the traditional turbulence. The traditional turbulence can be used as well but it is generally not necessary because agate is already very turbulent. You may control the amount of the built-in turbulence by adding the optional agate_turb keyword followed by a float value. For example:

pigment {
  agate
  agate_turb 0.5
  color_map {MyMap}
  }

The agate pattern has a default color_map built in that results in a brown and white pattern with smooth transitions.

Agate as used in a normal:

normal {
  agate [Bump_Size]
  [MODIFIERS...]
  }
3.4.7.1.2 Boxed Pattern

The boxed pattern creates a 2x2x2 unit cube centered at the origin. It is computed by: value =1.0- min(1, max(abs(X), abs(Y), abs(Z))) It starts at 1.0 at the origin and decreases to a minimum value of 0.0 as it approaches any plane which is one unit from the origin. It remains at 0.0 for all areas beyond that distance. This pattern was originally created for use with halo or media but it may be used anywhere any pattern may be used.

3.4.7.1.3 Bozo Pattern

The bozo pattern is a very smooth, random noise function that is traditionally used with some turbulence to create clouds. The spotted pattern is identical to bozo but in early versions of POV-Ray spotted did not allow turbulence to be added. Turbulence can now be added to any pattern so these are redundant but both are retained for backwards compatibility. The bumps pattern is also identical to bozo when used anywhere except in a normal statement. When used as a normal pattern, bumps uses a slightly different method to perturb the normal with a similar noise function.

The bozo noise function has the following properties:

1. It is defined over 3D space i.e., it takes x, y, and z and returns the noise value there.

2. If two points are far apart, the noise values at those points are relatively random.

3. If two points are close together, the noise values at those points are close to each other.

You can visualize this as having a large room and a thermometer that ranges from 0.0 to 1.0. Each point in the room has a temperature. Points that are far apart have relatively random temperatures. Points that are close together have close temperatures. The temperature changes smoothly but randomly as we move through the room.

Now let's place an object into this room along with an artist. The artist measures the temperature at each point on the object and paints that point a different color depending on the temperature. What do we get? A POV-Ray bozo texture!

The bozo pattern has a default color_map built in that results in a green, blue, red and white pattern with sharp transitions.

Note: The appearance of the bozo pattern depends on the noise generator used. The default type is 2. This may be changed using the noise_generator keyword. See the section Pattern Modifiers: noise_generator.

3.4.7.1.4 Brick Pattern

The brick pattern generates a pattern of bricks. The bricks are offset by half a brick length on every other row in the x- and z-directions. A layer of mortar surrounds each brick. The syntax is given by

pigment {
  brick COLOR_1, COLOR_2
  [brick_size <Size>] [mortar Size]
  }

where COLOR_1 is the color of the mortar and COLOR_2 is the color of the brick itself. If no colors are specified a default deep red and dark gray are used. The default size of the brick and mortar together is <8, 3, 4.5> units. The default thickness of the mortar is 0.5 units. These values may be changed using the optional brick_size and mortar pattern modifiers. You may also use pigment statements in place of the colors. For example:

pigment {
  brick pigment{Jade}, pigment{Black_Marble}
  }

This example uses normals:

normal { brick 0.5 }

The float value is an optional bump size. You may also use full normal statements. For example:

normal {
  brick normal{bumps 0.2}, normal{granite 0.3}
  }

When used with textures, the syntax is

texture {
  brick texture{T_Gold_1A}, texture{Stone12}
  }

This is a block pattern which cannot use wave types, color_map, or slope_map modifiers.

The brick pattern has a default color_map built in that results in red bricks and grey mortar.

3.4.7.1.5 Bumps Pattern

The bumps pattern was originally designed only to be used as a normal pattern. It uses a very smooth, random noise function that creates the look of rolling hills when scaled large or a bumpy orange peel when scaled small. Usually the bumps are about 1 unit apart.

When used as a normal pattern, this pattern uses a specialized normal perturbation function. This means that the pattern cannot be used with normal_map, slope_map or wave type modifiers in a normal statement.

When used as a pigment pattern or texture pattern, the bumps pattern is identical to bozo or spotted and is similar to normal bumps but is not identical as are most normals when compared to pigments.

Note: The appearance of the bumps pattern depends on the noise generator used. The default type is 2. This may be changed using the noise_generator keyword. See the section Pattern Modifiers: noise_generator.

3.4.7.1.6 Cubic Pattern

The cubic pattern takes six texture elements and maps each one to each of the six pyramids centered at each half-axis, effectively mapping each texture element to each side of a origin-centered cube.

The cubic pattern and the order of texture elements

The first group of elements map to the positive half-axis, in the X, Y and Z axes respectively. The same order is applied to the last group of elements, except on the negative half-axis.

The syntax is:

texture {
  cubic
    TEXTURE_ELEMENT_1
    ...
    TEXTURE_ELEMENT_6
  }
3.4.7.1.7 Cylindrical Pattern

The cylindrical pattern creates a one unit radius cylinder along the Y axis. It is computed by: value = 1.0-min(1, sqrt(X^2 + Z^2)) It starts at 1.0 at the origin and decreases to a minimum value of 0.0 as it approaches a distance of 1 unit from the Y axis. It remains at 0.0 for all areas beyond that distance. This pattern was originally created for use with halo or media but it may be used anywhere any pattern may be used.

3.4.7.1.8 Density File Pattern

The density_file pattern is a 3-D bitmap pattern that occupies a unit cube from location <0,0,0> to <1,1,1>. The data file is a raw binary file format created for POV-Ray called df3 format. The syntax provides for the possibility of implementing other formats in the future. This pattern was originally created for use with halo or media but it may be used anywhere any pattern may be used. The syntax is:

pigment {
  density_file df3 "filename.df3"
  [interpolate Type] [PIGMENT_MODIFIERS...]
  }

where "filename.df3" is a file name of the data file.

As a normal pattern, the syntax is

normal {
  density_file df3 "filename.df3" [, Bump_Size]
  [interpolate Type]
  [NORMAL_MODIFIERS...]
  }

The optional float Bump_Size should follow the file name and any other modifiers follow that.

The density pattern occupies the unit cube regardless of the dimensions in voxels. It remains at 0.0 for all areas beyond the unit cube. The data in the range of 0 to 255, in case of 8 bit resolution, are scaled into a float value in the range 0.0 to 1.0.

The interpolate keyword may be specified to add interpolation of the data. The default value of zero specifies no interpolation. A value of one specifies tri-linear interpolation, a value of two specifies tri-cubic interpolation

See the sample scenes for data file include\spiral.df3,and the scenes which use it: ~scenes\textures\patterns\densfile.pov, ~scenes\interior\media\galaxy.pov for examples.

3.4.7.1.8.1 df3 file format
Header:
The df3 format consists of a 6 byte header of three 16-bit integers with high order byte first. These three values give the x,y,z size of the data in pixels (or more appropriately called voxels ).
Data:
The header is followed by x*y*z unsigned integer bytes of data with a resolution of 8, 16 or 32 bit. The data are written with high order byte first (big-endian). The resolution of the data is determined by the size of the df3-file. That is, if the file is twice (minus header, of course) as long as an 8 bit file then it is assumed to contain 16 bit ints and if it is four times as long 32 bit ints.
3.4.7.1.9 Dents Pattern

The dents pattern was originally designed only to be used as a normal pattern. It is especially interesting when used with metallic textures. It gives impressions into the metal surface that look like dents have been beaten into the surface with a hammer. Usually the dents are about 1 unit apart.

When used as a normal pattern, this pattern uses a specialized normal perturbation function. This means that the pattern cannot be used with normal_map, slope_map or wave type modifiers in a normal statement.

When used as a pigment pattern or texture pattern, the dents pattern is similar to normal dents but is not identical as are most normals when compared to pigments.

3.4.7.1.10 Facets Pattern
normal {
  facets [coords SCALE_VALUE | size FACTOR]
  [NORMAL_ITEMS...]
  }

The facets pattern is designed to be used as a normal, it is not suitable for use as a pigment: it will cause an error.
There are two forms of the facets pattern. One is most suited for use with rounded surfaces, and one is most suited for use with flat surfaces.

If coords is specified, the facets pattern creates facets with a size on the same order as the specified SCALE_VALUE. This version of facets is most suited for use with flat surfaces, but will also work with curved surfaces. The boundaries of the facets coincide with the boundaries of the cells in the standard crackle pattern. The coords version of this pattern may be quite similar to a crackle normal pattern with solid specified.

If size is specified, the facets texture uses a different function that creates facets only on curved surfaces. The FACTOR determines how many facets are created, with smaller values creating more facets, but it is not directly related to any real-world measurement. The same factor will create the same pattern of facets on a sphere of any size.
This pattern creates facets by snapping normal vectors to the closest vectors in a perturbed grid of normal vectors. Because of this, if a surface has normal vectors that do not vary along one or more axes, there will be no facet boundaries along those axes.

3.4.7.1.11 Fractal Pattern

Fractal patterns supported in POV-Ray:

  • The Mandelbrot set with exponents up to 33. The formula for these is: z(n+1) = z(n)^p + c, where p is the correspondent exponent.
  • The equivalent Julia sets.
  • The magnet1 and magnet2 fractals (which are derived from some magnetic renormalization transformations; see the fractint help for more details). Both 'Mandelbrot' and 'Julia' versions of them are supported.

For the Mandelbrot and Julia sets, higher exponents will be slower for two reasons:

  1. For the exponents 2,3 and 4 an optimized algorithm is used. Higher exponents use a generic algorithm for raising a complex number to an integer exponent, and this is a bit slower than an optimized version for a certain exponent.
  2. The higher the exponent, the slower it will be. This is because the amount of operations needed to raise a complex number to an integer exponent is directly proportional to the exponent. This means that exponent 10 will be (very) roughly twice as slow as exponent 5.

Mandelbrot and Julia fractal patterns of exponents 2 to 5

The syntax is:

MANDELBROT:
  mandel ITERATIONS [, BUMP_SIZE]
  [exponent EXPONENT]
  [exterior EXTERIOR_TYPE, FACTOR]
  [interior INTERIOR_TYPE, FACTOR]

JULIA:
  julia COMPLEX, ITERATIONS [, BUMP_SIZE]
  [exponent EXPONENT]
  [exterior EXTERIOR_TYPE, FACTOR]
  [interior INTERIOR_TYPE, FACTOR]

MAGNET MANDEL:
  magnet MAGNET_TYPE mandel ITERATIONS [, BUMP_SIZE]
  [exterior EXTERIOR_TYPE, FACTOR]
  [interior INTERIOR_TYPE, FACTOR]

MAGNET JULIA:
  magnet MAGNET_TYPE julia COMPLEX, ITERATIONS [, BUMP_SIZE]
  [exterior EXTERIOR_TYPE, FACTOR]
  [interior INTERIOR_TYPE, FACTOR]

Where:

ITERATIONS is the number of times to iterate (up to 2^32-1) the algorithm.

COMPLEX is a 2D vector denoting a complex number.

MAGNET_TYPE is either 1 or 2.

exponent is an integer between 2 and 33. If not given, the default is 2.

interior and exterior specify special coloring algorithms. You can specify one of them or both at the same time. They only work with the fractal patterns.
EXTERIOR_TYPE and INTERIOR_TYPE are integer values between 0 and 6 (inclusive). When not specified, the default value of INTERIOR_TYPE is 0 and for EXTERIOR_TYPE 1.
FACTOR is a float. The return value of the pattern is multiplied by FACTOR before returning it. This can be used to scale the value range of the pattern when using interior and exterior coloring (this is often needed to get the desired effect). The default value of FACTOR is 1.

Magnet mandel and julia type 1 and 2 fractal patterns

The different values of EXTERIOR_TYPE and INTERIOR_TYPE have the following meaning:

  • 0: Returns just 1
  • 1: For exterior: The number of iterations until bailout divided by ITERATIONS.

    Note: This is not scaled by FACTOR (since it is internally scaled by 1/ITERATIONS instead).

    For interior: The absolute value of the smallest point in the orbit of the calculated point
  • 2: Real part of the last point in the orbit
  • 3: Imaginary part of the last point in the orbit
  • 4: Squared real part of the last point in the orbit
  • 5: Squared imaginary part of the last point in the orbit
  • 6: Absolute value of the last point in the orbit
  • 7: For exterior only: the number of iterations modulo FACTOR and divided by FACTOR.

    Note: This is of course not scaled by FACTOR. The covered range is 0 to FACTOR-1/FACTOR.

  • 8: For exterior only: the number of iterations modulo FACTOR+1 and divided by FACTOR.

    Note: This is of course not scaled by FACTOR. The covered range is 0 to 1.

Example:

box {<-2, -2, 0>, <2, 2, 0.1>
  pigment {
    julia <0.353, 0.288>, 30
    interior 1, 1
    color_map {
      [0 rgb 0]
      [0.2 rgb x]
      [0.4 rgb x+y]
      [1 rgb 1]
      [1 rgb 0]
      }
    }
  }

Different exterior and interior coloring types of fractal patterns
3.4.7.1.12 Function Pattern

Allows you to use a function { } block as pattern.

pigment {
  function { USER_DEFINED_FUNCTIONS }
  [PIGMENT_MODIFIERS...]
  }

Declaring a function:
By default a function takes three parameters (x,y,z) and you do not have to explicitly specify the parameter names when declaring it. When using the identifier, the parameters must be specified.

#declare Foo = function { x + y + z}

pigment {
  function { Foo(x, y, z) }
  [PIGMENT_MODIFIERS...]
  }

On the other hand, if you need more or less than three parameters when declaring a function, you also have to explicitly specify the parameter names.

#declare Foo = function(x,y,z,t) { x + y + z + t}

pigment {
  function { Foo(x, y, z, 4) }
  [PIGMENT_MODIFIERS...]
  }

Using function in a normal:

#declare Foo = function { x + y + z}

normal {
  function { Foo(x, y, z) } [Bump_Size]
  [MODIFIERS...]
  }
3.4.7.1.12.1 What can be used

All float expressions and operators. See the section User-Defined Functions for what is legal in POV-Ray. Of special interest here is the pattern option, that makes it possible to use patterns as functions

#declare FOO = function {
  pattern {
    checker
    }
  }

User defined functions (like equations).

Since pigments can be declared as functions, they can also be used in functions. They must be declared first. When using the identifier, you have to specify which component of the color vector should be used. To do this, the dot notation is used: Function(x,y,z).red

#declare FOO = function {pigment { checker } }
  pigment {
    function { FOO(x,y,z).green }
    [PIGMENT_MODIFIERS...]
    }

POV-Ray has a large amount of pre-defined functions. These are mainly algebraic surfaces but there is also a mesh function and noise3d function. See section Internal Functions for a complete list and some explanation on the parameters to use. These internal functions can be included through the functions.inc include file.

#include "functions.inc"
#declare FOO = function {pigment { checker } }
  pigment {
    function { FOO(x,y,z).green & f_noise3d(x*2, y*3,z)}
    [PIGMENT_MODIFIERS...]
    }
3.4.7.1.12.2 Function Image

Syntax :

function Width, Height { FUNCTION_BODY }

Not a real pattern, but listed here for convenience. This keyword defines a new 'internal' bitmap image type. The pixels of the image are derived from the Function_Body, with Function_Body either being a regular function, a pattern function or a pigment function. In case of a pigment function the output image will be in color, in case of a pattern or regular function the output image will be grayscale. All variants of grayscale pigment functions are available using the regular function syntax, too. In either case the image will use 16 bit per component

Note: Functions are evaluated on the x-y plane. This is different from the pattern image type for the reason that it makes using uv functions easier.

Width and Height specify the resolution of the resulting 'internal' bitmap image. The image is taken from the square region <0,0,0>, <1,1,0>

The function statement can be used wherever an image specifier like tga or png may be used. Some uses include creating heightfields from procedural textures or wrapping a slice of a 3d texture or function around a cylinder or extrude it along an axis.

Examples:

plane {y, -1
  pigment {
    image_map {
      function 10,10 {
        pigment { checker 1,0 scale .5  }
        }
      }
    rotate x*90
    }
  }

height_field {
  function 200,200 {
    pattern {
      bozo
      }
    }
  translate -0.5
  scale 10
  pigment {rgb 1}
  }

Note: For height fields and other situations where color is not needed it is easier to use function n,n {pattern{...}} than function n,n {pigment{...}}. The pattern functions are returning a scalar, not a color vector, thus a pattern is grayscale.

3.4.7.1.13 Gradient Pattern

One of the simplest patterns is the gradient pattern. It is specified as

pigment {
  gradient <Orientation>
  [PIGMENT_MODIFIERS...]
  }

where <Orientation> is a vector pointing in the direction that the colors blend. For example

pigment { gradient x } // bands of color vary as you move
                       // along the "x" direction.

produces a series of smooth bands of color that look like layers of colors next to each other. Points at x=0 are the first color in the color map. As the x location increases it smoothly turns to the last color at x=1. Then it starts over with the first again and gradually turns into the last color at x=2. In POV-Ray versions older than 3.5 the pattern reverses for negative values of x. As per POV-Ray 3.5 this is not the case anymore. Using gradient y or gradient z makes the colors blend along the y- or z-axis. Any vector may be used but x, y and z are most common.

As a normal pattern, gradient generates a saw-tooth or ramped wave appearance. The syntax is

normal {
  gradient <Orientation> [, Bump_Size]
  [NORMAL_MODIFIERS...]
  }

where the vector <Orientation> is a required parameter but the float Bump_Size which follows is optional.

Note: The comma is required especially if Bump_Size is negative.

If only the range -1 to 1 was used of the old gradient, for example in a sky_sphere, it can be replaced by the planar or marble pattern and revert the color_map. Also rotate the pattern for other orientations than y. A more general solution is to use function{abs(x)} as a pattern instead of gradient x and similar for gradient y and gradient z.

3.4.7.1.14 Granite Pattern

The granite pattern uses a simple 1/f fractal noise function to give a good granite pattern. This pattern is used with creative color maps in stones.inc to create some gorgeous layered stone textures.

As a normal pattern it creates an extremely bumpy surface that looks like a gravel driveway or rough stone.

Note: The appearance of the granite pattern depends on the noise generator used. The default type is 2. This may be changed using the noise_generator keyword. See the Pattern Modifiers section: noise_generator.

3.4.7.1.15 Leopard Pattern

Leopard creates regular geometric pattern of circular spots. The formula used is: value = Sqr((sin(x)+sin(y)+sin(z))/3)

3.4.7.1.16 Marble Pattern

The marble pattern is very similar to the gradient x pattern. The gradient pattern uses a default ramp_wave wave type which means it uses colors from the color map from 0.0 up to 1.0 at location x=1 but then jumps back to the first color for x > 1 and repeats the pattern again and again. However the marble pattern uses the triangle_wave wave type in which it uses the color map from 0 to 1 but then it reverses the map and blends from 1 back to zero. For example:

pigment {
  gradient x
  color_map {
    [0.0  color Yellow]
    [1.0  color Cyan]
    }
  }

This blends from yellow to cyan and then it abruptly changes back to yellow and repeats. However replacing gradient x with marble smoothly blends from yellow to cyan as the x coordinate goes from 0.0 to 0.5 and then smoothly blends back from cyan to yellow by x=1.0.

Earlier versions of POV-Ray did not allow you to change wave types. Now that wave types can be changed for most any pattern, the distinction between marble and gradient x is only a matter of default wave types.

When used with turbulence and an appropriate color map, this pattern looks like veins of color of real marble, jade or other types of stone. By default, marble has no turbulence.

The marble pattern has a default color_map built in that results in a red, black and white pattern with smooth and sharp transitions.

3.4.7.1.17 Onion Pattern

The onion is a pattern of concentric spheres like the layers of an onion. Value = mod(sqrt(Sqr(X)+Sqr(Y)+Sqr(Z)), 1.0) Each layer is one unit thick.

3.4.7.1.18 Pavement Pattern

The pavement is a pattern which paves the x-z plane with a single polyform tile. A polyform is a plane figure constructed by joining together identical basic polygons. The number_of_sides is used to choose that basic polygon: an equilateral triangle (3), a square (4) or a hexagon (6). The number_of_tiles is used to choose the number of basic polygons in the tile while pattern is used to choose amongst the variants.

The syntax is:

pigment {
  pavement
  [PAVEMENT_MODIFIERS...]
  }

PAVEMENT_MODIFIERS:
  number_of_sides SIDES_VALUE | number_of_tiles TILES_VALUE | pattern PATTERN_VALUE |
  exterior EXTERIOR_VALUE | interior INTERIOR_VALUE | form FORM_VALUE |
  PATTERN_MODIFIERS

A table of the number of patterns:

Sides | Tiles
 | 1 | 2 | 3 | 4 | 5 | 6
3 | 1 | 1 | 1 | 3 | 4 | 12
4 | 1 | 1 | 2 | 5 | 12 | 35
6 | 1 | 1 | 3 | 7 | 22 |

The various patterns with 6 squares.

There is no nomenclature for pattern, they are just numbered from 1 to the maximum relevant value.

form
0, 1 or 2, a special 3 is allowed for square only which copy the look of interior for some additional variations.
interior
0, 1 or 2
exterior
0, 1 or 2; Not used for hexagon.

The form, exterior and interior specify the look of angle used for respectively slow convex (turning side), quick convex (pointy tile) and concave angle (interior angle between many tiles).

  • 0 is a normal pointy angle. (a right angle for square)
  • 1 is the same as 0, but the pointy angle is broken in two. For square, the two corners are broken so as to share middle angle.
  • 2 is a smooth negotiation of the angle, without pointy part.

Note: The case of paving the plane with tiles made of 6 hexagons is not supported because not all such tiles would pave the plane. For example, the ring made of six hexagons is not able to pave the plane.

3.4.7.1.19 Pigment Pattern

Use any pigment as a pattern. Instead of using the pattern directly on the object, a pigment_pattern converts the pigment to gray-scale first. For each point, the gray-value is checked against a list and the corresponding item is then used for the texture at that particular point. For values between listed items, an averaged texture is calculated.
Texture items can be color, pigment, normal or texture and are specified in a color_map, pigment_map, normal_map or texture_map.
It takes a standard pigment specification.

Syntax:

PIGMENT:
  pigment {
    pigment_pattern { PIGMENT_BODY }
    color_map { COLOR_MAP_BODY } |
    colour_map { COLOR_MAP_BODY } |
    pigment_map { PIGMENT_MAP_BODY }
    }

NORMAL:
  normal {
    pigment_pattern { PIGMENT_BODY } [Bump_Size]
    normal_map { NORMAL_MAP_BODY }
    }

TEXTURE:
  texture {
    pigment_pattern { PIGMENT_BODY }
    texture_map { TEXTURE_MAP_BODY }
    }

ITEM_MAP_BODY:
  ITEM_MAP_IDENTIFIER | ITEM_MAP_ENTRY...
  ITEM_MAP_ENTRY:
  [ GRAY_VALUE  ITEM_MAP_ENTRY... ]

This pattern is also useful when parent and children patterns need to be transformed independently from each other. Transforming the pigment_pattern will not affect the child textures. When any of the child textures should be transformed, apply it to the specific MAP_ENTRY.

This can be used with any pigments, ranging from a simple checker to very complicated nested pigments. For example:

pigment {
  pigment_pattern {
    checker White, Black
    scale 2
    turbulence .5
    }
  pigment_map {
    [ 0, checker Red, Green scale .5 ]
    [ 1, checker Blue, Yellow scale .2 ]
    }
  }

Note: This pattern uses a pigment to get the gray values. If you want to get the pattern from an image, you should use the image_pattern.

3.4.7.1.20 Planar Pattern

The planar pattern creates a horizontal stripe plus or minus one unit above and below the X-Z plane. It is computed by: value =1.0- min(1, abs(Y)) It starts at 1.0 at the origin and decreases to a minimum value of 0.0 as the Y values approaches a distance of 1 unit from the X-Z plane. It remains at 0.0 for all areas beyond that distance. This pattern was originally created for use with halo or media but it may be used anywhere any pattern may be used.

3.4.7.1.21 Quilted Pattern

The quilted pattern was originally designed only to be used as a normal pattern. The quilted pattern is so named because it can create a pattern somewhat like a quilt or a tiled surface. The squares are actually 3-D cubes that are 1 unit in size.

When used as a normal pattern, this pattern uses a specialized normal perturbation function. This means that the pattern cannot be used with normal_map, slope_map or wave type modifiers in a normal statement.

When used as a pigment pattern or texture pattern, the quilted pattern is similar to normal quilted but is not identical as are most normals when compared to pigments.

The two parameters control0 and control1 are used to adjust the curvature of the seam or gouge area between the quilts.

The syntax is:

pigment {
  quilted
  [QUILTED_MODIFIERS...]
  }

QUILTED_MODIFIERS:
  control0 Value_0 | control1 Value_1 | PIGMENT_MODIFIERS

The values should generally be kept to around the 0.0 to 1.0 range. The default value is 1.0 if none is specified. Think of this gouge between the tiles in cross-section as a sloped line.

Quilted pattern with c0=0 and different values for c1.

Quilted pattern with c0=0.33 and different values for c1.

Quilted pattern with c0=0.67 and different values for c1.

Quilted pattern with c0=1 and different values for c1.

This straight slope can be made to curve by adjusting the two control values. The control values adjust the slope at the top and bottom of the curve. A control values of 0 at both ends will give a linear slope, as shown above, yielding a hard edge. A control value of 1 at both ends will give an "s" shaped curve, resulting in a softer, more rounded edge.

The syntax for use as a normal is:

normal {
  quilted [Bump_Size]
  [QUILTED_MODIFIERS...]
  }

QUILTED_MODIFIERS:
  control0 Value_0 | control1 Value_1 | PIGMENT_MODIFIERS
3.4.7.1.22 Radial Pattern

The radial pattern is a radial blend that wraps around the +y-axis. The color for value 0.0 starts at the +x-direction and wraps the color map around from east to west with 0.25 in the -z-direction, 0.5 in -x, 0.75 at +z and back to 1.0 at +x. Typically the pattern is used with a frequency modifier to create multiple bands that radiate from the y-axis. For example:

pigment {
  radial
  color_map {
    [0.5 Black]
    [0.5 White]
    }
  frequency 10
  }

creates 10 white bands and 10 black bands radiating from the y axis.

The radial pattern has a default color_map built in that results in a yellow, magenta and cyan pattern with smooth transitions.

3.4.7.1.23 Ripples Pattern

The ripples pattern was originally designed only to be used as a normal pattern. It makes the surface look like ripples of water. The ripples radiate from 10 random locations inside the unit cube area <0,0,0> to <1,1,1>. Scale the pattern to make the centers closer or farther apart.

Usually the ripples from any given center are about 1 unit apart. The frequency keyword changes the spacing between ripples. The phase keyword can be used to move the ripples outwards for realistic animation.

The number of ripple centers can be changed with the global parameter

global_settings { number_of_waves Count }

somewhere in the scene. This affects the entire scene. You cannot change the number of wave centers on individual patterns. See the section Number Of Waves for details.

When used as a normal pattern, this pattern uses a specialized normal perturbation function. This means that the pattern cannot be used with normal_map, slope_map or wave type modifiers in a normal statement.

When used as a pigment pattern or texture pattern, the ripples pattern is similar to normal ripples but is not identical as are most normals when compared to pigments.

3.4.7.1.24 Spherical Pattern

The spherical pattern creates a one unit radius sphere, with its center at the origin. It is computed by: value = 1.0-min(1, sqrt(X^2 + Y^2 + Z^2)) It starts at 1.0 at the origin and decreases to a minimum value of 0.0 as it approaches a distance of 1 unit from the origin in any direction. It remains at 0.0 for all areas beyond that distance. This pattern was originally created for use with halo or media but it may be used anywhere any pattern may be used.

3.4.7.1.25 Spiral1 Pattern

The spiral1 pattern creates a spiral that winds around the z-axis similar to a screw. When viewed sliced in the x-y plane, it looks like the spiral arms of a galaxy. Its syntax is:

pigment {
  spiral1 Number_of_Arms
  [PIGMENT_MODIFIERS...]
  }

The Number_of_Arms value determines how may arms are winding around the z-axis.

As a normal pattern, the syntax is

normal {
  spiral1 Number_of_Arms [, Bump_Size]
  [NORMAL_MODIFIERS...]
  }

where the Number_of_Arms value is a required parameter but the float Bump_Size which follows is optional.

Note: The comma is required especially if Bump_Size is negative.

The pattern uses the triangle_wave wave type by default but may use any wave type.

3.4.7.1.26 Spiral2 Pattern

The spiral2 pattern creates a double spiral that winds around the z-axis similar to spiral1 except that it has two overlapping spirals which twist in opposite directions. The result sometimes looks like a basket weave or perhaps the skin of pineapple. The center of a sunflower also has a similar double spiral pattern. Its syntax is:

pigment {
  spiral2 Number_of_Arms
  [PIGMENT_MODIFIERS...]
  }

The Number_of_Arms value determines how may arms are winding around the z-axis. As a normal pattern, the syntax is

normal {
  spiral2 Number_of_Arms [, Bump_Size]
  [NORMAL_MODIFIERS...]
  }

where the Number_of_Arms value is a required parameter but the float Bump_Size which follows is optional.

Note: The comma is required especially if Bump_Size is negative. The pattern uses the triangle_wave wave type by default but may use any wave type.

3.4.7.1.27 Spotted Pattern

The spotted pattern is identical to the bozo pattern. Early versions of POV-Ray did not allow turbulence to be used with spotted. Now that any pattern can use turbulence there is no difference between bozo and spotted. See the section Bozo for details.

3.4.7.1.28 Tiling Pattern

The tiling pattern creates a series tiles in the x-z plane. See the image below for examples of the twenty-seven available patterns.

The syntax is as follows:

pigment {
  tiling Pattern_Number
  [PATTERN_MODIFIERS...]
  }

The various tiling patterns annotated by tiling pattern and tiling type respectively

For each pattern, each individual tile of the pattern has the same beveling as the other tiles in that pattern, allowing regular caulking to be defined. For a pattern with N tile types (where N is the tiling type noted in the above image) the main color/texture of the tiles are at x/N with x going from 0 to N-1, and the extreme color/texture caulk for these tiles are at (x+1)/N. The bevel covers the range between these two values.

To begin exploring the tiling pattern right away, see the distribution file ~scenes/textures/pattern/tiling.pov. It uses obvious colors to better illustrate how the feature works, and you can optionally write it's color_map to a text file. Once you get a feel for the break points, you can always define you own map!

3.4.7.1.29 Waves Pattern

The waves pattern was originally designed only to be used as a normal pattern. It makes the surface look like waves on water. The waves pattern looks similar to the ripples pattern except the features are rounder and broader. The effect is to make waves that look more like deep ocean waves. The waves radiate from 10 random locations inside the unit cube area <0,0,0> to <1,1,1>. Scale the pattern to make the centers closer or farther apart.

Usually the waves from any given center are about 1 unit apart. The frequency keyword changes the spacing between waves. The phase keyword can be used to move the waves outwards for realistic animation.

The number of wave centers can be changed with the global parameter

global_settings { number_of_waves Count }

somewhere in the scene. This affects the entire scene. You cannot change the number of wave centers on individual patterns. See the section Number Of Waves for details.

When used as a normal pattern, this pattern uses a specialized normal perturbation function. This means that the pattern cannot be used with normal_map, slope_map or wave type modifiers in a normal statement.

When used as a pigment pattern or texture pattern, the waves pattern is similar to normal waves but is not identical as are most normals when compared to pigments.

3.4.7.1.30 Wood Pattern

The wood pattern consists of concentric cylinders centered on the z-axis. When appropriately colored, the bands look like the growth rings and veins in real wood. Small amounts of turbulence should be added to make it look more realistic. By default, wood has no turbulence.

Unlike most patterns, the wood pattern uses the triangle_wave wave type by default. This means that like marble, wood uses color map values 0.0 to 1.0 then repeats the colors in reverse order from 1.0 to 0.0. However you may use any wave type.

The wood pattern has a default color_map built in that results in a light and dark brown pattern with sharp transitions.

3.4.7.1.31 Wrinkles Pattern

The wrinkles pattern was originally designed only to be used as a normal pattern. It uses a 1/f noise pattern similar to granite but the features in wrinkles are sharper. The pattern can be used to simulate wrinkled cellophane or foil. It also makes an excellent stucco texture.

When used as a normal pattern, this pattern uses a specialized normal perturbation function. This means that the pattern cannot be used with normal_map, slope_map or wave type modifiers in a normal statement.

When used as a pigment pattern or texture pattern, the wrinkles pattern is similar to normal wrinkles but is not identical as are most normals when compared to pigments.

Note: The appearance of the wrinkles pattern depends on the noise generator used. The default type is 2. This may be changed using the noise_generator keyword. See the section Pattern Modifiers: noise_generator.

3.4.7.2 Discontinuous Patterns

Some patterns are discontinuous, meaning their slope is infinite. These patterns are not suitable for use as object norms, as objects with discontinuous norms may look odd. These patterns work best for textures and media. They are cells, checker, crackle, hexagon, object, square and triangular.

Note: The cell and crackle patterns are mixed cases, that is, they are discontinuous at their respective boundaries. However, there is no limit to the different number of values, in the range of 0 to 1, that they can generate.

3.4.7.2.1 Cells Pattern

The cells pattern fills 3d space with unit cubes. Each cube gets a random value from 0 to 1.

cells is not very suitable as a normal as it has no smooth transitions of one grey value to another.

3.4.7.2.2 Checker Pattern

The checker pattern produces a checkered pattern consisting of alternating squares of two colors. The syntax is:

pigment { checker [COLOR_1 [, COLOR_2]] [PATTERN_MODIFIERS...] }

If no colors are specified then default blue and green colors are used.

The checker pattern is actually a series of cubes that are one unit in size. Imagine a bunch of 1 inch cubes made from two different colors of modeling clay. Now imagine arranging the cubes in an alternating check pattern and stacking them in layer after layer so that the colors still alternate in every direction. Eventually you would have a larger cube. The pattern of checks on each side is what the POV-Ray checker pattern produces when applied to a box object. Finally imagine cutting away at the cube until it is carved into a smooth sphere or any other shape. This is what the checker pattern would look like on an object of any kind.

You may also use pigment statements in place of the colors. For example:

pigment { checker pigment{Jade}, pigment{Black_Marble} }

This example uses normals:

normal { checker 0.5 }

The float value is an optional bump size. You may also use full normal statements. For example:

normal {
  checker normal{gradient x scale .2}, normal{gradient y scale .2}
  }

When used with textures, the syntax is

texture { checker texture{T_Wood_3A}, texture{Stone12} }

The checker pattern has a default color_map built in that results in blue and green tiles.

This use of checker as a texture pattern replaces the special tiles texture in previous versions of POV-Ray. You may still use tiles but it may be phased out in future versions so checker textures are best.

This is a block pattern which cannot use wave types, color_map, or slope_map modifiers.

3.4.7.2.3 Crackle Pattern

The crackle pattern is a set of random tiled multifaceted cells. The crackle pattern is only semi-procedural, requiring random values to be computed and cached for subsequent queries, with a fixed amount of data per unit-cube in crackle pattern coordinate space. Scaled smaller than the density of actual ray-object-intersections computed, it will eventually lead to a separate crackle cache entry being created for each and every intersection. After the cache reaches a certain size (currently 30mb per thread), new entries for that particular block will be discarded after they are calculated. Starting a new block will allow the caching to resume working again. While discarding the data is of course inefficient, it's still preferable to chewing up 100% of the available physical RAM and then hitting the swap-file.

There is a choice between different types:

Standard Crackle

Mathematically, the set crackle(p)=0 is a 3D Voronoi diagram of a field of semi random points and crackle(p) < 0 is the distance from the set along the shortest path (a Voronoi diagram is the locus of points equidistant from their two nearest neighbors from a set of disjoint points, like the membranes in suds are to the centers of the bubbles).

  • With a large scale and no turbulence it makes a pretty good stone wall or floor.
  • With a small scale and no turbulence it makes a pretty good crackle ceramic glaze.
  • Using high turbulence it makes a good marble that avoids the problem of apparent parallel layers in traditional marble.

Form

pigment {
  crackle form <FORM_VECTOR>
  [PIGMENT_ITEMS ...]
  }

normal {
  crackle [Bump_Size]
  form <FORM_VECTOR>
  [NORMAL_ITEMS ...]
  }

Form determines the linear combination of distances used to create the pattern. Form is a vector.

  • The first component determines the multiple of the distance to the closest point to be used in determining the value of the pattern at a particular point.
  • The second component determines the coefficient applied to the second-closest distance.
  • The third component corresponds to the third-closest distance.

The standard form is <-1,1,0> (also the default), corresponding to the difference in the distances to the closest and second-closest points in the cell array. Another commonly-used form is <1,0,0>, corresponding to the distance to the closest point, which produces a pattern that looks roughly like a random collection of intersecting spheres or cells.

  • Other forms can create very interesting effects, but it is best to keep the sum of the coefficients low.
  • If the final computed value is too low or too high, the resultant pigment will be saturated with the color at the low or high end of the color_map. In this case, try multiplying the form vector by a constant.

Metric

pigment {
  crackle metric METRIC_VALUE
  [PIGMENT_ITEMS ...]
  }

normal {
  crackle [Bump_Size]
  metric METRIC_VALUE
  [NORMAL_ITEMS ...]
  }

Changing the metric changes the function used to determine which cell center is closer, for purposes of determining which cell a particular point falls in. The standard Euclidean distance function has a metric of 2. Changing the metric value changes the boundaries of the cells. A metric value of 3, for example, causes the boundaries to curve, while a very large metric constrains the boundaries to a very small set of possible orientations.

  • The default for metric is 2, as used by the standard crackle texture.
  • Metrics other than 1 or 2 can lead to substantially longer render times, as the method used to calculate such metrics is not as efficient.

Offset

pigment {
  crackle offset OFFSET_VALUE
  [PIGMENT_ITEMS ...]
  }

normal {
  crackle [Bump_Size]
  offset OFFSET_VALUE
  [NORMAL_ITEMS ...]
  }

The offset is used to displace the pattern from the standard xyz space along a fourth dimension.

  • It can be used to round off the pointy parts of a cellular normal texture or procedural heightfield by keeping the distances from becoming zero.
  • It can also be used to move the calculated values into a specific range if the result is saturated at one end of the color_map.
  • The default offset is zero.

Solid

pigment {
  crackle solid
  [PIGMENT_ITEMS ...]
  }

normal {
  crackle [Bump_Size]
  solid
  [NORMAL_ITEMS ...]
  }

Causes the same value to be generated for every point within a specific cell. This has practical applications in making easy stained-glass windows or flagstones. There is no provision for mortar, but mortar may be created by layering or texture-mapping a standard crackle texture with a solid one. The default for this parameter is off.

3.4.7.2.4 Hexagon Pattern

The hexagon pattern is a block pattern that generates a repeating pattern of hexagons in the x-z-plane. In this instance imagine tall rods that are hexagonal in shape and are parallel to the y-axis and grouped in bundles like shown in the example image. Three separate colors should be specified as follows:

pigment {
  hexagon [COLOR_1 [, COLOR_2 [, COLOR_3]]]
  [PATTERN_MODIFIERS...]
  }

The hexagon pattern.

The three colors will repeat the hexagonal pattern with hexagon COLOR_1 centered at the origin, COLOR_2 in the +z-direction and COLOR_3 to either side. Each side of the hexagon is one unit long. The hexagonal rods of color extend infinitely in the +y- and -y-directions. If no colors are specified then default blue, green and red colors are used.

You may also use pigment statements in place of the colors. For example:

pigment {
  hexagon
  pigment { Jade },
  pigment { White_Marble },
  pigment { Black_Marble }
  }

This example uses normals:

normal { hexagon 0.5 }

The float value is an optional bump size. You may also use full normal statements. For example:

normal {
  hexagon
  normal { gradient x scale .2 },
  normal { gradient y scale .2 },
  normal { bumps scale .2 }
  }

When used with textures, the syntax is...

texture {
  hexagon
  texture { T_Gold_3A },
  texture { T_Wood_3A },
  texture { Stone12 }
  }

The hexagon pattern has a default color_map built in that results in red, blue and green tiles.

This is a block pattern which cannot use wave types, color_map, or slope_map modifiers.

3.4.7.2.5 Object Pattern

The object pattern takes an object as input. It generates a, two item, color list pattern. Whether a point is assigned to one item or the other depends on whether it is inside the specified object or not.

Object's used in the object pattern cannot have a texture and must be solid - these are the same limitations as for bounded_by and clipped_by.

Syntax:

object {
  OBJECT_IDENTIFIER | OBJECT {}
  LIST_ITEM_A, LIST_ITEM_B
  }

Where OBJ_IDENTIFIER is the target object (which must be declared), or use the full object syntax. LIST_ITEM_A and LIST_ITEM_B are the colors, pigments, or whatever the pattern is controlling. LIST_ITEM_A is used for all points outside the object, and LIST_ITEM_B is used for all points inside the object.

Example:

pigment {
  object {
    myTextObject
    color White
    color Red
    }
  turbulence 0.15
  }

Note: This is a block pattern which cannot use wave types, color_map, or slope_map modifiers.

3.4.7.2.6 Square Pattern
 | The square pattern is a block pattern that generates a repeating pattern of squares in the x-z plane. In this instance imagine tall rods that are square in shape and are parallel to the y-axis and grouped in bundles like shown in the example image. Four separate colors should be specified as follows:
The square pattern. |
pigment {
  square [COLOR_1 [, COLOR_2 [, COLOR_3 [, COLOR_4]]]]
  [PATTERN_MODIFIERS...]
  }

Each side of the square is one unit long. The square rods of color extend infinitely in the +y and -y directions. If no colors are specified then default blue, green, red and yellow colors are used.

You may also use pigment statements in place of the colors. For example:

pigment {
  square
  pigment { Aquamarine },
  pigment { Turquoise },
  pigment { Sienna },
  pigment { SkyBlue }
}

When used with textures, the syntax is...

texture {
  square
  texture{ T_Wood1 },
  texture{ T_Wood2 },
  texture{ T_Wood4 },
  texture{ T_Wood8 }
}

The square pattern has a default color map built in that results in red, blue, yellow and green tiles.

This is a block pattern so, use of wave types, color_map, or slope_map modifiers is not allowed.

3.4.7.2.7 Triangular Pattern
 | The triangular pattern is a block pattern that generates a repeating pattern of triangles in the x-z plane. In this instance imagine tall rods that are triangular in shape and are parallel to the y-axis and grouped in bundles like shown in the example image. Six separate colors should be specified as follows:
The triangular pattern. |
pigment {
  triangular [COLOR_1 [, COLOR_2 [, COLOR_3 [, COLOR_4 [, COLOR_5  [, COLOR_6]]]]]]
  [PATTERN_MODIFIERS...]
  }

Each side of the triangle is one unit long. The triangular rods of color extend infinitely in the +y and -y directions. If no colors are specified then default blue, green, red, magenta, cyan and yellow colors are used.

You may also use pigment statements in place of the colors. For example:

pigment {
  triangular
  pigment { Aquamarine },
  pigment { Turquoise },
  pigment { Sienna },
  pigment { Aquamarine },
  pigment { Turquoise },
  pigment { SkyBlue }
}

When used with textures, the syntax is...

texture {
  triangular
  texture{ T_Wood1 },
  texture{ T_Wood2 },
  texture{ T_Wood4 },
  texture{ T_Wood8 },
  texture{ T_Wood16 },
  texture{ T_Wood10 }
}

The triangular pattern has a default color map built in that results in red, blue, cyan, magenta, yellow and green tiles.

This is a block pattern so, use of wave types, color_map, or slope_map modifiers is not allowed.

3.4.7.3 Normal-Dependent Patterns

Some patterns depend on the normal vector in addition to a position vector. As such, these patterns are suitable for object normals only. They are aoi and slope.

3.4.7.3.1 Aoi Pattern

The aoi pattern can be used with pigment, normal and texture statements. The syntax is as follows:

pigment {
  aoi
  pigment_map {
    [0.0 MyPigmentA]
    ...
    [1.0 MyPigmentZ]
    }
  }

normal {
  aoi
  normal_map {
    [0.0 MyNormalA]
    ...
    [1.0 MyNormalZ]
    }
  }

texture {
  aoi
  texture_map {
    [0.0 MyTextureA]
    ...
    [1.0 MyTextureZ]
    }
  }

It gives a value proportional to the angle between the ray and the surface; for consistency with the slope pattern, values range from 0.5 where ray is tangent to the surface, to 1.0 where perpendicular; in practice, values below 0.5 may occur in conjunction with smooth triangles or meshes.

Note: This differs from the current MegaPOV implementation, where the values range from 0.5 down to 0.0 instead. If compatibility with MegaPOV is desired, it is recommended to mirror the gradient at 0.5, e.g.:

pigment {
  aoi
  pigment_map {
    [0.0 MyPigment3]
    [0.2 MyPigment2]
    [0.5 MyPigment1]
    [0.8 MyPigment2]
    [1.0 MyPigment3]
    }
  }
3.4.7.3.2 Slope Pattern

The slope pattern uses the normal of a surface to calculate the slope at a given point. It then creates the pattern value dependent on the slope and optionally the altitude. It can be used for pigments, normals and textures, but not for media densities.For pigments the syntax is:

pigment {
  slope {
    <Direction> [, Lo_slope, Hi_slope ]
    [ altitude <Altitude> [, Lo_alt, Hi_alt ]]
    }
  [PIGMENT_MODIFIERS...]
  }

The slope value at a given point is dependent on the angle between the <Direction> vector and the normal of the surface at that point.

For example:

  • When the surface normal points in the opposite direction of the <Direction> vector (180 degrees), the slope is 0.0.
  • When the surface normal is perpendicular to the <Direction> vector (90 degrees), the slope is 0.5.
  • When the surface normal is parallel to the <Direction> vector (0 degrees), the slope is 1.0.

When using the simplest variant of the syntax:

slope { <Direction> }

the pattern value for a given point is the same as the slope value. <Direction> is a 3-D vector and will usually be <0,-1,0> for landscapes, but any direction can be used.

By specifying Lo_slope and Hi_slope you get more control:

slope { <Direction>, Lo_slope, Hi_slope }

Lo_slope and Hi_slope specifies which range of slopes are used, so you can control which slope values return which pattern values. Lo_slope is the slope value that returns 0.0 and Hi_slope is the slope value that returns 1.0.

For example, if you have a height_field and <Direction> is set to <0,-1,0>, then the slope values would only range from 0.0 to 0.5 because height_fields cannot have overhangs. If you do not specify Lo_slope and Hi_slope, you should keep in mind that the texture for the flat (horizontal) areas must be set at 0.0 and the texture for the steep (vertical) areas at 0.5 when designing the texture_map. The part from 0.5 up to 1.0 is not used then. But, by setting Lo_slope and Hi_slope to 0.0 and 0.5 respectively, the slope range will be stretched over the entire map, and the texture_map can then be defined from 0.0 to 1.0.

By adding an optional <Altitude> vector:

slope {
  <Direction>
  altitude <Altitude>
  }

the pattern will be influenced not only by the slope but also by a special gradient. <Altitude> is a 3-D vector that specifies the direction of the gradient. When <Altitude> is specified, the pattern value is a weighted average of the slope value and the gradient value. The weights are the lengths of the vectors <Direction> and <Altitude>. So if <Direction> is much longer than <Altitude> it means that the slope has greater effect on the results than the gradient. If on the other hand <Altitude> is longer, it means that the gradient has more effect on the results than the slope.

When adding the <Altitude> vector, the default gradient is defined from 0 to 1 units along the specified axis. This is fine when your object is defined within this range, otherwise a correction is needed. This can be done with the optional Lo_alt and Hi_alt parameters:

slope {
  <Direction>
  altitude <Altitude>, Lo_alt, Hi_alt
  }

They define the range of the gradient along the axis defined by the <Altitude> vector.

For example, with an <Altitude> vector set to y and an object going from -3 to 2 on the y axis, the Lo_alt and Hi_alt parameters should be set to -3 and 2 respectively.

Note: You should be aware of the following pitfalls when using the slope pattern.

  • You may use the turbulence keyword inside slope pattern definitions but it may cause unexpected results. Turbulence is a 3-D distortion of a pattern. Since slope is only defined on surfaces of objects, a 3-D turbulence is not applicable to the slope component. However, if you are using altitude, the altitude component of the pattern will be affected by turbulence.
  • If your object is larger than the range of altitude you have specified, you may experience unexpected discontinuities. In that case it is best to adjust the Lo_alt and Hi_alt values so they fit to your object.
  • The slope pattern does not work for the sky_sphere, because the sky_sphere is a background feature and does not have a surface. similarly, it does not work for media densities.

As of version 3.7 the slope pattern has been extended to specify a reference point instead of a direction; the new syntax variant is as follows:

slope {
  point_at <ReferencePoint> [, Lo_Slope, Hi_Slope ]
  }

Note: This variant currently does not allow for the altitude keyword to be used.

The functionality is similar to MegaPOV's aoi <ReferencePoint> pattern, except that the values are reversed, i.e. range from 0.0 for surfaces facing away from the point in question, to 1.0 for surfaces facing towards that point; thus, slope { <Vector> } and slope { point_at <Vector>*VeryLargeNumber } have virtually the same effect.

3.4.7.4 Special Patterns

Some patterns are not "real" patterns, but behave like patterns and are used in the same location as a regular pattern. They are average and image.

3.4.7.4.1 Average Pattern

Technically average is not a pattern type but it is listed here because the syntax is similar to other patterns. Typically a pattern type specifies how colors or normals are chosen from a pigment_map, texture_map, density_map, or normal_map , however average tells POV-Ray to average together all of the patterns you specify. Average was originally designed to be used in a normal statement with a normal_map as a method of specifying more than one normal pattern on the same surface. However average may be used in a pigment statement with a pigment_map or in a texture statement with a texture_map or media density with density_map to average colors too.

When used with pigments, the syntax is:

AVERAGED_PIGMENT:

pigment {
  pigment_map {
    PIGMENT_MAP_ENTRY...
    }
  }

PIGMENT_MAP_ENTRY:
[ [Weight] PIGMENT_BODY ]

Where Weight is an optional float value that defaults to 1.0 if not specified. This weight value is the relative weight applied to that pigment. Each PIGMENT_BODY is anything which can be inside a pigment{...} statement. The pigment keyword and {} braces need not be specified.

Note: The [] brackets are part of the actual PIGMENT_MAP_ENTRY. They are not notational symbols denoting optional parts. The brackets surround each entry in the pigment_map.

There may be from 2 to 256 entries in the map.

For example

pigment {
  average
  pigment_map {
    [1.0  Pigment_1]
    [2.0  Pigment_2]
    [0.5  Pigment_3]
    }
  }

All three pigments are evaluated. The weight values are multiplied by the resulting color. They are then divided by the total of the weights which, in this example is 3.5. When used with texture_map or density_map it works the same way.

When used with a normal_map in a normal statement, multiple copies of the original surface normal are created and are perturbed by each pattern. The perturbed normals are then weighted, added and normalized.

See the sections Pigment Maps and Pigment Lists, Normal Maps and Normal Lists, Texture Maps, and Density Maps and Density Lists for more information.

3.4.7.4.2 Image Pattern

Instead of placing the color of the image on the object like an image_map, an image_pattern specifies an entire texture item (color, pigment, normal or texture) based on the gray value at that point.

This gray-value is checked against a list and the corresponding item is then used for the texture at that particular point. For values between listed items, an averaged texture is calculated.

It takes a standard image specification and has one option, use_alpha, which works similar to use_color or use_index.

Note: See the section Using the Alpha Channel for some important information regarding the use of image_pattern.

Syntax:

PIGMENT:
  pigment {
    IMAGE_PATTERN
    color_map { COLOR_MAP_BODY } |
    colour_map { COLOR_MAP_BODY } |
    pigment_map { PIGMENT_MAP_BODY }
    }

NORMAL:
  normal {
    IMAGE_PATTERN [Bump_Size]
    normal_map { NORMAL_MAP_BODY }
    }

TEXTURE:
  texture {
    IMAGE_PATTERN
    texture_map { TEXTURE_MAP_BODY }
    }

IMAGE_PATTERN:
  image_pattern {
    BITMAP_TYPE "bitmap.ext" [gamma GAMMA] [premultiplied BOOL]
    [IMAGE_MAP_MODS...]
    }

IMAGE_MAP_MOD:
  map_type Type | once | interpolate Type | use_alpha
  ITEM_MAP_BODY:
  ITEM_MAP_IDENTIFIER | ITEM_MAP_ENTRY...
  ITEM_MAP_ENTRY:
  [ GRAY_VALUE  ITEM_MAP_ENTRY... ]

It is also useful for creating texture masks, like the following:

texture {
  image_pattern { tga "image.tga" use_alpha }
  texture_map {
    [0 Mytex ]
    [1 pigment { transmit 1 } ]
    }
  }

Note: This pattern uses an image to get the gray values from. If you want exactly the same possibilities but need to get gray values from a pigment, you can use the pigment_pattern.

While POV-Ray will normally interpret the image pattern input file as a container of linear data irregardless of file type, this can be overridden for any individual image pattern input file by specifying gamma GAMMA immediately after the file name. For example:

image_pattern {
  jpeg "foobar.jpg" gamma 1.8
  }

This will cause POV-Ray to perform gamma adjustment or -decoding on the input file data before building the image pattern. Alternatively to a numerical value, srgb may be specified to denote that the file format is pre-corrected or encoded using the sRGB transfer function instead of a power-law gamma function. See section Gamma Handling for more information on gamma.

3.4.7.5 Pattern Modifiers

Pattern modifiers are statements or parameters which modify how a pattern is evaluated or tells what to do with the pattern. The complete syntax is:

PATTERN_MODIFIER:
  BLEND_MAP_MODIFIER | AGATE_MODIFIER | DENSITY_FILE_MODIFIER |
  QUILTED_MODIFIER | BRICK_MODIFIER | SLOPE_MODIFIER |
  noise_generator Number| turbulence <Amount> |
  octaves Count | omega Amount | lambda Amount |
  warp { [WARP_ITEMS...] } | TRANSFORMATION
BLEND_MAP_MODIFIER:
  frequency Amount | phase Amount | ramp_wave | triangle_wave |
  sine_wave | scallop_wave | cubic_wave | poly_wave [Exponent]
AGATE_MODIFIER:
  agate_turb Value
BRICK_MODIFIER:
  brick_size Size | mortar Size
DENSITY_FILE_MODIFIER:
  interpolate Type
SLOPE_MODIFIERS:
  <Altitude>
  <Lo_slope,Hi_slope>
  <Lo_alt,Hi_alt>
QUILTED_MODIFIER:
  control0 Value | control1 Value
PIGMENT_MODIFIER:
  PATTERN_MODIFIER | COLOR_LIST | PIGMENT_LIST |
  color_map { COLOR_MAP_BODY } | colour_map { COLOR_MAP_BODY } |
  pigment_map{ PIGMENT_MAP_BODY } | quick_color COLOR |
  quick_colour COLOR
COLOR NORMAL_MODIFIER:
  PATTERN_MODIFIER | NORMAL_LIST |
  normal_map { NORMAL_MAP_BODY } | slope_map{ SLOPE_MAP_BODY } |
  bump_size Amount
TEXTURE_PATTERN_MODIFIER:
  PATTERN_MODIFIER | TEXTURE_LIST |
  texture_map{ TEXTURE_MAP_BODY }
DENSITY_MODIFIER:
  PATTERN_MODIFIER | DENSITY_LIST | COLOR_LIST |
  color_map { COLOR_MAP_BODY } | colour_map { COLOR_MAP_BODY } |
  density_map { DENSITY_MAP_BODY }

Default values for pattern modifiers:

dist_exp        : 0
falloff         : 2.0
frequency       : 1.0
lambda          : 2.0
major_radius    : 1
map_type        : 0
noise_generator : 2
octaves         : 6
omega           : 0.5
orientation     : <0,0,1>
phase           : 0.0
poly_wave       : 1.0
strength        : 1.0
turbulence      : <0,0,0>

The modifiers PIGMENT_LIST, quick_color, and pigment_map apply only to pigments. See the section Pigment for details on these pigment-specific pattern modifiers.

The modifiers COLOR_LIST and color_map apply only to pigments and densities. See the sections Pigment and Density for details on these pigment-specific pattern modifiers.

The modifiers NORMAL_LIST, bump_size, slope_map and normal_map apply only to normals. See the section Normal for details on these normal-specific pattern modifiers.

The TEXTURE_LIST and texture_map modifiers can only be used with patterned textures. See the section Texture Maps for details.

The DENSITY_LIST and density_map modifiers only work with media{density{..}} statements. See the section Density for details.

The agate_turb modifier can only be used with the agate pattern. See the section Agate for details.

The brick_size and mortar modifiers can only be used with the brick pattern. See the section Brick for details.

The control0 and control1 modifiers can only be used with the quilted pattern. See the section Quilted for details.

The interpolate modifier can only be used with the density_file pattern. See the section Density File for details.

The general purpose pattern modifiers in the following sections can be used with pigment, normal, texture, or density patterns.

3.4.7.5.1 Transforming Patterns

The most common pattern modifiers are the transformation modifiers translate, rotate, scale, transform, and matrix. For details on these commands see the section Transformations.

These modifiers may be placed inside pigment, normal, texture, and density statements to change the position, size and orientation of the patterns.

Transformations are performed in the order in which you specify them. However in general the order of transformations relative to other pattern modifiers such as turbulence, color_map and other maps is not important. For example scaling before or after turbulence makes no difference. The turbulence is done first, then the scaling regardless of which is specified first. However the order in which transformations are performed relative to warp statements is important. See the section Warp for details.

3.4.7.5.2 Frequency and Phase

The frequency and phase modifiers act as a type of scale and translate modifiers for various blend maps. They only have effect when blend maps are used. Blend maps are color_map, pigment_map, normal_map, slope_map, density_map, and texture_map. This discussion uses a color map as an example but the same principles apply to the other blend map types.

The frequency keyword adjusts the number of times that a color map repeats over one cycle of a pattern. For example gradient covers color map values 0 to 1 over the range from x=0 to x=1. By adding frequency 2.0 the color map repeats twice over that same range. The same effect can be achieved using scale 0.5*x so the frequency keyword is not that useful for patterns like gradient.

However the radial pattern wraps the color map around the +y-axis once. If you wanted two copies of the map (or 3 or 10 or 100) you would have to build a bigger map. Adding frequency 2.0 causes the color map to be used twice per revolution. Try this:

pigment {
  radial
  color_map{
    [0.5 color Red]
    [0.5 color White]
    }
  frequency 6
  }

The result is six sets of red and white radial stripes evenly spaced around the object.

The float after frequency can be any value. Values greater than 1.0 causes more than one copy of the map to be used. Values from 0.0 to 1.0 cause a fraction of the map to be used. Negative values reverses the map.

The phase value causes the map entries to be shifted so that the map starts and ends at a different place. In the example above if you render successive frames at phase 0 then phase 0.1, phase 0.2, etc. you could create an animation that rotates the stripes. The same effect can be easily achieved by rotating the radial pigment using rotate y*Angle but there are other uses where phase can be handy.

Sometimes you create a great looking gradient or wood color map but you want the grain slightly adjusted in or out. You could re-order the color map entries but that is a pain. A phase adjustment will shift everything but keep the same scale. Try animating a mandel pigment for a color palette rotation effect.

These values work by applying the following formula

New_Value = fmod ( Old_Value * Frequency + Phase, 1.0 ).

The frequency and phase modifiers have no effect on block patterns checker, brick, and hexagon nor do they effect image_map, bump_map or material_map. They also have no effect in normal statements when used with bumps, dents, quilted or wrinkles because these normal patterns cannot use normal_map or slope_map.

They can be used with normal patterns ripples and waves even though these two patterns cannot use normal_map or slope_map either. When used with ripples or waves, frequency adjusts the space between features and phase can be adjusted from 0.0 to 1.0 to cause the ripples or waves to move relative to their center for animating the features.

3.4.7.5.3 Waveforms

POV-Ray allows you to apply various wave forms to the pattern function before applying it to a blend map. Blend maps are color_map, pigment_map, normal_map, slope_map, density_map, and texture_map.

Most of the patterns which use a blend map, use the entries in the map in order from 0.0 to 1.0. The effect can most easily be seen when these patterns are used as normal patterns with no maps. Patterns such as gradient or onion generate a groove or slot that looks like a ramp that drops off sharply. This is called a ramp_wave wave type and it is the default wave type for most patterns. However the wood and marble patterns use the map from 0.0 to 1.0 and then reverses it and runs it from 1.0 to 0.0. The result is a wave form which slopes upwards to a peak, then slopes down again in a triangle_wave. In earlier versions of POV-Ray there was no way to change the wave types. You could simulate a triangle wave on a ramp wave pattern by duplicating the map entries in reverse, however there was no way to use a ramp wave on wood or marble.

Now any pattern that takes a map can have the default wave type overridden. For example:

pigment { wood color_map { MyMap } ramp_wave }

Also available are sine_wave, scallop_wave, cubic_wave and poly_wave types. These types are of most use in normal patterns as a type of built-in slope map. The sine_wave takes the zig-zag of a ramp wave and turns it into a gentle rolling wave with smooth transitions. The scallop_wave uses the absolute value of the sine wave which looks like corduroy when scaled small or like a stack of cylinders when scaled larger. The cubic_wave is a gentle cubic curve from 0.0 to 1.0 with zero slope at the start and end. The poly_wave is an exponential function. It is followed by an optional float value which specifies exponent. For example poly_wave 2 starts low and climbs rapidly at the end while poly_wave 0.5 climbs rapidly at first and levels off at the end. If no float value is specified, the default is 1.0 which produces a linear function identical to ramp_wave.

Although any of these wave types can be used for pigments, normals, textures, or density the effect of many of the wave types are not as noticeable on pigments, textures, or density as they are for normals.

Wave type modifiers have no effect on block patterns checker, brick, object and hexagon nor do they effect image_map, bump_map or material_map. They also have no effect in normal statements when used with bumps, dents, quilted, ripples, waves, or wrinkles because these normal patterns cannot use normal_map or slope_map.

3.4.7.5.4 Noise Generators

There are three noise generators implemented. Changing the noise_generator will change the appearance of noise based patterns, like bozo and granite.

  • noise_generator 1 the noise that was used in POV_Ray 3.1
  • noise_generator 2 range corrected version of the old noise, it does not show the plateaus seen with noise_generator 1
  • noise_generator 3 generates Perlin noise

The default is noise_generator 2

Note: The noise_generator can also be set in global_settings

3.4.7.5.5 Warp

The warp statement is a pattern modifier that is similar to turbulence. Turbulence works by taking the pattern evaluation point and pushing it about in a series of random steps. However warps push the point in very well-defined, non-random, geometric ways. The warp statement also overcomes some limitations of traditional turbulence and transformations by giving the user more control over the order in which turbulence, transformation and warp modifiers are applied to the pattern.

The turbulence warp provides an alternative way to specify turbulence. The others modify the pattern in geometric ways.

The syntax for using a warp statement is:

WARP:
  warp { WARP_ITEM }
WARP_ITEM:
  repeat <Direction> [REPEAT_ITEMS...] |
  black_hole <Location>, Radius [BLACK_HOLE_ITEMS...] |
  turbulence <Amount> [TURB_ITEMS...]
  cylindrical  [ orientation VECTOR | dist_exp FLOAT ]
  spherical  [ orientation VECTOR | dist_exp FLOAT ]
  toroidal  [ orientation VECTOR | dist_exp FLOAT | major_radius FLOAT ]
  planar [ VECTOR , FLOAT ]
REPEAT_ITEMS:
  offset <Amount> |
  flip <Axis>
BLACK_HOLE_ITEMS:
  strength Strength | falloff Amount | inverse |
  repeat <Repeat> | turbulence <Amount>
TURB_ITEMS:
  octaves Count | omega Amount | lambda Amount

You may have as many separate warp statements as you like in each pattern. The placement of warp statements relative to other modifiers such as color_map or turbulence is not important. However placement of warp statements relative to each other and to transformations is significant. Multiple warps and transformations are evaluated in the order in which you specify them. For example if you translate, then warp or warp, then translate, the results can be different.

3.4.7.5.5.1 Black Hole Warp

A black_hole warp is so named because of its similarity to real black holes. Just like the real thing, you cannot actually see a black hole. The only way to detect its presence is by the effect it has on things that surround it.

Take, for example, a wood grain. Using POV-Ray's normal turbulence and other texture modifier functions, you can get a nice, random appearance to the grain. But in its randomness it is regular - it is regularly random! Adding a black hole allows you to create a localized disturbance in a wood grain in either one or multiple locations. The black hole can have the effect of either sucking the surrounding texture into itself (like the real thing) or pushing it away. In the latter case, applied to a wood grain, it would look to the viewer as if there were a knothole in the wood. In this text we use a wood grain regularly as an example, because it is ideally suitable to explaining black holes. However, black holes may in fact be used with any texture or pattern. The effect that the black hole has on the texture can be specified. By default, it sucks with the strength calculated exponentially (inverse-square). You can change this if you like.

Black holes may be used anywhere a warp is permitted. The syntax is:

BLACK_HOLE_WARP:
  warp {
    black_hole <Location>, Radius
    [BLACK_HOLE_ITEMS...]
    }
BLACK_HOLE_ITEMS:
  strength Strength | falloff Amount | inverse | type Type |
  repeat <Repeat> | turbulence <Amount>

The minimal requirement is the black_hole keyword followed by a vector <Location> followed by a comma and a float Radius. Black holes effect all points within the spherical region around the location and within the radius. This is optionally followed by any number of other keywords which control how the texture is warped.

The falloff keyword may be used with a float value to specify the power by which the effect of the black hole falls off. The default is two. The force of the black hole at any given point, before applying the strength modifier, is as follows.

First, convert the distance from the point to the center to a proportion (0 to 1) that the point is from the edge of the black hole. A point on the perimeter of the black hole will be 0.0; a point at the center will be 1.0; a point exactly halfway will be 0.5, and so forth. Mentally you can consider this to be a closeness factor. A closeness of 1.0 is as close as you can get to the center (i.e. at the center), a closeness of 0.0 is as far away as you can get from the center and still be inside the black hole and a closeness of 0.5 means the point is exactly halfway between the two.

Call this value c. Raise c to the power specified in falloff. By default Falloff is 2, so this is c^2 or c squared. The resulting value is the force of the black hole at that exact location and is used, after applying the strength scaling factor as described below, to determine how much the point is perturbed in space. For example, if c is 0.5 the force is 0.5^2 or 0.25. If c is 0.25 the force is 0.125. But if c is exactly 1.0 the force is 1.0. Recall that as c gets smaller the point is farther from the center of the black hole. Using the default power of 2, you can see that as c reduces, the force reduces exponentially in an inverse-square relationship. Put in plain English, it means that the force is much stronger (by a power of two) towards the center than it is at the outside.

By increasing falloff, you can increase the magnitude of the falloff. A large value will mean points towards the perimeter will hardly be affected at all and points towards the center will be affected strongly. A value of 1.0 for falloff will mean that the effect is linear. A point that is exactly halfway to the center of the black hole will be affected by a force of exactly 0.5. A value of falloff of less than one but greater than zero means that as you get closer to the outside, the force increases rather than decreases. This can have some uses but there is a side effect. Recall that the effect of a black hole ceases outside its perimeter. This means that points just within the perimeter will be affected strongly and those just outside not at all. This would lead to a visible border, shaped as a sphere. A value for falloff of 0 would mean that the force would be 1.0 for all points within the black hole, since any number larger 0 raised to the power of 0 is 1.0.

The strength keyword may be specified with a float value to give you a bit more control over how much a point is perturbed by the black hole. Basically, the force of the black hole (as determined above) is multiplied by the value of strength, which defaults to 1.0. If you set strength to 0.5, for example, all points within the black hole will be moved by only half as much as they would have been. If you set it to 2.0 they will be moved twice as much.

There is a rider to the latter example, though - the movement is clipped to a maximum of the original distance from the center. That is to say, a point that is 0.75 units from the center may only be moved by a maximum of 0.75 units either towards the center or away from it, regardless of the value of strength. The result of this clipping is that you will have an exclusion area near the center of the black hole where all points whose final force value exceeded or equaled 1.0 were moved by a fixed amount.

If the inverse keyword is specified then the points pushed away from the center instead of being pulled in.

The repeat keyword followed by a vector, allows you to simulate the effect of many black holes without having to explicitly declare them. Repeat is a vector that tells POV-Ray to use this black hole at multiple locations. Using repeat logically divides your scene up into cubes, the first being located at <0,0,0> and going to <Repeat>. Suppose your repeat vector was <1,5,2>. The first cube would be from <0,0,0> to < 1,5,2>. This cube repeats, so there would be one at < -1,-5,-2>, <1,5,2>, <2,10,4> and so forth in all directions, ad infinitum.

When you use repeat, the center of the black hole does not specify an absolute location in your scene but an offset into each block. It is only possible to use positive offsets. Negative values will produce undefined results.

Suppose your center was <0.5,1,0.25> and the repeat vector is <2,2,2>. This gives us a block at < 0,0,0> and <2,2,2>, etc. The centers of the black hole's for these blocks would be <0,0,0> + < 0.5,1.0,0.25>, i. e. <0.5,1.0,0.25>, and < 2,2,2> + <0.5,1.0,0.25>, i. e. < 2,5,3.0,2.25>.

Due to the way repeats are calculated internally, there is a restriction on the values you specify for the repeat vector. Basically, each black hole must be totally enclosed within each block (or cube), with no part crossing into a neighboring one. This means that, for each of the x, y and z dimensions, the offset of the center may not be less than the radius, and the repeat value for that dimension must be >=the center plus the radius since any other values would allow the black hole to cross a boundary. Put another way, for each of x, y and z

Radius <= Offset or Center <= Repeat - Radius.

If the repeat vector in any dimension is too small to fit this criteria, it will be increased and a warning message issued. If the center is less than the radius it will also be moved but no message will be issued.

Note that none of the above should be read to mean that you cannot overlap black holes. You most certainly can and in fact this can produce some most useful effects. The restriction only applies to elements of the same black hole which is repeating. You can declare a second black hole that also repeats and its elements can quite happily overlap the first and causing the appropriate interactions. It is legal for the repeat value for any dimension to be 0, meaning that POV-Ray will not repeat the black hole in that direction.

The turbulence can only be used in a black hole with repeat. It allows an element of randomness to be inserted into the way the black holes repeat, to cause a more natural look. A good example would be an array of knotholes in wood - it would look rather artificial if each knothole were an exact distance from the previous.

The turbulence vector is a measurement that is added to each individual black hole in an array, after each axis of the vector is multiplied by a different random amount ranging from 0 to 1. The resulting actual position of the black hole's center for that particular repeat element is random (but consistent, so renders will be repeatable) and somewhere within the above coordinates. There is a rider on the use of turbulence, which basically is the same as that of the repeat vector. You cannot specify a value which would cause a black hole to potentially cross outside of its particular block.

In summary: For each of x, y and z the offset of the center must be >=radius and the value of the repeat must be >= center + radius + turbulence. The exception being that repeat may be 0 for any dimension, which means do not repeat in that direction.

Some examples are given by

warp {
  black_hole <0, 0, 0>, 0.5
  }

warp {
  black_hole <0.15, 0.125, 0>, 0.5
  falloff 7
  strength 1.0
  repeat <1.25, 1.25, 0>
  turbulence <0.25, 0.25, 0>
  inverse
  }

warp {
  black_hole <0, 0, 0>, 1.0
  falloff 2
  strength 2
  inverse
  }
3.4.7.5.5.2 Repeat Warp

The repeat warp causes a section of the pattern to be repeated over and over. It takes a slice out of the pattern and makes multiple copies of it side-by-side. The warp has many uses but was originally designed to make it easy to model wood veneer textures. Veneer is made by taking very thin slices from a log and placing them side-by-side on some other backing material. You see side-by-side nearly identical ring patterns but each will be a slice perhaps 1/32th of an inch deeper.

The syntax for a repeat warp is

REPEAT_WARP:
  warp { repeat <Direction> [REPEAT_ITEMS...] }
REPEAT_ITEMS:
  offset <Amount> | flip <Axis>

The repeat vector specifies the direction in which the pattern repeats and the width of the repeated area. This vector must lie entirely along an axis. In other words, two of its three components must be 0. For example

pigment {
  wood
  warp { repeat 2*x }
  }

which means that from x=0 to x=2 you get whatever the pattern usually is. But from x=2 to x=4 you get the same thing exactly shifted two units over in the x-direction. To evaluate it you simply take the x-coordinate modulo 2. Unfortunately you get exact duplicates which is not very realistic. The optional offset vector tells how much to translate the pattern each time it repeats. For example

pigment {
  wood
  warp {repeat x*2  offset z*0.05}
  }

means that we slice the first copy from x=0 to x=2 at z=0 but at x=2 to x=4 we offset to z=0.05. In the 4 to 6 interval we slice at z=0.10. At the n-th copy we slice at 0.05 n z. Thus each copy is slightly different. There are no restrictions on the offset vector.

Finally the flip vector causes the pattern to be flipped or mirrored every other copy of the pattern. The first copy of the pattern in the positive direction from the axis is not flipped. The next farther is, the next is not, etc. The flip vector is a three component x, y, z vector but each component is treated as a boolean value that tells if you should or should not flip along a given axis. For example

pigment {
  wood
  warp {repeat 2*x  flip <1,1,0>}
  }

means that every other copy of the pattern will be mirrored about the x- and y- axis but not the z-axis. A non-zero value means flip and zero means do not flip about that axis. The magnitude of the values in the flip vector does not matter.

3.4.7.5.5.3 Turbulence Warp

Inside the warp statement, the keyword turbulence followed by a float or vector may be used to stir up any pigment, normal or density. A number of optional parameters may be used with turbulence to control how it is computed. The syntax is:

TURBULENCE_ITEM:
  turbulence <Amount> | octaves Count | omega Amount | lambda Amount

Typical turbulence values range from the default 0.0, which is no turbulence, to 1.0 or more, which is very turbulent. If a vector is specified different amounts of turbulence are applied in the x-, y- and z-direction. For example

turbulence <1.0, 0.6, 0.1>

has much turbulence in the x-direction, a moderate amount in the y-direction and a small amount in the z-direction.

Turbulence uses a random noise function called DNoise. This is similar to the noise used in the bozo pattern except that instead of giving a single value it gives a direction. You can think of it as the direction that the wind is blowing at that spot. Points close together generate almost the same value but points far apart are randomly different.

Turbulence uses DNoise to push a point around in several steps called octaves. We locate the point we want to evaluate, then push it around a bit using turbulence to get to a different point then look up the color or pattern of the new point.

It says in effect Do not give me the color at this spot... take a few random steps in different directions and give me that color. Each step is typically half as long as the one before. For example:

The magnitude of these steps is controlled by the turbulence value. There are three additional parameters which control how turbulence is computed. They are octaves, lambda and omega. Each is optional, each is followed by a single float value, and each has no effect when there is no turbulence. |
 | Turbulence random walk.
3.4.7.5.5.4 Octaves

The octaves keyword may be followed by an integer value to control the number of steps of turbulence that are computed. Legal values range from 1 to <10. The default value of 6 is a fairly high value; you will not see much change by setting it to a higher value because the extra steps are too small. Float values are truncated to integer. Smaller numbers of octaves give a gentler, wavy turbulence and computes faster. Higher octaves create more jagged or fuzzy turbulence and takes longer to compute.

3.4.7.5.5.5 Lambda

The lambda parameter controls how statistically different the random move of an octave is compared to its previous octave. The default value is 2.0 which is quite random. Values close to lambda 1.0 will straighten out the randomness of the path in the diagram above. The zig-zag steps in the calculation are in nearly the same direction. Higher values can look more swirly under some circumstances.

3.4.7.5.5.6 Omega

The omega value controls how large each successive octave step is compared to the previous value. Each successive octave of turbulence is multiplied by the omega value. The default omega 0.5 means that each octave is 1/2 the size of the previous one. Higher omega values mean that 2nd, 3rd, 4th and up octaves contribute more turbulence giving a sharper, crinkly look while smaller omegas give a fuzzy kind of turbulence that gets blurry in places.

3.4.7.5.5.7 Mapping using warps

With the cylindrical, spherical and toroidal warps you can wrap checkers, bricks and other patterns around cylinders, spheres, tori and other objects. In essence, these warps use the same mapping as the image maps use.

The syntax is as follows:

CYLINDRICAL_WARP:
  warp { cylindrical [CYLINDRICAL_ITEMS...]}
CYLINDRICAL_ITEMS:
  orientation VECTOR | dist_exp FLOAT
SPHERICAL_WARP:
  warp { spherical [SPHERICAL_ITEMS...]}
SPHERICAL_ITEMS:
  orientation VECTOR | dist_exp FLOAT
TOROIDAL_WARP:
  warp { toroidal [TOROIDAL_ITEMS...]}
TOROIDAL_ITEMS:
  orientation VECTOR | dist_exp FLOAT | major_radius FLOAT
PLANAR_WARP:
  warp { planar [ VECTOR , FLOAT ]}
CUBIC_WARP:
  warp { cubic }

These defaults are in affect:

orientation <0,0,1>
dist_exp 0
major_radius 1

Although these warps do 3D mapping, some concession had to be made on depth.

The distance exponent is controlled by using the dist_exp keyword. When using the default value of 0, imagine a box from <0,0> to <1,1> stretching to infinity along the orientation vector.

The distance keyword is evaluated as follows:

  • sphere: distance from origin
  • cylinder: distance from y-axis
  • torus: distance from major radius

The planar warp was made to make a pattern act like an image_map, of infinite size and can be useful in combination with other mapping-warps. By default the pigment in the XY-plane is extruded along the Z-axis. The pigment can be taken from an other plane, by specifying the optional vector (normal of the plane) and float (distance along the normal). The result, again, is extruded along the Z-axis.

The cubic warp requires no parameters, and maps an area in the x-y plane between <0,0> and <1,1> around the origin in the same way as uv-mapping an origin-centered cube-shaped box would. The cubic warp works with any object whereas the uv-mapping only works for the box object. See the section on box uv-mapping for details.

The following code examples produced the images below:

torus {
  1, 0.5
  pigment {
    hexagon
    scale 0.1
    warp {
      toroidal
      orientation y
      dist_exp 1
      major_radius 1
      }
    }
  }

sphere {
  0,1
  pigment {
    hexagon
    scale <0.5/pi,0.25/pi,1>*0.1
    warp {
      spherical
      orientation y
      dist_exp 1
      }
    }
  }

cylinder {
  -y, y, 1
  pigment {
    hexagon
    scale <0.5/pi, 1, 1>*0.1
    warp {
      cylindrical
      orientation y
      dist_exp 1
      }
    }
  }

cylindrical warp | spherical warp | toroidal warp
3.4.7.5.5.8 Turbulence versus Turbulence Warp

The POV-Ray language contains an ambiguity and limitation on the way you specify turbulence and transformations such as translate, rotate, scale, matrix, and transform transforms. Usually the turbulence is done first. Then all translate, rotate, scale, matrix, and transform operations are always done after turbulence regardless of the order in which you specify them. For example this

pigment {
  wood
  scale .5
  turbulence .2
  }

works exactly the same as

pigment {
  wood
  turbulence .2
  scale .5
  }

The turbulence is always first. A better example of this limitation is with uneven turbulence and rotations.

pigment {
  wood
  turbulence 0.5*y
  rotate z*60
  }
// as compared to
pigment {
  wood
  rotate z*60
  turbulence 0.5*y
  }

The results will be the same either way even though you would think it should look different.

We cannot change this basic behavior in POV-Ray now because lots of scenes would potentially render differently if suddenly the order transformation vs. turbulence mattered when in the past, it did not.

However, by specifying our turbulence inside warp statement you tell POV-Ray that the order in which turbulence, transformations and other warps are applied is significant. Here is an example of a turbulence warp.

warp { turbulence <0,1,1> octaves 3 lambda 1.5 omega 0.3 }

The significance is that this

pigment {
  wood
  translate <1,2,3> rotate x*45 scale 2
  warp { turbulence <0,1,1> octaves 3 lambda 1.5 omega 0.3 }
  }

produces different results than this...

pigment {
  wood
  warp { turbulence <0,1,1> octaves 3 lambda 1.5 omega 0.3 }
  translate <1,2,3> rotate x*45 scale 2
  }

You may specify turbulence without using a warp statement. However you cannot control the order in which they are evaluated unless you put them in a warp.

The evaluation rules are as follows:

  1. First any turbulence not inside a warp statement is applied regardless of the order in which it appears relative to warps or transformations.
  2. Next each warp statement, translate, rotate, scale or matrix one-by-one, is applied in the order the user specifies. If you want turbulence done in a specific order, you simply specify it inside a warp in the proper place.
3.4.7.5.5.9 Turbulence

The turbulence pattern modifier is still supported for compatibility issues, but it is better nowadays to use the warp turbulence feature, which does not have turbulence's limitation in transformation order (turbulence is always applied first, before any scale, translate or rotate, whatever the order you specify). For a detailed discussion see Turbulence versus Turbulence Warp

The old-style turbulence is handled slightly differently when used with the agate, marble, spiral1, spiral2, and wood textures.

3.4.7.6 Image Map

When all else fails and none of the pigment pattern types meets your needs you can use an image_map to wrap a 2-D bit-mapped image around your 3-D objects.

3.4.7.6.1 Specifying an Image Map

The syntax for an image_map is:

 IMAGE_MAP:
  pigment {
    image_map {
      [BITMAP_TYPE] "bitmap[.ext]" [gamma GAMMA] [premultiplied BOOL]
      [IMAGE_MAP_MODS...]
      }
  [PIGMENT_MODFIERS...]
  }
 IMAGE_MAP:
  pigment {
   image_map {
     FUNCTION_IMAGE
     }
  [PIGMENT_MODFIERS...]
  }
 BITMAP_TYPE:
   exr | gif | hdr | iff | jpeg | pgm | png | ppm | sys | tga | tiff
 IMAGE_MAP_MODS:
   map_type Type | once | interpolate Type |
   filter Palette, Amount | filter all Amount |
   transmit Palette, Amount | transmit all Amount
 FUNCTION_IMAGE:
   function I_WIDTH, I_HEIGHT { FUNCTION_IMAGE_BODY }
 FUNCTION_IMAGE_BODY:
   PIGMENT | FN_FLOAT | pattern { PATTERN [PATTERN_MODIFIERS] }

After the optional BITMAP_TYPE keyword is a string expression containing the name of a bitmapped image file of the specified type. If the BITMAP_TYPE is not given, the same type is expected as the type set for output.

For example:

plane { -z,0
  pigment {
    image_map {png "Eggs.png"}
    }
  }

plane { -z,0
  pigment {
    image_map {"Eggs"}
    }
  }

The second method will look for, and use "Eggs.png" if the output file type is set to be png (Output_File_Type=N in INI-file or +FN on command line). It is particularly useful when the image used in the image_map is also rendered with POV-Ray.

Several optional modifiers may follow the file specification. The modifiers are described below.

Note: Earlier versions of POV-Ray allowed some modifiers before the BITMAP_TYPE but that syntax is being phased out in favor of the syntax described here.

Note: The sys format is a system-specific format. See the Output File Type section for more information.

Filenames specified in the image_map statements will be searched for in the home (current) directory first and, if not found, will then be searched for in directories specified by any +L or Library_Path options active. This would facilitate keeping all your image maps files in a separate subdirectory and giving a Library_Path option to specify where your library of image maps are. See Library Paths for details.

By default, the image is mapped onto the x-y-plane. The image is projected onto the object as though there were a slide projector somewhere in the -z-direction. The image exactly fills the square area from (x,y) coordinates (0,0) to (1,1) regardless of the image's original size in pixels. If you would like to change this default you may translate, rotate or scale the pigment or texture to map it onto the object's surface as desired.

In the section Checker, the checker pigment pattern is explained. The checks are described as solid cubes of colored clay from which objects are carved. With image maps you should imagine that each pixel is a long, thin, square, colored rod that extends parallel to the z-axis. The image is made from rows and columns of these rods bundled together and the object is then carved from the bundle.

If you would like to change this default orientation you may translate, rotate or scale the pigment or texture to map it onto the object's surface as desired.

The file name is optionally followed by one or more BITMAP_MODIFIERS. The filter, filter all, transmit, and transmit all modifiers are specific to image maps and are discussed in the following sections. An image_map may also use generic bitmap modifiers map_type, once and interpolate described in Bitmap Modifiers

3.4.7.6.2 The Gamma Option

The default gamma handling rules for any image input file can be overridden by specifying gamma GAMMA immediately after the file name. For example:

image_map {
  jpeg "foobar.jpg" gamma 1.8
  interpolate 2
  }

Alternatively to a numerical value, srgb may be specified to denote that the file is encoded or pre-corrected using the sRGB transfer function instead of a power-law gamma function.

See section Gamma Handling for more information on gamma.

3.4.7.6.3 The Filter and Transmit Bitmap Modifiers

To make all or part of an image map transparent you can specify filter and/or transmit values for the color palette/registers of PNG, GIF or IFF pictures (at least for the modes that use palettes). You can do this by adding the keyword filter or transmit following the filename. The keyword is followed by two numbers. The first number is the palette number value and the second is the amount of transparency. The values should be separated by a comma. For example:

image_map {
  gif "mypic.gif"
  filter   0, 0.5 // Make color 0 50% filtered transparent
  filter   5, 1.0 // Make color 5 100% filtered transparent
  transmit 8, 0.3 // Make color 8 30% non-filtered transparent
  }

You can give the entire image a filter or transmit value using filter all Amount or transmit all Amount. For example:

image_map {
  gif "stnglass.gif"
  filter all 0.9
  }

Note: Early versions of POV-Ray used the keyword alpha to specify filtered transparency however that word is often used to describe non-filtered transparency. For this reason alpha is no longer used.

See the section Color Expressions for details on the differences between filtered and non-filtered transparency.

3.4.7.6.4 Using the Alpha Channel

Another way to specify non-filtered transmit transparency in an image map is by using the alpha channel. POV-Ray will automatically use the alpha channel for transmittance when one is stored in the image. PNG file format allows you to store a different transparency for each color index in the PNG file, if desired. If your paint programs support this feature of PNG you can do the transparency editing within your paint program rather than specifying transmit values for each color in the POV file. Since PNG and TGA image formats can also store full alpha channel (transparency) information you can generate image maps that have transparency which is not dependent on the color of a pixel but rather its location in the image.

Although POV uses transmit 0.0 to specify no transparency and 1.0 to specify full transparency, the alpha data ranges from 0 to 255 in the opposite direction. Alpha data 0 means the same as transmit 1.0 and alpha data 255 produces transmit 0.0.

Note: In version 3.7 alpha handling for image file output has changed. Effectively, the background now requires a filter or transmit value in order for alpha transparency to work properly.

Previous versions of POV-Ray always expected straight alpha for file input, this has been changed on a per-file-format basis as follows:

  • PNG will use straight alpha as per specification.
  • OpenEXR and TIFF will use associated alpha as per specifications.
  • TGA and BMP 32-bit RGBA will use straight alpha, retaining file input compatibility for now, until a final decision has been made on these formats.

Additionally the premultiplied parameter may be used to specify the input image alpha handling. This boolean parameter specifies whether the file is stored in premultiplied associated or non-premultiplied straight alpha format, overriding the file format specific default. This keyword has no effect on files without an alpha channel. Like the gamma, it MUST immediately follow the filename, though the order does not matter.

Note: The following mechanism has some limitations with colored highlights.

When generating non-premultiplied alpha output to a classic low-dynamic-range file format (e.g. PNG), transparency of particularly bright areas will now be reduced, in order to better preserve highlights on transparent objects.

Note: When using an input image in a material_map, bump_map, or image_pattern definition, the following conditions apply.

  • For material maps, no alpha premultiplication handling is done whatsoever, instead the data as stored in the file is used.
  • For bump maps and image patterns, images with an alpha channel are treated as if they had a black background, unless the alpha channel itself is used.

Note: See also background and sky_sphere for additional information.

Activating alpha output via Output_Alpha=on or +UA, when used with unsupported file formats generates a warning.

3.4.7.7 Bitmap Modifiers

A bitmap modifier is a modifier used inside an image_map, bump_map or material_map to specify how the 2-D bitmap is to be applied to the 3-D surface. Several bitmap modifiers apply to specific kinds of maps and they are covered in the appropriate sections. The bitmap modifiers discussed in the following sections are applicable to all three types of bitmaps.

3.4.7.7.1 The once Option

Normally there are an infinite number of repeating image maps, bump maps or material maps created over every unit square of the x-y-plane like tiles. By adding the once keyword after a file name you can eliminate all other copies of the map except the one at (0,0) to (1,1). In image maps, areas outside this unit square are treated as fully transparent. In bump maps, areas outside this unit square are left flat with no normal modification. In material maps, areas outside this unit square are textured with the first texture of the texture list.

For example:

image_map {
  gif "mypic.gif"
  once
  }
3.4.7.7.2 The map_type Option

The default projection of the image onto the x-y-plane is called a planar map type. This option may be changed by adding the map_type keyword followed by an integer number specifying the way to wrap the image around the object.

A map_type 0 gives the default planar mapping already described.

A map_type 1 gives a spherical mapping. It assumes that the object is a sphere of any size sitting at the origin. The y-axis is the north/south pole of the spherical mapping. The top and bottom edges of the image just touch the pole regardless of any scaling. The left edge of the image begins at the positive x-axis and wraps the image around the sphere from west to east in a -y-rotation. The image covers the sphere exactly once. The once keyword has no meaning for this mapping type.

With map_type 2 you get a cylindrical mapping. It assumes that a cylinder of any diameter lies along the y-axis. The image wraps around the cylinder just like the spherical map but the image remains one unit tall from y=0 to y=1. This band of color is repeated at all heights unless the once keyword is applied.

Finally map_type 5 is a torus or donut shaped mapping. It assumes that a torus of major radius one sits at the origin in the x-z-plane. The image is wrapped around similar to spherical or cylindrical maps. However the top and bottom edges of the map wrap over and under the torus where they meet each other on the inner rim.

Types 3 and 4 are still under development.

Note: The map_type option may also be applied to bump_map and material_map statements.

For example:

sphere{<0,0,0>,1
  pigment{
    image_map {
      gif "world.gif"
      map_type 1
      }
    }
  }
3.4.7.7.3 The interpolate Option

Adding the interpolate keyword can smooth the jagged look of a bitmap. When POV-Ray checks a color for an image map or a bump amount for a bump map, it often checks a point that is not directly on top of one pixel but sort of between several differently colored pixels. Interpolations return an in-between value so that the steps between the pixels in the map will look smoother.

Although interpolate is legal in material maps, the color index is interpolated before the texture is chosen. It does not interpolate the final color as you might hope it would. In general, interpolation of material maps serves no useful purpose but this may be fixed in future versions.

There are currently three types of interpolation: interpolate 2 gives bilinear interpolation, interpolate 3 gives bicubic, and interpolate 4 gives normalized distance.

For example:

image_map {
  gif "mypic.gif"
  interpolate 2
  }

The default is no interpolation. Normalized distance is the slowest, bilinear does a better job of picking the between color, and arguably, bicubic interpolation is a slight improvement, however it is subject to over-sharpening at some color borders. Normally bilinear is used.

If your map looks jagged, try using interpolation instead of going to a higher resolution image. The results can be very good.

3.4.8 Media

The media statement is used to specify particulate matter suspended in a medium such air or water. It can be used to specify smoke, haze, fog, gas, fire, dust etc. Previous versions of POV-Ray had two incompatible systems for generating such effects. One was halo for effects enclosed in a transparent or semi-transparent object. The other was atmosphere for effects that permeate the entire scene. This duplication of systems was complex and unnecessary. Both halo and atmosphere have been eliminated. See Why are Interior and Media Necessary? for further details on this change. See Object Media for details on how to use media with objects. See Atmospheric Media for details on using media for atmospheric effects outside of objects. This section and the sub-sections which follow explains the details of the various media options which are useful for either object media or atmospheric media.

Media works by sampling the density of particles at some specified number of points along the ray's path. Sub-samples are also taken until the results reach a specified confidence level. POV-Ray provides three methods of sampling. When used in an object's interior statement, sampling only occurs inside the object. When used for atmospheric media, the samples run from the camera location until the ray strikes an object. Therefore for localized effects, it is best to use an enclosing object even though the density pattern might only produce results in a small area whether the media was enclosed or not.

The complete syntax for a media statement is as follows:

MEDIA:
  media { [MEDIA_IDENTIFIER] [MEDIA_ITEMS...] }
MEDIA_ITEMS:
  method Number | intervals Number | samples Min, Max |
  confidence Value  | variance Value | ratio Value | jitter Value
  absorption COLOR | emission COLOR | aa_threshold Value |
  aa_level Value |
  scattering {
    Type, COLOR [ eccentricity Value ] [ extinction Value ]
    }  |
  density {
    [DENSITY_IDENTIFIER] [PATTERN_TYPE] [DENSITY_MODIFIER...]
    }   |
  TRANSFORMATIONS
DENSITY_MODIFIER:
  PATTERN_MODIFIER | DENSITY_LIST | COLOR_LIST |
  color_map { COLOR_MAP_BODY } | colour_map { COLOR_MAP_BODY } |
  density_map { DENSITY_MAP_BODY }

Media default values:

aa_level     : 3
aa_threshold : 0.1
absorption   : <0,0,0>
confidence   : 0.9
emission     : <0,0,0>
intervals    : 1
jitter       : 0.0
method       : 3
ratio        : 0.9
samples      : Min 1, Max 1
variance     : 1/128
SCATTERING
COLOR        : <0,0,0>
eccentricity : 0.0
extinction   : 1.0

If a media identifier is specified, it must be the first item. All other media items may be specified in any order. All are optional. You may have multiple density statements in a single media statement. See Multiple Density vs. Multiple Media for details. Transformations apply only to the density statements which have been already specified. Any density after a transformation is not affected. If the media has no density statements and none was specified in any media identifier, then the transformation has no effect. All other media items except for density and transformations override default values or any previously set values for this media statement.

Note: Some media effects depend upon light sources. However the participation of a light source depends upon the media_interaction and media_attenuation keywords. See Atmospheric Media Interaction and Atmospheric Attenuation for details.

Note: If you specify transmit or filter to create a transparent container object, absorption media will always cast a shadow. The same applies to scattering media unless extinction is set to zero, so if a shadow is not desired, use the no_shadow keyword for the container object. This does not apply to emission media as it never casts a shadow.

3.4.8.2 Media Types

There are three types of particle interaction in media: absorbing, emitting, and scattering. All three activities may occur in a single media. Each of these three specifications requires a color. Only the red, green, and blue components of the color are used. The filter and transmit values are ignored. For this reason it is permissible to use one float value to specify an intensity of white color. For example, the following two lines are legal and produce the same results:

emission 0.75
emission rgb <0.75,0.75,0.75>
3.4.8.2.1 Absorption

The absorption keyword specifies a color of light which is absorbed when looking through the media. For example, absorption rgb<0,1,0> blocks the green light but permits red and blue to get through. Therefore a white object behind the media will appear magenta. The default value is rgb<0,0,0> which means no light is absorbed, meaning all light passes through normally.

3.4.8.2.2 Emission

The emission keyword specifies the color of the light emitted from the particles. Particles which emit light are visible without requiring additional illumination. However, they will only illuminate other objects if radiosity is used with media on. This is similar to an object with high ambient values. The default value is rgb<0,0,0> which means no light is emitted.

3.4.8.2.3 Scattering

The syntax of a scattering statement is:

SCATTERING:
  scattering {
    Type, COLOR [ eccentricity Value ] [ extinction Value ]
    }

The first float value specifies the type of scattering. This is followed by the color of the scattered light. The default value if no scattering statement is given is rgb <0,0,0> which means no scattering occurs.

The scattering effect is only visible when light is shining on the media from a light source. This is similar to diffuse reflection off of an object. In addition to reflecting light, scattering media also absorbs light like an absorption media. The balance between how much absorption occurs for a given amount of scattering is controlled by the optional extinction keyword and a single float value. The default value of 1.0 gives an extinction effect that matches the scattering. Values such as extinction 0.25 give 25% the normal amount. Using extinction 0.0 turns it off completely. Any value other than the 1.0 default is contrary to the real physical model but decreasing extinction can give you more artistic flexibility.

The integer value Type specifies one of five different scattering phase functions representing the different models: isotropic, Mie (haze and murky atmosphere), Rayleigh, and Henyey-Greenstein.

Type 1, isotropic scattering is the simplest form of scattering because it is independent of direction. The amount of light scattered by particles in the atmosphere does not depend on the angle between the viewing direction and the incoming light.

Types 2 and 3 are Mie haze and Mie murky scattering which are used for relatively small particles such as minuscule water droplets of fog, cloud particles, and particles responsible for the polluted sky. In this model the scattering is extremely directional in the forward direction, i.e. the amount of scattered light is largest when the incident light is anti-parallel to the viewing direction (the light goes directly to the viewer). It is smallest when the incident light is parallel to the viewing direction. The haze and murky atmosphere models differ in their scattering characteristics. The murky model is much more directional than the haze model.

The Mie haze scattering function

The Mie murky scattering function

Type 4 Rayleigh scattering models the scattering for extremely small particles such as molecules of the air. The amount of scattered light depends on the incident light angle. It is largest when the incident light is parallel or anti-parallel to the viewing direction and smallest when the incident light is perpendicular to the viewing direction. You should note that the Rayleigh model used in POV-Ray does not take the dependency of scattering on the wavelength into account.

The Rayleigh scattering function

Type 5 is the Henyey-Greenstein scattering model. It is based on an analytical function and can be used to model a large variety of different scattering types. The function models an ellipse with a given eccentricity e. This eccentricity is specified by the optional keyword eccentricity which is only used for scattering type five. The default eccentricity value of zero defines isotropic scattering while positive values lead to scattering in the direction of the light and negative values lead to scattering in the opposite direction of the light. Larger values of e (or smaller values in the negative case) increase the directional property of the scattering.

The Henyey-Greenstein scattering function for different eccentricity values

Note: See the section on Light Groups for additional information when using scattering media in a light group.

3.4.8.3 Sampling Parameters & Methods

Media effects are calculated by sampling the media along the path of the ray. It uses a process called Monte Carlo integration. POV-Ray provides three different types of media sampling. The method keyword lets you specify what sampling type is used.

Note: As of version 3.5 the default sampling method is 3, and it's default for intervals is 1. Sampling methods 1 and 2 have been retained for legacy purposes.

Sample method 3 uses adaptive sampling (similar to adaptive anti-aliasing) which is very much like the sampling method used in POV-Ray 3.0 atmosphere. This code was written from the ground-up to work with media. However, adaptive sampling works by taking another sample between two existing samples if there is too much variance in the original two samples. This leads to fewer samples being taken in areas where the effect from the media remains constant. The adaptive sampling is only performed if the minimum samples are set to 3 or more.

You can specify the anti-aliasing recursion depth using the aa_level keyword followed by an integer. You can specify the anti-aliasing threshold by using the aa_threshold followed by a float. The default for aa_level is 4 and the default aa_threshold is 0.1. jitter also works with method 3.

Note: It is usually best to only use one interval with method 3. Too many intervals can lead to artifacts, and POV will create more intervals if it needs them.

Sample method 1 used the intervals keyword to specify the integer number of intervals used to sample the ray. For object media, the intervals are spread between the entry and exit points as the ray passes through the container object. For atmospheric media, the intervals spans the entire length of the ray from its start until it hits an object. For media types which interact with spotlights or cylinder lights, the intervals which are not illuminated by these light types are weighted differently than the illuminated intervals when distributing samples.

The ratio keyword distributes intervals differently between lit and unlit areas. The default value of ratio 0.9 means that lit intervals get more samples than unlit intervals. Note that the total number of intervals must exceed the number of illuminated intervals. If a ray passes in and out of 8 spotlights but you have only specified 5 intervals then an error occurs.

The samples Min, Max keyword specifies the minimum and maximum number of samples taken per interval. The default values are samples 1,1. The value for Max may be omitted, in which case the range Min = Max will be used.

As each interval is sampled, the variance is computed. If the variance is below a threshold value, then no more samples are needed. The variance and confidence keywords specify the permitted variance allowed and the confidence that you are within that variance. The exact calculations are quite complex and involve chi-squared tests and other statistical principles too messy to describe here. The default values are variance 1.0/128 and confidence 0.9. For slower more accurate results, decrease the variance and increase the confidence.

Note: The maximum number of samples limits the calculations even if the proper variance and confidence are never reached.

Sample method 2 distributed samples evenly along the viewing ray or light ray. The latter can make things look smoother sometimes. If you specify a maximum number of samples higher than the minimum number of samples, POV will take additional samples, but they will be random, just like in method 1. Therefore, it is suggested you set the max samples equal to the minimum samples. jitter will cause method 2 to look similar to method 1. It should be followed by a float, and a value of 1 will stagger the samples in the full range between samples.

3.4.8.4 Density

Particles of media are normally distributed in constant density throughout the media. However, the density statement allows you to vary the density across space using any of POV-Ray's pattern functions such as those used in textures. If no density statement is given then the density remains a constant value of 1.0 throughout the media. More than one density may be specified per media statement. See Multiple Density vs. Multiple Media.

The syntax for density is:

DENSITY:
  density {
    [DENSITY_IDENTIFIER]
    [DENSITY_TYPE]
    [DENSITY_MODIFIER...]
    }

DENSITY_TYPE:
  PATTERN_TYPE | COLOR
  DENSITY_MODIFIER:
  PATTERN_MODIFIER | DENSITY_LIST | color_map { COLOR_MAP_BODY } |
  colour_map { COLOR_MAP_BODY } | density_map { DENSITY_MAP_BODY }

The density statement may begin with an optional density identifier. All subsequent values modify the defaults or the values in the identifier. The next item is a pattern type. This is any one of POV-Ray's pattern functions such as bozo, wood, gradient, waves, etc. Of particular usefulness are the spherical, planar, cylindrical, and boxed patterns which were previously available only for use with our discontinued halo feature. All patterns return a value from 0.0 to 1.0. This value is interpreted as the density of the media at that particular point. See the section Pattern for details on particular pattern types. Although a solid COLOR pattern is legal, in general it is used only when the density statement is inside a density_map.

3.4.8.4.1 General Density Modifiers

A density statement may be modified by any of the general pattern modifiers such as transformations, turbulence and warp. See Pattern Modifiers for details. In addition, there are several density-specific modifiers which can be used.

3.4.8.4.2 Density with color_map

Typically, a media uses just one constant color throughout. Even if you vary the density, it is usually just one color which is specified by the absorption, emission, or scattering keywords. However, when using emission to simulate fire or explosions, the center of the flame (high density area) is typically brighter and white or yellow. The outer edge of the flame (less density) fades to orange, red, or in some cases deep blue. To model the density-dependent change in color which is visible, you may specify a color_map. The pattern function returns a value from 0.0 to 1.0 and the value is passed to the color map to compute what color or blend of colors is used. See Color Maps for details on how pattern values work with color_map. This resulting color is multiplied by the absorption, emission and scattering color. Currently there is no way to specify different color maps for each media type within the same media statement.

Consider this example:

media {
  emission 0.75
  scattering {1, 0.5}
  density {
    spherical
    color_map {
      [0.0 rgb <0,0,0.5>]
      [0.5 rgb <0.8, 0.8, 0.4>]
      [1.0 rgb <1,1,1>]
      }
    }
  }

The color map ranges from white at density 1.0 to bright yellow at density 0.5 to deep blue at density 0. Assume we sample a point at density 0.5. The emission is 0.75*<0.8,0.8,0.4> or <0.6,0.6,0.3>. Similarly the scattering color is 0.5*<0.8,0.8,0.4> or <0.4,0.4,0.2>.

For block pattern types checker, hexagon, and brick you may specify a color list such as this:

density {
 checker
   density {rgb<1,0,0>}
   density {rgb<0,0,0>}
   }

See Color List Pigments which describes how pigment uses a color list. The same principles apply when using them with density.

3.4.8.4.3 Density Maps and Density Lists

In addition to specifying blended colors with a color map you may create a blend of densities using a density_map. The syntax for a density map is identical to a color map except you specify a density in each map entry (and not a color).

The syntax for density_map is as follows:

DENSITY_MAP:
  density_map { DENSITY_MAP_BODY }
DENSITY_MAP_BODY:
  DENSITY_MAP_IDENTIFIER | DENSITY_MAP_ENTRY...
DENSITY_MAP_ENTRY:
  [ Value DENSITY_BODY ]

Where Value is a float value between 0.0 and 1.0 inclusive and each DENSITY_BODY is anything which can be inside a density{...} statement. The density keyword and {} braces need not be specified.

Note: The [] brackets are part of the actual DENSITY_MAP_ENTRY. They are not notational symbols denoting optional parts. The brackets surround each entry in the density map.

There may be from 2 to 256 entries in the map.

Density maps may be nested to any level of complexity you desire. The densities in a map may have color maps or density maps or any type of density you want.

Density lists may also be used with block patterns such as checker, hexagon and brick, as well as the object pattern object.

For example:

density {
  checker
    density { Flame scale .8 }
    density { Fire scale .5 }
    }

Note: In the case of block patterns the density wrapping is required around the density information.

A density map is also used with the average density type. See Average for details.

You may declare and use density map identifiers but the only way to declare a density block pattern list is to declare a density identifier for the entire density.

3.4.8.4.4 Multiple Density vs. Multiple Media

It is possible to have more than one media specified per object and it is legal to have more than one density per media. The effects are quite different.

Consider this example:

object {
  MyObject
  pigment { rgbf 1 }
  interior {
    media {
      density { Some_Density }
      density { Another_Density }
      }
    }
  }

As the media is sampled, calculations are performed for each density pattern at each sample point. The resulting samples are multiplied together. Suppose one density returned rgb<.8,.8,.4> and the other returned rgb<.25,.25,0>. The resulting color is rgb<.2,.2,0>.

Note: In areas where one density returns zero, it will wipe out the other density. The end result is that only density areas which overlap will be visible. This is similar to a CSG intersection operation. Now consider:

object {
  MyObject
  pigment { rgbf 1 }
  interior {
    media {
      density { Some_Density }
      }
    media {
      density { Another_Density }
      }
    }
  }

In this case each media is computed independently. The resulting colors are added together. Suppose one density and media returned rgb<.8,.8,.4> and the other returned rgb<.25,.25,0>. The resulting color is rgb<1.05,1.05,.4>. The end result is that density areas which overlap will be especially bright and all areas will be visible. This is similar to a CSG union operation. See the sample scene ~scenes\interior\media\media4.pov for an example which illustrates this.

3.4.8.1 Interior

Introduced in POV-Ray 3.1 is an object modifier statement called interior. The syntax is:

INTERIOR:
  interior { [INTERIOR_IDENTIFIER] [INTERIOR_ITEMS...] }
INTERIOR_ITEM:
  ior Value | caustics Value | dispersion Value |
  dispersion_samples Samples | fade_distance Distance |
  fade_power Power | fade_color <Color>
  MEDIA...

Interior default values:

ior                : 1.0
caustics           : 0.0
dispersion         : 1.0
dispersion_samples : 7
fade_distance      : 0.0
fade_power         : 0.0
fade_color         : <0,0,0>

The interior contains items which describe the properties of the interior of the object. This is in contrast to the texture and interior_texture which describe the surface properties only. The interior of an object is only of interest if it has a transparent texture which allows you to see inside the object. It also applies only to solid objects which have a well-defined inside/outside distinction.

Note: The open keyword, or clipped_by modifier also allows you to see inside but interior features may not render properly. They should be avoided if accurate interiors are required.

Interior identifiers may be declared to make scene files more readable and to parameterize scenes so that changing a single declaration changes many values. An identifier is declared as follows.

INTERIOR_DECLARATION:
  #declare IDENTIFIER = INTERIOR |
  #local IDENTIFIER = INTERIOR

Where IDENTIFIER is the name of the identifier up to 40 characters long and INTERIOR is any valid interior statement. See #declare vs. #local for information on identifier scope.

3.4.8.1.1 Why are Interior and Media Necessary?

In previous versions of POV-Ray, most of the items in the interior statement were previously part of the finish statement. Also the halo statement which was once part of the texture statement has been discontinued and has been replaced by the media statement which is part of interior.

You are probably asking WHY? As explained earlier, the interior contains items which describe the properties of the interior of the object. This is in contrast to the texture which describes the surface properties only. However this is not just a philosophical change. There were serious inconsistencies in the old model.

The main problem arises when a texture_map or other patterned texture is used. These features allow you to create textures that are a blend of two textures and which vary the entire texture from one point to another. It does its blending by fully evaluating the apparent color as though only one texture was applied and then fully reevaluating it with the other texture. The two final results are blended.

It is totally illogical to have a ray enter an object with one index or refraction and then recalculate with another index. The result is not an average of the two ior values. Similarly it makes no sense to have a ray enter at one ior and exit at a different ior without transitioning between them along the way. POV-Ray only calculates refraction as the ray enters or leaves. It cannot incrementally compute a changing ior through the interior of an object. Real world objects such as optical fibers or no-line bifocal eyeglasses can have variable iors but POV-Ray cannot simulate them.

Similarly the halo calculations were not performed as the syntax implied. Using a halo in such multi-textured objects did not vary the halo through the interior of the object. Rather, it computed two separate halos through the whole object and averaged the results. The new design for media which replaces halo makes it possible to have media that varies throughout the interior of the object according to a pattern but it does so independently of the surface texture. Because there are other changes in the design of this feature which make it significantly different, it was not only moved to the interior but the name was changed.

During our development, someone asked if we will create patterned interiors or a hypothetical interior_map feature. We will not. That would defeat the whole purpose of moving these features in the first place. They cannot be patterned and have logical or self-consistent results.

3.4.8.1.2 Empty and Solid Objects

It is very important that you know the basic concept behind empty and solid objects in POV-Ray to fully understand how features like interior and translucency are used. Objects in POV-Ray can either be solid, empty or filled with (small) particles.

A solid object is made from the material specified by its pigment and finish statements (and to some degree its normal statement). By default all objects are assumed to be solid. If you assign a stone texture to a sphere you will get a ball made completely of stone. It is like you had cut this ball from a block of stone. A glass ball is a massive sphere made of glass. You should be aware that solid objects are conceptual things. If you clip away parts of the sphere you will clearly see that the interior is empty and it just has a very thin surface.

This is not contrary to the concept of a solid object used in POV-Ray. It is assumed that all space inside the sphere is covered by the sphere's interior. Light passing through the object is affected by attenuation and refraction properties. However there is no room for any other particles like those used by fog or interior media.

Empty objects are created by adding the hollow keyword (see Hollow) to the object statement. An empty (or hollow) object is assumed to be made of a very thin surface which is of the material specified by the pigment, finish and normal statements. The object's interior is empty, it normally contains air molecules.

An empty object can be filled with particles by adding fog or atmospheric media to the scene or by adding an interior media to the object. It is very important to understand that in order to fill an object with any kind of particles it first has to be made hollow.

There is a pitfall in the empty/solid object implementation that you have to be aware of.

In order to be able to put solid objects inside a media or fog, a test has to be made for every ray that passes through the media. If this ray travels through a solid object the media will not be calculated. This is what anyone will expect. A solid glass sphere in a fog bank does not contain fog.

The problem arises when the camera ray is inside any non-hollow object. In this case the ray is already traveling through a solid object and even if the media's container object is hit and it is hollow, the media will not be calculated. There is no way of telling between these two cases.

POV-Ray has to determine whether the camera is inside any object prior to tracing a camera ray in order to be able to correctly render medias when the camera is inside the container object. There is no way around doing this.

The solution to this problem (that will often happen with infinite objects like planes) is to make those objects hollow too. Thus the ray will travel through a hollow object, will hit the container object and the media will be calculated.

3.4.8.1.3 Scaling objects with an interior

All the statements that can be put in an interior represent aspects of the matter that an object is made of. Scaling an object, changing its size, does not change its matter. Two pieces of the same quality steel, one twice as big as the other, both have the same density. The bigger piece is quite a bit heavier though.

So, in POV-Ray, if you design a lens from a glass with an ior of 1.5 and you scale it bigger, the focal distance of the lens will get longer as the ior stays the same. For light attenuation it means that an object will be darker after being scaled up. The light intensity decreases a certain amount per pov-unit. The object has become bigger, more pov-units, so more light is faded. The fade_distance, fade_power themselves have not been changed.

The same applies to media. Imagine media as a density of particles, you specify 100 particles per cubic pov-unit. If we scale a 1 cubic pov-unit object to be twice as big in every direction, we will have a total of 800 particles in the object. The object will look different, as we have more particles to look through. Yet the objects density is still 100 particles per cubic pov-unit. In media this particle density is set by the color after emission, absorption, or in the scattering statement

#version 3.5;
global_settings {
  assumed_gamma 1.0
  }

camera {location <0, 0,-12.0> look_at 0 angle 30 }

#declare Container_T =
  texture {
    pigment {rgbt <1,1,1,1>}
  finish {ambient 0 diffuse 0}
  }

#declare Scale=2;

box {                             //The reference
  <-1,-1,0>,<1,1,.3>
  hollow
  texture {Container_T}
  interior {
    media {
      intervals 1
      samples 1,1
      emission 1
      }
    }
  translate <-2.1,0,0>
  }

box {                             //Object scaled twice as big
  <-1,-1,0>,<1,1,.3>  //looks different but same
  hollow                          //particle density
  texture {Container_T}
    interior {
      media {
        intervals 1
        samples 1,1
        emission 1
        }
      }
  scale Scale
  translate<0,0,12>
  }

box {                             //Object scaled twice as big
  <-1,-1,0>,<1,1,.3>  //looks the same but particle
  hollow                          //density scaled down
  texture {Container_T}
    interior {
      media {
        intervals 1
        samples 1,1
        emission 1/Scale
        }
      }
  scale Scale
  translate<0,0,12>
  translate<4.2,0,0>
  }

The third object in the scene above, shows what to do, if you want to scale the object and want it to keep the same look as before. The interior feature has to be divided by the same amount, that the object was scaled by. This is only possible when the object is scaled uniform.

In general, the correct approach is to scale the media density proportionally to the change in container volume. For non-uniform scaling to get an unambiguous result, that can be explained in physical terms, we need to do:

Density*sqrt(3)/vlength(Scale)

where Density is your original media density and Scale is the scaling vector applied to the container.

Note: The density modifiers inside the density{} statement are scaled along with the object.

3.4.8.1.4 Refraction

When light passes through a surface either into or out of a dense medium the path of the ray of light is bent. Such bending is called refraction. The amount of bending or refracting of light depends upon the density of the material. Air, water, crystal and diamonds all have different densities and thus refract differently. The index of refraction or ior value is used by scientists to describe the relative density of substances. The ior keyword is used in POV-Ray in the interior to turn on refraction and to specify the ior value. For example:

object { MyObject pigment {Clear } interior { ior 1.5 } }

The default ior value of 1.0 will give no refraction. The index of refraction for air is 1.0, water is 1.33, glass is 1.5 and diamond is 2.4.

Normally transparent or semi-transparent surfaces in POV-Ray do not refract light. Earlier versions of POV-Ray required you to use the refraction keyword in the finish statement to turn on refraction. This is no longer necessary. Any non-zero ior value now turns refraction on.

In addition to turning refraction on or off, the old refraction keyword was followed by a float value from 0.0 to 1.0. Values in between 0.0 and 1.0 would darken the refracted light in ways that do not correspond to any physical property. Many POV-Ray scenes were created with intermediate refraction values before this bug was discovered so the feature has been maintained. A more appropriate way to reduce the brightness of refracted light is to change the filter or transmit value in the colors specified in the pigment statement or to use the fade_power and fade_distance keywords. See Attenuation.

Note: Neither the ior nor refraction keywords cause the object to be transparent. Transparency only occurs if there is a non-zero filter or transmit value in the color.

The refraction and ior keywords were originally specified in finish but are now properly specified in interior. They are accepted in finish for backward compatibility and generate a warning message.

3.4.8.1.5 Dispersion

For all materials with a ior different from 1.0 the refractive index is not constant throughout the spectrum. It changes as a function of wavelength. Generally the refractive index decreases as the wavelength increases. Therefore light passing through a material will be separated according to wavelength. This is known as chromatic dispersion.

By default POV-Ray does not calculate dispersion as light travels through a transparent object. In order to get a more realistic effect the dispersion and dispersion_samples keywords can be added to the interior{} block. They will simulate dispersion by creating a prismatic color effect in the object.

The dispersion value is the ratio of refractive indices for violet to red. It controls the strength of dispersion (how much the colors are spread out) used. A DISPERSION_VALUE of 1 will give no dispersion, good values are 1.01 to 1.1.

Note: There will be no dispersion, unless the ior keyword has been specified in interior{ }. An ior of 1 is legal. The ior has no influence on the dispersion strength, only on the angle of refraction.

As POV-Ray does not use wavelengths for raytracing, a spectrum is simulated. The dispersion_samples value controls the amount of color-steps and smoothness in the spectrum. The default value is 7, the minimum is 2. Values up to 100 or higher may be needed to get a very smooth result.

3.4.8.1.5.1 Dispersion & Caustics

Dispersion only affects the interior of an object and has no effect on faked caustics (See Faked Caustics).
To see the effects of dispersion in caustics, photon mapping is needed. See the sections Photons and Photons and Dispersion.

3.4.8.1.6 Attenuation

Light attenuation is used to model the decrease in light intensity as the light travels through a transparent object. The keywords fade_power, fade_distance and fade_color are specified in the interior statement.

The fade_distance value determines the distance the light has to travel to reach half intensity while the fade_power value determines how fast the light will fall off. fade_color colorizes the attenuation. For realistic effects a fade power of 1 to 2 should be used. Default values for fade_power and fade_distance is 0.0 which turns this feature off. Default for fade_color is <0,0,0>, if fade_color is <1,1,1> there is no attenuation. The actual colors give colored attenuation. <1,0,0> looks red, not cyan as in media.

The attenuation is calculated by a formula similar to that used for light source attenuation.

Media Attenuation

If you set fade_power in the interior of an object at 1000 or above, a realistic exponential attenuation function will be used:

   Attenuation = exp(-depth/fade_dist)

The fade_power and fade_distance keywords were originally specified in finish but are now properly specified in interior. They are accepted in finish for backward compatibility and generate a warning message.

3.4.8.1.7 Simulated Caustics

Caustics are light effects that occur if light is reflected or refracted by specular reflective or refractive surfaces. Imagine a glass of water standing on a table. If sunlight falls onto the glass you will see spots of light on the table. Some of the spots are caused by light being reflected by the glass while some of them are caused by light being refracted by the water in the glass.

Since it is a very difficult and time-consuming process to actually calculate those effects (though it is not impossible), see the sections Photons. POV-Ray uses a quite simple method to simulate caustics caused by refraction. The method calculates the angle between the incoming light ray and the surface normal. Where they are nearly parallel it makes the shadow brighter. Where the angle is greater, the effect is diminished. Unlike real-world caustics, the effect does not vary based on distance. This caustic effect is limited to areas that are shaded by the transparent object. You will get no caustic effects from reflective surfaces nor in parts that are not shaded by the object.

The caustics Power keyword controls the effect. Values typically range from 0.0 to 1.0 or higher. Zero is the default which is no caustics. Low, non-zero values give broad hot-spots while higher values give tighter, smaller simulated focal points.

The caustics keyword was originally specified in finish but is now properly specified in interior. It is accepted in finish for backward compatibility and generates a warning message.

3.4.8.1.8 Object-Media

The interior statement may contain one or more media statements. Media is used to simulate suspended particles such as smoke, haze, or dust. Or visible gasses such as steam or fire and explosions. When used with an object interior, the effect is constrained by the object's shape. The calculations begin when the ray enters an object and ends when it leaves the object. This section only discusses media when used with object interior. The complete syntax and an explanation of all of the parameters and options for media is given in the section Media.

Typically the object itself is given a fully transparent texture however media also works in partially transparent objects. The texture pattern itself does not effect the interior media except perhaps to create shadows on it. The texture pattern of an object applies only to the surface shell. Any interior media patterns are totally independent of the texture.

In previous versions of POV-Ray, this feature was called halo and was part of the texture specification along with pigment, normal, and finish. See the section: Why are Interior and Media Necessary? for an explanation of the reasons for the change.

Media may also be specified outside an object to simulate atmospheric media. There is no constraining object in this case. If you only want media effects in a particular area, you should use object media rather than only relying upon the media pattern. In general it will be faster and more accurate because it only calculates inside the constraining object. See Atmospheric Media for details on unconstrained uses of media.

You may specify more than one media statement per interior statement. In that case, all of the media participate and where they overlap, they add together.

Any object which is supposed to have media effects inside it, whether those effects are object media or atmospheric media, must have the hollow on keyword applied. Otherwise the media is blocked. See the section: Empty and Solid Objects for details.

3.4.9 Include Files

This section covers the include files that come with every distribution of POV-Ray. File location varies, so see your platform specific documentation for more information.

3.4.9.1 Main Files

The main include files in alphabetical order:

3.4.9.1.1 Arrays.inc

This file contains macros for manipulating arrays.

ARRAYS_WriteDF3(Array, FileName, BitDepth): Write an array to a df3 file.

Parameters:

  • Array = The array that contains the data.
  • FileName = The name of the file to be written.
  • BitDepth = The size of the binary word.

Note: See the #write directive for more information.

Rand_Array_Item(Array, Stream): Randomly Picks an item from a 1D array.

Parameters:

  • Array = The array from which to choose the item.
  • Stream = A random number stream.

Resize_Array(Array, NewSize): Resize a 1D array, retaining its contents.

Parameters:

  • Array = The array to be resized.
  • NewSize = The desired new size of the array.

Reverse_Array(Array): Reverses the order of items in a 1D array.

Parameters:

  • Array = The array to be reversed.

Sort_Compare(Array, IdxA, IdxB): This macro is used by the Sort_Array() and Sort_Partial_Array() macros. The given macro works for 1D arrays of floats, but you can redefine it in your scene file for more complex situations, arrays of vectors or multidimensional arrays for example. Just make sure your macro returns true if the item at IdxA < the item at IdxB, and otherwise returns false.

Parameters:

  • Array = The array containing the data being sorted.
  • IdxA, IdxB = The array offsets of the data elements being compared.

Sort_Swap_Data(Array, IdxA, IdxB): This macro is used by the Sort_Array() and Sort_Partial_Array() macros. The given macro works for 1D arrays only, but you can redefine it in your scene file to handle multidimensional arrays if needed. The only requirement is that your macro swaps the data at IdxA with that at IdxB.

Parameters:

  • Array = The array containing the data being sorted.
  • IdxA, IdxB = The array offsets of the data elements being swapped.

Sort_Array(Array): This macro sorts a 1D array of floats, though you can redefine the Sort_Compare() and Sort_Swap_Data() macros to handle multidimensional arrays and other data types.

Parameters:

  • Array = The array to be sorted.

Sort_Partial_Array(Array, FirstInd, LastInd): This macro is like Sort_Array(), but sorts a specific range of an array instead of the whole array.

Parameters:

  • Array = The array to be sorted.
  • FirstInd, LastInd = The start and end indices of the range being sorted.
3.4.9.1.2 Chars.inc

This file includes 26 upper-case letter and other characters defined as objects. The size of all characters is 4 * 5 * 1. The center of the bottom side of a character face is set to the origin, so you may need to translate a character appropriately before rotating it about the x or z axes.

Letters:
char_A, char_B, char_C,
char_D, char_E, char_F,
char_G, char_H, char_I,
char_J, char_K, char_L,
char_M, char_N, char_O,
char_P, char_Q, char_R,
char_S, char_T, char_U,
char_V, char_W, char_X,
char_Y, char_Z

Numerals:
char_0, char_1,
char_2, char_3,
char_4, char_5,
char_6, char_7,
char_8, char_9

Symbols:
char_Dash, char_Plus, char_ExclPt,
char_Amps, char_Num, char_Dol,
char_Perc, char_Astr, char_Hat,
char_LPar, char_RPar, char_AtSign,
char_LSqu, char_RSqu

Usage:

#include "chars.inc"
.
.
object {char_A ...}
3.4.9.1.3 Colors.inc

This file is mainly a list of predefined colors, but also has a few color manipulation macros.

3.4.9.1.3.1 Predefined colors

This file contains 127 predefined colors that you can use in your scenes. Simply #include them in your scene file to use them:

  #include "colors.inc"

These basic colors:

  • Red
  • Green
  • Blue
  • Yellow
  • Cyan
  • Magenta
  • Clear
  • White
  • Black

A series of percentage grays that are useful for fine-tuning lighting color values and for other areas where subtle variations of grays are needed, and a palette 99 additional color definitions are available. See the distribution file ~include/colors.inc for more details.

3.4.9.1.3.2 Color macros

In POV-Ray all colors are handled in RGB color space with a component for the amount of red, green and blue light. However, not everybody thinks this is the most intuitive way to specify colors. For your convenience there are macros included in colors.inc that converts between a few different types of color spaces.

The three supported color spaces:

  • RGB = < Red, Green, Blue, Filter, Transmit >
  • HSL = < Hue, Saturation, Lightness, Filter, Transmit >
  • HSV = < Hue, Saturation, Value, Filter, Transmit >

Note: The Hue parameter is given in degrees.

CHSL2RGB(Color): Converts a color given in HSL space to one in RGB space.

Parameters:

  • Color = HSL color to be converted.

CRGB2HSL(Color): Converts a color given in RGB space to one in HSL space.

Parameters:

  • Color = RGB color to be converted.

CHSV2RGB(Color): Converts a color given in HSV space to one in RGB space.

Parameters:

  • Color = HSV color to be converted.

CRGB2HSV(Color): Converts a color given in RGB space to one in HSV space.

Parameters:

  • Color = RGB color to be converted.

Convert_Color(SourceType, DestType, Color): Converts a color from one color space to another. Color spaces available are: RGB, HSL, and HSV:

Parameters:

  • SourceType = Color space of input color.
  • DestType = Desired output color space.
  • Color = Color to be converted, in SourceType color space.
3.4.9.1.4 Consts.inc

This file defines a number of constants, including things such as mapping types and ior definitions.

3.4.9.1.4.1 Vector constants
o = < 0, 0, 0> (origin)
xy = < 1, 1, 0>
yz = < 0, 1, 1>
xz = < 1, 0, 1>
3.4.9.1.4.2 Map type constants
Plane_Map = 0
Sphere_Map = 1
Cylinder_Map = 2
Torus_Map = 5
3.4.9.1.4.3 Interpolation type constants
Bi = 2
Norm = 4
3.4.9.1.4.4 Fog type constants
Uniform_Fog = 1
Ground_Fog = 2
3.4.9.1.4.5 Focal blur hexgrid constants
Hex_Blur1 = 7
Hex_Blur2 = 19
Hex_Blur3 = 37
3.4.9.1.4.6 IORs
Air_Ior = 1.000292
Amethyst_Ior = 1.550
Apatite_Ior = 1.635
Aquamarine_Ior = 1.575
Beryl_Ior = 1.575
Citrine_Ior = 1.550
Crown_Glass_Ior = 1.51
Corundum_Ior = 1.765
Diamond_Ior = 2.47
Emerald_Ior = 1.575
Flint_Glass_Ior = 1.71
Flint_Glass_Heavy_Ior = 1.8
Flint_Glass_Medium_Ior = 1.63
Flint_Glass_Light_Ior = 1.6
Fluorite_Ior = 1.434
Gypsum_Ior = 1.525
Ice_Ior = 1.31
Plexiglas_Ior = 1.5
Quartz_Ior = 1.550
Quartz_Glass_Ior = 1.458
Ruby_Ior = 1.765
Salt_Ior = 1.544
Sapphire_Ior = 1.765
Topaz_Ior = 1.620
Tourmaline_Ior = 1.650
Water_Ior = 1.33
3.4.9.1.4.7 Dispersion amounts
Quartz_Glass_Dispersion = 1.012
Water_Dispersion = 1.007
Diamond_Dispersion = 1.035
Sapphire_Dispersion = 1.015
3.4.9.1.4.8 Scattering media type constants
ISOTROPIC_SCATTERING = 1;
MIE_HAZY_SCATTERING = 2;
MIE_MURKY_SCATTERING = 3;
RAYLEIGH_SCATTERING = 4;
HENYEY_GREENSTEIN_SCATTERING = 5;
3.4.9.1.5 Debug.inc

This file contains a set of macros designed to make debugging easier. It also functions like the old debug.inc, with the exception that you have to call the Debug_Inc_Stack() macro to get the include stack output.

Debug_Inc_Stack(): Activates include file tracking, each included file will send a debug message when it is included.

Parameters:

  • None.

Set_Debug(Bool): Activate or deactivate the debugging macros.

Parameters:

  • Bool = A boolean (true/false) value.

Debug_Message(Str): If debugging, sends the message to the debug stream.

Parameters:

  • Str = The desired message.

Debug(Condition, Message): Sends a message to the #debug stream depending on a given condition.

Parameters:

  • Condition = Any boolean expression.
  • Message = The message to be sent if Condition evaluates as true.

Warning(Condition, Message): Sends a message to the #warning stream depending on a given condition.

Parameters:

  • Condition = Any boolean expression.
  • Message = The message to be sent if Condition evaluates as true.

Error(Condition, Message): Sends a message to the #error stream depending on a given condition.

Parameters:

  • Condition = Any boolean expression.
  • Message = The message to be sent if Condition evaluates as true.
3.4.9.1.6 Finish.inc

This file contains some predefined finishes.

Dull
Dull, with a large, soft specular highlight.
Shiny
Shiny, with a small, tight specular highlight.
Glossy
Very shiny with very tight specular highlights and a fair amount of reflection.
Phong_Dull
Dull, with a large, soft phong highlight.
Phong_Shiny
Shiny, with a small, tight phong highlight.
Phong_Glossy
Very shiny with very tight phong highlights and a fair amount of reflection.
Luminous
A glowing surface, unaffected by light_sources.
Mirror
A perfectly reflective surface, no highlights or shading.
3.4.9.1.7 Functions.inc

This include file contains interfaces to internal functions as well as several predefined functions. The ID's used to access the internal functions through calls to internal(XX), are not guaranteed to stay the same between POV-Ray versions, so users are encouraged to use the functions declared here.

The number of required parameters and what they control are also given in the include file, this chapter gives more information. For starter values of the parameters, see the ~scenes/incdemo/i_internal.pov demo file.

Syntax to be used:

#include "functions.inc"
isosurface {
  function { f_torus_gumdrop(x,y,z, P0) }
  ...
  }

pigment {
  function { f_cross_ellipsoids(x,y,z, P0, P1, P2, P3) }
  COLOR_MAP ...
  }

Some special parameters are found in several of these functions. These are described in the next section and later referred to as Cross section type, Field Strength, Field Limit, SOR parameters.

3.4.9.1.7.1 Common Parameters
3.4.9.1.7.2 Cross Section Type

In the helixes and spiral functions, the 9th parameter is the cross section type.

Some shapes are:

  • 0: square
  • 0.0 to 1.0: rounded squares
  • 1: circle
  • 1.0 to 2.0: rounded diamonds
  • 2: diamond
  • 2.0 to 3.0: partially concave diamonds
  • 3: concave diamond
3.4.9.1.7.3 Field Strength

The numerical value at a point in space generated by the function is multiplied by the Field Strength. The set of points where the function evaluates to zero are unaffected by any positive value of this parameter, so if you are just using the function on its own with threshold = 0, the generated surface is still the same.

In some cases, the field strength has a considerable effect on the speed and accuracy of rendering the surface. In general, increasing the field strength speeds up the rendering, but if you set the value too high the surface starts to break up and may disappear completely.

Setting the field strength to a negative value produces the inverse of the surface, like making the function negative.

3.4.9.1.7.4 Field Limit

This will not make any difference to the generated surface if you are using threshold that is within the field limit (and will kill the surface completely if the threshold is greater than the field limit). However, it may make a huge difference to the rendering times.

If you use the function to generate a pigment, then all points that are a long way from the surface will have the same color, the color that corresponds to the numerical value of the field limit.

3.4.9.1.7.5 SOR Switch

If greater than zero, the curve is swept out as a surface of revolution (SOR). If the value is zero or negative, the curve is extruded linearly in the Z direction.

3.4.9.1.7.6 SOR Offset

If the SOR switch is on, then the curve is shifted this distance in the X direction before being swept out.

3.4.9.1.7.7 SOR Angle

If the SOR switch is on, then the curve is rotated this number of degrees about the Z axis before being swept out.

3.4.9.1.7.8 Invert Isosurface

Sometimes, when you render a surface, you may find that you get only the shape of the container. This could be caused by the fact that some of the build in functions are defined inside out.

We can invert the isosurface by negating the whole function: -(function) - threshold

3.4.9.1.7.9 Internal Functions

Here is a list of the internal functions in the order they appear in the functions.inc include file

f_algbr_cyl1(x,y,z, P0, P1, P2, P3, P4): An algebraic cylinder is what you get if you take any 2d curve and plot it in 3d. The 2d curve is simply extruded along the third axis, in this case the z axis. With the SOR Switch switched on, the figure-of-eight curve will be rotated around the Y axis instead of being extruded along the Z axis.

  • P0 : Field Strength
  • P1 : Field Limit
  • P2 : SOR Switch
  • P3 : SOR Offset
  • P4 : SOR Angle

f_algbr_cyl2(x,y,z, P0, P1, P2, P3, P4): An algebraic cylinder is what you get if you take any 2d curve and plot it in 3d. The 2d curve is simply extruded along the third axis, in this case the z axis.With the SOR Switch switched on, the cross section curve will be rotated around the Y axis instead of being extruded along the Z axis.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Field Limit
  • P2 : SOR Switch
  • P3 : SOR Offset
  • P4 : SOR Angle

f_algbr_cyl3(x,y,z, P0, P1, P2, P3, P4): An algebraic cylinder is what you get if you take any 2d curve and plot it in 3d. The 2d curve is simply extruded along the third axis, in this case the Z axis. With the SOR Switch switched on, the cross section curve will be rotated around the Y axis instead of being extruded along the Z axis.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Field Limit
  • P2 : SOR Switch
  • P3 : SOR Offset
  • P4 : SOR Angle

f_algbr_cyl4(x,y,z, P0, P1, P2, P3, P4): An algebraic cylinder is what you get if you take any 2d curve and plot it in 3d. The 2d curve is simply extruded along the third axis, in this case the z axis. With the SOR Switch switched on, the cross section curve will be rotated around the Y axis instead of being extruded along the Z axis.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Field Limit
  • P2 : SOR Switch
  • P3 : SOR Offset
  • P4 : SOR Angle

f_bicorn(x,y,z, P0, P1): The surface is a surface of revolution.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Scale. The mathematics of this surface suggest that the shape should be different for different values of this parameter. In practice the difference in shape is hard to spot. Setting the scale to 3 gives a surface with a radius of about 1 unit

f_bifolia(x,y,z, P0, P1): The bifolia surface looks something like the top part of a a paraboloid bounded below by another paraboloid.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Scale. The surface is always the same shape. Changing this parameter has the same effect as adding a scale modifier. Setting the scale to 1 gives a surface with a radius of about 1 unit

f_blob(x,y,z, P0, P1, P2, P3, P4): This function generates blobs that are similar to a CSG blob with two spherical components. This function only seems to work with negative threshold settings.

  • P0 : X distance between the two components
  • P1 : Blob strength of component 1
  • P2 : Inverse blob radius of component 1
  • P3 : Blob strength of component 2
  • P4 : Inverse blob radius of component 2

f_blob2(x,y,z, P0, P1, P2, P3): The surface is similar to a CSG blob with two spherical components.

  • P0 : Separation. One blob component is at the origin, and the other is this distance away on the X axis
  • P1 : Inverse size. Increase this to decrease the size of the surface
  • P2 : Blob strength
  • P3 : Threshold. Setting this parameter to 1 and the threshold to zero has exactly the same effect as setting this parameter to zero and the threshold to -1

f_boy_surface(x,y,z, P0, P1): For this surface, it helps if the field strength is set low, otherwise the surface has a tendency to break up or disappear entirely. This has the side effect of making the rendering times extremely long.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Scale. The surface is always the same shape. Changing this parameter has the same effect as adding a scale modifier

f_comma(x,y,z, P0): The comma surface is very much like a comma-shape.

  • P0 : Scale

f_cross_ellipsoids(x,y,z, P0, P1, P2, P3): The cross ellipsoids surface is like the union of three crossed ellipsoids, one oriented along each axis.

  • P0 : Eccentricity. When less than 1, the ellipsoids are oblate, when greater than 1 the ellipsoids are prolate, when zero the ellipsoids are spherical (and hence the whole surface is a sphere)
  • P1 : Inverse size. Increase this to decrease the size of the surface
  • P2 : Diameter. Increase this to increase the size of the ellipsoids
  • P3 : Threshold. Setting this parameter to 1 and the threshold to zero has exactly the same effect as setting this parameter to zero and the threshold to -1

f_crossed_trough(x,y,z, P0):

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_cubic_saddle(x,y,z, P0): For this surface, it helps if the field strength is set quite low, otherwise the surface has a tendency to break up or disappear entirely.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_cushion(x,y,z, P0):

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_devils_curve(x,y,z, P0):

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_devils_curve_2d(x,y,z, P0, P1, P2, P3, P4, P5): The f_devils_curve_2d curve can be extruded along the z axis, or using the SOR parameters it can be made into a surface of revolution. The X and Y factors control the size of the central feature.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : X factor
  • P2 : Y factor
  • P3 : SOR Switch
  • P4 : SOR Offset
  • P5 : SOR Angle

f_dupin_cyclid(x,y,z, P0, P1, P2, P3, P4, P5):

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Major radius of torus
  • P2 : Minor radius of torus
  • P3 : X displacement of torus
  • P4 : Y displacement of torus
  • P5 : Radius of inversion

f_ellipsoid(x,y,z, P0, P1, P2): f_ellipsoid generates spheres and ellipsoids. Needs threshold 1. Setting these scaling parameters to 1/n gives exactly the same effect as performing a scale operation to increase the scaling by n in the corresponding direction.

  • P0 : X scale (inverse)
  • P1 : Y scale (inverse)
  • P2 : Z scale (inverse)

f_enneper(x,y,z, P0):

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_flange_cover(x,y,z, P0, P1, P2, P3):

  • P0 : Spikiness. Set this to very low values to increase the spikes. Set it to 1 and you get a sphere
  • P1 : Inverse size. Increase this to decrease the size of the surface. (The other parameters also drastically affect the size, but this parameter has no other effects)
  • P2 : Flange. Increase this to increase the flanges that appear between the spikes. Set it to 1 for no flanges
  • P3 : Threshold. Setting this parameter to 1 and the threshold to zero has exactly the same effect as setting this parameter to zero and the threshold to -1

f_folium_surface(x,y,z, P0, P1, P2): A folium surface looks something like a paraboloid glued to a plane.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Neck width factor - the larger you set this, the narrower the neck where the paraboloid meets the plane
  • P2 : Divergence - the higher you set this value, the wider the paraboloid gets

f_folium_surface_2d(x,y,z, P0, P1, P2, P3, P4, P5): The f_folium_surface_2d curve can be rotated around the X axis to generate the same 3d surface as the f_folium_surface, or it can be extruded in the Z direction (by switching the SOR switch off)

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Neck width factor - same as the 3d surface if you are revolving it around the Y axis
  • P2 : Divergence - same as the 3d surface if you are revolving it around the Y axis
  • P3 : SOR Switch
  • P4 : SOR Offset
  • P5 : SOR Angle

f_glob(x,y,z, P0): One part of this surface would actually go off to infinity if it were not restricted by the contained_by shape.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_heart(x,y,z, P0):

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_helical_torus(x,y,z, P0, P1, P2, P3, P4, P5, P6, P7, P8, P9): With some sets of parameters, it looks like a torus with a helical winding around it. The winding optionally has grooves around the outside.

  • P0 : Major radius
  • P1 : Number of winding loops
  • P2 : Twistiness of winding. When zero, each winding loop is separate. When set to one, each loop twists into the next one. When set to two, each loop twists into the one after next
  • P3 : Fatness of winding?
  • P4 : Threshold. Setting this parameter to 1 and the threshold to zero has s similar effect as setting this parameter to zero and the threshold to 1
  • P5 : Negative minor radius? Reducing this parameter increases the minor radius of the central torus. Increasing it can make the torus disappear and be replaced by a vertical column. The value at which the surface switches from one form to the other depends on several other parameters
  • P6 : Another fatness of winding control?
  • P7 : Groove period. Increase this for more grooves
  • P8 : Groove amplitude. Increase this for deeper grooves
  • P9 : Groove phase. Set this to zero for symmetrical grooves

f_helix1(x,y,z, P0, P1, P2, P3, P4, P5, P6):

  • P0 : Number of helixes - e.g. 2 for a double helix
  • P1 : Period - is related to the number of turns per unit length
  • P2 : Minor radius (major radius > minor radius)
  • P3 : Major radius
  • P4 : Shape parameter. If this is greater than 1 then the tube becomes fatter in the y direction
  • P5 : Cross section type
  • P6 : Cross section rotation angle (degrees)

f_helix2(x,y,z, P0, P1, P2, P3, P4, P5, P6): Needs a negated function

  • P0 : Not used
  • P1 : Period - is related to the number of turns per unit length
  • P2 : Minor radius (minor radius > major radius)
  • P3 : Major radius
  • P4 : Not used
  • P5 : Cross section type
  • P6 : Cross section rotation angle (degrees)

f_hex_x(x,y,z, P0): This creates a grid of hexagonal cylinders stretching along the z-axis. The fatness is controlled by the threshold value. When this value equals 0.8660254 or cos(30) the sides will touch, because this is the distance between centers. Negating the function will inverse the surface and create a honey-comb structure. This function is also useful as pigment function.

  • P0 : No effect (but the syntax requires at least one parameter)

f_hex_y(x,y,z, P0): This is function forms a lattice of infinite boxes stretching along the z-axis. The fatness is controlled by the threshold value. These boxes are rotated 60 degrees around centers, which are 0.8660254 or cos(30) away from each other. This function is also useful as pigment function.

  • P0 : No effect (but the syntax requires at least one parameter)

f_hetero_mf(x,y,z, P0, P1, P2, P3, P4, P5): f_hetero_mf (x,0,z) makes multifractal height fields and patterns of 1/f noise. Multifractal refers to their characteristic of having a fractal dimension which varies with altitude. Built from summing noise of a number of frequencies, the hetero_mf parameters determine how many, and which frequencies are to be summed. An advantage to using these instead of a height_field {} from an image (a number of height field programs output multifractal types of images) is that the hetero_mf function domain extends arbitrarily far in the x and z directions so huge landscapes can be made without losing resolution or having to tile a height field. Other functions of interest are f_ridged_mf and f_ridge.

  • P0 : H is the negative of the exponent of the basis noise frequencies used in building these functions (each frequency f's amplitude is weighted by the factor f - H ). In landscapes, and many natural forms, the amplitude of high frequency contributions are usually less than the lower frequencies. When H is 1, the fractalization is relatively smooth (1/f noise). As H nears 0, the high frequencies contribute equally with low frequencies as in white noise.
  • P1 : Lacunarity is the multiplier used to get from one octave to the next. This parameter affects the size of the frequency gaps in the pattern. Make this greater than 1.0
  • P2 : Octaves is the number of different frequencies added to the fractal. Each Octave frequency is the previous one multiplied by Lacunarity, so that using a large number of octaves can get into very high frequencies very quickly.
  • P3 : Offset is the base altitude (sea level) used for the heterogeneous scaling
  • P4 : T scales the heterogeneity of the fractal. T=0 gives straight 1/f (no heterogeneous scaling). T=1 suppresses higher frequencies at lower altitudes
  • P5 : Generator type used to generate the noise3d. 0, 1, 2 and 3 are legal values.

f_hunt_surface(x,y,z, P0):

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_hyperbolic_torus(x,y,z, P0, P1, P2):

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Major radius: separation between the centers of the tubes at the closest point
  • P2 : Minor radius: thickness of the tubes at the closest point

f_isect_ellipsoids(x,y,z, P0, P1, P2, P3): The isect ellipsoids surface is like the intersection of three crossed ellipsoids, one oriented along each axis.

  • P0 : Eccentricity. When less than 1, the ellipsoids are oblate, when greater than 1 the ellipsoids are prolate, when zero the ellipsoids are spherical (and hence the whole surface is a sphere)
  • P1 : Inverse size. Increase this to decrease the size of the surface
  • P2 : Diameter. Increase this to increase the size of the ellipsoids
  • P3 : Threshold. Setting this parameter to 1 and the threshold to zero has exactly the same effect as setting this parameter to zero and the threshold to -1

f_kampyle_of_eudoxus(x,y,z, P0, P1, P2): The kampyle of eudoxus is like two infinite planes with a dimple at the center.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Dimple: When zero, the two dimples punch right through and meet at the center. Non-zero values give less dimpling
  • P2 : Closeness: Higher values make the two planes become closer

f_kampyle_of_eudoxus_2d(x,y,z, P0, P1, P2, P3, P4, P5): The 2d curve that generates the above surface can be extruded in the Z direction or rotated about various axes by using the SOR parameters.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Dimple: When zero, the two dimples punch right through and meet at the center. Non-zero values give less dimpling
  • P2 : Closeness: Higher values make the two planes become closer
  • P3 : SOR Switch
  • P4 : SOR Offset
  • P5 : SOR Angle

f_klein_bottle(x,y,z, P0):

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_kummer_surface_v1(x,y,z, P0): The Kummer surface consists of a collection of radiating rods.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_kummer_surface_v2(x,y,z, P0, P1, P2, P3): Version 2 of the kummer surface only looks like radiating rods when the parameters are set to particular negative values. For positive values it tends to look rather like a superellipsoid.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Rod width (negative): Setting this parameter to larger negative values increases the diameter of the rods
  • P2 : Divergence (negative): Setting this number to -1 causes the rods to become approximately cylindrical. Larger negative values cause the rods to become fatter further from the origin. Smaller negative numbers cause the rods to become narrower away from the origin, and have a finite length
  • P3 : Influences the length of half of the rods.Changing the sign affects the other half of the rods. 0 has no effect

f_lemniscate_of_gerono(x,y,z, P0): The Lemniscate of Gerono surface is an hourglass shape, or two teardrops with their ends connected.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_lemniscate_of_gerono_2d(x,y,z, P0, P1, P2, P3, P4, P5): The 2d version of the Lemniscate can be extruded in the Z direction, or used as a surface of revolution to generate the equivalent of the 3d version, or revolved in different ways.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Size: increasing this makes the 2d curve larger and less rounded
  • P2 : Width: increasing this makes the 2d curve fatter
  • P3 : SOR Switch
  • P4 : SOR Offset
  • P5 : SOR Angle

f_mesh1(x,y,z, P0, P1, P2, P3, P4): The overall thickness of the threads is controlled by the isosurface threshold, not by a parameter. If you render a mesh1 with zero threshold, the threads have zero thickness and are therefore invisible. Parameters P2 and P4 control the shape of the thread relative to this threshold parameter.

  • P0 : Distance between neighboring threads in the x direction
  • P1 : Distance between neighboring threads in the z direction
  • P2 : Relative thickness in the x and z directions
  • P3 : Amplitude of the weaving effect. Set to zero for a flat grid
  • P4 : Relative thickness in the y direction

f_mitre(x,y,z, P0): The Mitre surface looks a bit like an ellipsoid which has been nipped at each end with a pair of sharp nosed pliers.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_nodal_cubic(x,y,z, P0): The Nodal Cubic is something like what you would get if you were to extrude the Stophid2D curve along the X axis and then lean it over.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_noise3d(x,y,z):

f_noise_generator(x,y,z, P0):

  • P0 : Noise generator number

f_odd(x,y,z, P0):

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_ovals_of_cassini(x,y,z, P0, P1, P2, P3): The Ovals of Cassini are a generalization of the torus shape.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Major radius - like the major radius of a torus
  • P2 : Filling. Set this to zero, and you get a torus. Set this to a higher value and the hole in the middle starts to heal up. Set it even higher and you get an ellipsoid with a dimple
  • P3 : Thickness. The higher you set this value, the plumper is the result

f_paraboloid(x,y,z, P0): This paraboloid is the surface of revolution that you get if you rotate a parabola about the Y axis.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_parabolic_torus(x,y,z, P0, P1, P2):

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Major radius
  • P2 : Minor radius

f_ph(x,y,z): When used alone, the PH function gives a surface that consists of all points that are at a particular latitude, i.e. a cone. If you use a threshold of zero (the default) this gives a cone of width zero, which is invisible. Also look at f_th and f_r

f_pillow(x,y,z, P0):

  • P0 : Field Strength

f_piriform(x,y,z, P0): The piriform surface looks rather like half a lemniscate.

  • P0 : Field Strength

f_piriform_2d(x,y,z, P0, P1, P2, P3, P4, P5, P6): The 2d version of the Piriform can be extruded in the Z direction, or used as a surface of revolution to generate the equivalent of the 3d version.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Size factor 1: increasing this makes the curve larger
  • P2 : Size factor 2: making this less negative makes the curve larger but also thinner
  • P3 : Fatness: increasing this makes the curve fatter
  • P4 : SOR Switch
  • P5 : SOR Offset
  • P6 : SOR Angle

f_poly4(x,y,z, P0, P1, P2, P3, P4): This f_poly4 can be used to generate the surface of revolution of any polynomial up to degree 4. To put it another way: If we call the parameters A, B, C, D, E; then this function generates the surface of revolution formed by revolving x = A + By + Cy2 + Dy3 + Ey4 around the Y axis.

  • P0 : Constant
  • P1 : Y coefficient
  • P2 : Y2 coefficient
  • P3 : Y3 coefficient
  • P4 : Y4 coefficient

f_polytubes(x,y,z, P0, P1, P2, P3, P4, P5): The Polytubes surface consists of a number of tubes. Each tube follows a 2d curve which is specified by a polynomial of degree 4 or less. If we look at the parameters, then this function generates P0 tubes which all follow the equation x = P1 + P2y + P3y2 + P4y3 + P5y4 arranged around the Y axis. This function needs a positive threshold (fatness of the tubes).

  • P0 : Number of tubes
  • P1 : Constant
  • P2 : Y coefficient
  • P3 : Y2 coefficient
  • P4 : Y3 coefficient
  • P5 : Y4 coefficient

f_quantum(x,y,z, P0): It resembles the shape of the electron density cloud for one of the d orbitals.

  • P0 : Not used, but required

f_quartic_paraboloid(x,y,z, P0): The Quartic Paraboloid is similar to a paraboloid, but has a squarer shape.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_quartic_saddle(x,y,z, P0): The Quartic saddle is similar to a saddle, but has a squarer shape.

  • P0 : Field Strength

f_quartic_cylinder(x,y,z, P0, P1, P2): The Quartic cylinder looks a bit like a cylinder that is swallowed an egg.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Diameter of the egg
  • P2 : Controls the width of the tube and the vertical scale of the egg

f_r(x,y,z): When used alone, the R function gives a surface that consists of all the points that are a specific distance (threshold value) from the origin, i.e. a sphere. Also look at f_ph and f_th

f_ridge(x,y,z, P0, P1, P2, P3, P4, P5): This function is mainly intended for modifying other surfaces as you might use a height field or to use as pigment function. Other functions of interest are f_hetero_mf and f_ridged_mf.

  • P0 : Lambda
  • P1 : Octaves
  • P2 : Omega
  • P3 : Offset
  • P4 : Ridge
  • P5 : Generator type used to generate the noise3d. 0, 1, 2 and 3 are legal values.

f_ridged_mf(x,y,z, P0, P1, P2, P3, P4, P5): The Ridged Multifractal surface can be used to create multifractal height fields and patterns. Multifractal refers to their characteristic of having a fractal dimension which varies with altitude. They are built from summing noise of a number of frequencies. The f_ridged_mf parameters determine how many, and which frequencies are to be summed, and how the different frequencies are weighted in the sum.

An advantage to using these instead of a height_field{} from an image is that the ridged_mf function domain extends arbitrarily far in the x and z directions so huge landscapes can be made without losing resolution or having to tile a height field. Other functions of interest are f_hetero_mf and f_ridge.

  • P0 : H is the negative of the exponent of the basis noise frequencies used in building these functions (each frequency f's amplitude is weighted by the factor fE- H ). When H is 1, the fractalization is relatively smooth. As H nears 0, the high frequencies contribute equally with low frequencies
  • P1 : Lacunarity is the multiplier used to get from one octave to the next in the fractalization. This parameter affects the size of the frequency gaps in the pattern. (Use values greater than 1.0)
  • P2 : Octaves is the number of different frequencies added to the fractal. Each octave frequency is the previous one multiplied by Lacunarity. So, using a large number of octaves can get into very high frequencies very quickly
  • P3 : Offset gives a fractal whose fractal dimension changes from altitude to altitude. The high frequencies at low altitudes are more damped than at higher altitudes, so that lower altitudes are smoother than higher areas
  • P4 : Gain weights the successive contributions to the accumulated fractal result to make creases stick up as ridges
  • P5 : Generator type used to generate the noise3d. 0, 1, 2 and 3 are legal values.

f_rounded_box(x,y,z, P0, P1, P2, P3): The Rounded Box is defined in a cube from <-1, -1, -1> to <1, 1, 1>. By changing the Scale parameters, the size can be adjusted, without affecting the Radius of curvature.

  • P0 : Radius of curvature. Zero gives square corners, 0.1 gives corners that match sphere {0, 0.1}
  • P1 : Scale x
  • P2 : Scale y
  • P3 : Scale z

f_sphere(x,y,z, P0):

  • P0: radius of the sphere

f_spikes(x,y,z, P0, P1, P2, P3, P4):

  • P0 : Spikiness. Set this to very low values to increase the spikes. Set it to 1 and you get a sphere
  • P1 : Hollowness. Increasing this causes the sides to bend in more
  • P2 : Size. Increasing this increases the size of the object
  • P3 : Roundness. This parameter has a subtle effect on the roundness of the spikes
  • P4 : Fatness. Increasing this makes the spikes fatter

f_spikes_2d(x,y,z, P0, P1, P2, P3):

  • P0 : Height of central spike
  • P1 : Frequency of spikes in the X direction
  • P2 : Frequency of spikes in the Z direction
  • P3 : Rate at which the spikes reduce as you move away from the center

f_spiral(x,y,z, P0, P1, P2, P3, P4, P5):

  • P0 : Distance between windings
  • P1 : Thickness
  • P2 : Outer radius of the spiral. The surface behaves as if it is contained_by a sphere of this diameter
  • P3 : Not used
  • P4 : Not used
  • P5 : Cross section type

f_steiners_roman(x,y,z, P0): The Steiners Roman is composed of four identical triangular pads which together make up a sort of rounded tetrahedron. There are creases along the X, Y and Z axes where the pads meet.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_strophoid(x,y,z, P0, P1, P2, P3): The Strophoid is like an infinite plane with a bulb sticking out of it.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Size of bulb. Larger values give larger bulbs. Negative values give a bulb on the other side of the plane
  • P2 : Sharpness. When zero, the bulb is like a sphere that just touches the plane. When positive, there is a crossover point. When negative the bulb simply bulges out of the plane like a pimple
  • P3 : Flatness. Higher values make the top end of the bulb fatter

f_strophoid_2d(x,y,z, P0, P1, P2, P3, P4, P5, P6): The 2d strophoid curve can be extruded in the Z direction or rotated about various axes by using the SOR parameters.

  • P0 : Field Strength
  • P1 : Size of bulb. Larger values give larger bulbs. Negative values give a bulb on the other side of the plane
  • P2 : Sharpness. When zero, the bulb is like a sphere that just touches the plane. When positive, there is a crossover point. When negative the bulb simply bulges out of the plane like a pimple
  • P3 : Fatness. Higher values make the top end of the bulb fatter
  • P4 : SOR Switch
  • P5 : SOR Offset
  • P6 : SOR Angle

f_superellipsoid(x,y,z, P0, P1): Needs a negative field strength or a negated function.

  • P0 : east-west exponentx
  • P1 : north-south exponent

f_th(x,y,z): f_th() is a function that is only useful when combined with other surfaces. It produces a value which is equal to the theta angle, in radians, at any point. The theta angle is like the longitude coordinate on the Earth. It stays the same as you move north or south, but varies from east to west. Also look at f_ph and f_r

f_torus(x,y,z, P0, P1):

  • P0 : Major radius
  • P1 : Minor radius

f_torus2(x,y,z, P0, P1, P2): This is different from the f_torus function which just has the major and minor radii as parameters.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Major radius
  • P2 : Minor radius

f_torus_gumdrop(x,y,z, P0): The Torus Gumdrop surface is something like a torus with a couple of gumdrops hanging off the end.

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_umbrella(x,y,z, P0):

  • P0 : Field Strength (Needs a negative field strength or a negated function)

f_witch_of_agnesi(x,y,z, P0, P1, P2, P3, P4, P5): The Witch of Agnesi surface looks something like a witches hat.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Controls the width of the spike. The height of the spike is always about 1 unit

f_witch_of_agnesi_2d(x,y,z, P0, P1, P2, P3, P4, P5): The 2d version of the Witch of Agnesi curve can be extruded in the Z direction or rotated about various axes by use of the SOR parameters.

  • P0 : Field Strength (Needs a negative field strength or a negated function)
  • P1 : Controls the size of the spike
  • P2 : Controls the height of the spike
  • P3 : SOR Switch
  • P4 : SOR Offset
  • P5 : SOR Angle
3.4.9.1.7.10 Pre defined functions

eval_pigment(Pigm, Vect): This macro evaluates the color of a pigment at a specific point. Some pigments require more information than simply a point, slope pattern based pigments for example, and will not work with this macro. However, most pigments will work fine.

Parameters:

  • Vect = The point at which to evaluate the pigment.
  • Pigm = The pigment to evaluate.

f_snoise3d(x, y, z): Just like f_noise3d(), but returns values in the range [-1, 1].

f_sine_wave(val, amplitude, frequency): Turns a ramping waveform into a sine waveform.

f_scallop_wave(val, amplitude, frequency): Turns a ramping waveform into a scallop wave waveform.

3.4.9.1.7.11 Pattern functions

Predefined pattern functions, useful for building custom function patterns or performing displacement mapping on isosurfaces. Many of them are not really useful for these purposes, they are simply included for completeness.

Some are not implemented at all because they require special parameters that must be specified in the definition, or information that is not available to pattern functions. For this reason, you probably would want to define your own versions of these functions.

All of these functions take three parameters, the XYZ coordinates of the point to evaluate the pattern at.

f_agate(x, y, z)
f_boxed(x, y, z)
f_bozo(x, y, z)
f_brick(x, y, z)
f_bumps(x, y, z)
f_checker(x, y, z)
f_crackle(x, y, z)
This pattern has many more options, this function uses the defaults.
f_cylindrical(x, y, z)
f_dents(x, y, z)
f_gradientX(x, y, z)
f_gradientY(x, y, z)
f_gradientZ(x, y, z)
f_granite(x, y, z)
f_hexagon(x, y, z)
f_leopard(x, y, z)
f_mandel(x, y, z)
Only the basic mandel pattern is implemented, its variants and the other fractal patterns are not implemented.
f_marble(x, y, z)
f_onion(x, y, z)
f_planar(x, y, z)
f_radial(x, y, z)
f_ripples(x, y, z)
f_spherical(x, y, z)
f_spiral1(x, y, z)
f_spiral2(x, y, z)
f_spotted(x, y, z)
f_waves(x, y, z)
f_wood(x, y, z)
f_wrinkles(x, y, z)
3.4.9.1.8 Glass.inc

This file contains glass materials using new features introduced in POV 3.1 and 3.5. The old glass.inc file is still included for backwards compatibility (it is named glass_old.inc, and is included by glass.inc, so you do not need to change any scenes), but these materials will give more realistic results.

3.4.9.1.8.1 Glass colors (with transparency)
Col_Glass_Beerbottle
Col_Glass_Bluish
Col_Glass_Clear
Col_Glass_Dark_Green
         Col_Glass_General
Col_Glass_Green
Col_Glass_Old
Col_Glass_Orange
         Col_Glass_Ruby
Col_Glass_Vicksbottle
Col_Glass_Winebottle
Col_Glass_Yellow
3.4.9.1.8.2 Glass colors (without transparency, for fade_color)
Col_Amber_01
Col_Amber_02
Col_Amber_03
Col_Amber_04
Col_Amber_05
         Col_Amber_06
Col_Amber_07
Col_Amber_08
Col_Amber_09
Col_Amethyst_01
         Col_Amethyst_02
Col_Amethyst_03
Col_Amethyst_04
Col_Amethyst_05
Col_Amethyst_06
Col_Apatite_01
Col_Apatite_02
Col_Apatite_03
Col_Apatite_04
Col_Apatite_05
         Col_Aquamarine_01
Col_Aquamarine_02
Col_Aquamarine_03
Col_Aquamarine_04
Col_Aquamarine_05
         Col_Aquamarine_06
Col_Azurite_01
Col_Azurite_02
Col_Azurite_03
Col_Azurite_04
Col_Beerbottle
Col_Blue_01
Col_Blue_02
Col_Blue_03
Col_Blue_04
         Col_Citrine_01
Col_Dark_Green
Col_Emerald_01
Col_Emerald_02
Col_Emerald_03
         Col_Emerald_04
Col_Emerald_05
Col_Emerald_06
Col_Emerald_07
Col_Fluorite_01
Col_Fluorite_02
Col_Fluorite_03
Col_Fluorite_04
Col_Fluorite_05
Col_Fluorite_06
         Col_Fluorite_07
Col_Fluorite_08
Col_Fluorite_09
Col_Green
Col_Green_01
         Col_Green_02
Col_Green_03
Col_Green_04
Col_Gypsum_01
Col_Gypsum_02
Col_Gypsum_03
Col_Gypsum_04
Col_Gypsum_05
Col_Gypsum_06
Col_Orange
         Col_Red_01
Col_Red_02
Col_Red_03
Col_Red_04
Col_Ruby
         Col_Ruby_01
Col_Ruby_02
Col_Ruby_03
Col_Ruby_04
Col_Ruby_05
Col_Sapphire_01
Col_Sapphire_02
Col_Sapphire_03
Col_Topaz_01
Col_Topaz_02
         Col_Topaz_03
Col_Tourmaline_01
Col_Tourmaline_02
Col_Tourmaline_03
Col_Tourmaline_04
         Col_Tourmaline_05
Col_Tourmaline_06
Col_Vicksbottle
Col_Winebottle
Col_Yellow
Col_Yellow_01
Col_Yellow_02
Col_Yellow_03
Col_Yellow_04
3.4.9.1.8.3 Glass finishes
F_Glass5, ..., F_Glass10
3.4.9.1.8.4 Glass interiors
I_Glass1, ..., I_Glass4
I_Glass_Fade_Sqr1 (identical to I_Glass1)
I_Glass_Fade_Exp1 (identical to I_Glass2)
I_Glass_Fade_Exp2 (identical to I_Glass3)
I_Glass_Fade_Exp3 (identical to I_Glass4)
Glass interiors with various fade_power settings.
I_Glass_Dispersion1, I_Glass_Dispersion2
Glass interiors with dispersion. I_Glass_Dispersion1 has an approximately natural glass dispersion. I_Glass_Dispersion2 is exaggerated.
I_Glass_Caustics1, I_Glass_Caustics2
Glass interiors with caustics.
3.4.9.1.8.5 Glass interior macros

I_Glass_Exp(Distance) and I_Glass_Sqr(Distance): These macros return an interior with either exponential or fade_power 2 falloff, and a fade_distance of Distance.

3.4.9.1.9 Golds.inc

This file has its own versions of F_MetalA through F_MetalB. The gold textures themselves are T_Gold_1A through T_Gold_5E.

3.4.9.1.10 Logo.inc

The official POV-Ray logo designed by Chris Colefax, in two versions

Povray_Logo
The POV-Ray logo object
Povray_Logo_Prism
The POV-Ray logo as a prism
Povray_Logo_Bevel
The POV-Ray logo as a beveled prism
3.4.9.1.11 Makegrass.inc

makegrass.inc - grass and prairie building macros.

MakeBlade()
creates an individual blade of grass as mesh.
MakeGrassPatch()
creates a patch of grass (mesh)
optional with saving the mesh in a text file.
MakePrairie()
creates a prairie of grass patches.
3.4.9.1.12 Math.inc

This file contains many general math functions and macros.

3.4.9.1.12.1 Float functions and macros

even(N): A function to test whether N is even, returns 1 when true, 0 when false.

Parameters:

  • N = Input value

odd(N): A function to test whether N is odd, returns 1 when true, 0 when false.

Parameters:

  • N = Input value

Interpolate(GC, GS, GE, TS, TE, Method): Interpolation macro, interpolates between the float values TS and TE. The method of interpolation is cosine, linear or exponential. The position where to evaluate the interpolation is determined by the position of GC in the range GS - GE. See the example below.

Parameters:

  • GC = global current, float value within the range GS - GE
  • GS = global start
  • GE = global end
  • TS = target start
  • TE = target end
  • Method = interpolation method, float value:
    • Method < 0 : exponential, using the value of Method as exponent.
    • Method = 0 : cosine interpolation.
    • Method > 0 : exponential, using the value of Method as exponent.
      • Method = 1 : linear interpolation,

Example:

#declare A = Interpolate(0.5, 0, 1, 0, 10, 1);
#debug str(A,0,2)
// result A = 5.00

#declare A = Interpolate(0.0,-2, 2, 0, 10, 1);
#debug str(A,0,2)
// result A = 5.00

#declare A = Interpolate(0.5, 0, 1, 0, 10, 2);
#debug str(A,0,2)
// result A = 2.50

Mean(A): A macro to compute the average of an array of values.

Parameters:

  • A = An array of float or vector values.

Std_Dev(A, M): A macro to compute the standard deviation.

Parameters:

  • A = An array of float values.
  • M = Mean of the floats in the array.

GetStats(A): This macro declares a global array named StatisticsArray containing: N, Mean, Min, Max, and Standard Deviation

Parameters:

  • A = An array of float values.

Histogram(ValArr, Intervals): This macro declares a global, 2D array named HistogramArray. The first value in the array is the center of the interval/bin, the second the number of values in that interval.

Parameters:

  • ValArr = An array with values.
  • Intervals = The desired number of intervals/bins.

sind(v), cosd(v), tand(v), asind(v), acosd(v), atand(v), atan2d(a, b): These functions are versions of the trigonometric functions using degrees, instead of radians, as the angle unit.

Parameters:

  • The same as for the analogous built-in trig function.

max3(a, b, c): A function to find the largest of three numbers.

Parameters:

  • a, b, c = Input values.

min3(a, b, c): A function to find the smallest of three numbers.

Parameters:

  • a, b, c = Input values.

f_sqr(v): A function to square a number.

Parameters:

  • v = Input value.

sgn(v): A function to show the sign of the number. Returns -1 or 1 depending on the sign of v.

Parameters:

  • v = Input value.

clip(V, Min, Max): A function that limits a value to a specific range, if it goes outside that range it is clipped. Input values larger than Max will return Max, those less than Min will return Min.

Parameters:

  • V = Input value.
  • Min = Minimum of output range.
  • Max = Maximum of output range.

clamp(V, Min, Max): A function that limits a value to a specific range, if it goes outside that range it is clamped to this range, wrapping around. As the input increases or decreases outside the given range, the output will repeatedly sweep through that range, making a sawtooth waveform.

Parameters:

  • V = Input value.
  • Min = Minimum of output range.
  • Max = Maximum of output range.

adj_range(V, Min, Max): A function that adjusts input values in the range [0, 1] to a given range. An input value of 0 will return Min, 1 will return Max, and values outside the [0, 1] range will be linearly extrapolated (the graph will continue in a straight line).

Parameters:

  • V = Input value.
  • Min = Minimum of output range.
  • Max = Maximum of output range.

adj_range2(V, InMin, InMax, OutMin, OutMax): Like f_range(), but adjusts input values in the range [InMin, InMax] to the range [OutMin, OutMax].

Parameters:

  • V = Input value.
  • InMin = Minimum of input range.
  • InMax = Maximum of input range.
  • OutMin = Minimum of output range.
  • OutMax = Maximum of output range.
3.4.9.1.12.2 Vector functions and macros

These are all macros in the current version because functions can not take vector parameters, but this may change in the future.

VSqr(V): Square each individual component of a vector, equivalent to V*V.

Parameters:

  • V = Vector to be squared.

VPow(V, P), VPow5D(V, P): Raise each individual component of a vector to a given power.

Parameters:

  • V = Input vector.
  • P = Power.

VEq(V1, V2): Tests for equal vectors, returns true if all three components of V1equal the respective components of V2.

Parameters:

  • V1, V2 = The vectors to be compared.

VEq5D(V1, V2): A 5D version of VEq(). Tests for equal vectors, returns true if all 5 components of V1 equal the respective components of V2.

Parameters:

  • V1, V2 = The vectors to be compared.

VZero(V): Tests for a < 0, 0, 0> vector.

Parameters:

  • V = Input vector.

VZero5D(V): Tests for a < 0, 0, 0, 0, 0> vector.

Parameters:

  • V = Input vector.

VLength5D(V): Computes the length of a 5D vector.

Parameters:

  • V = Input vector.

VNormalize5D(V): Normalizes a 5D vector.

Parameters:

  • V = Input vector.

VDot5D(V1, V2): Computes the dot product of two 5D vectors. See vdot() for more information on dot products.

Parameters:

  • V = Input vector.

VCos_Angle(V1, V2): Compute the cosine of the angle between two vectors.

Parameters:

  • V1, V2 = Input vectors.

VAngle(V1, V2), VAngleD(V1, V2): Compute the angle between two vectors. VAngle() returns the angle in radians, VAngleD() in degrees.

Parameters:

  • V1, V2 = Input vectors.

VRotation(V1, V2, Axis) and VRotationD(V1, V2, Axis): Compute the rotation angle from V1 to V2 around Axis. Axis should be perpendicular to both V1 and V2. The output will be in the range between -pi and pi radians or between -180 degrees and 180 degrees if you are using the degree version. However, if Axis is set to <0,0,0> the output will always be positive or zero, the same result you will get with the VAngle() macros.

Parameters:

  • V1, V2 = Input vectors.

VDist(V1, V2): Compute the distance between two points.

Parameters:

  • V1, V2 = Input vectors.

VPerp_To_Vector(V): Find a vector perpendicular to the given vector.

Parameters:

  • V = Input vector.

VPerp_To_Plane(V1, V2): Find a vector perpendicular to both given vectors. In other words, perpendicular to the plane defined by the two input vectors.

Parameters:

  • V1, V2 = Input vectors.

VPerp_Adjust(V1, Axis): Find a vector perpendicular to Axis and in the plane of V1 and Axis. In other words, the new vector is a version of V1 adjusted to be perpendicular to Axis.

Parameters:

  • V1, Axis = Input vectors.

VProject_Plane(V1, Axis): Project vector V1 onto the plane defined by Axis.

Parameters:

  • V1 = Input vectors.
  • Axis = Normal of the plane.

VProject_Axis(V1, Axis): Project vector V1 onto the axis defined by Axis.

Parameters:

  • V1, Axis = Input vectors.

VMin(V), VMax(V): Find the smallest or largest component of a vector.

Parameters:

  • V = Input vector.

VWith_Len(V, Len): Create a vector parallel to a given vector but with a given length.

Parameters:

  • V = Direction vector.
  • Len = Length of desired vector.
3.4.9.1.12.3 Vector Analysis

SetGradientAccuracy(Value): All the macros below make use of a constant named __Gradient_Fn_Accuracy_ for numerical approximation of the derivatives. This constant can be changed with the macro, the default value is 0.001.

fn_Gradient(Fn): A macro calculating the gradient of a function as a function.

Parameters:

  • Fn = function to calculate the gradient from.

Output: the length of the gradient as a function.

fn_Gradient_Directional(Fn, Dir): A macro calculating the gradient of a function in one direction as a function.

Parameters:

  • Fn = function to calculate the gradient from.
  • Dir = direction to calculate the gradient.

Output: the gradient in that direction as a function.

fn_Divergence(Fnx, Fny, Fnz): A macro calculating the divergence of a (vector) function as a function.

Parameters:

  • Fnx, Fny, Fnz= x, y and z components of a vector function.

Output: the divergence as a function.

vGradient(Fn, p0): A macro calculating the gradient of a function as a vector expression.

Parameters:

  • Fn = function to calculate the gradient from.
  • p0 = point where to calculate the gradient.

Output: the gradient as a vector expression.

vCurl(Fnx, Fny, Fnz, p0): A macro calculating the curl of a (vector) function as a vector expression.

Parameters:

  • Fnx, Fny, Fnz = x, y and z components of a vector function.
  • p0 = point where to calculate the gradient.

Output: the curl as a vector expression

Divergence(Fnx, Fny, Fnz, p0): A macro calculating the divergence of a (vector) function as a float expression.

Parameters:

  • Fnx, Fny, Fnz = x, y and z components of a vector function.
  • p0 = point where to calculate the gradient.

Output: the divergence as a float expression.

Gradient_Length(Fn, p0): A macro calculating the length of the gradient of a function as a float expression.

Parameters:

  • Fn = function to calculate the gradient from.
  • p0 = point where to calculate the gradient.

Output: the length of the gradient as a float expression.

Gradient_Directional(Fn, p0, Dir): A macro calculating the gradient of a function in one direction as a float expression.

Parameters:

  • Fn = function to calculate the gradient from.
  • p0 = point where to calculate the gradient.
  • Dir = direction to calculate the gradient.

Output: the gradient in that direction as a float expression

3.4.9.1.13 Meshmaker.inc

meshmaker.inc - various mesh2 objects by splines.

MSM(SplineArray, SplRes, Interp_type, InterpRes, FileName)
Generates a mesh2 from an array of splines and optionally writes the mesh2 object as a file of the given FileName.
The uv_coordinates come from the square <0,0> - <1,1>.
The spline is evaluated from t=0 to t=1.
For the normal calculation, it is required that all splines (also linear_spline) have one extra point before t=0 and after t=1.
BuildWriteMesh2(VecArr, NormArr, UVArr, U, V, FileName)
Generates and optionally writes a mesh2 object based on 3 input arrays, the number of quads in U and V direction and a filename.
VecArr : The array that contains the vertices of the triangles in the mesh.
NormArr : The array with the normal vectors that go with the vertices.
UVArr : The array containing the uv_vectors.
U : The amount of subdivisions of the surface in the u-direction.
V : The amount of subdivisions in the v-direction.
Based on the U and V values the face_indices of the triangles in the mesh are calculated.
FileName : The name of the file to which the mesh will be written. If is an empty string (""), no file will be written.
If the file extension is 'obj' a Wavefront objectfile will be written.
If the extension is 'pcm' a compressed mesh file is written.
If a file name is given, the macro will first check if it already exists.
If that is so, it will try to parse the existing file unless it's a '*.obj', '*.pcm' or '*.arr' file as POV-Ray can not read them directly. In this case a new mesh will be generated, but the existing files will _not_ be over-written.
BuildSpline(Arr, SplType)
A helper macro for MSM()
Generates from a array Arr a spline of the given spline type SplType.
CheckFileName(FileName)
A helper macro for MSM()
If Return has a value of 0 the mesh will not be build, but it will be parsed from file.
LInterpolate(Val, Min, Max)
A helper macro for MSM()
Linear interpolation of a vector or float between Min and Max.
Min : minimal float value or vector.
Max : Maximal float value or vector.
Val : A float in the range 0 - 1.
RangeMM() = function(Val,Rmin,Rmax,Min,Max)
A helper function for MSM()
Adjusts input values in the range [RMin, RMax] to fit in the range [Min, Max]. Val: A float value in the range [Rmin, Rmax].
Parametric(__F1__, __F2__, __F3__, UVmin, UVmax, Iter_U, Iter_V, FileName)
Generates a mesh2 object from the parametric uv functions __F1__, __F2__, __F3__ in the ranges between UVmin and UVmax with the iteration steps Iter_U and Iter_V and optionally saves the mesh2 object as a file with the name FileName.
Paramcalc(UVmin, UVmax, Iter_U, Iter_V, FileName)
The kernel of the macro Parametric(). See Parametric().
Prism1(Spl, ResSpl, PSpl, PRes, FileName)
Generates a mesh2 object by extruding the spline Spl along the y-axis with the resolution spline ResSpl. In every step the spline is scaled by the 'relative' distance from the y-axis of the second spline (PSpl).
The uv_coordinates come from the square <0,0> - <1,1>.
Spl : The spline to be extruded.
The spline is evaluated from t=0 to t=1. For the normal calculation,
it is required that all splines (also linear_spline) have one extra
point before t=0 and after t=1. ResSpl : The amount of triangles to be used along the spline. PSpl : The spline that determines by what amount the extrusion
is scaled in each step. The scaling is based on the relative distance from the y-axis.
That is, at t=0 the scale is always 1, so that the start of the shape is
identical to the spline Spl.
PSpl also sets the height of the resulting shape (its y-value at t=1).
The spline is evaluated from t=0 to t=1. For the normal calculation,
it is required that all splines (also linear_spline) have one extra
point before t=0 and after t=1.
FileName : The name of the file to which the mesh will be written.
If is an empty string (""), no file will be written. If a file name is given, the macro
will first check if it already exists. If that is so, it will expect a
mesh2 with the name "Surface" and try to parse the existing file.
Lathe(Spl, ResSpl, Rot, ResRot, FileName)
This macro generates a mesh2 object by rotating a two-dimensional curve about the y-axis.
The uv_coordinates come from the square <0,0> - <1,1>.
Spl : The spline to be rotated. The spline is evaluated from t=0 to t=1. For the normal calculation, it is required that all splines (also linear_spline) have one extra point before t=0 and after t=1. ResSpl : The amount of triangles to be used along the spline. Rot : The angle the spline has to be rotated.
ResRot : The amount of triangles to be used in the circumference.
FileName : The name of the file to which the mesh will be written.
If is an empty string (""), no file will be written.
If the file extension is 'obj' a Wavefront objectfile will be written.
If the extension is 'pcm' a compressed mesh file is written.
If a file name is given, the macro will first check if it already exists.
If that is so, it will try to parse the existing file unless it's a '*.obj',
'*.pcm' or '*.arr' file as POV-Ray can not read them directly. In this case a new
mesh will be generated, but the existing files will _not_ be over-written.
Coons(Spl1, Spl2, Spl3, Spl4, Iter_U, Iter_V, FileName)
Generates a mesh2 'coons surface' defined by four splines, all attached head to tail to the previous / next one.
The uv_coordinates come from the square <0,0> - <1,1>.
Spl1 - 4 : The four spline that define the surface.
The splines are evaluated from t=0 to t=1.
Iter_U : The resolution for the splines 1 and 3.
Iter_V : The resolution for the splines 2 and 4.
FileName : The name of the file to which the mesh will be written.
If is an empty string (""), no file will be written.
If the file extension is 'obj' a Wavefront objectfile will be written.
If the extension is 'pcm' a compressed mesh file is written.
If a file name is given, the macro will first check if it already exists.
If that is so, it will try to parse the existing file unless it's a '*.obj',
'*.pcm' or '*.arr' file as POV-Ray can not read them directly. In this case a new
mesh will be generated, but the existing files will _not_ be over-written.
TwoVarSurf(__Fuv, Urange, Vrange, Iter_U, Iter_V, FileName)
Generates a mesh2 object by extruding an uv-function. Urange : The range in x direction.
Vrange : The range in y direction.
Iter_U : The resolution in x direction.
Iter_V : The resolution in y direction.
FileName : The name of the file to which the mesh will be written.
If is an empty string (""), no file will be written. If a file name is given, the macro
will first check if it already exists. If that is so, it will expect a
mesh2 with the name "Surface" and try to parse the existing file.
SweepSpline1(Track,Shape,Waist,U,V,Filename)
Generates a mesh2 object by extruding a spline Shape along Track and optionally writes it as a file with method 1.
FileName : The name of the file to which the mesh will be written. If is an empty string (""), no file will be written. If a file name is given, the macro
will first check if it already exists. If that is so, it will expect a
mesh2 with the name "Surface" and try to parse the existing file.
SweepSpline2(Track,Shape,Waist,U,V,Filename)
Generates a mesh2 object by extruding a spline Shape along Track and optionally writes it as a file with method 2.
FileName : The name of the file to which the mesh will be written. If is an empty string (""), no file will be written. If a file name is given, the macro
will first check if it already exists. If that is so, it will expect a
mesh2 with the name "Surface" and try to parse the existing file.

3.4.9.1.14 Metals.inc

These files define several metal textures. The file metals.inc contains copper, silver, chrome, and brass textures, and golds.inc contains the gold textures. Rendering the demo files will come in useful in using these textures.

Pigments:

P_Brass1
Dark brown bronze.
P_Brass2
Somewhat lighter brown than Brass4. Old penny, in soft finishes.
P_Brass3
Used by Steve Anger's Polished_Brass. Slightly coppery.
P_Brass4
A little yellower than Brass1.
P_Brass5
Very light bronze, ranges from med tan to almost white.
P_Copper1
Bronze-like. Best in finish #C.
P_Copper2
Slightly brownish copper/bronze. Best in finishes #B-#D.
P_Copper3
Reddish-brown copper. Best in finishes #C-#E.
P_Copper4
Pink copper, like new tubing. Best in finishes #C-#E.
P_Copper5
Bronze in softer finishes, gold in harder finishes.
P_Chrome1
20% Gray. Used in Steve Anger's Polished_Chrome.
P_Chrome2
Slightly blueish 60% gray. Good steel w/finish #A.
P_Chrome3
50% neutral gray.
P_Chrome4
75% neutral gray.
P_Chrome5
95% neutral gray.
P_Silver1
Yellowish silverplate. Somewhat tarnished looking.
P_Silver2
Not quite as yellowish as Silver1 but more so than Silver3.
P_Silver3
Reasonably neutral silver.
P_Silver4
P_Silver5

Finishes:

F_MetalA
Very soft and dull.
F_MetalB
Fairly soft and dull.
F_MetalC
Medium reflectivity. Holds color well.
F_MetalD
Very hard and highly polished. High reflectivity.
F_MetalE
Very highly polished and reflective.

Textures:

T_Brass_1A to T_Brass_5E
T_Copper_1A to T_Copper_5E
T_Chrome_1A to T_Chrome_5E
T_Silver_1A to T_Silver_5E
3.4.9.1.15 Rad_def.inc

This file defines a macro that sets some common radiosity settings. These settings are extremely general and are intended for ease of use, and do not necessarily give the best results.

Usage:

#include "rad_def.inc"
global_settings {
  ...
  radiosity {
    Rad_Settings(Setting, Normal, Media)
    }
  }

Parameters:

  • Setting = Quality setting. Use one of the predefined constants:
    • Radiosity_Default
    • Radiosity_Debug
    • Radiosity_Fast
    • Radiosity_Normal
    • Radiosity_2Bounce
    • Radiosity_Final
    • Radiosity_OutdoorLQ
    • Radiosity_OutdoorHQ
    • Radiosity_OutdoorLight
    • Radiosity_IndoorLQ
    • Radiosity_IndoorHQ
  • Normal = Boolean value, whether or not to use surface normal modifiers for radiosity samples.
  • Media = Boolean value, whether or not to calculate media for radiosity samples.
3.4.9.1.16 Rand.inc

A collection of macros for generating random numbers, as well as 4 predefined random number streams: RdmA, RdmB, RdmC, and RdmD. There are macros for creating random numbers in a flat distribution (all numbers equally likely) in various ranges, and a variety of other distributions.

3.4.9.1.16.1 Flat Distributions

SRand(Stream): Signed rand(), returns random numbers in the range [-1, 1].

Parameters:

  • Stream = Random number stream.

RRand(Min, Max, Stream): Returns random numbers in the range [Min, Max].

Parameters:

  • Min = The lower end of the output range.
  • Max = The upper end of the output range.
  • Stream = Random number stream.

VRand(Stream): Returns random vectors in a box from < 0, 0, 0> to < 1, 1, 1>

Parameters:

  • Stream = Random number stream.

VRand_In_Box(PtA, PtB, Stream): Like VRand(), this macro returns a random vector in a box, but this version lets you specify the two corners of the box.

Parameters:

  • PtA = Lower-left-bottom corner of box.
  • PtB = Upper-right-top corner of box.
  • Stream = Random number stream.

VRand_In_Sphere(Stream): Returns a random vector in a unit-radius sphere located at the origin.

Parameters:

  • Stream = Random number stream.

VRand_On_Sphere(Stream): Returns a random vector on the surface of a unit-radius sphere located at the origin.

Parameters:

  • Stream = Random number stream.

VRand_In_Obj(Object, Stream): This macro takes a solid object and returns a random point that is inside it. It does this by randomly sampling the bounding box of the object, and can be quite slow if the object occupies a small percentage of the volume of its bounding box (because it will take more attempts to find a point inside the object). This macro is best used on finite, solid objects (non-solid objects, such as meshes and bezier patches, do not have a defined inside, and will not work).

Parameters:

  • Object = The object the macro chooses the points from.
  • Stream = Random number stream.
3.4.9.1.16.2 Other Distributions
3.4.9.1.16.3 Continuous Symmetric Distributions

Rand_Cauchy(Mu, Sigma, Stream): Cauchy distribution.

Parameters:

  • Mu = Mean.
  • Sigma = Standard deviation.
  • Stream = Random number stream.

Rand_Student(N, Stream): Student's distribution.

Parameters:

  • N = degrees of freedom.
  • Stream = Random number stream.

Rand_Normal(Mu, Sigma, Stream): Normal distribution.

Parameters:

  • Mu = Mean.
  • Sigma = Standard deviation.
  • Stream = Random number stream.

Rand_Gauss(Mu, Sigma, Stream): Gaussian distribution. Like Rand_Normal(), but a bit faster.

Parameters:

  • Mu = Mean.
  • Sigma = Standard deviation.
  • Stream = Random number stream.
3.4.9.1.16.4 Continuous Skewed Distributions

Rand_Spline(Spline, Stream): This macro takes a spline describing the desired distribution. The T value of the spline is the output value, and the .y value its chance of occuring.

Parameters:

  • Spline = A spline determining the distribution.
  • Stream = Random number stream.

Rand_Gamma(Alpha, Beta, Stream): Gamma distribution.

Parameters:

  • Alpha = Shape parameter > 0.
  • Beta = Scale parameter > 0.
  • Stream = Random number stream.

Rand_Beta(Alpha, Beta, Stream): Beta variate.

Parameters:

  • Alpha = Shape Gamma1.
  • Beta = Scale Gamma2.
  • Stream = Random number stream.

Rand_Chi_Square(N, Stream): Chi Square random variate.

Parameters:

  • N = Degrees of freedom (integer).
  • Stream = Random number stream.

Rand_F_Dist(N, M, Stream): F-distribution.

Parameters:

  • N, M = Degrees of freedom.
  • Stream = Random number stream.

Rand_Tri(Min, Max, Mode, Stream): Triangular distribution

Parameters:

  • Min, Max, Mode: Min < Mode < Max.
  • Stream = Random number stream.

Rand_Erlang(Mu, K, Stream): Erlang variate.

Parameters:

  • Mu = Mean >= 0.
  • K = Number of exponential samples.
  • Stream = Random number stream.

Rand_Exp(Lambda, Stream): Exponential distribution.

Parameters:

  • Lambda = rate = 1/mean.
  • Stream = Random number stream.

Rand_Lognormal(Mu, Sigma, Stream): Lognormal distribution.

Parameters:

  • Mu = Mean.
  • Sigma = Standard deviation.
  • Stream = Random number stream.

Rand_Pareto(Alpha, Stream): Pareto distribution.

Parameters:

  • Alpha = ?
  • Stream = Random number stream.

Rand_Weibull(Alpha, Beta, Stream): Weibull distribution.

Parameters:

  • Alpha = ?
  • Beta = ?
  • Stream = Random number stream.
3.4.9.1.16.5 Discrete Distributions

Rand_Bernoulli(P, Stream) and Prob(P, Stream): Bernoulli distribution. Output is true with probability equal to the value of P and false with a probability of 1 - P.

Parameters:

  • P = probability range (0-1).
  • Stream = Random number stream.

Rand_Binomial(N, P, Stream): Binomial distribution.

Parameters:

  • N = Number of trials.
  • P = Probability (0-1)
  • Stream = Random number stream.

Rand_Geo(P, Stream): Geometric distribution.

Parameters:

  • P = Probability (0-1).
  • Stream = Random number stream.

Rand_Poisson(Mu, Stream): Poisson distribution.

Parameters:

  • Mu = Mean.
  • Stream = Random number stream.
3.4.9.1.17 Screen.inc

Screen.inc will enable you to place objects and textures right in front of the camera. When you move the camera, the objects placed with screen.inc will follow the movement and stay in the same position on the screen. One use of this is to place your signature or a logo in the corner of the image.

You can only use screen.inc with the perspective camera. Screen.inc will automatically create a default camera definition for you when it is included. All aspects of the camera can than be changed, by invoking the appropriate 'Set_Camera_...' macros in your scene. After calling these setup macros you can use the macros Screen_Object and Screen_Plane.

Note: Even though objects aligned using screen.inc follow the camera, they are still part of the scene. That means that they will be affected by perspective, lighting, the surroundings etc.

For an example of use, see the screen.pov demo file.

Set_Camera_Location(Loc): Changes the position of the default camera to a new location as specified by the Loc vector.

Set_Camera_Look_At(LookAt): Changes the position the default camera looks at to a new location as specified by the LookAt vector.

Set_Camera_Aspect_Ratio(Aspect): Changes the default aspect ratio, Aspect is a float value, usually width divided by the height of the image.

Set_Camera_Aspect(Width,Height): Changes the default aspect ratio of the camera.

Set_Camera_Sky(Sky): Sets a new Sky-vector for the camera.

Set_Camera_Zoom(Zoom): The amount to zoom in or out, Zoom is a float.

Set_Camera_Angle(Angle): Sets a new camera angle.

Set_Camera(Location, LookAt, Angle): Set location, look_at and angle in one go.

Reset_Camera(): Resets the camera to its default values.

Screen_Object (Object, Position, Spacing, Confine, Scaling): Puts an object in front of the camera.

Parameters:

  • Object = The object to place in front of the screen.
  • Position = UV coordinates for the object. <0,0> is lower left corner of the screen and <1,1> is upper right corner.
  • Spacing = Float describing minimum distance from object to the borders. UV vector can be used to get different horizontal and vertical spacing.
  • Confine = Set to true to confine objects to visible screen area. Set to false to allow objects to be outside visible screen area.
  • Scaling = If the object intersects or interacts with the scene, try to move it closer to the camera by decreasing Scaling.

Screen_Plane (Texture, Scaling, BLCorner, TRCorner): Screen_Plane is a macro that will place a texture of your choice on a plane right in front of the camera.

Parameters:

  • Texture = The texture to be displayed on the camera plane. <0,0,0> is lower left corner and <1,1,0> is upper right corner.
  • Scaling = If the plane intersects or interacts with the scene, try to move it closer to the camera by decreasing Scaling.
  • BLCorner = The bottom left corner of the Screen_Plane.
  • TRCorner = The top right corner of the Screen_Plane.
3.4.9.1.18 Shapes.inc

These files contain predefined shapes and shape-generation macros.

shapes.inc includes shapes_old.inc and contains many macros for working with objects, and for creating special objects, such as bevelled text, spherical height fields, and rounded shapes.

Many of the objects in shapes_old.inc are not very useful in the newer versions of POV-Ray, and are kept for backwards compatability with old scenes written for versions of POV-Ray that lacked primitives like cones, disks, planes, etc.

The file shapes2.inc contains some more useful shapes, including regular polyhedrons, and shapesq.inc contains several quartic and cubic shape definitions.

Some of the shapes in shapesq.inc would be much easier to generate, more flexible, and possibly faster rendering as isosurfaces, but are still useful for two reasons: backwards compatability, and the fact that isosurfaces are always finite.

Isect(Pt, Dir, Obj, OPt) and IsectN(Pt, Dir, Obj, OPt, ONorm): These macros are interfaces to the trace() function. Isect() only returns the intersection point, IsectN() returns the surface normal as well. These macros return the point and normal information through their parameters, and true or false depending on whether an intersection was found: If an intersection is found, they return true and set OPt to the intersection point, and ONorm to the normal. Otherwise they return false, and do not modify OPt or ONorm.

Parameters:

  • Pt = The origin (starting point) of the ray.
  • Dir = The direction of the ray.
  • Obj = The object to test for intersection with.
  • OPt = A declared variable, the macro will set this to the intersection point.
  • ONorm = A declared variable, the macro will set this to the surface normal at the intersection point.

Extents(Obj, Min, Max): This macro is a shortcut for calling both min_extent() and max_extent() to get the corners of the bounding box of an object. It returns these values through the Min and Max parameters.

Parameters:

  • Obj = The object you are getting the extents of.
  • Min = A declared variable, the macro will set this to the min_extent of the object.
  • Max = A declared variable, the macro will set this to the max_extent of the object.

Center_Object(Object, Axis): A shortcut for using the Center_Trans() macro with an object.

Parameters:

  • Object = The object to be centered.
  • Axis = See Center_Trans() in the transforms.inc documentation.

Align_Object(Object, Axis, Pt): A shortcut for using the Align_Trans() macro with an object.

Parameters:

  • Object = The object to be aligned.
  • Axis = See Align_Trans() in the transforms.inc documentation.
  • Point = The point to which to align the bounding box of the object.

Bevelled_Text(Font, String, Cuts, BevelAng, BevelDepth, Depth, Offset, UseMerge): This macro attempts to bevel the front edges of a text object. It accomplishes this by making an intersection of multiple copies of the text object, each sheared in a different direction. The results are no perfect, but may be entirely acceptable for some purposes. Warning: the object generated may render considerably more slowly than an ordinary text object.

Parameters:

  • Font = A string specifying the font to use.
  • String = The text string the object is generated from.
  • Cuts = The number of intersections to use in bevelling the text. More cuts give smoother results, but take more memory and are slower rendering.
  • BevelAng = The angle of the bevelled edge.
  • BevelDepth = The thickness of the bevelled portion.
  • Depth = The total thickness of the resulting text object.
  • Offset = The offset parameter for the text object. The z value of this vector will be ignored, because the front faces of all the letters need to be coplanar for the bevelling to work.
  • UseMerge = Switch between merge (1) and union (0).

Text_Space(Font, String, Size, Spacing): Computes the width of a text string, including white space, it returns the advance widths of all n letters. Text_Space gives the space a text, or a glyph, occupies in regard to its surroundings.

Parameters:

  • Font = A string specifying the font to use.
  • String = The text string the object is generated from.
  • Size = A scaling value.
  • Spacing = The amount of space to add between the characters.

Text_Width(Font, String, Size, Spacing): Computes the width of a text string, it returns the advance widths of the first n-1 letters, plus the glyph width of the last letter. Text_Width gives the physical width of the text and if you use only one letter the physical width of one glyph.

Parameters:

  • Font = A string specifying the font to use.
  • String = The text string the object is generated from.
  • Size = A scaling value.
  • Spacing = The amount of space to add between the characters.

Align_Left, Align_Right, Align_Center: These constants are used by the Circle_Text() macro.

Circle_Text(Font, String, Size, Spacing, Depth, Radius, Inverted, Justification, Angle): Creates a text object with the bottom (or top) of the character cells aligned with all or part of a circle. This macro should be used inside an object{...} block.

Parameters:

  • Font = A string specifying the font to use.
  • String = The text string the object is generated from.
  • Size = A scaling value.
  • Spacing = The amount of space to add between the characters.
  • Depth = The thickness of the text object.
  • Radius = The radius of the circle the letters are aligned to.
  • Inverted = Controls what part of the text faces outside. If this parameter is nonzero, the tops of the letters will point toward the center of the circle. Otherwise, the bottoms of the letters will do so.
  • Justification = Align_Left, Align_Right, or Align_Center.
  • Angle = The point on the circle from which rendering will begin. The +x direction is 0 and the +y direction is 90 (i.e. the angle increases anti-clockwise).

Wedge(Angle): This macro creates an infinite wedge shape, an intersection of two planes. It is mainly useful in CSG, for example to obtain a specific arc of a torus. The edge of the wedge is positioned along the y axis, and one side is fixed to the zy plane, the other side rotates clockwise around the y axis.

Parameters:

  • Angle = The angle, in degrees, between the sides of the wedge shape.

Spheroid(Center, Radius): This macro creates an unevenly scaled sphere. Radius is a vector where each component is the radius along that axis.

Parameters:

  • Center = Center of the spheroid.
  • Radius = A vector specifying the radii of the spheroid.

Supertorus(MajorRadius, MinorRadius, MajorControl, MinorControl, Accuracy, MaxGradient): This macro creates an isosurface of the torus equivalent of a superellipsoid. If you specify a MaxGradient of less than 1, evaluate will be used. You will have to adjust MaxGradient to fit the parameters you choose, a squarer supertorus will have a higher gradient. You may want to use the function alone in your own isosurface.

Parameters:

  • MajorRadius, MinorRadius = Base radii for the torus.
  • MajorControl, MinorControl = Controls for the roundness of the supertorus. Use numbers in the range [0, 1].
  • Accuracy = The accuracy parameter.
  • MaxGradient = The max_gradient parameter.

Supercone(EndA, A, B, EndB, C, D): This macro creates an object similar to a cone, but where the end points are ellipses. The actual object is an intersection of a quartic with a cylinder.

Parameters:

  • EndA = Center of end A.
  • A, B = Controls for the radii of end A.
  • EndB = Center of end B.
  • C, D = Controls for the radii of end B.

Connect_Spheres(PtA, RadiusA, PtB, RadiusB): This macro creates a cone that will smoothly join two spheres. It creates only the cone object, however, you will have to supply the spheres yourself or use the Round_Cone2() macro instead.

Parameters:

  • PtA = Center of sphere A.
  • RadiusA = Radius of sphere A.
  • PtB = Center of sphere B.
  • RadiusB = Radius of sphere B.

Wire_Box_Union(PtA, PtB, Radius),

Wire_Box_Merge(PtA, PtB, Radius),

Wire_Box(PtA, PtB, Radius, UseMerge): Creates a wire-frame box from cylinders and spheres. The resulting object will fit entirely within a box object with the same corner points.

Parameters:

  • PtA = Lower-left-front corner of box.
  • PtB = Upper-right-back corner of box.
  • Radius = The radius of the cylinders and spheres composing the object.
  • UseMerge = Whether or not to use a merge.

Round_Box_Union(PtA, PtB, EdgeRadius),

Round_Box_Merge(PtA, PtB, EdgeRadius),

Round_Box(PtA, PtB, EdgeRadius, UseMerge): Creates a box with rounded edges from boxes, cylinders and spheres. The resulting object will fit entirely within a box object with the same corner points. The result is slightly different from a superellipsoid, which has no truely flat areas.

Parameters:

  • PtA = Lower-left-front corner of box.
  • PtB = Upper-right-back corner of box.
  • EdgeRadius = The radius of the edges of the box.
  • UseMerge = Whether or not to use a merge.

Round_Cylinder_Union(PtA, PtB, Radius, EdgeRadius),

Round_Cylinder_Merge(PtA, PtB, Radius, EdgeRadius),

Round_Cylinder(PtA, PtB, Radius, EdgeRadius, UseMerge): Creates a cylinder with rounded edges from cylinders and tori. The resulting object will fit entirely within a cylinder object with the same end points and radius. The result is slightly different from a superellipsoid, which has no truely flat areas.

Parameters:

  • PtA, PtB = The end points of the cylinder.
  • Radius = The radius of the cylinder.
  • EdgeRadius = The radius of the edges of the cylinder.
  • UseMerge = Whether or not to use a merge.

Round_Cone_Union(PtA, RadiusA, PtB, RadiusB, EdgeRadius),

Round_Cone_Merge(PtA, RadiusA, PtB, RadiusB, EdgeRadius),

Round_Cone(PtA, RadiusA, PtB, RadiusB, EdgeRadius, UseMerge): Creates a cone with rounded edges from cones and tori. The resulting object will fit entirely within a cone object with the same end points and radii.

Parameters:

  • PtA, PtB = The end points of the cone.
  • RadiusA, RadiusB = The radii of the cone.
  • EdgeRadius = The radius of the edges of the cone.
  • UseMerge = Whether or not to use a merge.

Round_Cone2_Union(PtA, RadiusA, PtB, RadiusB),

Round_Cone2_Merge(PtA, RadiusA, PtB, RadiusB),

Round_Cone2(PtA, RadiusA, PtB, RadiusB, UseMerge): Creates a cone with rounded edges from a cone and two spheres. The resulting object will not fit entirely within a cone object with the same end points and radii because of the spherical caps. The end points are not used for the conical portion, but for the spheres, a suitable cone is then generated to smoothly join them.

Parameters:

  • PtA, PtB = The centers of the sphere caps.
  • RadiusA, RadiusB = The radii of the sphere caps.
  • UseMerge = Whether or not to use a merge.

Round_Cone3_Union(PtA, RadiusA, PtB, RadiusB),

Round_Cone3_Merge(PtA, RadiusA, PtB, RadiusB),

Round_Cone3(PtA, RadiusA, PtB, RadiusB, UseMerge): Like Round_Cone2(), this creates a cone with rounded edges from a cone and two spheres, and the resulting object will not fit entirely within a cone object with the same end points and radii because of the spherical caps. The difference is that this macro takes the end points of the conical portion and moves the spheres to be flush with the surface, instead of putting the spheres at the end points and generating a cone to join them.

Parameters:

  • PtA, PtB = The end points of the cone.
  • RadiusA, RadiusB = The radii of the cone.
  • UseMerge = Whether or not to use a merge.

Quad(A, B, C, D) and Smooth_Quad(A, NA, B, NB, C, NC, D, ND): These macros create quads, 4-sided polygonal objects, using triangle pairs.

Parameters:

  • A, B, C, D = Vertices of the quad.
  • NA, NB, NC, ND = Vertex normals of the quad.
3.4.9.1.18.1 The HF Macros

There are several HF macros in shapes.inc, which generate meshes in various shapes. All the HF macros have these things in common:

  • The HF macros do not directly use an image for input, but evaluate a user-defined function. The macros deform the surface based on the function values.
  • The macros can either write to a file to be included later, or create an object directly. If you want to output to a file, simply specify a filename. If you want to create an object directly, specify "" as the file name (an empty string).
  • The function values used for the heights will be taken from the square that goes from <0,0,0> to <1,1,0> if UV height mapping is on. Otherwise the function values will be taken from the points where the surface is (before the deformation).
  • The texture you apply to the shape will be evaluated in the square that goes from <0,0,0> to <1,1,0> if UV texture mapping is on. Otherwise the texture is evaluated at the points where the surface is (after the deformation.

The usage of the different HF macros is described below.

HF_Square (Function, UseUVheight, UseUVtexture, Res, Smooth, FileName, MnExt, MxExt): This macro generates a mesh in the form of a square height field, similar to the built-in height_field primitive. Also see the general description of the HF macros above.

Parameters:

  • Function = The function to use for deforming the height field.
  • UseUVheight = A boolean value telling the macro whether or not to use UV height mapping.
  • UseUVtexture = A boolean value telling the macro whether or not to use UV texture mapping.
  • Res = A 2D vector specifying the resolution of the generated mesh.
  • Smooth = A boolean value telling the macro whether or not to smooth the generated mesh.
  • FileName = The name of the output file.
  • MnExt = Lower-left-front corner of a box containing the height field.
  • MxExt = Upper-right-back corner of a box containing the height field.

HF_Sphere(Function, UseUVheight, UseUVtexture, Res, Smooth, FileName, Center, Radius, Depth): This macro generates a mesh in the form of a spherical height field. When UV-mapping is used, the UV square will be wrapped around the sphere starting at +x and going anti-clockwise around the y axis. Also see the general description of the HF macros above.

Parameters:

  • Function = The function to use for deforming the height field.
  • UseUVheight = A boolean value telling the macro whether or not to use UV height mapping.
  • UseUVtexture = A boolean value telling the macro whether or not to use UV texture mapping.
  • Res = A 2D vector specifying the resolution of the generated mesh.
  • Smooth = A boolean value telling the macro whether or not to smooth the generated mesh.
  • FileName = The name of the output file.
  • Center = The center of the height field before being displaced, the displacement can, and most likely will, make the object off-center.
  • Radius = The starting radius of the sphere, before being displaced.
  • Depth = The depth of the height field.

HF_Cylinder(Function, UseUVheight, UseUVtexture, Res, Smooth, FileName, EndA, EndB, Radius,Depth): This macro generates a mesh in the form of an open-ended cylindrical height field. When UV-mapping is used, the UV square will be wrapped around the cylinder. Also see the general description of the HF macros above.

Parameters:

  • Function = The function to use for deforming the height field.
  • UseUVheight = A boolean value telling the macro whether or not to use UV height mapping.
  • UseUVtexture = A boolean value telling the macro whether or not to use UV texture mapping.
  • Res = A 2D vector specifying the resolution of the generated mesh.
  • Smooth = A boolean value telling the macro whether or not to smooth the generated mesh.
  • FileName = The name of the output file.
  • EndA, EndB = The end points of the cylinder.
  • Radius = The (pre-displacement) radius of the cylinder.
  • Depth = The depth of the height field.

HF_Torus (Function, UseUVheight, UseUVtexture, Res, Smooth, FileName, Major, Minor, Depth): This macro generates a mesh in the form of a torus-shaped height field. When UV-mapping is used, the UV square is wrapped around similar to spherical or cylindrical mapping. However the top and bottom edges of the map wrap over and under the torus where they meet each other on the inner rim. Also see the general description of the HF macros above.

Parameters:

  • Function = The function to use for deforming the height field.
  • UseUVheight = A boolean value telling the macro whether or not to use UV height mapping.
  • UseUVtexture = A boolean value telling the macro whether or not to use UV texture mapping.
  • Res = A 2D vector specifying the resolution of the generated mesh.
  • Smooth = A boolean value telling the macro whether or not to smooth the generated mesh.
  • FileName = The name of the output file.
  • Major = The major radius of the torus.
  • Minor = The minor radius of the torus.
3.4.9.1.19 Shapes2.inc
Tetrahedron
4-sided regular polyhedron.
Octahedron
8-sided regular polyhedron.
Dodecahedron
12-sided regular polyhedron.
Icosahedron
20-sided regular polyhedron.
Rhomboid
Three dimensional 4-sided diamond, basically a sheared box.
Hexagon
6-sided regular polygonal solid, axis along x.
HalfCone_Y
Convenient finite cone primitive, pointing up in the Y axis.
Pyramid
4-sided pyramid (union of triangles, can not be used in CSG).
Pyramid2
4-sided pyramid (intersection of planes, can be used in CSG).
Square_X, Square_Y, Square_Z
Finite planes stretching 1 unit along each axis. In other words, 2X2 unit squares.
3.4.9.1.20 Shapes3.inc

This file contains macros for segments of shapes, facetted shapes and others.

Segments of shapes:

Segment_of_Torus ( R_major, R_minor, Segment_Angle )
Segment of a torus around the y axis. The angle starts at positive x axis.
Segment_of_CylinderRing ( R_out, R_in, Height, Segment_Angle )
Segment of a cylindrical ring around the y axis. The angle starts at positive x axis.
Segment_of_Object ( Segment_Object, Segment_Angle )
Segment of an object around the y axis. The angle starts at positive x axis.
Based on min_extend and max_extend.

Angular shapes:

Column_N (N, R_in, Height )
A regular n-sided column around the y axis, defined by the incircle radius R_in. Height is the height in y direction.
Column_N_AB (N, A, B, R_in)
A regular n-sided column from point A to point B, defined by the incircle radius R_in.
Pyramid_N (N, R_in_1, R_in_2, Height )
A regular n-sided pyramid around the y axis, defined by the incircle radii:
R_in_1 at y = 0 and R_in_2 at y = Height.
Pyramid_N_AB(N, A, R_in_A, B, R_in_B)
A regular n-sided column from point A to point B, defined by the incircle radii:
R_in_A at point A and R_in_B at point B.

Facetted shapes:

Facetted_Sphere (Quarter_Segments, Radial_Segments)
A facetted sphere with incircle radius 1.
Quarter_Segments = number of equitorial facetts in one quarter (1/2 of the total number).
Radial_Segments = number of radial facetts.
Facetted_Egg_Shape (Quarter_Segments, Radial_Segments, Lower_Scale, Upper_Scale)
A facetted egg shape. The number of facetts are defined analog to Facetted_Egg_Shape().
Equitorial incircle radius = 1. Lower half scaled in y by Lower_Scale, Upper half scaled in y by Upper_Scale.
Facetted_Egg (N_Quarter_Segments, N_Radial_Segments)
A facetted egg with total height = 2. Lower half scaled in y by 1.15, Upper half scaled in y by 1.55.

Round shapes:

Egg_Shape (Lower_Scale, Upper_Scale)
An egg shape with equitorial radius 1.
Lower half scaled in y by Lower_Scale, Upper half scaled in y by Upper_Scale.
Egg
Uses the macro Egg_Shape.
Lower half scaled in y by 1.15, upper half scaled in y by 1.55.
Wireframe shape (mostly also optionally filled:
Ring_Sphere (Rmaj_H, Rmaj_V, Rmin_H, Rmin_V, Number_of_Rings_horizontal, Number_of_Rings_vertical)
A wireframe sphere by vertical and horizontal torii.
Horizontal tori: equatorial radius major Rmaj_H, radius minor Rmin_H.
Vertical tori: radius major Rmaj_V, radius minor Rmin_V.
Round_Pyramid_N_out (N, A, CornerR_out_A, B, CornerR_out_B, R_Border, Filled, Merge )
A regular n-sided column from point A to point B, defined by the outcircle radii: R_in_A at point A and R_in_B at point B.
Round_Pyramid_N_in (N, A, FaceR_in_A, B, FaceR_in_B, R_Border, Filled, Merge_On )
A regular n-sided column from point A to point B, defined by the incircle radii: R_in_A at point A and R_in_B at point B..
Round_Cylinder_Tube( A, B, R_out, R_border, Filled, Merge)
A cylindrical tube from point A to point B, with the outer radius R_out and the border radius R_border. The inner radius is R_out - R_border.
With Filled = 1 we get a Round_Cylinder.
Rounded_Tube( R_out, R_in, R_Border, Height, Merge)
A cylindrical tube around the y axis with the Height in y, with the outer radius R_out, the inner radius R_in and the radius of the rounded borders R_border.
Rounded_Tube_AB( A, B, R_out, R_in, R_Border, Merge)
A cylindrical tube from point A to point B.
The outer radius is R_out, the inner radius is R_in and the radius of the rounded borders is R_border.
Round_Conic_Torus( Center_Distance, R_upper, R_lower, R_border, Merge)
A toroid ring the z axis, with the lower torus part at y = 0 and the upper part at y = Center_Distance.
The radius of the lower part is R_lower, the radius of the lower part is R_lower The minor radius of the toroid is R_border.
Round_Conic_Prism( Center_Distance, R_upper, R_lower, Length_Zminus, R_Border, Merge)
A shape of the toroidal form like Round_Conic_Torus(), but filled and in the negativ z direction with the length Length_Zminus.
Half_Hollowed_Rounded_Cylinder1( Length, R_out, R_border, BorderScale, Merge)
A hollowed half rounded cylinder with the Length in x, of the outer radius R_out, with round ends. The borders have a minor radius R_border with the scale in y BorderScale.
The inner radius is R_out - R_border.
Half_Hollowed_Rounded_Cylinder2( Length, R_out, R_corner, R_border, BorderScale, Merge)
A hollowed half rounded cylinder with the Length in x, of the outer radius R_out, with flat ends. The corners have a minor radius of R_corner, the borders have a minor radius of R_border with the scale in y BorderScale.
The inner radius is R_out - R_border, the inner lenght is Length - 2*R_border.
Round_N_Tube_Polygon (N, Tube_R, R_incircle, Edge_R, Filled, Merge)
A regular polygon with N edges (or corners) with incircle radius R_incircle, formed by a tube with the minor radius Tube_R. The corners are formed by torus segments with the major radius Edge_R.
3.4.9.1.21 Shapesq.inc
Bicorn
This curve looks like the top part of a paraboloid, bounded from below by another paraboloid. The basic equation is:
y^2 - (x^2 + z^2) y^2 - (x^2 + z^2 + 2 y - 1)^2 = 0
Crossed_Trough
This is a surface with four pieces that sweep up from the x-z plane.
The equation is: y = x^2 z^2
Cubic_Cylinder
A drop coming out of water? This is a curve formed by using the equation:
y = 1/2 x^2 (x + 1)
as the radius of a cylinder having the x-axis as its central axis. The final form of the equation is:
y^2 + z^2 = 0.5 (x^3 + x^2)
Cubic_Saddle_1
A cubic saddle. The equation is: z = x^3 - y^3
Devils_Curve
Variant of a devil's curve in 3-space. This figure has a top and bottom part that are very similar to a hyperboloid of one sheet, however the central region is pinched in the middle leaving two teardrop shaped holes. The equation is:
x^4 + 2 x^2 z^2 - 0.36 x^2 - y^4 + 0.25 y^2 + z^4 = 0
Folium
This is a folium rotated about the x-axis. The formula is:
2 x^2 - 3 x y^2 - 3 x z^2 + y^2 + z^2 = 0
Glob_5
Glob - sort of like basic teardrop shape. The equation is:
y^2 + z^2 = 0.5 x^5 + 0.5 x^4
Twin_Glob
Variant of a lemniscate - the two lobes are much more teardrop-like.
Helix, Helix_1
Approximation to the helix z = arctan(y/x). The helix can be approximated with an algebraic equation (kept to the range of a quartic) with the following steps:
tan(z) = y/x => sin(z)/cos(z) = y/x =>
(1) x sin(z) - y cos(z) = 0 Using the taylor expansions for sin, cos about z = 0,
sin(z) = z - z^3/3! + z^5/5! - ...
cos(z) = 1 - z^2/2! + z^6/6! - ...
Throwing out the high order terms, the expression (1) can be written as:
x (z - z^3/6) - y (1 + z^2/2) = 0, or

(2) -1/6 x z^3 + x z + 1/2 y z^2 - y = 0
This helix (2) turns 90 degrees in the range 0 <= z <= sqrt(2)/2. By using scale <2 2 2>, the helix defined below turns 90 degrees in the range 0 <= z <= sqrt(2) = 1.4042.
Hyperbolic_Torus
Hyperbolic Torus having major radius sqrt(40), minor radius sqrt(12). This figure is generated by sweeping a circle along the arms of a hyperbola. The equation is:
x^4 + 2 x^2 y^2 - 2 x^2 z^2 - 104 x^2 + y^4 - 2 y^2 z^2 + 56 y^2 + z^4 + 104 z^2 + 784 = 0
Lemniscate
Lemniscate of Gerono. This figure looks like two teardrops with their pointed ends connected. It is formed by rotating the Lemniscate of Gerono about the x-axis. The formula is:
x^4 - x^2 + y^2 + z^2 = 0
Quartic_Loop_1
This is a figure with a bumpy sheet on one side and something that looks like a paraboloid (but with an internal bubble). The formula is:
(x^2 + y^2 + a c x)^2 - (x^2 + y^2)(c - a x)^2
-99*x^4+40*x^3-98*x^2*y^2-98*x^2*z^2+99*x^2+40*x*y^2
+40*x*z^2+y^4+2*y^2*z^2-y^2+z^4-z^2
Monkey_Saddle
This surface has three parts that sweep up and three down. This gives a saddle that has a place for two legs and a tail. The equation is:
z = c (x^3 - 3 x y^2)
The value c gives a vertical scale to the surface - the smaller the value of c, the flatter the surface will be (near the origin).
Parabolic_Torus_40_12
Parabolic Torus having major radius sqrt(40), minor radius sqrt(12). This figure is generated by sweeping a circle along the arms of a parabola. The equation is:
x^4 + 2 x^2 y^2 - 2 x^2 z - 104 x^2 + y^4 - 2 y^2 z + 56 y^2 + z^2 + 104 z + 784 = 0
Piriform
This figure looks like a hersheys kiss. It is formed by sweeping a Piriform about the x-axis. A basic form of the equation is:
(x^4 - x^3) + y^2 + z^2 = 0.
Quartic_Paraboloid
Quartic parabola - a 4th degree polynomial (has two bumps at the bottom) that has been swept around the z axis. The equation is:
0.1 x^4 - x^2 - y^2 - z^2 + 0.9 = 0
Quartic_Cylinder
Quartic Cylinder - a Space Needle?
Steiner_Surface
Steiners quartic surface
Torus_40_12
Torus having major radius sqrt(40), minor radius sqrt(12).
Witch_Hat
Witch of Agnesi.
Sinsurf
Very rough approximation to the sin-wave surface z = sin(2 pi x y).
In order to get an approximation good to 7 decimals at a distance of 1 from the origin would require a polynomial of degree around 60, which would require around 200,000 coefficients. For best results, scale by something like <1 1 0.2>.
3.4.9.1.22 Skies.inc

These files contain some predefined skies for you to use in your scenes.

skies.inc: There are textures and pigment definitions in this file.

  • all pigment definitions start with "P_"
  • all sky_spheres start with "S_"
  • all textures start with "T_"
  • and all objects start with "O_"

Pigments:

P_Cloud1
P_Cloud2
P_Cloud3

Sky Spheres:

S_Cloud1
This sky_sphere uses P_Cloud2 and P_Cloud3.
S_Cloud2
This sky_sphere uses P_Cloud4.
S_Cloud3
This sky_sphere uses P_Cloud2.
S_Cloud4
This sky_sphere uses P_Cloud3.
S_Cloud5
This sky_sphere uses a custom pigment.

Textures:

T_Cloud1
2-layer texture using P_Cloud1 pigment, contains clear regions.
T_Cloud2
1-layer texture, contains clear regions.
T_Cloud3
2-layer texture, contains clear regions.

Objects:

O_Cloud1
Sphere, radius 10000 with T_Cloud1 texture.
O_Cloud2
Union of 2 planes, with T_Cloud2 and T_Cloud3.
3.4.9.1.23 Stars.inc

stars.inc: This file contains predefined starfield textures. The starfields become denser and more colorful with the number, with Starfield6 being the densest and most colorful.

Starfield1
Starfield2
Starfield3
Starfield4
Starfield5
Starfield6
3.4.9.1.24 Stones.inc

The file stones.inc simply includes both stones1.inc and stones2.inc, and the file stoneold.inc provides backwards compatability for old scenes, the user is advised to use the textures in stones1.inc instead.

The two files stones1.inc and stones2.inc contain lists of predefined stone textures.

The file stones1.inc contains texture definitions for:

  • T_Grnt0 to T_Grnt29
  • T_Grnt1a to T_Grnt24a
  • T_Stone0 to T_Stone24

The T_GrntXX, T_GrntXXa, and CrackX textures are building blocks that are used to create the final usable T_StoneX textures (and other textures that *you* design, of course!)

The T_GrntXX textures generally contain no transparency, but the T_GrntXXa textures DO contain transparency. The CrackX textures are clear with thin opaque bands, simulating cracks.

The file stones2.inc provides additional stone textures, and contains texture definitions for T_Stone25 to T_Stone44.

3.4.9.1.25 Stdinc.inc

This file simply includes the most commonly used include files, so you can get all of them with a single #include. The files included are:

  • colors.inc
  • shapes.inc
  • transforms.inc
  • consts.inc
  • functions.inc
  • math.inc
  • rand.inc
3.4.9.1.26 Strings.inc

This include contains macros for manipulating and generating text strings.

CRGBStr(C, MinLen, Padding) and CRGBFTStr(C, MinLen, Padding): These macros convert a color to a string. The format of the output string is "rgb < R, G, B>" or "rgbft < R, G, B, F, T>", depending on the macro being called.

Parameters:

  • C = The color to be turned into a string.
  • MinLen = The minimum length of the individual components, analogous to the second parameter of str().
  • Padding = The padding to use for the components, see the third parameter of the str() function for details.

Str(A): This macro creates a string containing a float with the systems default precision. It is a shortcut for using the str() function.

Parameters:

  • A = The float to be converted to a string.

VStr2D(V), VStr(V): These macros create strings containing vectors using POV syntax (<X,Y,Z>) with the default system precision. VStr2D() works with 2D vectors, VStr() with 3D vectors. They are shortcuts for using the vstr() function.

Parameters:

  • V = The vector to be converted to a string.

Vstr2D(V,L,P), Vstr(V,L,P): These macros create strings containing vectors using POV syntax (<X,Y,Z>) with user specified precision. Vstr2D() works with 2D vectors, Vstr() with 3D vectors. They are shortcuts for using the vstr() function. The function of L and P is the same as in vstr specified in String Functions.

Parameters:

  • V = The vector to be converted to a string.
  • L = Minimum length of the string and the type of left padding used if the string's representation is shorter than the minimum.
  • P = Number of digits after the decimal point.

Triangle_Str(A, B, C) and Smooth_Triangle_Str(A, NA, B, NB, C, NC): These macros take vertex and normal information and return a string representing a triangle in POV-Ray syntax. They are mainly useful for generating mesh files.

Parameters:

  • A, B, C = Triangle vertex points.
  • NA, NB, NC = Triangle vertex normals (Smooth_Triangle_Str() only).

Parse_String(String): This macro takes a string, writes it to a file, and then includes that file. This has the effect of parsing that string: "Parse_String("MyColor")" will be seen by POV-Ray as "MyColor".

Parameters:

  • String = The string to be parsed.
3.4.9.1.27 Sunpos.inc

This file only contains the sunpos() macro

sunpos(Year, Month, Day, Hour, Minute, Lstm, LAT, LONG): The macro returns the position of the sun, for a given date, time, and location on earth. The suns position is also globally declared as the vector SolarPosition. Two other declared vectors are the Az (Azimuth) and Al (Altitude), these can be useful for aligning an object (media container) with the sunlight. Assumption: in the scene north is in the +Z direction, south is -Z.

Parameters:

  • Year= The year in four digits.
  • Month= The month number (1-12).
  • Day= The day number (1-31).
  • Hour= The hour of day in 24 hour format (0-23).
  • Minute= The minutes (0-59).
  • Lstm= Meridian of your local time zone in degrees (+1 hour = +15 deg, east = positive, west = negative)
  • LAT= Lattitude in degrees.decimal, northern hemisphere = positive, southern = negative
  • LONG= Longitude in degrees.decimal, east = positive, west is negative

Usage:

#include "sunpos.inc"

light_source {
  //Greenwich, noon on the longest day of 2000
  SunPos(2000, 6, 21, 12, 2, 0, 51.4667, 0.00)
  rgb 1
  }

cylinder{
  <-2,0,0>,<2,0,0>,0.1
  rotate <0, Az-90, Al>  //align cylinder with sun
  texture {...}
  }

Note: The default distance of the sun from the origin is 1e+9 units.

3.4.9.1.28 Textures.inc

This file contains many predefined textures, including wood, glass, and metal textures, and a few texture/pattern generation macros.

3.4.9.1.28.1 Stones

Stone Pigments:

Jade_Map, Jade
Drew Wells' superb Jade. Color map works nicely with other textures, too.
Red_Marble_Map, Red_Marble
Classic white marble with red veins. Over-worked, like checkers.
White_Marble_Map, White_Marble
White marble with black veins.
Blood_Marble_Map, Blood_Marble
Light blue and black marble with a thin red vein.
Blue_Agate_Map, Blue_Agate
A grey blue agate -- kind of purplish.
Sapphire_Agate_Map, Sapphire_Agate
Deep blue agate -- almost glows.
Brown_Agate_Map, Brown_Agate
Brown and white agate -- very pretty.
Pink_Granite_Map, Pink_Granite
Umm, well, pink granite.

Stone textures:

PinkAlabaster
Gray-pink alabaster or marble. Layers are scaled for a unit object and relative to each other.

Note: This texture has very tiny dark blue specks that are often mistaken for rendering errors.

Underlying surface is very subtly mottled with bozo.
Second layer texture has some transmit values, yet a fair amount of color.
Veining is kept quite thin in color map and by the largish scale.
3.4.9.1.28.2 Skies

Sky pigments:

Blue_Sky_Map, Blue_Sky
Basic blue sky with clouds.
Bright_Blue_Sky
Bright blue sky with very white clouds.
Blue_Sky2
Another sky.
Blue_Sky3
Small puffs of white clouds.
Blood_Sky
Red sky with yellow clouds -- very surreal.
Apocalypse
Black sky with red and purple clouds.
Try adding turbulence values from 0.1 - 5.0
Clouds
White clouds with transparent sky.
FBM_Clouds
Shadow_Clouds
A multilayered cloud texture (a real texture, not a pigment).
3.4.9.1.28.3 Woods

Wood pigments:

Several wooden pigments by Tom Price:

Cherry_Wood
A light reddish wood.
Pine_Wood
A light tan wood whiteish rings.
Dark_Wood
Dark wood with a,ish hue to it.
Tan_Wood
Light tan wood with brown rings.
White_Wood
A very pale wood with tan rings -- kind of balsa-ish.
Tom_Wood
Brown wood - looks stained.
DMFWood1, DMFWood2, DMFWood3, DMFWood4, DMFWood5
The scaling in these definitions is relative to a unit-sized object (radius 1).

Note: These wood definitions are functionally equivalent to a log lying along the z axis. For best results, think like a woodcutter trying to extract the nicest board out of that log. A little tilt along the x axis will give elliptical rings of grain like you would expect to find on most boards.

Wood textures:

DMFWood6
This is a three-layer wood texture. Renders rather slowly because of the transparent layers and the two layers of turbulence, but it looks great. Try other colors of varnish for simple variations.
DMFLightOak
Is this really oak? I dunno. Quite light, maybe more like spruce.
DMFDarkOak
Looks like old desk oak if used correctly.
EMBWood1
Wood by Eric Barish

Doug Otwell woods:

Yellow_Pine
Yellow pine, close grained.
Rosewood
Sandalwood
makes a great burled maple, too
3.4.9.1.28.4 Glass

Glass_Finish is a generic glass finish, Glass_Interior is a generic glass interior, it just adds an ior of 1.5.

Glass materials:

M_Glass
Just glass.
M_Glass2
Probably more of a Plexiglas than glass.
M_Glass3
An excellent lead crystal glass!
M_Green_Glass

Glass textures contributed by Norm Bowler, of Richland WA. NBglass_finish is used by these materials.

M_NBglass
M_NBoldglass
M_NBwinebottle
M_NBbeerbottle

A few color variations on Norm's glass.

M_Ruby_Glass
M_Dark_Green_Glass
M_Yellow_Glass
M_Orange_Glass
M_Vicks_Bottle_Glass
3.4.9.1.28.5 Metals

Metal finishes:

Metal
Generic metal finish.
SilverFinish
Basic silver finish
Metallic_Finish

Metal textures:

Chrome_Metal, Brass_Metal, Bronze_Metal, Gold_Metal, Silver_Metal, Copper_Metal
A series of metallic textures using the Metal finish (except for Chrome_Metal, which has a custom finish). There are identical textures ending in _Texture instead of _Metal, but use of those names is discouraged.
Polished_Chrome
A highly reflective Chrome texture.
Polished_Brass
A highly reflective brass texture.
New_Brass
Beautiful military brass texture!
Spun_Brass
Spun Brass texture for cymbals & such
Brushed_Aluminum
Brushed aluminum (brushed along X axis)
Silver1
Silver2
Silver3
Brass_Valley
Sort of a Black Hills Gold, black, white, and orange specks or splotches.
Rust
Rusty_Iron
Soft_Silver
New_Penny
Tinny_Brass
Gold_Nugget
Aluminum
Bright_Bronze
3.4.9.1.28.6 Special textures
Candy_Cane
Red and white stripes - Looks best on a y axis Cylinder.
It spirals because it's gradient on two axis.
Peel
Orange and Clear stripes spiral around the texture to make an object look like it was Peeled. Now, you too can be M.C. Escher!
Y_Gradient
X_Gradient
M_Water
Wavy water material. Requires a sub-plane, and may require scaling to fit your scene.

Warning: Water texture has been changed to M_Water material, see explanation in the glass section of this file.

Cork
Lightning_CMap1, Lightning1, and Lightning_CMap2, Lightning2
These are just lightning textures, they look like arcing electricity...earlier versions misspelled them as Lightening.
Starfield
A starfield texture by Jeff Burton
3.4.9.1.28.7 Texture and pattern macros

Irregular_Bricks_Ptrn (Mortar Thickness, X-scaling, Variation, Roundness): This function pattern creates a pattern of bricks of varying lengths on the x-y plane. This can be useful in building walls that do not look like they were built by a computer. Note that mortar thickness between bricks can vary somewhat, too.

Parameters:

  • Mortar Thickness = Thickness of the mortar (0-1).
  • X-scaling = The scaling of the bricks (but not the mortar) in the x direction.
  • Variation = The amount by which brick lengths will vary (0=none, 1=100%).
  • Roundness = The roundness of the bricks (0.01=almost rectangular, 1=very round).

Tiles_Ptrn(): This macro creates a repeating box pattern on the x-y plane. It can be useful for creating grids. The cells shade continuously from the center to the edges.

Parameters: None.

Hex_Tiles_Ptrn(): This macro creates a pattern that is a sort of cross between the hexagon pattern and a repeating box pattern. The hexagonal cells shade continuously from the center to the edges.

Parameters: None.

Star_Ptrn (Radius, Points, Skip): This macro creates a pattern that resembles a star. The pattern is in the x-y plane, centered around the origin.

Parameters:

  • Radius = The radius of a circle drawn through the points of the star.
  • Points = The number of points on the star.
  • Skip = The number of points to skip when drawing lines between points to form the star. A normal 5-pointed star skips 2 points. A Star of David also skips 2 points. Skip must be less than Points/2 and greater than 0. Integers are preferred but not required. Skipping 1 point makes a regular polygon with Points sides.
  • Pigment = The pigment to be applied to the star.
  • Background = The pigment to be applied to the background.
3.4.9.1.29 Transforms.inc

Several useful transformation macros. All these macros produce transformations, you can use them anywhere you can use scale, rotate, etc. The descriptions will assume you are working with an object, but the macros will work fine for textures, etc.

Shear_Trans(A, B, C): This macro reorients and deforms an object so its original XYZ axes point along A, B, and C, resulting in a shearing effect when the vectors are not perpendicular. You can also use vectors of different lengths to affect scaling, or use perpendicular vectors to reorient the object.

Parameters:

  • A, B, C = Vectors representing the new XYZ axes for the transformation.

Matrix_Trans(A, B, C, D): This macro provides a way to specify a matrix transform with 4 vectors. The effects are very similar to that of the Shear_Trans() macro, but the fourth parameter controls translation.

Parameters:

  • A, B, C, D = Vectors for each row of the resulting matrix.

Axial_Scale_Trans(Axis, Amt): A kind of directional scale, this macro will stretch an object along a specified axis.

Parameters:

  • Axis = A vector indicating the direction to stretch along.
  • Amt = The amount to stretch.

Axis_Rotate_Trans(Axis, Angle): This is equivalent to the transformation done by the vaxis_rotate() function, it rotates around an arbitrary axis.

Parameters:

  • Axis = A vector representing the axis to rotate around.
  • Angle = The amount to rotate by.

Rotate_Around_Trans(Rotation, Point): Ordinary rotation operates around the origin, this macro rotates around a specific point.

Parameters:

  • Rotation = The rotation vector, the same as the parameter to the rotate keyword.
  • Point = The point to rotate around.

Reorient_Trans(Axis1, Axis2): This aligns Axis1 to Axis2 by rotating the object around a vector perpendicular to both axis1 and axis2.

Parameters:

  • Axis1 = Vector to be rotated.
  • Axis2 = Vectors to be rotated towards.

Point_At_Trans(YAxis): This macro is similar to Reorient_Trans(), but it points the y axis along Axis.

Parameters:

  • YAxis = The direction to point the y axis in.

Center_Trans(Object, Axis): Calculates a transformation which will center an object along a specified axis. You indicate the axes you want to center along by adding "x", "y", and "z" together in the Axis parameter.

Note: This macro actually computes the transform to center the bounding box of the object, which may not be entirely accurate. There is no way to define the center of an arbitrary object.

Parameters:

  • Object = The object the center transform is being computed for.
  • Axis = The axes to center the object on.

Usage:

object {MyObj Center_Trans(MyObj, x)} //center along x axis

You can also center along multiple axes:

object {MyObj Center_Trans(MyObj, x+y)} //center along x and y axis

Align_Trans(Object, Axis, Pt): Calculates a transformation which will align the sides of the bounding box of an object to a point. Negative values on Axis will align to the sides facing the negative ends of the coordinate system, positive values will align to the opposite sides, 0 means not to do any alignment on that axis.

Parameters:

  • Object = The object being aligned.
  • Axis = A combination of +x, +y, +z, -x, -y, and -z, or a vector where each component is -1, 0, or +1 specifying the faces of the bounding box to align to the point.
  • Point = The point to which to align the bounding box of the object.

Usage:

object {
  MyObj
  Align_Trans(MyObj, x, Pt) //Align right side of object to be
                            //coplanar with Pt
  Align_Trans(MyObj,-y, Pt) //Align bottom of object to be
                            // coplanar with Pt
  }

vtransform(Vect, Trans) and vinv_transform(Vect, Trans): The vtransform() macro takes a transformation (rotate, scale, translate, etc...) and a point, and returns the result of applying the transformation to the point. The vinv_transform() macro is similar, but applies the inverse of the transform, in effect undoing the transformation. You can combine transformations by enclosing them in a transform block.

Parameters:

  • Vect = The vector to which to apply the transformation.
  • Trans = The transformation to apply to Vect.

Spline_Trans(Spline, Time, SkyVector, ForeSight, Banking): This macro aligns an object to a spline for a given time value. The Z axis of the object will point in the forward direction of the spline and the Y axis of the object will point upwards.

Parameters:

  • Spline = The spline that the object is aligned to.
  • Time = The time value to feed to the spline, for example clock.
  • Sky = The vector that is upwards in your scene, usually y.
  • Foresight = A positive value that controls how much in advance the object will turn and bank. Values close to 0 will give precise results, while higher values give smoother results. It will not affect parsing speed, so just find the value that looks best.
  • Banking = How much the object tilts when turning. The amount of tilting is equally much controlled by the ForeSight value.

Usage:

object {MyObj Spline_Trans(MySpline, clock, y, 0.1, 0.5)}
3.4.9.1.30 Woods.inc

The file woods.inc contains predefined wood textures and pigments.

The pigments are prefixed with P_, and do not have color_maps, allowing you to specify a color map from woodmaps.inc or create your own. There are two groups, "A" and "B": the A series is designed to work better on the bottom texture layer, and the B series is designed for the upper layers, with semitransparent color maps. The pigments with the same number were designed to work well together, but you do not necessarily have to use them that way.

The textures are prefixed with T_, and are ready to use. They are designed with the major axis of the woodgrain cylinder aligned along the Z axis. With the exception of the few of the textures which have a small amount of rotation built-in, the textures will exhibit a very straight grain pattern unless you apply a small amount of x-axis rotation to them (generally 2 to 4 degrees seems to work well).

Pigments:

P_WoodGrain1A, ..., P_WoodGrainA
P_WoodGrain1B, ..., P_WoodGrainB

Textures:

T_Wood1
Natural oak (light)
T_Wood2
Dark brown
T_Wood3
Bleached oak (white)
T_Wood4
Mahogany (purplish-red)
T_Wood5
Dark yellow with reddish overgrain
T_Wood6
Cocabola (red)
T_Wood7
Yellow pine (ragged grain)
T_Wood8
Dark brown. Walnut?
T_Wood9
Yellowish-brown burl (heavily turbulated)
T_Wood10
Soft pine (light yellow, smooth grain)
T_Wood11
Spruce (yellowish, very straight, fine grain)
T_Wood12
Another very dark brown. Walnut-stained pine, perhaps?
T_Wood13
Very straight grained, whitish
T_Wood14
Red, rough grain
T_Wood15
Medium brown
T_Wood16
Medium brown
T_Wood17
Medium brown
T_Wood18
Orange
T_Wood19, ..., T_Wood30
Golden Oak.
T_Wood31
A light tan wood - heavily grained (variable coloration)
T_Wood32
A rich dark reddish wood, like rosewood, with smooth-flowing grain
T_Wood33
Similar to T_WoodB, but brighter
T_Wood34
Reddish-orange, large, smooth grain.
T_Wood35
Orangish, with a grain more like a veneer than a plank
3.4.9.1.31 Woodmaps.inc

The file woodmaps.inc contains color_maps designed for use in wood textures. The M_WoodXA maps are intended to be used in the first layer of a multilayer texture, but can be used in single-layer textures. The M_WoodXB maps contain transparent areas, and are intended to be used in upper texture layers.

Color maps:

M_Wood1A, ..., M_Wood19A
M_Wood1B, ..., M_Wood19B

3.4.9.2 Old Files

These files could be considered either obsolete or deprecated. They have been included for legacy reasons.

3.4.9.2.1 Glass_old.inc

This file contains glass textures for POV-Ray versions 3.1 and earlier. These textures do not take advantage of the new features introduced with POV-Ray 3.5 and are included for backwards compatability, you will get better results with the materials in glass.inc.

Note: As of version 3.7 the definitions in glass_old.inc have been deprecated. To suppress warnings generated from using these textures you should consider converting them to materials.

Using the following example:

texture {T_Glass4} interior {I_Glass caustics 1}

should be rewritten as:

material {
  texture {
    pigment { color rgbf <0.98, 1.0, 0.99, 0.75> }
    finish { F_Glass4 }
    }
  interior { I_Glass caustics 1 }
  }
3.4.9.2.1.1 Glass finishes

F_Glass1, ..., F_Glass4

3.4.9.2.1.2 Glass textures
T_Glass1
Simple clear glass.
T_Glass2
More like an acrylic plastic.
T_Glass3
An excellent lead crystal glass.
T_Glass4
T_Old_Glass
T_Winebottle_Glass
T_Beerbottle_Glass
T_Ruby_Glass
T_Green_Glass
T_Dark_Green_Glass
T_Yellow_Glass
T_Orange_Glass
Orange/amber glass.
T_Vicksbottle_Glass
3.4.9.2.2 Shapes_old.inc
Ellipsoid, Sphere
Unit-radius sphere at the origin.
Cylinder_X, Cylinder_Y, Cylinder_Z
Infinite cylinders.
QCone_X, QCone_Y, QCone_Z
Infinite cones.
Cone_X, Cone_Y, Cone_Z
Closed capped cones: unit-radius at -1 and 0 radius at +1 along each axis.
Plane_YZ, Plane_XZ, Plane_XY
Infinite planes passing through the origin.
Paraboloid_X, Paraboloid_Y, Paraboloid_Z
y^2 + z^2 - x = 0
Hyperboloid, Hyperboloid_Y
y - x^2 + z^2 = 0
UnitBox, Cube
A cube 2 units on each side, centered on the origin.
Disk_X, Disk_Y, Disk_Z
Capped cylinders, with a radius of 1 unit and a length of 2 units, centered on the origin.
3.4.9.2.3 Stage1.inc

This file simply contains a camera, a light_source, and a ground plane, and includes colors.inc, textures.inc, and shapes.inc.

3.4.9.2.4 Stdcam.inc

This file simply contains a camera, a light_source, and a ground plane.

3.4.9.2.5 Stones1.inc
T_Grnt0
Gray/Tan with Rose.
T_Grnt1
Creamy Whites with Yellow & Light Gray.
T_Grnt2
Deep Cream with Light Rose, Yellow, Orchid, & Tan.
T_Grnt3
Warm tans olive & light rose with cream.
T_Grnt4
Orchid, Sand & Mauve.
T_Grnt5
Medium Mauve Med.Rose & Deep Cream.
T_Grnt6
Med. Orchid, Olive & Dark Tan mud pie.
T_Grnt7
Dark Orchid, Olive & Dark Putty.
T_Grnt8
Rose & Light Cream Yellows
T_Grnt9
Light Steely Grays
T_Grnt10
Gray Creams & Lavender Tans
T_Grnt11
Creams & Grays Kahki
T_Grnt12
Tan Cream & Red Rose
T_Grnt13
Cream Rose Orange
T_Grnt14
Cream Rose & Light Moss w/Light Violet
T_Grnt15
Black with subtle chroma
T_Grnt16
White Cream & Peach
T_Grnt17
Bug Juice & Green
T_Grnt18
Rose & Creamy Yellow
T_Grnt19
Gray Marble with White feather Viens
T_Grnt20
White Marble with Gray feather Viens
T_Grnt21
Green Jade
T_Grnt22
Clear with White feather Viens (has some transparency)
T_Grnt23
Light Tan to Mauve
T_Grnt24
Light Grays
T_Grnt25
Moss Greens & Tan
T_Grnt26
Salmon with thin Green Viens
T_Grnt27
Dark Green & Browns
T_Grnt28
Red Swirl
T_Grnt29
White, Tan, w/ thin Red Viens
T_Grnt0a
Translucent T_Grnt0
T_Grnt1a
Translucent T_Grnt1
T_Grnt2a
Translucent T_Grnt2
T_Grnt3a
Translucent T_Grnt3
T_Grnt4a
Translucent T_Grnt4
T_Grnt5a
Translucent T_Grnt5
T_Grnt6a
Translucent T_Grnt6
T_Grnt7a
Translucent T_Grnt7
T_Grnt8a
Aqua Tints
T_Grnt9a
Transmit Creams With Cracks
T_Grnt10a
Transmit Cream Rose & light yellow
T_Grnt11a
Transmit Light Grays
T_Grnt12a
Transmit Creams & Tans
T_Grnt13a
Transmit Creams & Grays
T_Grnt14a
Cream Rose & light moss
T_Grnt15a
Transmit Sand & light Orange
T_Grnt16a
Cream Rose & light moss (again?)
T_Grnt17a
???
T_Grnt18a
???
T_Grnt19a
Gray Marble with White feather Viens with Transmit
T_Grnt20a
White Feather Viens
T_Grnt21a
Thin White Feather Viens
T_Grnt22a
???
T_Grnt23a
Transparent Green Moss
T_Grnt24a
???
T_Crack1
T_Crack & Red Overtint
T_Crack2
Translucent Dark T_Cracks
T_Crack3
Overtint Green w/ Black T_Cracks
T_Crack4
Overtint w/ White T_Crack

The StoneXX textures are the complete textures, ready to use.

T_Stone1
Deep Rose & Green Marble with large White Swirls
T_Stone2
Light Greenish Tan Marble with Agate style veining
T_Stone3
Rose & Yellow Marble with fog white veining
T_Stone4
Tan Marble with Rose patches
T_Stone5
White Cream Marble with Pink veining
T_Stone6
Rose & Yellow Cream Marble
T_Stone7
Light Coffee Marble with darker patches
T_Stone8
Gray Granite with white patches
T_Stone9
White & Light Blue Marble with light violets
T_Stone10
Dark Brown & Tan swirl Granite with gray undertones
T_Stone11
Rose & White Marble with dark tan swirl
T_Stone12
White & Pinkish Tan Marble
T_Stone13
Medium Gray Blue Marble
T_Stone14
Tan & Olive Marble with gray white veins
T_Stone15
Deep Gray Marble with white veining
T_Stone16
Peach & Yellow Marble with white veining
T_Stone17
White Marble with gray veining
T_Stone18
Green Jade with white veining
T_Stone19
Peach Granite with white patches & green trim
T_Stone20
Brown & Olive Marble with white veining
T_Stone21
Red Marble with gray & white veining
T_Stone22
Dark Tan Marble with gray & white veining
T_Stone23
Peach & Cream Marble with orange veining
T_Stone24
Green & Tan Moss Marble
3.4.9.2.6 Stones2.inc

T_Stone25, ..., T_Stone44

3.4.9.3 Other Files

There are various other files in the include files collection. For example font files, color maps, and images for use in height fields or image maps.

3.4.9.3.1 Font Files

The fonts cyrvetic.ttf and timrom.ttf were donated to the POV-Team by their creator, Ted Harrison (CompuServe:70220,344) and were built using his FontLab for Windows by SoftUnion, Ltd. of St. Petersburg, Russia.

The font crystal.ttf was donated courtesy of Jerry Fitzpatrick, Red Mountain Corporation, redmtn [at] ix.netcom.com

The font povlogo.ttf is created by Fabien Mosen and based on the POV-Ray logo design by Chris Colefax.

crystal.ttf
A fixed space programmer's font.
cyrvetic.ttf
A proportional spaces sans-serif font.
timrom.ttf
A proportional spaces serif font.
povlogo.ttf
Only contains the POV-Ray logo.

Note: In version 3.7 these fonts were built-in to the application. See the text object for more details.

3.4.9.3.2 Color Map Files

These are 255-color color_maps, and are in individual files because of their size.

ash.map
benediti.map
bubinga.map
cedar.map
marbteal.map
orngwood.map
pinkmarb.map
rdgranit.map
teak.map
whiteash.map
3.4.9.3.3 Image Files
bumpmap_.png
A color mandelbrot fractal image, presumably intended for use as a bumpmap.
fract003.png
Some kind of fractal landscape, with color for blue water, brown land, and white peaks.
maze.png
A maze.
mtmand.pot
A grayscale mandelbrot fractal.
mtmandj.png
A 2D color julia fractal.
plasma2.png, plasma3.png
Plasma fractal images, mainly useful for landscape height fields. The file plasma3.png is a smoother version of plasma2.png, plasma1.png does not exist.
povmap.png
The text "Persistance of Vision" in green on a blue background, framed in black and red.
test.png
A test image, the image is divided into 4 areas of different colors (magenta, yellow, cyan, red) with black text on them, and the text "POV-Ray" is centered on the image in white.
spiral.df3
A 3D bitmap density file. A spiral, galaxy shape.


Welcome

The Persistence of Vision Raytracer

Introduction

Welcome to the POV-Ray for Windows version 3.7 documentation.

This content is divided into three major sections. A platform specific section, a tutorial section, and a reference section. New to POV-Ray? You'd most likely want to begin with the tutorial section. Need to locate something quickly? The list of identifiers and keywords is a good place to start. See the changes and new features summary for what's new with this release.

Enjoy!