Persistence of Vision (tm) Ray-Tracer POV-Ray (tm) Version 3.1g User's Documentation May 1999 Copyright 1999 POV-Team (tm) POV-Ray (tm) is based on DKBTrace 2.12 by David K. Buck and Aaron A. Collins. POV-Ray, POV-Help, POV-Team, and Persistence of Vision are trademarks of the POV-Team. 1 Introduction 1.1 Program Description 1.2 What is Ray-Tracing? 1.3 What is POV-Ray? 1.4 How Do I Begin? 1.5 Notation and Basic Assumptions 1.6 What's New in POV-Ray 3.1? 1.6.1 Media Replaces Halo & Atmosphere 1.6.2 New #macro Feature 1.6.3 Arrays Added 1.6.4 File I/O and other Directives 1.6.5 Additional New Features 2 Beginning Tutorial 2.1 Our First Image 2.1.1 Understanding POV-Ray's Coordinate System 2.1.2 Adding Standard Include Files 2.1.3 Adding a Camera 2.1.4 Describing an Object 2.1.5 Adding Texture to an Object 2.1.6 Defining a Light Source 2.2 Simple Shapes 2.2.1 Box Object 2.2.2 Cone Object 2.2.3 Cylinder Object 2.2.4 Plane Object 2.3 CSG Objects 2.3.1 What is CSG? 2.3.2 CSG Union 2.3.3 CSG Intersection 2.3.4 CSG Difference 2.3.5 CSG Merge 2.3.6 CSG Pitfalls 2.3.6.1 Coincidence Surfaces 2.4 Advanced Shapes 2.4.1 Bicubic Patch Object 2.4.2 Blob Object 2.4.2.1 Component Types and Other New Features 2.4.2.2 Complex Blob Constructs and Negative Strength 2.4.3 Height Field Object 2.4.4 Lathe Object 2.4.4.1 Understanding The Concept of Splines 2.4.5 Mesh Object 2.4.6 Polygon Object 2.4.7 Prism Object 2.4.7.1 Teaching An Old Spline New Tricks 2.4.7.2 Smooth Transitions 2.4.7.3 Multiple Sub-Shapes 2.4.7.4 Conic Sweeps And The Tapering Effect 2.4.8 Superquadric Ellipsoid Object 2.4.9 Surface of Revolution Object 2.4.10 Text Object 2.4.11 Torus Object 2.5 The Light Source 2.5.1 The Pointlight Source 2.5.2 The Spotlight Source 2.5.3 The Cylindrical Light Source 2.5.4 The Area Light Source 2.5.5 The Ambient Light Source 2.5.6 Light Source Specials 2.5.6.1 Using Shadowless Lights 2.5.6.2 Assigning an Object to a Light Source 2.5.6.3 Using Light Fading 2.6 Simple Texture Options 2.6.1 Surface Finishes 2.6.2 Adding Bumpiness 2.6.3 Creating Color Patterns 2.6.4 Pre-defined Textures 2.7 Advanced Texture Options 2.7.1 Pigments 2.7.1.1 Using Color List Pigments 2.7.1.2 Using Pigment and Patterns 2.7.1.3 Using Pattern Modifiers 2.7.1.4 Using Transparent Pigments and Layered Textures 2.7.1.5 Using Pigment Maps 2.7.2 Normals 2.7.2.1 Using Basic Normal Modifiers 2.7.2.2 Blending Normals 2.7.3 Finishes 2.7.3.1 Using Ambient 2.7.3.2 Using Surface Highlights 2.7.3.3 Using Reflection and Metallic 2.7.3.4 Using Iridescence 2.7.4 Working With Pigment Maps 2.7.5 Working With Normal Maps 2.7.6 Working With Texture Maps 2.7.7 Working With List Textures 2.7.8 What About Tiles? 2.7.9 Average Function 2.7.10 Working With Layered Textures 2.7.10.1 Declaring Layered Textures 2.7.10.2 Another Layered Textures Example 2.7.11 When All Else Fails: Material Maps 2.7.12 Limitations Of Special Textures 2.8 Using the Camera 2.8.1 Using Focal Blur 2.9 Using Atmospheric Effects 2.9.1 The Background 2.9.2 The Sky Sphere 2.9.2.1 Creating a Sky with a Color Gradient 2.9.2.2 Adding the Sun 2.9.2.3 Adding Some Clouds 2.9.3 The Fog 2.9.3.1 A Constant Fog 2.9.3.2 Setting a Minimum Translucency 2.9.3.3 Creating a Filtering Fog 2.9.3.4 Adding Some Turbulence to the Fog 2.9.3.5 Using Ground Fog 2.9.3.6 Using Multiple Layers of Fog 2.9.3.7 Fog and Hollow Objects 2.9.4 The Rainbow 2.9.4.1 Starting With a Simple Rainbow 2.9.4.2 Increasing the Rainbow's Translucency 2.9.4.3 Using a Rainbow Arc 2.9.5 Animation 2.9.5.1 The Clock Variable: Key To It All 2.9.5.2 Clock Dependant Variables And Multi-Stage Animations 2.9.5.3 The Phase Keyword 2.9.5.4 Do Not Use Jitter Or Crand 2.9.5.5 INI File Settings 3 POV-Ray Options 3.1 Setting POV-Ray Options 3.1.1 Command Line Switches 3.1.2 Using INI Files 3.1.3 Using the POVINI Environment Variable 3.2 Options Reference 3.2.1 Animation Options 3.2.1.1 External Animation Loop 3.2.1.2 Internal Animation Loop 3.2.1.3 Subsets of Animation Frames 3.2.1.4 Cyclic Animation 3.2.1.5 Field Rendering 3.2.2 Output Options 3.2.2.1 General Output Options 3.2.2.1.1 Height and Width of Output 3.2.2.1.2 Partial Output Options 3.2.2.1.3 Interrupting Options 3.2.2.1.4 Resuming Options 3.2.2.2 Display Output Options 3.2.2.2.1 Display Hardware Settings 3.2.2.2.2 Display Related Settings 3.2.2.2.3 Mosaic Preview 3.2.2.3 File Output Options 3.2.2.3.1 Output File Type 3.2.2.3.2 Output File Name 3.2.2.3.3 Output File Buffer 3.2.2.4 CPU Utilization Histogram 3.2.2.4.1 File Type 3.2.2.4.2 File Name 3.2.2.4.3 Grid Size 3.2.3 Scene Parsing Options 3.2.3.1 Input File Name 3.2.3.2 Library Paths 3.2.3.3 Language Version 3.2.4 Shell-out to Operating System 3.2.4.1 String Substitution in Shell Commands 3.2.4.2 Shell Command Sequencing 3.2.4.3 Shell Command Return Actions 3.2.5 Text Output 3.2.5.1 Text Streams 3.2.5.2 Console Text Output 3.2.5.3 Directing Text Streams to Files 3.2.5.4 Help Screen Switches 3.2.6 Tracing Options 3.2.6.1 Quality Settings 3.2.6.2 Radiosity Setting 3.2.6.3 Automatic Bounding Control 3.2.6.4 Removing User Bounding 3.2.6.5 Anti-Aliasing Options 4 Scene Description Language 4.1 Language Basics 4.1.1 Identifiers and Keywords 4.1.2 Comments 4.1.3 Float Expressions 4.1.3.1 Float Literals 4.1.3.2 Float Identifiers 4.1.3.3 Float Operators 4.1.3.4 Built-in Float Identifiers 4.1.3.5 Boolean Keywords 4.1.3.6 Float Functions 4.1.4 Vector Expressions 4.1.4.1 Vector Literals 4.1.4.2 Vector Identifiers 4.1.4.3 Vector Operators 4.1.4.4 Operator Promotion 4.1.4.5 Built-in Vector Identifiers 4.1.4.6 Vector Functions 4.1.5 Specifying Colors 4.1.5.1 Color Vectors 4.1.5.2 Color Keywords 4.1.5.3 Color Identifiers 4.1.5.4 Color Operators 4.1.5.5 Common Color Pitfalls 4.1.6 Strings 4.1.6.1 String Literals 4.1.6.2 String Identifiers 4.1.6.3 String Functions 4.1.7 Array Identifiers 4.1.7.1 Declaring Arrays 4.1.7.2 Array Initalizers 4.2 Language Directives 4.2.1 Include Files and the #include Directive. 4.2.2 The #declare and #local Directives 4.2.2.1 Declaring identifiers 4.2.2.2 #declare vs. #local 4.2.2.3 Identifier Name Collisions 4.2.2.4 Destroying Identifiers with #undef 4.2.3 File I/O Directives 4.2.3.1 The #fopen Directive 4.2.3.2 The #fclose Directive 4.2.3.3 The #read Directive 4.2.3.4 The #write Directive 4.2.4 The #default Directive 4.2.5 The #version Directive 4.2.6 Conditional Directives 4.2.6.1 The #if...#else...#end Directives 4.2.6.2 The #ifdef and #ifndef Directives 4.2.6.3 The #switch, #case, #range and #break Directives 4.2.6.4 The #while...#end Directive 4.2.7 User Message Directives 4.2.7.1 Text Message Streams 4.2.7.2 Text Formatting 4.2.8 User Defined Macros 4.2.8.1 The #macro Directive 4.2.8.2 Invoking Macros 4.2.8.3 Are POV-Ray Macros a Function or a Macro? 4.2.8.4 Returning a Value Like a Function 4.2.8.5 Returning Values Via Parameters 4.3 POV-Ray Coordinate System 4.3.1 Transformations 4.3.1.1 Translate 4.3.1.2 Scale 4.3.1.3 Rotate 4.3.1.4 Matrix Keyword 4.3.2 Transformation Order 4.3.3 Transform Identifiers 4.3.4 Transforming Textures and Objects 4.4 Camera 4.4.1 Placing the Camera 4.4.1.1 Location and Look_At 4.4.1.2 The Sky Vector 4.4.1.3 Angle 4.4.1.4 The Direction Vector 4.4.1.5 Up and Right Vectors 4.4.1.5.1 Aspect Ratio 4.4.1.5.2 Handedness 4.4.1.6 Transforming the Camera 4.4.2 Types of Projection 4.4.3 Focal Blur 4.4.4 Camera Ray Perturbation 4.4.5 Camera Identifiers 4.5 Objects 4.5.1 Finite Solid Primitives 4.5.1.1 Blob 4.5.1.2 Box 4.5.1.3 Cone 4.5.1.4 Cylinder 4.5.1.5 Height Field 4.5.1.6 Julia Fractal 4.5.1.7 Lathe 4.5.1.8 Prism 4.5.1.9 Sphere 4.5.1.10 Superquadric Ellipsoid 4.5.1.11 Surface of Revolution 4.5.1.12 Text 4.5.1.13 Torus 4.5.2 Finite Patch Primitives 4.5.2.1 Bicubic Patch 4.5.2.2 Disc 4.5.2.3 Mesh 4.5.2.4 Polygon 4.5.2.5 Triangle and Smooth Triangle 4.5.3 Infinite Solid Primitives 4.5.3.1 Plane 4.5.3.2 Poly, Cubic and Quartic 4.5.3.3 Quadric 4.5.4 Constructive Solid Geometry 4.5.4.1 Inside and Outside 4.5.4.2 Union 4.5.4.3 Intersection 4.5.4.4 Difference 4.5.4.5 Merge 4.5.5 Light Sources 4.5.5.1 Point Lights 4.5.5.2 Spotlights 4.5.5.3 Cylindrical Lights 4.5.5.4 Area Lights 4.5.5.5 Shadowless Lights 4.5.5.6 Looks_like 4.5.5.7 Light Fading 4.5.5.8 Atmospheric Media Interaction 4.5.5.9 Atmospheric Attenuation 4.5.6 Object Modifiers 4.5.6.1 Clipped_By 4.5.6.2 Bounded_By 4.5.6.3 Material 4.5.6.4 Inverse 4.5.6.5 Hollow 4.5.6.6 No_Shadow 4.5.6.7 Sturm 4.6 Interior 4.6.1 Why are Interior and Media Necessary? 4.6.2 Empty and Solid Objects 4.6.3 Refraction 4.6.4 Attenuation 4.6.5 Faked Caustics 4.6.6 Object Media 4.7 Textures 4.7.1 Pigment 4.7.1.1 Solid Color Pigments 4.7.1.2 Color List Pigments 4.7.1.3 Color Maps 4.7.1.4 Pigment Maps and Pigment Lists 4.7.1.5 Image Maps 4.7.1.5.1 Specifying an Image Map 4.7.1.5.2 The Filter and Transmit Bitmap Modifiers 4.7.1.5.3 Using the Alpha Channel 4.7.1.6 Quick Color 4.7.2 Normal 4.7.2.1 Slope Maps 4.7.2.2 Normal Maps and Normal Lists 4.7.2.3 Bump Maps 4.7.2.3.1 Specifying a Bump Map 4.7.2.3.2 Bump_Size 4.7.2.3.3 Use_Index and Use_Color 4.7.3 Finish 4.7.3.1 Ambient 4.7.3.2 Diffuse Reflection Items 4.7.3.2.1 Diffuse 4.7.3.2.2 Brilliance 4.7.3.2.3 Crand Graininess 4.7.3.3 Highlights 4.7.3.3.1 Phong Highlights 4.7.3.3.2 Specular Highlight 4.7.3.3.3 Metallic Highlight Modifier 4.7.3.4 Specular Reflection 4.7.3.5 Iridescence 4.7.4 Halo 4.7.5 Patterned Textures 4.7.5.1 Texture Maps 4.7.5.2 Tiles 4.7.5.3 Material Maps 4.7.5.3.1 Specifying a Material Map 4.7.6 Layered Textures 4.7.7 Patterns 4.7.7.1 Agate 4.7.7.2 Average 4.7.7.3 Boxed 4.7.7.4 Bozo 4.7.7.5 Brick 4.7.7.6 Bumps 4.7.7.7 Checker 4.7.7.8 Crackle 4.7.7.9 Cylindrical 4.7.7.10 Density_File 4.7.7.11 Dents 4.7.7.12 Gradient 4.7.7.13 Granite 4.7.7.14 Hexagon 4.7.7.15 Leopard 4.7.7.16 Mandel 4.7.7.17 Marble 4.7.7.18 Onion 4.7.7.19 Planar 4.7.7.20 Quilted 4.7.7.21 Radial 4.7.7.22 Ripples 4.7.7.23 Spherical 4.7.7.24 Spiral1 4.7.7.25 Spiral2 4.7.7.26 Spotted 4.7.7.27 Waves 4.7.7.28 Wood 4.7.7.29 Wrinkles 4.7.8 Pattern Modifiers 4.7.8.1 Transforming Patterns 4.7.8.2 Frequency and Phase 4.7.8.3 Waveforms 4.7.8.4 Turbulence 4.7.8.5 Octaves 4.7.8.6 Lambda 4.7.8.7 Omega 4.7.8.8 Warps 4.7.8.8.1 Black Hole Warp 4.7.8.8.2 Repeat Warp 4.7.8.8.3 Turbulence Warp 4.7.8.9 Bitmap Modifiers 4.7.8.9.1 The once Option 4.7.8.9.2 The map_type Option 4.7.8.9.3 The interpolate Option 4.8 Media 4.8.1 Media Types 4.8.1.1 Absorption 4.8.1.2 Emission 4.8.1.3 Scattering 4.8.2 Sampling Parameters 4.8.3 Density 4.8.3.1 General Density Modifiers 4.8.3.2 Density with color_map 4.8.3.3 Density Maps and Density Lists 4.8.3.4 Multiple Density vs. Multiple Media 4.9 Atmospheric Effects 4.9.1 Atmospheric Media 4.9.2 Background 4.9.3 Fog 4.9.4 Sky Sphere 4.9.5 Rainbow 4.10 Global Settings 4.10.1 ADC_Bailout 4.10.2 Ambient Light 4.10.3 Assumed_Gamma 4.10.3.1 Monitor Gamma 4.10.3.2 Image File Gamma 4.10.3.3 Scene File Gamma 4.10.4 HF_Gray_16 4.10.5 Irid_Wavelength 4.10.6 Max_Trace_Level 4.10.7 Max_Intersections 4.10.8 Number_Of_Waves 4.10.9 Radiosity 4.10.9.1 How Radiosity Works 4.10.9.2 Adjusting Radiosity 4.10.9.2.1 brightness 4.10.9.2.2 count 4.10.9.2.3 distance_maximum 4.10.9.2.4 error_bound 4.10.9.2.5 gray_threshold 4.10.9.2.6 low_error_factor 4.10.9.2.7 minimum_reuse 4.10.9.2.8 nearest_count 4.10.9.2.9 recursion_limit 4.10.9.3 Tips on Radiosity 5 APPENDICES 5.1 Copyright, Legal Information and License -- POVLEGAL.DOC 5.1.1 General License Agreement -- POVLEGAL.DOC 5.1.2 Usage Provisions 5.1.3 General Rules For All Distribution 5.1.4 Definition Of "Full Package" 5.1.5 Conditions For CD-ROM or Shareware/Freeware Distribution 5.1.6 Conditions For On-Line Services And Bbs's Including Internet 5.1.7 Online Or Remote Execution Of POV-Ray 5.1.8 Permitted Modification And Custom Versions 5.1.9 Conditions For Distribution Of Custom Versions 5.1.10 Conditions For Commercial Bundling 5.1.11 POV-Team Endorsement Prohibitions 5.1.12 Retail Value Of This Software 5.1.13 Other Provisions 5.1.14 Revocation Of License 5.1.15 Disclaimer 5.1.16 Technical Support 5.2 Authors 5.2.1 Contacting the Authors 5.3 What to do if you don't have POV-Ray 5.3.1 Which Version of POV-Ray should you use? 5.3.1.1 Microsoft Windows 95/98/NT 5.3.1.2 MS-Dos & Windows 3.x 5.3.1.3 Linux for Intel x86 5.3.1.4 Apple Macintosh 5.3.1.5 Amiga 5.3.1.6 SunOS 5.3.1.7 Generic Unix 5.3.1.8 All Versions 5.3.2 Where to Find POV-Ray Files 5.3.2.1 World Wide Website www.povray.org 5.3.2.2 Books, Magazines and CD-ROMs 5.4 Compiling POV-Ray 5.4.1 Directory Structure 5.4.2 Configuring POV-Ray Source 5.4.3 Conclusion 5.5 Suggested Reading 1.0 Introduction This document details the use of the Persistence of Vision (tm) Ray- Tracer (POV-Ray (tm)). It is divided into five 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)A complete reference on "Scene Description Language" in which you describe the scene. 4)A complete reference on "POV-Ray Options" which explains options (set either by command line switches or by INI file keywords) that tell POV-Ray how to render the scenes. 5)And in our "APPENDICES" you will find some tips and hints, where to get the latest version and versions for other platforms, information on compiling custom versions of POV- Ray, suggested reading, contact addresses and legal information. POV-Ray runs on MS-Dos, Windows 3.x, Windows for Workgroups 3.11, Windows 95, Windows NT, Apple Macintosh 68k, Macintosh Power PC, Amiga, Linux, Sun-OS, UNIX and other platforms. We assume that if you are reading this document then 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 don't have POV-Ray or aren't sure you have the official version or the latest version, see appendix "What to do if you don't have POV-Ray". This document covers only the generic parts of the program which are common to each version. Each version has platform-specific documentation not included here. We recommend you finish reading this introductory section then read the platform-specific information before trying the tutorial here. The platform-specific docs will show you how to render a sample scene and will give you detailed description of the platform- specific features. The MS-Dos version documentation contains a plain text file POVMSDOS.DOC which contains its specific docs. It can be found in the main directory where you installed POV-Ray such as C:\POVRAY3. The Windows version documentation is available on the POV-Ray program's Help menu or press the F1 key while in the program. The Mac platform documentation consists of a self-displaying document called "POV-Ray MacOS Read Me" which contains information specific to the Mac version of POV-Ray. It is best to read this document first, to learn how to set up and start using the Mac version of POV-Ray. This document is in the "Documentation" folder in the main "POV-Ray 3" folder. The Amiga version documentation is made up of Html documents, stored in the same place of general POV-Ray docs; the 'root' document is "POVRAY3:POV-Reference/AmigaPOV.html" when the program is installed following the instruction given. Amiga specific documentation and POV-Ray general docs are available pressing Help key in the POV-Gui program; this feature is available in POV-Gui since version 2.1 The Linux version documentation contains a plain text file povlinux.doc which contains its specific docs. It can be found in the main directory where you installed POV-Ray such as /usr/povray3. The SunOS version documentation contains a plain text file povsunos.doc which contains its specific docs. It can be found in the main directory where you installed POV-Ray such as /usr/povray3. The generic Unix version documentation contains a plain text file povunix.doc which contains its specific docs. It can be found in the main directory where you installed POV-Ray such as /usr/povray3. 1.1 Program Description The Persistence of Vision(tm) 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. 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 its job backwards. In the real world, rays of light are emitted from a light source and illuminate objects. The light reflects off of the objects or passes through transparent objects. This reflected light hits our eyes or perhaps a camera lens. Because the vast majority of rays never hit an observer, it would take forever to trace a scene. 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, light sources, and objects 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 final image). Every time an object is hit, the color of the surface at that point is calculated. For this purpose rays are sent backwards to each light source to determine the amount of light coming from the 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. 1.3 What is POV-Ray? The Persistence of Vision (tm) Ray-Tracer was developed from DKBTrace 2.12 (written by David K. Buck and Aaron A. Collins) by a bunch of people, called the POV-Team (tm), in their spare time. The headquarters of the POV-Team is on the internet at http://www.povray.org (see "Where to Find POV-Ray Files" for more details). The POV-Ray (tm) 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 be modified so you don't have to start from scratch. In addition to the pre-defined scenes, a large 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. 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). * 15 and 24 bit color display on many computer platforms using appropriate hardware. * Create landscapes using smoothed height fields. * Many camera types, including perspective, panorama, orthographic, fisheye, etc. * Spotlights, cylindrical lights and area lights for sophisticated lighting. * 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 Targa, PNG and PPM. * Basic shape primitives such as ... spheres, boxes, quadrics, cylinders, cones, triangles and planes. * Advanced shape primitives such as ... Torii (donuts), bezier patches, height fields (mountains), blobs, quartics, smooth triangles, text, fractals, superquadrics, surfaces of revolution, prisms, polygons, lathes and fractals. * Shapes can easily be combined to create new complex shapes using Constructive Solid Geometry (CSG). POV-Ray supports unions, merges, intersections and differences. * Objects are assigned materials called textures (a texture describes the coloring and surface properties of a shape) and interior properties such as index of refraction and particle media (formerly known as "halos"). * Built-in color and normal patterns: Agate, Bozo, Bumps, Checker, Crackle, Dents, Granite, Gradient, Hexagon, Leopard, Mandel, Marble, Onion, Quilted, Ripples, Spotted, Spiral, Radial, Waves, Wood, Wrinkles and image file mapping. * Users can create their own textures or use pre-defined textures such as ... Brass, Chrome, Copper, Gold, Silver, Stone, Wood. * Combine textures using layering of semi-transparent textures or tiles of textures or material map files. * Display preview of image while rendering (not available on all platforms). * Halt and save a render part way through, and continue rendering the halted partial render later. 1.4 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. 1.5 Notation and Basic Assumptions Throughout the tutorial and reference section of this document, the following notation is used to mark keywords of the scene description language, command line switches, INI file keywords and file names. keyword mono-spaced bold POV-Ray keywords and punctuation +W640 +H480 mono-spaced bold command-line switches C:\MYFILE.PO mono-spaced file names, V directories, paths SYNTAX_ITEM italics, all caps required syntax item [SYNTAX_ITEM italics, all caps, optional syntax item ] braces SYNTAX_ITEM. italics, all caps, one or more syntax .. ellipsis items [SYNTAX_ITEM italics, all caps, zero or more syntax ...] braces, ellipsis items Value_1 italics, mixed a float value or case expression italics, mixed a vector value or case, angle braces expression [ ITEM ] bold square braces ITEM enclosed in required braces ITEM1 | vertical bar choice of ITEM1 or ITEM2 ITEM2 In the plain ASCII version of the document there is no visible difference between the different notations. Note that POV-Ray is a command-line program on MS-Dos, Unix and other text-based operating system 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's no way to escape it. Here are some assumptions we make... 1) You installed POV-Ray in the "C:\POVRAY3" 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", for Mac it might be "MyHD:Apps:POV-Ray 3:", or you may have used some other drive or directory. So if we tell you that "Include files are stored in the \povray3\include directory," we assume you can translate that to something like "::POVRAY3:INCLUDE" or "C:\Program Files\POV-Ray for Windows\include" or whatever is appropriate for your platform, operating system and installation. 2) POV-Ray uses command-line switches and INI files 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're using. We'll say "See the chapter on "Setting POV-Ray Option" we assume you can click, scroll, browse, flip pages or whatever to get there. 1.6 What's New in POV-Ray 3.1? Here is an overview of what is new in POV-Ray 3.1 since version 3.0. 1.6.1 Media Replaces Halo & Atmosphere The keywords halo and atmosphere have been totally eliminated with no backwards compatibility of any kind provided. They have been replaced by a new feature called media. At the scene level, media acts as atmospheric media for fog, haze, dust, etc. On objects, media is not part of texture like halo was. Object media is now part of a new feature called interior. Media is not just a rename for halo. It is a new model with some similar features of halo. BECAUSE POV-Ray 3.1 DISCONTINUES SOME 3.0 FEATURES YOU MAY WISH TO KEEP 3.0 TO RENDER OLDER SCENES. Any pattern type (bozo, wood, dents, etc.) may be used as a density function for media. New patterns spherical, cylindrical, planar, and boxed added for pigment, normal, texture, and density. New wave types cubic_wave and poly_wave Float have been added. New object modifier interior{...}. Interior 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 finish items moved are ior, caustic, fade_power, and fade_distance. The refraction keyword is no longer necessary. Any ior other than 1.0 turns on refraction. These 5 finish keywords which are now part of interior will still work in finish but will generate warnings. Some obscure texture_map statements with varying ior will not work. Added reflection_exponent Float to finish to give more realistic reflection of very bright objects. 1.6.2 New #macro Feature Add fully recursive and parameterized #macro directive. Define like this... #macro MyMacro (P1,P2,P3) ... #end Invoke like this... MyMacro (5,x*5,MyTexture) Note no '#' sign precedes invocation. Macros can be invoked almost anywhere. Parameters must be identifiers or any item that can be declared, MyMacro(pigment{Green},MyObject) for example. Added #local IDENTIFIER= STATEMENT as alternative to #declare to create temporary local identifier in macros or include files. 1.6.3 Arrays Added Added multi-dimension arrays #declare MyArray=array[20] or #local PrivateArray=array[30] or #declare Rows=5; #declare Cols=4; #declare Table=array[Rows][Cols] Added optional initializer syntax for arrays. #declare MyArray=array[2][3]{{1,2,3},{4,5,6}} Subscripts start at 0. Anything that can be declared may be in an array. Arrays are initialized as null. You must later fill each element with values. Added float functions for arrays. Given #declare MyArray = array[4][5] then dimensions(MyArray) is 2 and dimension_size(MyArray,2) is 5. 1.6.4 File I/O and other Directives Added #fopen, #fclose, #read, and #write directives for user text files. Added #undef identifier directive. Un-declares previously declared identifier. Works on locals or globals. Added requirement that any directive which can end in a float or expression must be terminated by a semi-colon. Specifically this means any #declare or #local of float, vector or color or the #version directive. 1.6.5 Additional New Features Added Bezier splines to lathe and prism. The spline is made of segments having four points each. Thus there are always four times the number of segments in a prism or lathe. A four point Bezier spline uses 3rd order Bernstein blending functions which are sufficient for smooth curves. Added float constant clock_delta returns time between frames. 2.0 Beginning Tutorial The beginning tutorial explains step by step how to use POV-Ray's scene description language to create own your 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.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.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: The left-handed coordinate system (the z-axis is pointing away) 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 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. "Computer Graphics Aerobics" to determine the rotation direction. 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.1.2 Adding Standard Include Files Using our personal favorite text editor, we create a file called demo.pov. Note 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 don't 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 installation of POV-Ray place these files in the \povray3\include directory. 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.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.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.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 The values after each keyword should be in the range from 0.0 to 2.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> Colors are explained in more detail in section "Specifying Colors". 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 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 that 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 isn't 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 Simple 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.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 that 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 Cone Object Here's 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.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.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. We note that 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 that 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.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.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 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.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.3.3 CSG Intersection Now let's use these same spheres to illustrate the next kind of CSG object, the intersection. 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.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 red. 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.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.3.6 CSG Pitfalls There is a severe pitfall in the CSG code that we have to be aware of. 2.3.6.1 Coincidence 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 numerical problems) 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 that 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.4 Advanced 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 below are not trivial to understand. We needn't 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.4.1 Bicubic Patch Object Bicubic or Bezier 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. For ray-tracing (or rendering) the patches are approximated using triangles. Bezier patches are almost always created using a third party modeler so for this tutorial, we will use moray (any other modeler that supports Bezier patches and POV-Ray can also be used). We will use moray only to create the patch itself, not the other elements of the scene. Note that moray is not included with POV-Ray. It is a separate shareware program that currently only runs on MS-Dos and Win95/NT but this tutorial assumes you are using the MS-Dos version. If you do not have moray or are not on MS-Dos, you can still render the sample scene described below, even though you cannot see how moray created it. Simply type in the bicubic_patch declaration listed below. Bezier patches are actually very useful and, with a little practice, some pretty amazing things can be created with them. For our first tutorial, let's make a sort of a teepee/tent shape using a single sheet patch. First, we start moray and, from the main edit screen, we click on "CREATE". We Name our object Teepee. The "CREATE BEZIER PATCH" dialogue box will appear. We have to make sure that "SHEET" is depressed. We click on "OK, CREATE". At the bottom of the main edit screen, we click on "EXTENDED EDIT". We hold the cursor over the "TOP" view and right click to make the pop-up menu appear. We click on "MAXIMIZE". We [ALT]-drag to zoom in a little. We click on "MARK ALL", and under the transformation mode box, "UFRM SCL". We drag the mouse to scale the patch until it is approximately four units wide. We click on "TRANSLATE", and move the patch so that its center is over the origin. We right click "MINIMIZE" and "UNMARK ALL". We [SHIFT]-drag a box around the lower right control point to mark it. We [ALT]-zoom into the "FRONT" view so that we can see the patch better. In the "FRONT" view, we "TRANSLATE" that point 10 units along the negative z-axis (we note that in MORAY z is up). We "UNMARK ALL". We repeat this procedure for each of the other three corner points. We make sure we remember to "UNMARK ALL" once each point has been translated. We should have a shape that looks as though it is standing on four pointed legs. We "UNMARK ALL". Working once again in the "TOP" view, we [SHIFT]-drag a box around the four center control points to mark them. We right- click over the "TOP" view and "MAXIMIZE". We click on "UFRM SCL" and drag the mouse to scale the four points close together. We [ALT]-drag to zoom closer and get them as close together as we can. We [ALT]-drag to zoom out, right click and "MINIMIZE". In the "FRONT" view, we "TRANSLATE" the marked points 10 units along the positive z-axis. We "UNMARK ALL". The resulting shape is quite interesting, was simple to model, and could not be produced using CSG primitives. Now let's use it in a scene. We click on "DONE" to return to the main edit screen. We note that u_steps and v_steps are both set to 3 and flatness is set to 0.01. We leave them alone for now. We click on "FILES" and then "SAVE SEL" (save selection). We name our new file teepee1.mdl. We press [F3] and open teepee1.mdl. There is no need to save the original file. When teepee1 is open, we create a quick "dummy" texture (moray will not allow us to export data without a texture). We use white with default finish and name it TeePeeTex. We apply it to the object, save the file and press [CTRL-F9]. moray will create two files: teepee1.inc and teepee1.pov. We exit moray and copy teepee1.inc and teepee1.pov into our working directory where we are doing these tutorials. We create a new file called bezdemo.pov and edit it as follows: #include "colors.inc" camera { location <0, .1, -60> look_at 0 angle 40 } background { color Gray25 } //to make the patch easier to see light_source { <300, 300, -700> White } plane { y, -12 texture { pigment { checker color Green color Yellow } } } Using a text editor, we create and declare a simple texture for our teepee object: #declare TeePeeTex = texture { pigment { color rgb <1, 1, 1,> } finish { ambient .2 diffuse .6 } } We paste in the bezier patch data from teepee1.pov (the additional object keywords added by moray were removed): bicubic_patch { type 1 flatness 0.0100 u_steps 3 v_steps 3, <-5.174134, 5.528420, -13.211995>, <-1.769023, 5.528420, 0.000000>, <1.636088, 5.528420, 0.000000>, <5.041199, 5.528420, -13.003932>, <-5.174134, 1.862827, 0.000000>, <0.038471, 0.031270, 18.101474>, <0.036657, 0.031270, 18.101474>, <5.041199, 1.862827, 0.000000>, <-5.174134, -1.802766, 0.000000>, <0.038471, 0.028792, 18.101474>, <0.036657, 0.028792, 18.101474>, <5.041199, -1.802766, 0.000000>, <-5.174134, -5.468359, -13.070366>, <-1.769023, -5.468359, 0.000000>, <1.636088, -5.468359, 0.000000>, <4.974128, -5.468359, -12.801446> texture { TeePeeTex } rotate -90*x // to orient the object to LHC rotate 25*y // to see the four "legs" better } We add the above rotations so that the patch is oriented to POV- Ray's left-handed coordinate system (remember the patch was made in moray in a right handed coordinate system), so we can see all four legs. Rendering this at 200x150 -a we see pretty much what we expect, a white teepee over a green and yellow checkered plane. Let's take a little closer look. We render it again, this time at 320x200. Now we see that something is amiss. There appears to be sharp angling, almost like facing, especially near the top. This is indeed a kind of facing and is due to the u_steps and v_steps parameters. Let's change these from 3 to 4 and see what happens. That's much better, but it took a little longer to render. This is an unavoidable tradeoff. If we want even finer detail, we must use a u_steps and v_steps value of 5 and set flatness to 0. But we must expect to use lots of memory and an even longer tracing time. Well, we can't just leave this scene without adding a few items just for interest. We declare the patch object and scatter a few of them around the scene: #declare TeePee = bicubic_patch { type 1 flatness 0.0100 u_steps 3 v_steps 3, <-5.174134, 5.528420, -13.211995>, <-1.769023, 5.528420, 0.000000>, <1.636088, 5.528420, 0.000000>, <5.041199, 5.528420, -13.003932>, <-5.174134, 1.862827, 0.000000>, <0.038471, 0.031270, 18.101474>, <0.036657, 0.031270, 18.101474>, <5.041199, 1.862827, 0.000000>, <-5.174134, -1.802766, 0.000000>, <0.038471, 0.028792, 18.101474>, <0.036657, 0.028792, 18.101474>, <5.041199, -1.802766, 0.000000>, <-5.174134, -5.468359, -13.070366>, <-1.769023, -5.468359, 0.000000>, <1.636088, -5.468359, 0.000000>, <4.974128, -5.468359, -12.801446> texture { TeePeeTex } rotate -90*x // to orient the object to LHC rotate 25*y // to see the four "legs" better } object { TeePee } object { TeePee translate <8, 0, 8> } object { TeePee translate <-9, 0, 9> } object { TeePee translate <18, 0, 24> } object { TeePee translate <-18, 0, 24> } That looks good. Let's do something about that boring gray background. We delete the background declaration and replace it with: plane { y, 500 texture { pigment { SkyBlue } finish { ambient 1 diffuse 0} } texture { pigment { bozo turbulence .5 color_map { [0 White] [1 White filter 1] } } finish { ambient 1 diffuse 0 } scale <1000, 250, 250> rotate <5, 45, 0> } } This adds a pleasing cirrus-cloud filled sky. Now, let's change the checkered plane to rippled sand dunes: plane {y,-12 texture { pigment { color <.85, .5, .15> } finish { ambient .25 diffuse .6 crand .5 } normal { ripples .35 turbulence .25 frequency 5 } scale 10 translate 50*x } } We render this. Not bad! Let's just add one more element. Let's place a golden egg under each of the teepees. And since this is a bezier patch tutorial, let's make the eggs out of bezier patches. We return to moray and create another bezier patch. We name it Egg1 and select "CYLINDRICAL 2 - PATCH" from the "CREATE BEZIER PATCH" dialogue box. We click on "EXTENDED EDIT". We "MARK ALL" and rotate the patch so that the cylinder lays on its side. We "UNMARK ALL". In the "FRONT" view, we [SHIFT]-drag a box around the four points on the right end to mark them. In the "SIDE" view, we right click and "MAXIMIZE". We [ALT]-drag to zoom in a little closer. We "UFRM SCL" the points together as close as possible. We zoom in closer to get them nice and tight. We zoom out, right click and "MINIMIZE". We click on "TRANSLATE" and drag the points to the left so that they are aligned on the z-axis with the next group of four points. This should create a blunt end to the patch. We repeat this procedure for the other end. We "UNMARK ALL". In the "FRONT" view, the control grid should be a rectangle now and the patch should be an ellipsoid. We [SHIFT]-drag a box around the upper right corner of the control grid to mark those points. We then [SHIFT]-drag a box around the lower right corner to mark those points as well. In the "SIDE" view, we "UFRM SCL" the points apart a little to make that end of the egg a little wider than the other. We "UNMARK ALL". The egg may need a little proportional adjustment. We should be able to "MARK ALL" and "LOCAL SCL" in the three views until we get it to look like an egg. When we are satisfied that it does, we "UNMARK ALL" and click on done. Learning from our teepee object, we now go ahead and change u_steps and v_steps to 4. We create a dummy texture, white with default finish, name it EggTex and apply it to the egg. From the FILES menu, we "SAVE SEL" to filename egg1.mdl. We load this file and export ([CTRL F9]). We exit moray and copy the files egg1.inc and egg1.pov into our working directory. Back in bezdemo.pov, we create a nice, shiny gold texture: #declare EggTex = texture { pigment { BrightGold } finish { ambient .1 diffuse .4 specular 1 roughness 0.001 reflection .5 metallic } } And while we're at it, let's dandy up our TeePeeTex texture: #declare TeePeeTex = texture { pigment { Silver } finish { ambient .1 diffuse .4 specular 1 roughness 0.001 reflection .5 metallic } } Now we paste in our egg patch data and declare our egg: #declare Egg = union { // Egg1 bicubic_patch { type 1 flatness 0.0100 u_steps 4 v_steps 4, <2.023314, 0.000000, 4.355987>, <2.023314, -0.000726, 4.355987>, <2.023312, -0.000726, 4.356867>, <2.023312, 0.000000, 4.356867>, <2.032037, 0.000000, 2.734598>, <2.032037, -1.758562, 2.734598>, <2.027431, -1.758562, 6.141971>, <2.027431, 0.000000, 6.141971>, <-1.045672, 0.000000, 3.281572>, <-1.045672, -1.758562, 3.281572>, <-1.050279, -1.758562, 5.414183>, <-1.050279, 0.000000, 5.414183>, <-1.044333, 0.000000, 4.341816>, <-1.044333, -0.002947, 4.341816>, <-1.044341, -0.002947, 4.345389>, <-1.044341, 0.000000, 4.345389> } bicubic_patch { type 1 flatness 0.0100 u_steps 4 v_steps 4, <2.023312, 0.000000, 4.356867>, <2.023312, 0.000726, 4.356867>, <2.023314, 0.000726, 4.355987>, <2.023314, 0.000000, 4.355987>, <2.027431, 0.000000, 6.141971>, <2.027431, 1.758562, 6.141971>, <2.032037, 1.758562, 2.734598>, <2.032037, 0.000000, 2.734598>, <-1.050279, 0.000000, 5.414183>, <-1.050279, 1.758562, 5.414183>, <-1.045672, 1.758562, 3.281572>, <-1.045672, 0.000000, 3.281572>, <-1.044341, 0.000000, 4.345389>, <-1.044341, 0.002947, 4.345389>, <-1.044333, 0.002947, 4.341816>, <-1.044333, 0.000000, 4.341816> } texture { EggTex } translate <0.5, 0, -5> // centers the egg around the origin translate -9.8*y // places the egg on the ground } We now place a copy of the egg under each teepee. This should require only the x- and z-coordinates of each teepee to be changed: object { Egg } object { Egg translate <8, 0, 8> } object { Egg translate <-9, 0, 9> } object { Egg translate <18, 0, 24> } object { Egg translate <-18, 0, 24> } Scene build with different Bezier patches. We render this at low resolution such as 320x240. Everything looks good so we run it again at 640x480. Now we see that there is still some facing near the top of the teepees and on the eggs as well. The only solution is to raise u_steps and v_steps from 4 to 5 and set flatness to 0 for all our bezier objects. We make the changes and render it again at 640x480. The facets are gone. 2.4.2 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 (this scene is called blobdem1.pov): #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 (see file blobdem2.pov). 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.4.2.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,
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 hem-spheres. 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.4.2.2 Complex Blob Constructs and Negative Strength Beginning a new POV-Ray file called blobdem3.pov, 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 (see file blobdem4.pov). sphere { <-.65,.28,-.05>, .26, -1 } //counteract pinky knuckle bulge 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.4.3 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: #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.4.4 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 artifacts 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 (called lathdem1.pov). #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 } } A simple lathe object. 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 are 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. 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 doesn't 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, its 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.4.4.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 (see file lathdem2.pov): #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, 0>; #declare Orange_Point = <1.75, 1.00, 0>; #declare Yellow_Point = <2.50, 2.00, 0>; #declare Green_Point = <2.00, 3.00, 0>; #declare Blue_Point = <1.50, 4.00, 0>; /* make the control points visible */ cylinder { Red_Point, Red_Point - 20*z, .1 pigment { Red } finish { ambient 1 } } cylinder { Orange_Point, Orange_Point - 20*z, .1 pigment { Orange } finish { ambient 1 } } cylinder { Yellow_Point, Yellow_Point - 20*z, .1 pigment { Yellow } finish { ambient 1 } } cylinder { Green_Point, Green_Point - 20*z, .1 pigment { Green } finish { ambient 1 } } cylinder { Blue_Point, Blue_Point- 20*z, .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 } } A simple "Spline Workshop". 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 haven't 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 new 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. 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's 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 isn't 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've 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's 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 (see file lathdem3.pov). #declare Red_Point = <2.00, 0.00, 0>; #declare Blue_Point = <0.00, 4.00, 0>; Moving some points of the spline. 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? Let's try something different. First, we change the points to the following (see file lathdem4.pov). #declare Red_Point = <1.00, 0.00, 0>; #declare Orange_Point = <2.00, 1.00, 0>; #declare Yellow_Point = <3.50, 2.00, 0>; #declare Green_Point = <2.00, 3.00, 0>; #declare Blue_Point = <1.50, 4.00, 0>; A quadratic spline lathe. We then go down to the lathe declaration and change linear_spline to quadratic_spline. We re-render and what do we have? Well, there's 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? 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's 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 long for 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. Still longer needs 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 (see file lathdem5.pov). We render one more time, and take a look at what we have. A cubic spline lathe. 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. The concept of splines is a handy and necessary one, which will be seen again in the prism and polygon objects. But with a little tinkering we can quickly get a feel for working with them. 2.4.5 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. 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 and robotmsh.pov. 2.4.6 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'll 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'll 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's all we have to do. There'll 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'll 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.4.7 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 didn't 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 mustn't get too casual about those warning messages! 2.4.7.1 Teaching An Old Spline New Tricks If we followed the section on splines covered under the lathe tutorial (see 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 won't 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's 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 don't match the correct points on a quadratic or cubic shape, that's 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 aren't part of the shape - they're just there to help compute what curves to use between the other points. 2.4.7.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've 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.4.7.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've got. It's 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.4.7.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, we what we've 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's 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're 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've stretched it out a little. At this point, we're 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's 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 don't 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.4.8 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 { } 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 trace it at 200x150 -A 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 don't know exactly what to call it, but it is interesting. Finally, lets 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 that 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 don't 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.4.9 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 edit a file called sordemo.pov and enter the following text. #include "colors.inc" #include "golds.inc" global_settings { assumed_gamma 2.2 } 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> 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 with ascending heights. Each point determines the radius of the curve for a given height. E. g. the first point tells POV-Ray that at height -0.5 the radius is 0. 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. 2.4.10 Text Object Creating text objects using POV-Ray always used to mean that the letters had to be built either from CSG, a painstaking process or by using a black and white image of the letters as a height field, a method that was only somewhat satisfactory. Now, for POV- Ray 3.0, a new primitive has been introduced that can use any TrueType font 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 at 200x150 -A, 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's 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's 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. We render this at 200x150 -A. We can see the inlay clearly and that it is indeed a bright gold color. We re-render at 640x480 +A0.2 to see the results more clearly, but be forewarned... this trace will take a little time. 2.4.11 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's 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 isn't much else we can do to a torus besides change its texture... or is there? Let's see... Torii 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 can't 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-direct