Prev | Next



The Brick Map Geometric Primitive

December, 2005 (Revised March, 2009)

1   Introduction

Brick maps were introduced in PRMan 12.0 as a 3D data structure for textures on surfaces and in volumes. PRMan 13.0 extended the use of brick maps to also allow their use as a geometric primitive (on equal footing with the other geometric primitives such as quadrics, polygon meshes, NURBS patches, and subdivision surfaces). Being a geometric primitive, brick maps can be rendered (using the Reyes algorithm), ray-traced, motion blurred, shaded, displacement mapped, and most of the other things that geometric primitives can do.

The purpose of this application note is to provide examples for the use of brick map geometric primitives using PRMan 13.0 and higher.


2   Rendering

A brick map can be rendered as a geometric primitive using the following RIB syntax:

Geometry "brickmap" "filename" <filename>

2.1   Surface brick map

For example, assume you have a brick map of surface data. The brick map is called 'irmateapot.bkm' and the color data at the four coarsest levels look like this:

images/figures.brickmapgprim/irmateapot_bkm0.jpg

Level 0

images/figures.brickmapgprim/irmateapot_bkm1.jpg

Level 1

images/figures.brickmapgprim/irmateapot_bkm2.jpg

Level 2

images/figures.brickmapgprim/irmateapot_bkm3.jpg

Level 3

(For reference, Appendix A contains the shader and RIB file used to generate this brick map.)

In addition to the color data, each voxel in this brick map also contains surface position data, normal data, and opacity data. (All opacity data are 1.)

We recommend storing P and N channels in the brick map if it is intended for use as a geometric primitive. This gives a higher accuracy of the rendered brick map surface, particularly along the silhouettes. The P and N channels can either be explicitly baked into the point cloud, or the -addpn option to brickmake will add them automatically. More on this in appendix A.

Here is a short RIB file to illustrate the use of the brick map as a geometric primitive.

FrameBegin 0

  Format 400 300 1
  ShadingInterpolation "smooth"
  #ShadingRate 100   # high shading rate
  PixelSamples 4 4
  Display "teapot_render" "it" "rgba"
  Projection "perspective" "fov" 25
  Translate 0 0 12

  WorldBegin

    # Brick map geometric primitive: large textured teapot
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: medium textured teapot (left)
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      Translate -2.5 -0.85 -1
      Scale 0.15 0.15 0.15
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: smallest textured teapot (right)
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      Translate 2.5 -0.95 -2
      Scale 0.05 0.05 0.05
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd
  WorldEnd
FrameEnd

Note that the brick map geometric primitive has no surface shader in this example, so the color and opacity will be read from the Cs and Os data in the brick map. (Surface "" can also be used instead of Surface "null".) If the brick map has no Cs data, the Color attribute will be used instead. If the brick map has no Os data, the Opacity attribute will be used instead. (See the Shading section for examples.) Running this RIB file gives the following result:

images/figures.brickmapgprim/teapot_render.jpg

Rendered brick map geometric primitive

The appropriate level in the brick map is chosen based on the screen size of the brick map geometric primitive and the shading rate. During rendering, the bricks are read on demand at the appropriate size and cached in a brick cache.

Implementation detail: Each brick voxel is rendered as a disk. This can be seen more clearly if the shading rate is increased. The images below are rendered with shading rate 100 and 100000, respectively, and the disks can be seen clearly.

images/figures.brickmapgprim/teapot_render_shadingrate100.jpg

Shading rate 100

images/figures.brickmapgprim/teapot_render_shadingrate100000.jpg

Shading rate 100000

In the left image, some of the disks along the edges are rendered as partially transparent. This is due to lerping of two different levels of detail of the brick map. In the image on the right, all three teapots are rendered using the coarsest level in the brick map (8x8x8 voxels).

If P and N aren't baked among the data, each brick voxel is rendered as a disk centered at the voxel center and facing the camera - as illustrated below. This inevitably leads to bloated silhouettes.

images/figures.brickmapgprim/teapot_render_shadingrate100_noPN.jpg

Shading rate 100 (no P and N data)

images/figures.brickmapgprim/teapot_render_shadingrate100000_noPN.jpg

Shading rate 100000 (no P and N data)

For long thin geometry such as cylinders there is an additional source of silhouette bloat. This happens because the points along the cylinder are much further apart than along the radial direction. The radius values have to be large enough that the disks cover the space between points along the cylinder. This unfortunately gives point radii that makes the thin geometry bloat a lot. Creating a brick map from this point cloud will give brick voxels that are much larger than the width of the cylinder. The workaround to avoid this is to reduce the ShadingRate when the point cloud is baked and rendered. This will of course lead to larger point cloud and brick map files, but it is unfortunately the only way the brick map geometric primitive can be made to represent very thin geometry correctly.

2.2   Semitransparent (volume) brick map

For another example, consider a brick map that has been generated from volume data: the data points do not have normals and each brick voxel is semitransparent. (For reference, appendix B at the end of this document contains the shader and RIB file used to generate this brick map.) When rendered, all the semitransparent brick voxels are alpha-composited. Here is an example RIB file:

FrameBegin 0

  Format 300 300 1
  ShadingInterpolation "smooth"
  PixelSamples 4 4
  Display "torusvol_render" "it" "rgba"
  Projection "perspective" "fov" 15
  Translate 0 0 10

  WorldBegin
    # Brick map geometric primitive: semitransparent torus
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      Rotate 25 1 0 0
      Rotate 25 0 1 0
      Geometry "brickmap" "filename" "torus.bkm"
    AttributeEnd
  WorldEnd
FrameEnd

The colors and opacities are read from the brick map. Here is the rendered image of the semitransparent brick map:

images/figures.brickmapgprim/torusvol_render.jpg

Rendered brick map geometric primitive (volume data)

images/note_note.gif

PRMan version 15.0 introduced a better way to render volume brick maps. A volume brick map is rendered as an implicit ("blobby") object using the following syntax:

Blobby 1 [8 1004  0 0 0 1 1] [0] ["impl_brickmap.so" "foobar.bkm"] "varying color Cs" []

Rendering brick maps as blobby volumes is covered in detail in the Volume Rendering application note.


3   Ray tracing

Brick maps can also be ray-traced. The appropriate level in the brick map is chosen based on the ray differential size. For an example of a ray-traced brick map, consider the following rib file:

FrameBegin 0

  Format 400 300 1
  ShadingInterpolation "smooth"
  PixelSamples 4 4
  Display "teapot_raytrace" "it" "rgba"
  Projection "perspective" "fov" 25
  Translate 0 0 12

  WorldBegin

    Attribute "visibility" "specular" 1   # make objects visible to rays

    # Brick map geometric primitive: large textured teapot
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: medium textured teapot (left)
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      Translate -2.5 -0.85 -1
      Scale 0.15 0.15 0.15
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: smallest textured teapot (right)
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      Translate 2.5 -0.95 -2
      Scale 0.05 0.05 0.05
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Reflecting ground plane
    AttributeBegin
      Surface "aachrome"
      Translate 0 -1 0
      Scale 10 10 10
      Polygon "P" [ -1 0 1  1 0 1  1 0 -1  -1 0 -1 ]
    AttributeEnd

  WorldEnd
FrameEnd

Running this RIB file generates the following image (with ray-traced reflections at the bottom):

images/figures.brickmapgprim/teapot_raytrace.jpg

Directly rendered and ray-traced brick map geometric primitive

The previous example showed ray-traced reflection of a brick map geometric primitive. Brick map geometric primitives can also cast ray-traced shadows.

As another example, we can add a reflecting ground plane to the rib file for the semitransparent torus brick map. When a ray hits a semitransparent brick voxel it automatically continues to the next voxel, etc. The colors and opacities are composited along the way. This corresponds to ray marching through the volume of the brick map.

images/figures.brickmapgprim/torusvol_raytrace.jpg

Rendered and ray-traced brick map geometric primitive

Brick map geometric primitives with opacity data can also be used to cast semitransparent shadows. The shadow rays are automatically propagated through the brick map voxels, and the opacity values are composited along the way.

images/figures.brickmapgprim/torusvol_raytrace_shadow.jpg

Ray-traced shadow from a brick map geometric primitive


4   Color bleeding

It is simple to compute color bleeding from a brick map geometric primitive. For example:

FrameBegin 0

  Format 400 300 1
  ShadingInterpolation "smooth"
  PixelSamples 4 4
  Display "teapot_indirectdiffuse" "it" "rgba"
  Projection "perspective" "fov" 25
  Translate 0 0 12

  WorldBegin

    # Brick map geometric primitive: large textured teapot
    AttributeBegin
      Attribute "visibility" "diffuse" 1
      Attribute "shade" "diffusehitmode" "primitive"
      Surface "null"   # no surface shader: use Cs and Os data
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Ground plane with indirectdiffuse computation
    AttributeBegin
      Surface "indirectsurf" "samples" 256 "maxvariation" 0.01
      Translate 0 -1 0
      Scale 10 10 10
      Polygon "P" [ -1 0 1  1 0 1  1 0 -1  -1 0 -1 ]
    AttributeEnd

  WorldEnd
FrameEnd

The indirectsurf shader simply calls the indirectdiffuse() function and assigns the result to Ci.

The resulting image is shown below. The colors of the teapot-shaped brick map geometric primitive are bleeding onto the ground plane.

images/figures.brickmapgprim/teapot_indirectdiffuse.jpg

Color bleeding from a brick map geometric primitive


5   Motion blur

Brick map geometric primitives can be rendered with transformation motion blur. Here is a RIB file illustrating various transformations:

FrameBegin 0

  Format 400 300 1
  ShadingInterpolation "smooth"
  PixelSamples 10 10
  Display "teapot_rendermb" "it" "rgba"
  Projection "perspective" "fov" 25
  Translate 0 0 12

  Shutter 0.0 1.0

  WorldBegin

    Attribute "visibility" "specular" 1   # make objects visible to rays
    Attribute "trace" "samplemotion" 1   # ray tracing motion blur

    # Brick map geometric primitive: moving large textured teapot
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      MotionBegin [0.0 1.0]
        Translate -0.25 0 0
        Translate 0.25 0 0
      MotionEnd
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: rotating medium textured teapot (left)
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      Translate -2.5 -0.85 -1
      MotionBegin [0.0 1.0]
        Rotate 0  0 1 0
        Rotate 45.0  0 1 0
      MotionEnd
      Scale 0.15 0.15 0.15
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: shrinking small textured teapot (right)
    AttributeBegin
      Surface "null"   # no surface shader: use Cs and Os data
      Translate 2.5 -0.95 -2
      MotionBegin [0.0 1.0]
        Scale 0.15 0.15 0.15
        Scale 0.05 0.05 0.05
      MotionEnd
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Reflecting ground plane
    AttributeBegin
      Surface "aachrome" "samples" 64
      Translate 0 -1 0
      Scale 15 15 15
      Polygon "P" [ -1 0 1  1 0 1  1 0 -1  -1 0 -1 ]
    AttributeEnd

  WorldEnd
FrameEnd

Running this RIB file generates the following motion-blurred image (with ray-traced reflections at the bottom):

images/figures.brickmapgprim/teapot_rendermb.jpg

Motion-blurred brick map geometric primitive

At the present time it is not possible to render brick map geometric primitives with deformation motion blur. It might be implemented in a future release.


6   Shading

In the previous examples, the brick maps "inherited" their color and opacity from the voxel data. However, it is also possible to run shaders on the brick map geometry (just as for other geometric primitives).

6.1   Color

Here is an example that runs three different shaders on the three instances of the brick map geometric primitive. The P, N, Cs, and Os values are read from the data in the brick map. (Again, the Color and Opacity attributes are used if those data are not present in the brick map. And voxel centers are used if there are no P and N data in the brick map.)

FrameBegin 0

  Format 400 300 1
  ShadingInterpolation "smooth"
  PixelSamples 4 4
  Display "teapot_rendershaded1" "it" "rgba"
  Projection "perspective" "fov" 25
  Translate 0 0 12

  WorldBegin

    Attribute "visibility" "specular" 1   # make objects visible to rays
    Attribute "visibility" "transmission" "opaque"
    Attribute "trace" "bias" 0.1   # large bias to avoid self-shadows

    LightSource "pointlight_rts" 1 "from" [-10 10 -10] "intensity" 500
    LightSource "ambientlight" 2 "intensity" 0.2

    # Brick map geometric primitive: large teapot
    AttributeBegin
      Surface "paintedplastic"
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: medium teapot (left)
    AttributeBegin
      Surface "matte"
      Translate -2.5 -0.85 -1
      Scale 0.15 0.15 0.15
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: smallest teapot (right)
    AttributeBegin
      Surface "constant"
      Translate 2.5 -0.95 -2
      Scale 0.05 0.05 0.05
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Reflecting ground plane
    AttributeBegin
      Attribute "trace" "bias" 0.0001 # normal bias for the reflection rays
      Surface "aachrome"
      Translate 0 -1 0
      Scale 10 10 10
      Polygon "P" [ -1 0 1  1 0 1  1 0 -1  -1 0 -1 ]
    AttributeEnd

  WorldEnd
FrameEnd

The resulting image looks like this:

images/figures.brickmapgprim/teapot_rendershaded1.jpg

Shaded brick map geometric primitive

The light source shader traces shadow rays; the ray-traced shadows are most clearly visible at the base of the spout of the largest teapot. Since the brick voxels are a rather coarse approximation of the true surface, the ray tracing bias has to be rather high to avoid "surface acne" due to false self-intersections. Finding a proper value for the ray tracing bias is a general problem for shading of brick map geometric primitives.

The visual result of running the constant shader (as shown here on the smallest teapot) is the same as when running no shader. However, running the constant shader will take longer than no shader, mostly due to shader set-up overhead.

If (s,t), (u,v), Pref, or other parameters are needed for the surface shader they have to be baked in the brick map data - similar to how P, N, Cs, and Os were baked in this example.

Here is another example of shading of a brick map. In this case the shader does not rely on any baked data in the brick map. The shader computes a checkerboard pattern based on the x- and y-component of the position. (This shader does not properly anti-alias the edges between the two colors, but is chosen here for simplicity.)

Checkerboard shader:

surface
checkerxy(float frequency = 1)
{
  float x, y, cx, cy, c;

  x = frequency * xcomp(P);
  x = x - floor(x);
  y = frequency * ycomp(P);
  y = y - floor(y);

  cx = (x > 0.5) ? 1 : 0;
  cy = (y > 0.5) ? 1 : 0;
  if (cx == cy)
    Ci = 1; // white
  else
    Ci = color(1,0,0); // red
  Oi = 1;
}

RIB file:

FrameBegin 0

  Format 400 300 1
  ShadingInterpolation "smooth"
  PixelSamples 4 4
  Display "teapot_rendershaded2" "it" "rgba"
  Projection "perspective" "fov" 25
  Translate 0 0 12

  WorldBegin

    Surface "checkerxy"

    # Brick map geometric primitive: large teapot
    AttributeBegin
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: medium teapot (left)
    AttributeBegin
      Translate -2.5 -0.85 -1
      Scale 0.15 0.15 0.15
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: smallest teapot (right)
    AttributeBegin
      Translate 2.5 -0.95 -2
      Scale 0.05 0.05 0.05
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

  WorldEnd
FrameEnd

The resulting image:

images/figures.brickmapgprim/teapot_rendershaded2.jpg

Shaded brick map geometric primitive: checkerboard shader

Finally, here is an ambient occlusion example. The shader is replaced with a shader that computes ambient occlusion using the occlusion() function. Again, ray tracing bias is an issue; it must be set large enough to avoid false self-occlusion. Beware that computing ray-traced ambient occlusion and indirect diffuse illumination on brick map geometric primitives can be rather slow since no information is shared between shading points (maxvariation is ignored).

images/figures.brickmapgprim/teapot_renderoccl.jpg

Shaded brick map geometric primitive: ambient occlusion

6.2   Opacity

As an example of transparency, we can change the surface shader in the previous example to make checkered transparency:

surface
checkerxyopacity(float frequency = 1)
{
  float x, y, cx, cy, c;

  x = frequency * xcomp(P);
  x = x - floor(x);
  y = frequency * ycomp(P);
  y = y - floor(y);

  cx = (x > 0.5) ? 1 : 0;
  cy = (y > 0.5) ? 1 : 0;
  if (cx == cy) {
    Ci = 0; // black
    Oi = 0; // transparent
  } else {
    Ci = Cs; // color from baked data (or Color attribute)
    Oi = 1; // opaque
  }
}

The result is an image of a very fragmented teapot:

images/figures.brickmapgprim/teapot_rendertrans.jpg

Shaded brick map geometric primitive with checkered transparency

This example shows that fully transparent and fully opaque voxels are rendered correctly. However, semitransparent voxels can end up being rendered such that they look too opaque. This is because each surface point can be stored in up to eight voxels, i.e. surface data are often stored two voxels deep. When those voxels are rendered they are alpha-composited using their (baked or assigned) opacities. The end result is too much opacity. If the brick map contains semitransparent volume data, the brick map should be rendered as a volume brick map ("rendermode" "volume") for the opacity of semitransparent voxels to be correct. See the Volume Rendering application note for the details.

6.3   Displacement

It is often advantageous to run the displacement shader when the brick map geometry is created (as a point cloud). But it is also possible to run a displacement shader on the brick map geometric primitive, as shown in the following example.

Displacement shader that displaces the surface along the x-axis (with displacement magnitude depending on sine of y):

displacement
xydisp (float scale = 1, freq = 1)
{
  point Pobj = transform("object", P); // position in object space
  float y = ycomp(Pobj);

  float disp = scale * sin(freq * y); // displacement magnitude
  P += disp * vector(1,0,0); // displace along the x-axis

  N = calculatenormal(P); // compute new normal
}

Here is a RIB file that uses the displacement shader:

FrameBegin 0

  Format 400 300 1
  ShadingInterpolation "smooth"
  PixelSamples 4 4
  Display "teapot_renderdisplaced" "it" "rgba"
  Projection "perspective" "fov" 25
  Translate 0 0 12

  WorldBegin

    Attribute "displacementbound" "sphere" 0.1

    # Brick map geometric primitive: large teapot
    AttributeBegin
      Displacement "xydisp" "scale" 0.1 "freq" 10
      Surface "null"
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: medium teapot (left)
    AttributeBegin
      Displacement "xydisp" "scale" 0.05 "freq" 10
      Surface "null"
      Translate -2.5 -0.85 -1
      Scale 0.15 0.15 0.15
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

    # Brick map geometric primitive: smallest teapot (right)
    AttributeBegin
      Displacement "xydisp" "scale" 0.02 "freq" 10
      Surface "null"
      Translate 2.5 -0.95 -2
      Scale 0.05 0.05 0.05
      Geometry "brickmap" "filename" "irmateapot.bkm"
    AttributeEnd

  WorldEnd
FrameEnd

The resulting image of three displacement-mapped brick map geometric primitives looks like this:

images/figures.brickmapgprim/teapot_renderdisplaced.jpg

Brick map geometric primitive with displacement shader

There are a couple of limitations on the use of displacement-mapping on brick map geometric primitives: 1) If the displacement shader gives discontinuous (non-smooth) displacements, the result can be "torn" geometry, i.e. a surface with holes. 2) Ray tracing of brick maps with displacement shading is not implemented (the displacement will be ignored for ray tracing).

6.4   A note on transformations

Baked data of type point, vector, and normal are transformed to world space at baking time. Likewise, data of those types are transformed to the current camera space at lookup and shading time. These transformations are consistent with the transformations of vertex variables on other geometric primitives, and ensures that e.g. shading normals are correct. (If the transformation is not desired, it is a common trick to assign these data types to e.g. colors or three floats since those are not transformed.)

6.5   Texture filtering

If the brick map has baked P, N, and (s,t) data and the shader calls the texture() function, appropriate texture filter widths will be computed automatically. (In PRMan releases prior to 13.5 the texture filter widths on brick map geometric primitives were always set to 0, leading to texture aliasing artifacts.)

6.6   dPdu, dPdv, du, and dv

The vectors dPdu and dPdv are (1,0,0) and (0,1,0), respectively, transformed according to the world-to-camera transformation. (Length(dPdu) * du) and (Length(dPdv) * dv) are smooth approximations of the size (in camera space) of the brick voxels.

Currently the functions Du() and Dv() always return 0 when run on a brick map geometric primitive. This may change in the future.


7   Levels of detail

A fundamental problem with PRMan (and similar renderers) is that it cannot simplify complex geometry. For this reason, level-of-detail representation was introduced in the RenderMan specification. But the existing explicit level-of-detail method requires that the objects are modeled multiple times (with different amounts of detail). Here we will show that brick maps can sometimes provide a more convenient automatic level-of-detail representation.

Imagine a collection of complex objects that are only a few pixels large in most frames, for example, an armada of spaceships that have been individually modeled with full details, including all rivets and bolts. Each spaceship is seen up close in a few frames of a shot, so the details are required sometimes, but, in each shot, most of the spaceships are distant and only cover a few pixels. Now imagine that there is no time to model simpler versions of the spaceships due to production pressures and deadlines. If the fully detailed spaceships are used for rendering, their entire definitions will be read in (for example NURBS patch knot values or subdivision base meshes), converted to geometry, shaded, and rendered. Since there are so many spaceships and they are all specified in full detail, PRMan will soon run out of memory.

In contrast, brick maps have no overhead: no NURBS knots, no subdivision base mesh or the like. If a brick map geometric primitive only covers a few pixels, only the top level bricks will be read in. PRMan automatically chooses the appropriate level in the brick map (based on size on screen or ray differential).

If we get too close to a brick map (closer than the detail level the data were originally generated at), the finest brick map level is insufficient. The needed data are "missing", and the disks that represent the finest brick voxels become visible. The solution to this problem is to use the original geometric primitive in that case. For any single frame, there will be only a few objects that require the full, original object definition.

The following is a useful RIB file idiom for switching between the original geometry and the brick map representation:

AttributeBegin
  Detail [xmin xmax ymin ymax zmin zmax]   # "ruler" for detail calculations

  # Brick map for low detail
  DetailRange [0 0 detail1 detail2]
  Geometry "brickmap" ...

  # Original geometry for high detail
  DetailRange [detail1 detail2 1e38 1e38]
  ...
AttributeEnd

Here detail1 and detail2 determine at which size the brick map fades out and the original geometry fades in.


8   Brick cache

The brick cache is shared between brick map geometric primitives and brick map textures. This is natural since the bricks are the same underlying data structure.

The default size of the brick cache is 10 MB pr. thread (corresponding to e.g. 758 bricks if the brick voxel data consist of 6 floats). The brick cache size can be changed with the option:

Option "limits" "brickmemory" 10240

The memory size is specified in kilobytes, so the example above is 10 MB (same as the default size).

The brick cache size can also be specified in the rendermn.ini file. The syntax is as follows:

/prman/brickmemory          10240

As usual, the option overrides the rendermn.ini setting if both are specified.

More details and advice regarding brick cache sizes are described in the Baking 3D Textures application note.


9   Known limitations


10   Frequently Asked Questions

Q: How do I create a point cloud file?

A: Point cloud files can be generated in several ways: a) By rendering a scene with shaders that call the bake3d() function. b) By some stand-alone program that writes data points using the point cloud API described in the Baking 3D Textures application note.

Q: How do I create a brick map?

A: Brick maps are created from point cloud files using the stand-alone program brickmake.

Q: Can I go the other way, i.e. create a point cloud from a brick map?

A: Yes. If you assign a surface shader to the brick map primitive, and that shader calls bake3d(), you can generate a point cloud with one point pr. brick voxel. You can adjust the number and density of the generated points by changing the shading rate and/or image resolution.

Q: Is there a brick map API?

A: Yes and no. There is an API for reading brick maps - see The Brick Map File API. However, there is no API for writing brick maps since that would be hard to do efficiently: if you insert data at one level in the brick map all other levels have to be updated accordingly.

Q: When I render my brick map, it only renders the top level brick - no matter how I set the screen resolution and shading rate. What's up with that?

A: This can happen if some of the points in the point cloud (that was used to generate the brick map) have very large radius values. Try to eliminate the excessively large radii.


11   More information

The brick map data structure is described in Baking 3D Textures and also in the following publication:


12   Appendix A: Generating the textured teapot brick map

For ease of reference, here is the shader and RIB file that were used to generate the textured teapot brick map.

We recommend baking the positions P along with the normals N and other data for brick maps that are to be used as geometric primitives. The variable names must be "P" and "N". These extra data enable the rendered brick map to better approximate the original surface, and also reduce trace bias issues when ray tracing the brick map geometric primitives. A point cloud is no longer required to have explicit P and N channels with this data; instead, the brickmake -addpn command-line option can add them to the brick map even if the channels are not present in the point cloud.

Shader for baking surface color and opacity:

surface
bakeCsOs(string filename = "", displaychannels = "", texturename = "";
           float interpolate = 1)
{
    color irrad, tex = 1, illumsurfcolor;
    normal Nn = normalize(N);

    // Compute direct illumination (ambient and diffuse)
    irrad = ambient() + diffuse(Nn);

    // Multiply by surface color
    if (texturename != "")
        tex = texture(texturename);
    illumsurfcolor = irrad * tex * Cs;

    // Store in point cloud file
    bake3d(filename, displaychannels, P, Nn, "interpolate", interpolate,
           "Cs", illumsurfcolor, "Os", Os);

    Ci = illumsurfcolor * Os;
    Oi = Os;
}

RIB file:

FrameBegin 0

  Format 400 300 1
  PixelSamples 4 4

  Display "teapot_bake" "it" "rgba"
  DisplayChannel "color Cs"
  DisplayChannel "color Os"

  Projection "perspective" "fov" 25
  Translate 0 0 12

  WorldBegin

    LightSource "ambientlight" 1 "intensity" 1

    Attribute "cull" "hidden" 0   # don't cull hidden surfaces
    Attribute "cull" "backfacing" 0   # don't cull backfacing surfaces
    Attribute "dice" "rasterorient" 0   # view-independent dicing !

    # Teapot
    AttributeBegin
      Surface "bakeCsOs" "filename" "irmateapot.ptc"
        "displaychannels" "Cs,Os" "texturename" "irma.tex"
      Translate 0 -1 0
      Rotate -90  1 0 0
      Geometry "teapot"   # standard "Utah" Bezier patch teapot
    AttributeEnd

  WorldEnd
FrameEnd

Running this RIB file generates the point cloud file irmateapot.ptc. (The point cloud file can be inspected using the interactive viewing program ptviewer, as shown in the image below.)

images/figures.brickmapgprim/teapot_ptc.jpg

Point cloud for textured teapot

A brick map is then generated using the brickmake program:

brickmake -addpn 1 irmateapot.ptc irmateapot.bkm

The brick map can be inspected using the interactive viewing program brickviewer - as shown in the first figure at the beginning of this application note.


13   Appendix B: Generating the semitransparent torus brick map

For easy reference, here is the shader and RIB file that were used to generate the brick map for the semitransparent torus.

Shader for baking volume color and opacity:

volume
baketorusvol(string filename = "", displaychannel = "";
             point center = (0,0,0);
             float a = 0.75; // major radius
             float b = 0.25; // minor radius
             float opacity = 0.05; // opacity at each point
             float frequency = 3, depth = 1, steplength = 0.1)
{
    color cs, os = opacity;
    point Pfront, Pcurrent, Pshad;
    normal N0 = 0;
    vector In = normalize(I);
    vector dx = steplength * In;
    vector diff;
    float d, x, z;
    uniform float steps = depth / steplength, step = 0;

    Pfront = P - depth * In;
    Pcurrent = Pfront;

    // March along ray through the volume
    while (step < steps) {

      Pshad = transform("shader", Pcurrent);

      d = length(Pshad - center);
      x = Pshad[0];
      z = Pshad[2];

      // Select points inside torus
      if ((d*d - a*a - b*b) * (d*d - a*a - b*b) < 4 * a*a * (b*b - z*z)) {
        // Compute marble texture
        float sum = 0, freq = frequency, i;
        for (i = 0; i < 6; i = i + 1) {
          sum = sum + 1/freq * abs(0.5 - noise(4 * freq * Pshad));
          freq = 2 * freq;
        }
        cs = 3 * sum + color(0.2, 0, 0); // brighten and add reddish tint

        // Write the marble texture data point to a point cloud file
        bake3d(filename, displaychannel, Pcurrent, N0, "Cs", cs, "Os", os);
      }

      // Advance one step
      step += 1;
      Pcurrent += dx;
    }

    Ci = cs;
    Oi = os;
}

RIB file:

FrameBegin 0

  Format 300 300 1
  ShadingInterpolation "smooth"
  PixelSamples 4 4
  ShadingRate 4   # coarse shading gives sparse baked points

  Display "torusvol_bake" "it" "rgba"
  DisplayChannel "color Cs"
  DisplayChannel "color Os"

  Projection "orthographic"
  Translate 0 0 10

  WorldBegin
    # Atmosphere shader bakes point cloud of volume texture
    Atmosphere "baketorusvol"
      "filename" "torus.ptc" "displaychannel" "Cs,Os" "opacity" 0.02
      "frequency" 1 "depth" 0.5 "steplength" 0.02

    # Back wall -- necessary to execute the atmosphere shader
    Surface "constant"
    Translate 0 0 0.25
    Polygon "P" [-1 -1 0  1 -1 0  1 1 0  -1 1 0]
  WorldEnd
FrameEnd

Running this RIB file generates the point cloud file 'torus.ptc'. Two ptviewer views of the point cloud are shown below:

images/figures.brickmapgprim/torus_ptc1.jpg

Point cloud for torus volume: front view

images/figures.brickmapgprim/torus_ptc2.jpg

Point cloud for torus volume: off-axis view

A brick map is then generated using the brickmake program:

brickmake torus.ptc torus.bkm

In this example, the color is varying (modulated by a procedural marble texture) while the opacity is constant. A more correct model of an inhomogeneous volume would have constant color but varying opacity.


Prev | Next


Pixar Animation Studios
Copyright© Pixar. All rights reserved.
Pixar® and RenderMan® are registered trademarks of Pixar.
All other trademarks are the properties of their respective holders.