I Introduction

This documentation describes POVMAN program, which is custom version of Persistence of Vision (tm) Ray Tracer program (POV-Ray further).  This custom version adds limited support of RenderMan (R) Shading Language to POV-Ray program.
This document gives slight overview of shading language and its use within POV-Ray, then some examples are given. This is followed by discussion of  differences between RenderMan specification and current implementation.  Document concludes with legal section and contact information.

II Contents

  • Overview
  • Shading Language
  • Interface with POV-Ray
  • Examples
  • First shaders
  • Advanced shaders
  • Bump mapping
  • POV-Ray vs. shader
  • Parametric mapping and opacity
  • Anisotropic scattering
  • Bricks, bricks, bricks
  • "Cellular pattern (a.k.a. Voronoi function)
  • Skin shader
  • X-Rays?
  • Isosurfaces with SL
  • Torus
  • Menger's sponge
  • Shading Language reference and useful links
  • Implementation notes
  • Limitations/shortcomings
  • POV-Ray specific notes
  • How slow are shaders?
  • Changes list
  • Legal stuff
  • Contact information
  • Overview

    Shading Language

    Shading language, used in this program, is subset of RenderMan shading language. This language resembles C with additional data types for color and geometry and built-in operations and functions for these types. Code, which is written by shading language is called shader. RenderMan specification describes number of different shader types. Some of them are:


    This program implements surface shaders. Surface shader has access to various geometry attributes (shading point, surface normal at shading point, ray direction, eye position, initial surface color and opacity) and should calculate resulting surface color and opacity. List of some shader built-in variables, which are used for communication between POV-Ray and shader virtual machine, is given below.
     
    Name Type Description
    Input parameters
    Cs color Default color for geometry surface
    Os color default opacity for geometry surface
    P point shading point
    Ng normal surface normal at shading point
    u,v float surface parameters
    E point eye position
    I vector incident ray direction
    Output parameters
    Ci color output color
    Oi color output opacity
    N normal surface normal

    Shading language contains following types:
    float
    color
    vector
    normal
    point
    Types other than floats could be referred as triples, last 3 as geometric triples.

    Following operators between these types are supported:
    unary(-,!)
    arithmetic (+, -, *, /)
    geometric (., ^) (dot product and cross product)
    logical (==, !=, >, >=, <, <=, &&, ||)
    assignment (=, +=, -=, *=, /=)
    conditional (?:)

    If operation is involved between float and triple, then float is promoted automatically to appropriate type.
    Additionally, there is number of built-in functions (mathematical, geometric, color, shading and lighting), which implement most useful operations.
    Shading Language supports following language constructs:
    blocks  ({})
    conditionals (if,else)
    loops (while, for, continue, break, illuminance)
    user defined functions (return expression).

    Interface with POV-Ray

    Shading language is compiled into byte code with shading language compiler (POVSLC). This byte code is read with POV-Ray scene and attached to geometric primitives as pigment. During scene calculation byte code interpreter is invoked for given  primitive and as a result, output color and opacity is set for given shading point.

    Examples

    First shaders

    Source code for this example could be found in examples/red subdirectory.
    As a first shader, we create shader, which assigns red color to given primitive. Shader code is as follows:
    surface red(){
        Ci = color (1,0,0);
    }
    


    First line specifies, that this shader is surface shader. In parentheses are shader parameters specified. This simple shader does not use any parameters, so we leave it just empty.
    Second line assigns color (1,0,0) to output color. Colors are described in triples (R,G,B).

    By saving this code into file red.sl (as custom, shader files have extension .sl) and compiling:
    >povslc red.sl
    we should have file red.slp, which contains byte code for our shader. Test POV-Ray file (red.pov) is as follows:

    camera {
        location <0.5, 1, -3>
        direction <0, 0, 1>
        up <0, 1, 0>
        right <4/3, 0,0>
        look_at <0,0,0>
    }
    light_source{
        <10, 10, -10>
        color <1,1,1>
    }    
    
    sphere{
        <0,0,0>, 1
        texture{
            pigment{
                shader{
                    shader_file "red.slp"
                }
            }
            finish{
                ambient 1
                diffuse 0
            }
        }
    }
    


    This scene contains sphere, which pigment is calculated by shader. By rendering this scene, we can see, that sphere has indeed red color.

    Now lets try to change color of sphere from POV-Ray, as modifying shader and recompiling it each time is a little bit cumbersome. For this we take shader parameters in use.
    (Following examples are located in examples/params )
    First the shader file (params.sl):

    surface params(color ResultCol = color(1,1,1);)
    {
        Ci 0 ResultCol;
    }
    

    In scene file params.pov we replace shader file name with params.slp and after shader compilation and rendering we see, that color of sphere is white, as expected.

    In order to change this color from scene file, we change texture of sphere as follows:
    texture{
        pigment{
            shader{
                shader_file "params.slp"
                "ResultCol"  <1,1,0>
            }
        }
    }
    

    As we see, parameter is specified by its name, following by value.
    By rendering this scene (params1.pov) we see, that color of sphere is changed to yellow, as expected.

    Note: there is specific built-in variable for specifying object color: Cs. This means, that usually in order to specify different base color from default one (white), user has to specify it in POV-Ray scene file similar to above:
        "Cs" <;1,1,0>
    

    but in shader there is no need to declare this as parameter to shader  and user can use it immediately, as any other built-in variable:
        Ci = Cs;
    

    Advanced shaders

    Bump mapping

    With shading language it is easy to create bump mapping (examples/bumps):
    surface bumps(float scale=25, amp=1)
    {
        point w,x;
        x = noise(transform("shader", P)*scale)*amp;
        w = normalize(N) + x/2;
        if (I.w <= 0){
            N = normalize(w);
        }
        Oi = Os;
        Ci = Cs;
    }
    

    Here we tranform shading point to texture space (shader space), scale it 25 times (make bumps smaller!) and create noise from this point. Then noise value is multiplied by amp, divided by 2 and added to normal vector. Then check is performed to ensure, that resulting value has same direction, as original normal ( I.w<=0 ) to avoid normal direction change to opposite direction. Result is as follows:

    POV-Ray vs. shader

    Now we try to create shader, which creates output, which is similar to POV-Ray calculated. For this we use a little bit modified plastic surface shader from RenderMan standard shader. Shader file is as follows (examples/povshad/povshad.sl):
    surface povshad(){ 
    
        normal Nf = normalize(N); 
        float Ka = 0.5; 
        float Kd = 0.0; 
        float Ks = 0.6; 
        float Kp = 0.0; 
        float roughness = 0.5; 
        color base = color (1,1,1)*0.8; 
    
        color spec = specular(Nf, -normalize(I), roughness); 
        Ci = base *(Ka*ambient() + Kd * diffuse(Nf)) + 
            Ks * spec + Kp*phong(Nf, -normalize(I), 5); 
    
    } 
    

    Here variable Ka denotes ambient coefficient, Kd stands for diffuse, Ks for specular, Kp for phong. roughness is used in specular calculation and base is base color for given surface.
    In POV-Ray scene we create 2 spheres, one with this shader for surface color calculation, other uses "standard" POV-Ray features with similar values in texture for color, ambient, diffuse, specular and roughness (file examples/povshad/povshad.pov):
    
    camera { 
        location  <0, 1, -13> 
        direction <0, 0,  1> 
        up        <0, 1,  0> 
        right     <4/3, 0,0> 
        look_at   <0, 0, 0> 
    } 
    
    light_source{ 
        <0, 10, 1>*1000 
        color <1,1,1> 
    } 
    
    sphere{ 
      <-4,0,0>,3 
    
      texture{ 
        pigment{ 
          shader{ 
            shader_file "povshad.slp" 
          } 
        } 
        finish{ 
          ambient 1 
          diffuse 0 
        } 
      } 
    } 
    
    sphere{ 
      <4,0,0>,3 
      texture{ 
        pigment{ 
            color rgb<1,1,1>*0.8 
        } 
        finish{ 
          ambient 0.5 
          diffuse 0. 
          specular 0.6 
          roughness 0.5 
        } 
      } 
    } 
    

    By rendering this scene, one can see, that indeed, this shader calculates surface color similarly to POV-Ray.

    Parametric mapping and opacity

    Following example demonstrates use of surface parameter values and modification of opacity (examples/uvtest/uvtest.sl):
    surface uvtest(){ 
        Oi=Os; 
        if (mod(u*150,10)<4){ 
            Ci=(1,0,1); 
        } 
        else if(mod(v*150, 10)<4){ 
            Ci=(1,1,0); 
        } 
        else{ 
            Ci = 1; 
            Oi = 0; 
        } 
    } 
    

    Here u and v are built-in variables, which show surface parameter values for given shading point. (For description of these values refer to Megapov documentation.)
    First if statement divides sphere to 15 regions along direction of u parameter. In each one of them, if shading point resides in first 4/10th of this region, then it will be coloured to magenta (color (1,0,1)).
    Second if statement performs similarly along v direction and colors according areas to yellow.
    If shading point is in neither part, then its color is set to white and opacity (Oi) is set to 0 (i.e. its transparency is set to 1). Rendering of sphere with given shader (file uvtest.pov) results in following picture:

    Anisotropic scattering

    For next we try something really interesting: anisotropic specular reflection by Greg Ward Larson. For this we use slightly modified file from "Advanced RenderMan" (current version does not support surface derivatives, therefore this part is left out). Shader is given in file examples/anisotrop/aniso.sl, scene file is in examples/anisortop/aniso.pov.
    This example creates 3 spheres with different roughness and reference direction for anisotropy. Rendering it shows clearly (perhaps even too clearly) anisotropic nature of specular component.

    Bricks, bricks, bricks

    Laying bricks in CG in one of favourite activities among artists, so without much ado here is shader file for bricks (examples/brick/brick.sl). For description of this algorithm one can refer to "Texturing and modeling", by Ebert, Musgrave, et al. Once again this is "limited version", as it does not perform antialiasing due to missing implementation of surface derivatives.
    Scene file is in examples/brick/brick.pov.

    Cellular pattern (a.k.a. Voronoi function)

    Cellular patterns are similar to the crackle pattern in POV-Ray. Code for voronoi shader, taken from "Advanced RenderMan" is in examples/voronoi/voronoi.sl.
    By changing fracScale value, one can change jagginess of borders, similar to turbulence value in cracle pattern.

    Skin shader

    Directory examples/skin contains sample skin shader by Matt Pharr and scene file for it. This shader takes into account subsurface scattering of skin, which makes skin "glow" and glossy component from top level. Example scene could be found in examples/skin (left head has skin shader, right one has POV-Ray shading):

    Observe, how skin shader defines specular component, which is visible in grazing angles and results in more natural shading.

    X-Rays?

    Simon Bunker (http://www.rendermania.com) created simple yet interesting shader, which produces "x-ray" pictures. Sample of this shader is in directory examples/xray.

    Isosurfaces with SL

    POVMan version 0.7 adds ability to calculate isosurface potential value for given point by shader.

    Torus

    Directory examples/torus contains example of torus shader.

    Menger's sponge

    Directory examples/menger contains example of Menger sponge. With such function definition it is quite easy to calculate sponge with arbitrary recursion depth, given enough time and processing power. However, if depth is greater than xx (ca. 15 I guess, 486 is not really the best 'puter for such calculations, so I haven't tried it out), then sponge will diminish due to aliasing...

    Great number of functions to use/play with shader could be found in POV-Ray source code (isofunc.c).

    Shading Language Reference and useful links

    For best information about shading language see Pixar documentation http://www.pixar.com/products/renderman/toolkit/RISpec/
    http://www.pixar.com/products/renderman/toolkit/Toolkit/slextensions.html
    Differences between POVMAN implementation and RenderMan specification are discussed below.

    Additionally, books "Advanced RenderMan" and "Texturing & Modeling" are recommended reading, as they contain good deal of information about shading language.
    Additional online references:
    BMRT homepage: http://www.bmrt.org
    RenderMan Repository (contains number of shaders): http://www.renderman.org
    Usenet newsgroup news://comp.graphics.rendering.renderman is useful place for discussion about Shading Language.

    Implementation notes

    Limitations/shortcomings of shading language

    Current implementation has several limitations with respect to PRMan 3.8 Shading Language. Here is list of them, grouped by probability of correction/implementation.
     

    Partially implemented/to be improved:

    Support for strings and string functions. Currently strings have limited support: assignment to string and comparision is supported. String arrays are not supported.
    Support for different coordinate systems in transformation functions. Currently only "current" space (this accords to world coordinate system) and "shader" space (this accords to object's texture coordinate system) are supported.
    Support for different splines. Currently all spline types, which are described in SL extensions document, are supported, but "bspline" and "hermite" spline types may be incompatible with RenderMan specification in terms of control points specifying: I was unable to find documentation about control point specification for these types.
    fresnel() function returns transmitting coefficient as 1-kr, instead of returning valid physical amount. But is this problem at all, as it seems that PRMan returns similar value?
    Type handling in compiler is not very robust, it should be improved. Result types of some expressions and builtin functions are not determined by language and are "guessed" by expression, but this guess could be wrong. Therefore it is better to use explicit casts, if several different types (especially floats and triples) are involved in expression.
     

    Not yet implemented/planned in next version(s):

    Surface derivative functions (Du, Dv, Deriv, area, filterstep) and surface differentials (du, dv).
    Texure mapping functions (texture, bump).
    Support for matrix type and its functions.
     

    Not implemented/implementation under consideration.

    Imager shader ("postprocessing" shader).
    Displacement shader.
    Message passing between shader and POV-Ray.

    Not implemented/not planned:

    Time derivatives
    Light/volume/transformation shaders.
     

    POV-Ray specific notes

    Overview

    Main goal of this patch was compatibility with RenderMan shaders: there is number of excellent shaders available and possibility to use them without modifications (or with little modifications) opens box full of possibilities for POV-Ray users. Following this goal caused 2-step-approach in scene development:


    Compiled byte code is in ASCII format, so it does not depend from system endianess, floating point representation etc. ASCII format means also, that use of byte code does not require binary "linking" to POV-Ray ( as it would require, if .DLL-s or binary modules were created).
    Interpreting byte code is slower, than running pre-compiled machine code, of course; this is the price to pay for flexibility.
     

    Shading Language Compiler

    Shading language compiler POVSLC is created with lexx and yacc tools. Shading language compiler has following features:

    Virtual Machine & POV-Ray


    Shader is attached to POV-Ray as pigment. This means, that shader output color and opacity are seen by POV-Ray as pigment color (opacity is mapped to pigment transmittance by equation 1-comp(Oi,0) (or 1-'red component of opacity'). This means, that finish statements could modify shader output color. If shader calculates only "pure" color (without taking into account light sources), then it is acceptable. But if shader calculates color with respect to light sources (by using illuminance statement or diffuse, specular and phong functions), then finish statement should set ambient to 1 and diffuse to 0:

    texture{
        pigment{
            shader{
                ...
            }
        }
        finish{
            ambient 1
            diffuse 0
        }
    }
    


    In order to change surface color Cs and opacity Os (by default Cs == color(1,1,1) and Os == color (1,1,1)), user can set them from POV-Ray scene file similar to shader parameters.

    Shadow calculation for surface, which has shader as pigment, could execute shader again in order to determine whether surface is opaque or has transparency component (remember, that shader can change surface opacity arbitrarily). This leads to number of problems:

    In order to avoid shader execution on each shadow ray tracing, shader block can contain additional keyword shadow_type, followed by keyword which specifies, how shadows are calculated for surface:
     
    no_shadow surface has no shadow
    opaque_shadow surface has full shadow
    Os_shadow surface shadow is specified by red component of Os; by default Os is (1,1,1)
    shader_shadow shadow is calculated by Oi component of shader 

    Default value for shadow_type is opaque_shadow (i.e. surface has full shadow). Opacity value, returned by shader, is used for shadow calculations only in the case of shader_shadow (see examples/uvtest/uvtest.pov for example of partially transparent object with correct shadows).
    Here is example of different shadow types (source could be found in examples/shadows). Shadow types from left to right: no_shadow, opaque_shadow, Os_shadow (Os=0.3), shader_shadow.

    Built-in variables

    NOTE: Starting from POVMan version 0.7 and shading language version 0.3 POV-Ray texture finish values are removed! If there is need to access them from shader, then these values could be passed as shader parameters.
     

    Here is description of built-in variables.
    Cs Default surface color is set to white (1,1,1). Could be changed in POV-Ray scene file as shader parameter.
    Os Default surface opacity is set to full for all channels (1,1,1). Could be changed in scene file as shader parameter.
    P Intersection point
    N Surface normal at intersection point. This is normal after POV-Ray perturberation (bumps, dents, etc.) Normal direction is same with the surface normal direction (POV-Ray flips normals toward camera, but Shading Language assumes true geometric normal, without flipping, so shader code flips it back, if necessary). Modification of this normal from shader affects surface colouring calculation, if this is performed by POV-Ray (i.e. texture finish contains diffuse or specular component).
    Ng Surface geometric normal. This is normal, returned by intersection calculation.
    I Ray direction.
    Ci Result rgb component for color, which is sent to  POV-Ray as pigment color.
    Oi 1-st channel's (R component) value is set as transmittance component of POV-Ray pigment color.
    u surface's u value
    v surface's v value
    s is set to u 
    t is set to v
    du not used
    dv not used
    time is set equal to POV-Ray clock value
    E Camera position.
    Cl color of evaluated light source
    L direction of evaluated light source.
    As Ambient component, returned by ambient() function in shading language. Could be set in scene file as shader parameter. If this value in not set, then default value <0,0,0> is used instead. 


    POVMan supports in limited way non-object pigment definitions. By non-object here is meant POV-Ray features, which don't have all the properties of "usual objects", such as clearly defined intersection with ray, normal at given point, support for transformations etc. Example of such non-object is sky_sphere. If shader is used as pigment for such object, then available built-ins are:

    POVMan issues warning, if shader is used for such non-object, but does not limit shader use in such cases, so it is up to user to ensure, that no other built-in variables are used, as it may lead to undefined behaviour.

    Additionally, non-object shaders do not support shading and lighting functions, such as illuminance, diffuse, etc.

    POVMan version 0.7 has support for isosurface shaders, i.e. shading language could be used to calculate isosurface functions. Shading language has new keyword iso_function, which specifies, that current shader is used for isosurface calculation. iso_function should return float value, which is used in isosurface calculation as potential value for given point P. For example sphere could be created with following shader file:

    iso_function sphere(float radius=1){
        return length(P)-radius;
    }
    
    In scene language isosurface function could be used as follows:
    #declare ShaderSphere = function{
        shader{
            shader_file "sphere.slp"
            "radius" 3
        }
    }
    isosurface{
        function{
            ShaderSphere
        }
        ...
    
    
    For isosurface shaders only initialized built-in value is evaluation point P. All other built-in variables are uninitialized and should not be used. Current version of SL compiler does not check for this, so shader creator should ensure correctness of shaders. See also examples section for other examples of isosurface shaders.

    How slow are shaders?

    One question, which is often asked, is "how slow are shaders with comparison to POV-Ray textures?" Well, that depends! would be probably most correct answer. Here are some numbers to ponder (note: they were measured with my 486/DX2 66 MHz,which is rather old box in today's terms, so with newer processors and configurations it may vary): Test scene was as follows:
    camera{
        location <0.5, 1, -7>
        direction <0, 0, 1>
        up <0, 1, 0>
        right <4/3, 0, 0>
        look_at <0.5, 1, 0>
    }
    light_source{
        <10, 10, -10>
        color rgb 1
    }
    // set this var. to 0 to test POV-Ray pigment
    #declare TestShader=1;
    
    sphere{
        0, 6
        texture{
            pigment{
                #if (TestShader)
                shader{shader_file "red.slp"}
                #else
                color <1,0,0>
                #end
            }
            finish{
                ambient 1
                diffuse 0
            }
        }
    }
    
    and red.sl was as follows:
    surface red(color cl=color(1,0,0)){
        Ci = cl;
    }
    
    With shader this scene was rendered in 16 seconds, with POV-Ray pigment in 14 seconds. So pure shader call is ca. 15 % slower than setting just POV-Ray pigment value. If shaders are more complicated, then shader execution time will grow as well, but taken into account the flexibility of shaders this seems to be good tradoff.

    If SL is used for isosurface functions, then this combination could be in some scenes even faster than MegaPOV's isosurface functions, which are written in scene description. Here are some results of isosurface measurments in seconds:
    isosurface type builtin function user function shader
    sphere 35 68 46
    torus 35 161 62
    surfaces from math_pigm.pov N/A 29 10
    ridgedMF 300 N/A 658

    As it could be seen, shaders are slower, than built-in functions, but faster than user functions. This of course depends from actual function, but given the flexibility of shader language (one can use loops and conditionals quite easily, e.g. see sponge scene!) and possible faster execution, it seems to be good idea to implement user defined functions in SL.
    Additionally, it pays off to tinker with shader code a little bit and try various solutions for given algorithm. I've quite often reduced code size (and execution time) by factor of 2 after recoding. Thing to observe is code size in compiled file. And sometimes it is good to look at bytecode (compile with option -c) in order to get idea about possible optimizations.

    Changes list

    Version 0.71.3

    Version 0.7

    Version 0.62

    Legal stuff


    "POV-Ray", "Persistence of Vision", "POV-Team" and "POV-Help" are trademarks of POV-Team.
    RenderMan (R) is a registered trademark of Pixar.

    This is unofficial version of POV-Ray. Do not ask the POV-Team for help with this patch. Official version of POV-Ray can be downloaded from http://www.povray.org  and POV-Ray licence could be found in povlegal.doc file.

    Original POVMAN version was created and copyrighted by Bob Mercier, who kindly gave me permission to use his code for merging it with current POV-Ray version and adding new features. Original POVMAN version's homepage could be found in http://www.cinenet.com/~mercier/bigpict.html

    Current version (0.7) contains cloth patch code from ClothMan program, created by Christophe Bouffartigue(tofbouf@free.fr) and used with his permission. Merci, Bouf!


    This program is copyrighted freeware, which follows POV-Ray license agreement. If POV-Team decides to incorporate this patch to official version, then POV-Team team aquires rights, mentioned in POV-Ray licence agreement.

    THIS SOFTWARE IS PROVIDED AS IS, WITHOUT ANY GUARANTEES OR WARRANTY. AUTHORS ARE NOT RESPONSIBLE FOR ANY DAMAGE OR LOSSES OF ANY KIND CAUSED BY USE OR MISUSE OF THIS SOFTWARE.
     

    Contact information

    Author of this patch could be contacted at following e-mail address:
    vahur@aetec.ee
    This is the most sure way to contact me and to be sure, that I'll see your message. I'll try to answer to all mails, but please take into account, that this is my free time project and Real Life (TM) doesn't leave me much of it. So please mail only if necessary.
    Additionally, I try to keep up with most of newsgroups in POVRay server. So, if question is posted there, then I might see it and answer to it. But there is no guarantee for this, as due to lack of time I read them selectionally.
    As a last resort, I follow comp.graphics.rendering.raytracing and comp.graphic.rendering.renderman newsgroups and they can be used for communication.
      Current version (0.7) contains cloth patch code from ClothMan program, created by Christophe Bouffartigue(tofbouf@free.fr) and used with his permission. Merci, Bouf!