next up previous contents
Next: Caustics Up: Get Your Hands Dirty Previous: Stairs   Contents


Simple Room

Figure 16: A simple scene in a room with a window
\includegraphics[scale=0.75]{houdini.01.ps}

To understand how rendering works it's always a good idea to take an example from one renderer and try to create a similar picture with another renderer. If you can't get away by using standard shaders it might be a good starting point for writing a few shaders.

I started a few years ago a comparison between different renderers and came across a renderer called Radiance27. This simple example is based on a tutorial28 for this renderer.

Have a look at figure 16. You will see a simple room with a floor, a ceiling, and four walls. One of the walls has a hole where a window can be placed. The camera looks at two simple objects in the room: A glass sphere and a blue box. The light is coming from two light sources: There is another sphere in the room which acts as a light source and we can think of daylight coming from outside through the window. Although the scene is quite simple it can give you some headache how to produce certain effects29 with your favourite renderer:

  1. First of all a glass sphere reflects and refracts light rays. Which makes it hard to fake it with a simple scanline renderer.

  2. None of the light sources is directly visible but the spherical light inside the room is shown several times in the glass sphere. Most of the renderers don't show a light source even if you would look directly into the direction where the light is located. You have to take care yourself that there is a geometry which looks like a light bulb or anything which motivates where the light comes from.

  3. The light which comes from outside through the window is seen as a direct reflection of the window itself from the front of the sphere, as a refracted and therefore distorted copy on the back side of the sphere, and as a direct reflection of the light which is cast on the floor and one of the walls30.

  4. In theory you could have caustics in the scene created by focusing and dispersion of light by specular reflection or refraction but let's talk about that later31.

Figure 17: Reflections in a glass sphere (Radiance)
\includegraphics[scale=1.0]{radiance.ps}

Figure 18: Reflections in a glass sphere (mental ray)
\includegraphics[scale=1.0]{room.mr.ps}

Let's first try to make life easier by using a renderer with ray tracing and a lot of standard shaders coming with it. I reproduced the scene with mental ray and here are some comments about the effects I was talking about before and how they were achieved:

  1. The material used in the original Radiance file is called dielectric and described in the Radiance Reference Manual as: ``A dielectric material is transparent, and it refracts light as well as reflecting it. Its behaviour is determined by the index of refraction and transmission coefficient in each wavelength band per unit length. Common glass has a index of refraction around 1.5, and a transmission coefficient of roughly 0.92 over an inch. An additional number, the Hartmann constant, describes how the index of refraction changes as a function of wavelength. It is usually zero.'' Mental Ray comes with a physics library and you should be able to get the source code for the shaders from mental images' FTP site. If you look into the header file32 of the shader called dielectric_material you will find all parameters for this material shader. In this case I used the col parameter for the light absorption per unit-length and the ior parameter for the index of refraction:

    material "crystal"
            opaque
            "dielectric_material" (
                    "ior" 1.5,
                    "col" 0.5 0.5 0.5,
                    "lights" [ "Lamp_inst", "Sun_inst" ]
            )
    end material
    

    Ray tracing can be either turned on in the global options statement or a shader33 specifies that it can operate only if ray tracing is enabled. In the later case mental ray will enable ray tracing even if no ray tracing was specified in the global options statement.

  2. I decided to make the light source inside the room visible by using an area light source:

    light "Lamp"
            "physical_light" (
                "color"     60 60 60
            )
            visible 
            origin  0.0 0.0 0.0
            sphere .125 15 15
    end light
    

    For mental ray the type of a light source is determined by the absence or presence of some parameters. If you define only an origin you will have a point light. An infinite light requires only a direction whereas a spot light must be given an origin, a direction, and a spread value. Please be aware that the spread value is already the cosine value of a given angle. Most of the standard shaders for spot lights will have a cone parameter which is also given as a cosine value instead of specifying the angle in degrees or radians. For RenderMan compatible renderers the spotlight shader requires angles in radians and calculates the cosine value inside the shader.

    There are four different shapes of area light sources: rectangles, flat discs, spheres, and cylinders. Although mental ray 3.1 adds arbitrary geometric objects, and a user-defined shape we can simply use a sphere with an radius of $0.125$ and $15$ samples in u- and v-direction. To make the light source sphere visible in the reflection and refraction of the glass sphere on the blue box we use the keyword visible. Have a look in the source code of light source shaders to see how to deal with rays which hit the geometry of the light source directly. Another aspect of area light sources are soft shadows. You don't get soft shadows for the light source inside the room by using Radiance but you do get soft shadows for mental ray. The difference is that Radiance uses always visible light sources but this does not necessarily mean that Radiance uses area lights.

  3. One thing we can't easily translate into other renderers is the usage of the illum material used by Radiance for the window. Have a look again at figure 17 or 18. There are two aspects of the light coming through the window. There is a very bright spot of light cast on the ground and one of the walls, and there is the visibility of the window itself. If you compare figure 17 and 18 more carefully you might notice that you get a reflection of the light source inside the room even in the reflections of the window itself in the image created by Radiance. This additional reflection is missing in the image I created with mental ray.

    Let's first read what the illum material in Radiance does: ``Illum is used for secondary light sources with broad distributions. A secondary light source is treated like any other light source, except when viewed directly. It then acts like it is made of a different material (indicated by the string argument), or becomes invisible (if no string argument is given, or the argument is "void"). Secondary sources are useful when modelling windows or brightly illuminated surfaces.''

    I decided to split the two aspects into two different solutions for mental ray. The very bright spot of light cast on the ground and one of the walls is simulated by adding another light source to the scene which acts like the sun shining from outside through the window on the floor. The sky simulation in Radiance creates the following file called sky.rad:

    # gensky 3 20 10 -a 40 -o 98 -m 105
    # Local solar time: 10.34
    # Solar altitude and azimuth: 43.3 -35.4
    # Ground ambient level: 17.7
    
    void light solar
    0
    0
    3 6.73e+06 6.73e+06 6.73e+06
    
    solar source sun
    0
    0
    4 0.421409 -0.593560 0.685639 0.5
    
    void brightfunc skyfunc
    2 skybr skybright.cal
    0
    7 1 1.10e+01 2.12e+01 5.45e-01 0.421409 -0.593560 0.685639
    

    I don't want to explain exactly how this works but the important information from this file is the direction where the sun is. There is a vector $v = (0.421409, -0.593560, 0.685639)^\top$ used twice in this file. This is the direction vector to the sun. Instead of using a very distant light with a very high color value representing the energy I decided to calculate a matrix which will position the light source for the sun 100 units away from the middle of the window34 along the vector mentioned above and find some values for the light energy which do look good:

    light "Sun"
            "physical_light" (
                "color"     1e7 1e7 1e7
            )
            origin 0 0 0
    end light
    
    instance "Sun_inst" "Sun"
            transform
                            1.0 0.0 0.0 0.0
                            0.0 1.0 0.0 0.0
                            0.0 0.0 1.0 0.0
                            -45.1409 58.356 -69.5639 1.0
    end instance
    

    The reason why I didn't use a distant light source is that in mental ray a distant light source has no origin. But how can I specify that the light source representing the sun is outside the room and does not illuminate other objects directly beside that little portion of the ground and one of the walls? I think 100 units is far away enough to make the light rays which are emitted from a point light and go through the window nearly parallel and the values for the light color a purely found by ``try and error''.

    The second aspect is the visibility of the window itself. Because the window is never seen directly in the final image I decided to represent the ``window'' just by the absence of geometry at the hole in the back wall. This hole means that the reflected rays will leave the scene without hitting any geometry. In this case an environment shader is called by mental ray if the MI file representing the scene defines one. I first tried to use a simple phenomenon:

    declare phenomenon
            color "env_sh" (
            )
            shader "tex" "mib_opacity" (
                    "input" 9.0 9.0 10.0,
                    "opacity" 1.0 1.0 1.0
            )
            root = "tex"
    end declare
    
    camera "Camera"
            frame           1
            output          "rgb" "room.rgb"
            focal           35.0
            aperture        32.0
            aspect          1.0
            resolution      510 510
            environment "env_sh" ()
    end camera
    

    This phenomenon creates an unwanted artefact. The rim of the sphere gets the same slightly blue color as the reflections of the window. Why is that? Well, at the rim of the sphere the refracted and reflected rays hitting the front and back of the sphere might bounce back and forth. This effect can happen a lot with material similar to glass especially if it's attached to geometry with a lot of curvature or local displacements. The solution to this problem is to write a very simple environment shader:

    /* myEnvironment.c */
    
    #include <shader.h>
    
    struct myEnvironment
    {
      miColor color;
    };
    
    DLLEXPORT miBoolean 
    myEnvironment(
                  miColor* result,
                  miState* state,
                  struct myEnvironment* paras
                  )
    {
      miColor* color;
    
      /* get parameters */
      color = mi_eval_color(&paras->color);
      /* result */
      if (state->reflection_level >= (state->options->reflection_depth - 1) ||
          state->refraction_level >= (state->options->refraction_depth - 1) ||
          (state->reflection_level + state->refraction_level) >= 
          (state->options->trace_depth - 1))
        {
          result->r = 0.0;
          result->g = 0.0;
          result->b = 0.0;
        }
      else
        {
          *result = *color;
        }
    
      return(miTRUE);
    }
    

    Basically environment shaders get called for rays that leave the scene entirely, and for rays that would exceed the trace depth limit. If mental ray reaches the maximum number of reflection or refraction rays or a combination of them my simple environment shader will return ``black'' instead of the color which was given to the shader as a parameter.

    Now you can change the environment shader attached to the camera to render the same image as shown in figure 18:

    ...
    link "myEnvironment.so"
    $include <myEnvironment.mi>
    ...
    camera "Camera"
    ...
            environment "myEnvironment" ("color" 9.0 9.0 10.0)
    end camera
    ...
    

    The high values for the color are not motivated by proper physics. I used ``try and error'' again to find values which do look good but be aware that if you would rotate the camera and look straight at the ``window'' the result would be very bright. In Radiance however you could do that because the illum material takes care of that.

    Another thing which is missing in the final image rendered with mental ray are the shadows cast by light which was emitted from the sun, scattered around by hitting the ground, buildings or plants, and finally contributed to the illumination of the room. I thought about adding another area light at the window position which is not visible but does emit a few rays to create a soft shadow on the wall behind the glass sphere. But I leave that as an exercise.

  4. Finally, I didn't add caustics to the scene. I made some experiments with that but the effect didn't contribute that much to the quality of the picture. So I dropped it. Radiance didn't calculate caustics either. Beside that the rendering time can be quite high for caustics and the color values for the physical_light shader should match the energy used to emit photons. See section 4.4 for a better example with caustics.


next up previous contents
Next: Caustics Up: Get Your Hands Dirty Previous: Stairs   Contents
Jan Walter 2004-02-09