CS348B Project Final Writeup: Rendering Sashimi

Crystal Chen
Peter Lai

Project Goal

Our goal was to realistically render sashimi. Right now, using pbrt, we can't render the subsurface scattering of light that occurs in raw fish. Also, we can't get the veins of the fish to look correct unless we were to use image texture maps, which are inflexible and hard to generate.

Subsurface Scattering

To implement Jensen et al's algorithm for subsurface light transport, we started off by defining a BSSRDF class that inherited from BSDF and encapsulated the extra parameters required to describe a translucent material. Finally, to this BSSRDF we added a FresnelBlend BRDF to give us the ability to render the glossy, oily surface of fish.

To make use of this BSSRDF class, we defined a new integrator that was responsible for subsurface light calculations. The new BSSRDFIntegrator basically used direct lighting calculations for all materials that weren't translucent. Translucent materials were also lit using direct lighting, but we added the single & multiple scattering terms from the Jensen paper. So, for each lit point, we calculate both scattering terms (using the analytic solution for single scattering and the dipole approximation for multiple scattering) and then add the glossy term from the BRDF on top of that. These terms are weighted equally in determining the lighting at the intersect point.

Calculating the scattering & absorption parameters for our salmon & tuna materials was an extremely time intensive process that involved a lot of trial and error (more error.) It was difficult to get both the color and amount of translucency correct -- deeper colors scattered less, so it was especially difficult to reproduce the dark purplish color of the tuna.

Procedurally Generated Vein Textures

The veins on the fish are generated procedurally as a solid texture. Parameters in the scene file allow the user to specify the normals of the planes along which the veins should appear, as well as the spacing between them. The veins are then generated as splines centered along those planes. The points around which to interpolate the spline are generated from user-specified parameters with some perturbation from Perlin noise.

In order to determine the texture at a particular point, the fish is sectioned into different slices, with one spline per slice. The noise for the spline is based on which slice on the fish that the point is in. We generate the spline for the particular depth in the object of the point, and then test to see whether or not our point falls on the spline. The thickness and spacing of the veins is also randomly perturbed using Perlin noise. Overall, the noise factor ensures that different veins on the same fish, and the same vein on different fish vary slightly.

This solid texture was applied as the scattering texture for the fish, so we were able to specify opaque veins within the translucent fish.


To generate the models, we used AC3D. Our meshes were quite simple, but the translucency, textures, and specular reflection smoothed out some of the sharp edges somewhat. Also, we used the built-in pbrt FBm texture as a bumpmap for the fish to generate the slightly rough appearance.


This is what we started off with, using pbrt's translucent material plugin. The translucent side is the side facing the camera, and the spottiness is caused by the decision at each pixel whether or not to let light transmit through.

wax block

This is an image of a wax-like block using our subsurface surface algorithm. We used an area light in a vacuum, so the sides aren't well-illuminated.

striped block

Stripes on a block, to demonstrate our procedurally generated solid texture.


This picture demonstrates the effect of bump mapping, some scattering, and some veins. It resembles wrinkled skin, we think, but this shows what we could do just by changing parameters.

final image

This is our final image. The tuna isn't as translucent as we would have wished, the color's a little off, and there are some dark spots where there shouldn't be thanks to the models and the fact that we used an area light instead of an infinite light, but everything's there. For comparison, here's our picture with none of our added effects, just our meshes & lighting:

no effects

And this is our original picture: original picture

Conclusions & Comments

Looking at our final image, there are some things that we could have done with extra time that would have improved our image. The first is finding better coefficients to produce more realistic colors & scattering in our fish. As we mentioned above, it was very difficult to get coefficients that were even close to the correct color, so knowing these numbers would enable us to produce a far better picture. Additionally, experimenting with the parameters defining the veins might have produced more natural variations.
Another thing we could have done is implemented the two-pass algorithm as described by Jensen -- our final render with 64 samples/pixel and 16 samples/light took nearly three hours to render. For our current scene file, the non-accelerated version was adequate because we didn't have that many objects, but if we were to include more translucent objects, it would probably slow down greatly.
Lastly, we probably could have spent more time on the models to produce smoother pieces of fish, where you aren't able to see the seams as much.


David S. Ebert, Texturing & Modeling: a Procedural Approach, 3rd ed.
Amsterdam; Boston: Morgan Kaufmann Publishers, 2003

A Practical Model for Subsurface Light Transport
Henrik Wann Jensen, Steve Marschner, Marc Levoy, and Pat Hanrahan
Proceedings of SIGGRAPH'2001, pages 511-518, Los Angeles, August 2001

A Rapid Hierarchical Rendering Technique for Translucent Materials
Henrik Wann Jensen and Juan Buhler
Proceedings of SIGGRAPH'2002, pages 576-581, San Antonio, July 2002