The Brick Map Geometric PrimitiveDecember 2005 (Revised December 2006) |
|
Brick maps were introduced in PRMan 12.0 as a 3D data structure for textures on surfaces and in volumes. PRMan 13.0 extends 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). Brick maps being a geometric primitive means that they 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.
A brick map can be rendered as a geometric primitive using the following rib syntax:
Geometry "brickmap" "filename" <filename>
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:
![]() |
![]() |
![]() |
![]() |
(For reference, appendix A at the end of this document 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.)
New for PRMan 13.0.4: We now recommend baking P and N if the brick map is intended for use as a geometric primitive. This gives a higher accuracy of the rendered brick map surface, particularly along the silhouettes. 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 Section 6 for examples of shading.) Running this rib file gives the following result:
![]() |
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.
![]() |
![]() |
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 is also how brick maps were rendered in PRMan versions before 13.0.4.) As it can be seen, this inevitably leads to bloated silhouettes.
![]() |
![]() |
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.
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 volume brick map:
![]() |
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" "trace" 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):
![]() |
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 torus volume 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.
![]() |
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" "trace" 1 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.
![]() |
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" "trace" 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):
![]() |
At the present time (PRMan 13.0.4) it is not possible to render brick map geometric primitives with deformation motion blur. It might be implemented in a future release.
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).
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" "trace" 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 FrameEndThe resulting image looks like this:
![]() |
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:
![]() |
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).
![]() |
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:
![]() |
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.
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:
![]() |
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).
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.)
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.
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" 10240The 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 Section 5.4 of PRMan application note "Baking 3D Textures: Point Clouds and Brick Maps"
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 PRMan application note #39 "Baking 3D Textures: Point Clouds and Brick Maps".
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: The point cloud API is great. Is there a similar API for brick maps?
A: No, not at the present time.
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.
The brick map data structure is described in PRMan application note #39 "Baking 3D Textures: Point Clouds and Brick Maps" and also in the following publication:
For easy reference, here is the shader and rib file that were used to generate the textured teapot brick map.
New for PRMan 13.0.4: We now recommend baking the positions P along with the normals N and other data for brick maps that are to be used as geometric primitives. 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.
Shader for baking surface position, normal, color and opacity:
surface bakePNCsOs(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, "P", P, "N", Nn, "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 "point P" DisplayChannel "normal N" 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 "bakePNCsOs" "filename" "irmateapot.ptc" "displaychannels" "P,N,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.)
![]() |
A brick map is then generated using the brickmake program:
brickmake 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.
For easy reference, here is the shader and rib file that were used to generate the torus volume brick map.
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:
![]() |
![]() |
A brick map is then generated using the brickmake program:
brickmake torus.ptc torus.bkmIn 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.
Pixar
Animation Studios
|