modified {{article.lastModStr}}
{{videoUrlObj.title || videoUrlObj.oEmbed.title}}
{{videoUrlObj.description || videoUrlObj.oEmbed.description}}
{{ article.videoUrls | totalDuration }}

Milk & Cookies

Created by Harsh Agrawal | @harsh2art


The project started with my interest in food photography. I had been planning to do a realistic CG food project for a while. I would go on Pinterest and drool upon plethora of amazing food photography that it has to offer. Decision making can be a hard process, and for me it was 10 months of procrastination until one late night I realize that I have been eating too many cookies while working. So here it is, a recipe to create some cookies and milk.

Recipe is very simple, and involves modelling, lighting, shading and rendering. There are some interesting parts when we get to create some cookie crumbs and milk bubbles.

Software Used

RenderMan 21, Maya 2016, ZBrush, MARI, Houdini, Photoshop

Completion time

25 hours

Downloadable Contents

Maya project with finished scene file Models ready to render Finished shading networks in RenderMan 21 Texture files Lighting with HDRI and Soft Boxes



We can start by creating a pinterest board of various cookies and milk photography, thinking about various composition and elements we like and dislike.

Let's take the cookie available with us and create a cheap setup for photography (Yes, it could be a cookie on a toothpick on a Toblerone) or a tripod. Take photographs all around the cookie so we can also use it as a sculpting and texturing reference later on. The hard part is not to eat the cookie.


We start by blocking out the scene in Maya using basic shapes. Modeling should be pretty straight forward using subdivs. While modeling, it's important to get the ratios, proportions and composition right. Once we have a general idea for our composition, we can then create the camera and set dress our elements accordingly.

Next we'll export the cookies to ZBrush so we can sculpt those nice organic details. For this composition we can just create one cookie, and then duplicate and rotate the cookie several times, to set dress, so we can be efficient and focus on making that one cookie look realistic. Using basic sculpt brushes, mainly move, clay and damian standard we can get a decent look. At this point we are focusing on basic shapes and some smaller cracks, choco chips etc. Micro-details can be added through displacements/bump maps when we shade. We can then export a mid-resolution version of our cookie to Maya, still containing most of the major sillouhette.

At this point we can also sculpt some bubbles in our milk. Making holes in geometry can be tricky, but ZBrush has us covered here. We simply paint a mask where we want holes in our mesh and then create polygroups based on mask selection. With our polygroups we can create panel loops to make it smooth and get desired shapes we want and then using the Curve Bridge tool we can create convincing bubbles in the milk.

Crumbs/Cookie Particles

Creating crumbs on the tray and on cookie surface is simple to setup in Houdini. Let's start by creating a Sphere, then creating multiple versions of distorted sphere using mountain node. We can then import our geometry in Houdini and create random points on surface. Using copy stamping we can easily scatter the cookie crumbs on the cookie.

To scatter on tray, we need a bit more control, and we can do that by painting density of crumbs we want on the tray and then duplicating those cookie crumbs on it.

Once all the geometry is created, we can then export it to Maya as an Alembic file.


Now that we have our scene setup in Maya, with all the geometry imported from Houdini and ZBrush, we can start to set up lights. Before setting up the lighting it is important to refer to some photographic references for lighting food and also read about real world lighting techniques. A lot of food photography uses a strong key light with a soft box, which is blocked by cards to create desired effects and bring the food to the focus. Good lighting is important for storytelling and leading the eyes of viewer to see what is important.

In our case we will start with a strong key light, adding some bounce light from a HDRI and then a rim light for shaping. To control the light emission energy we will explore several RenderMan features for control light, including geometrical light blockers.

Let's create a PxrRectLight, which is perfect for simulating a soft box. We can position it to the left of the scene and start an Interactive Preview Render(IPR) to visualize our lighting in real time. It's important to get correct placement of the light, looking at the composition and how the light falls onto the cookies and the shadows the light creates. Focusing on the light's position and intensity is a good starting point.

Intensity can be changed by adjusting exposure(F-Stops), intensity or scaling the light itself (make sure light is not normalized).

Once the light position and intensity starts to look good, we can also set the emission focus. This feature helps focus the light energy and in this case will help us achieve a nice gradation and fall-off. Using Cone Angle and Cone Softness can also help in refining the look of the gradient. Now let's plug in a Soft Box HDR as our Color Map within the light, so that we get subtle coloring in reflections and in the fall of areas of light. We want this key light to be fairly cool and the fill and bounces to be warm. This will help pop out the cookies and milk from the background elements.

We can now create a PxrDomeLight, this will act as our fill light. Similar to our key light we can adjust the intensity and plugin a HDRI in the Color Map channel.

We are using a free HDRIcreated by Maxime Roz available from this website: http://www.maximeroz.com/hdri-free-pack/

(soft box and environment HDRI are available with the asset files)

Finally let's create a rim light, this will help define the forms and allow the the silhouette to read more clearly. We can now fine tune the colors of each light by either adjusting the temperature control or the color swatch. Using IPR provides interactive control of the physically plausible lights, letting us focus on art direction and look development to quickly dial in the desired look, without having to worry about all the technical details or wait for a rendering to complete. .

Once The key, fill and rim lights are in ballpark, we can isolate each light for fine tuning. A lot of lighting tweaks will be also made while shading, going back and forth to achieve the correct look.


Now that we have our lighting setup, it's time to add some shading and textures to our scene. RenderMan 21 comes with various integrators, and we will be rendering this scene using PxrPathTracer. Since this is a forward path tracing algorithm, it will work well with our light setup with HDRI and key light. Let's start by setting up the shaders, Bxdfs, for our scene.

We can start by shading the set first, which involves background wall, tray and wooden table. We will use PxrSurface to shade all these objects. PxrSurface is an all purpose shader the provides a lot of freedom and versatility. Since these objects won't have any layers we can use PxrSurface to get the look we want (for a layered shader we'd choose pxrLayeredSurface). The material setup is simple and mostly involves Diffuse, Normal/Bump, Specular, Displacement and Specular Roughness.

It is good to think about building materials in lobes, i.e. Diffuse Lobe, Specular Lobe, Subsurface Lobe. This way we can focus on one material parameter at a time and build upon our shaders.

Diffuse Lobe: Typically we will define the albedo of a material by giving it a Diffuse map. We can paint on the UV's or give it a ptex map. We can adjust the multiplier (gain) to adjust the look.

Tip: Make sure your textures follow the linear workflow. In RenderMan 21 most of it is already taken care for us. While importing color map through PxrTexture node we can check the linearize button to make sure we see the expected color that we painted.

Tip: RenderMan has a special format for storing texture data, in .tex files. This format is useful for efficient LOD. It's a good idea to convert all your textures to .tex file format for PxrTexture node, you can do it manually one by one through txmake command or use the texture manager which allows to convert files recursively. Note, when using .tif, .exr or other formats, RenderMan for Maya will automatically run txmake and convert these images in the RenderMan folder. Pre-converting the files simply allows us to skip that step.

Specular Lobe: This is where we can plug in our maps to control the Specular Gain and also Roughness. Specular gain determines how reflective we want the material to be, and Roughness determines the glossiness of the material (shiny vs matte). A Specular map is generally added to the Face Color parameter, and the Roughness/Glossiness map is added to Specular Roughness parameter.

Face and Edge color controls the Fresnel fall off. Generally, all materials have high edge color thus increasing the reflection away from the camera viewing angle. RenderMan 21 also provides advanced controls like specular model, anisotropy and shading tangent. For our purposes we will leave those with default their settings and simply plug in our specular and roughness maps to get desired result.

Tip: Paint specular map (Face Color) to be black and white (0-1) and then use a PxrRemap node to control the output values of your map. Setting up shader this way will provide a lot of freedom for art direction without having to edit the image externally in Photoshop or Mari.

Bump/Normal: These can be created on a per lobe basis or globally. RenderMan 21 allows for adding bump to individual diffuse and/or specular channel or globally that affects each lobe. We can for most materials just use the global Bump Normal parameter to get those extra fine details. For the Normal map we can use, PxrNormalMap node instead of PxrTexture node. This way we can just point it to the normal map file and also adjust the scale of the bump in the same node. PxrSurface also allows for layered bump/normal which could be useful for getting additional layer of fine details.

SubSurface Lobe: This is useful to create some translucent effect where complex scattering of light occurs within the surface for example skin, ketchup or our cookie. RenderMan provides various Subsurface shading models to choose from for a variety of effects, like Jensen Dipole, d'Eon Better Dipole, Burley Normalized, and Multiple Mean Free Paths.

For our cookie, we will use Jenson Dipole model, since we are trying to produce a realistic result and using the same color map we used for diffuse it will give as a little more translucency in the occluded region of cookie, making it look natural.

There are 2 additional options: the Mean Free Path (MFP Distance and MFP Color.

MFP Distance defines how far that ray travels within the surface. MFP Color, on the other hand, defines which color/wavelength of light travels furthest.

RenderMan also gives us trace controls, Continuation Ray mode could be useful in scenarios where we are not getting enough scatter. By default it is off which means light simply traces out of the object.

By adjusting Subsurface gain, MFP Distance and MFP Color we can get the correct look for our cookie.

Single Scatter or Subsurface: Single scatter is an inexpensive scattering method, which can be used for most situations, but lacks fine controls. We will use Burley Normalized Subsurface, which provides added contrast and saturation for our milk.

In RenderMan 21 various Jensen subsurface models assume a locally flat, semi-infinite medium. PxrSurface gives us the added flexibility of combining single scatter with subsurface, for added Subsurface control in thin areas. This can be beneficial for added translucency if we are aiming for skim milk for example.

For our milk we will set Continuation Rays to All Hits, and then set our Max continuation hits to 10. These settings will generate a lot of scattering. We will also use the milk settings suggested in the RenderMan docs under Table of Scattering Values, keeping in mind scene scale in order to tweak our depth settings. The deeper the scattering, the more transparent the milk will look. Too much scattering, and our milk is at risk of looking too watery, too little scattering, and the milk will look waxy. Approximating a realistic subsurface balance is difficult, so always consult image references.

Another subsurface trick, was to use a very slight orange irradiance tint color value, which will tint the subsurface before the calculations happen, giving our milk a nice golden glow, this was done in order to counteract the cool lighting in the scene, which was making our milk too blue.

With most of our scene shaded, we can move on to creating our glass shader. The bottle requires a layered shader, so we will use PxrLayerSurface for this, and create several layers, base glass, milk droplets, dirt and dust. To add layers to PxrLayerSurface, we will plug in a PxrLayerMixer.

PxrLayerMixer is where we can define a base material and then layer other bxdf's on top of it using PxrLayer.

We will make a PxrLayer (glass) as our base layer. Then we will make another PxrLayer (milk) as layer 1 in PxrLayerMixer that goes on top of the glass. We will provide a Layer1 mask that will act as opacity for our milk on top of glass.

Glass Lobe: To create the bottle we will enable the Glass lobe. Here we can define the Refraction gain, Reflection gain and Refraction Roughness of the glass. We can also change IOR in the Advanced parameters, however we will use the default 1.5 because that is the IOR for glass. To make glass we want very low diffuse and high refraction.

Tip: Increase max Diffuse and max Specular depth based on the glass surface in render settings, this will ensure that you are seeing the correct refraction results by tracing objects inside and behind the glass geometry.


Now that we have shaded all of the objects in our scene, we can create different render elements that we can use to composite our image and do some color correction.

This is very straight forward in RenderMan, we can just enable various Light path Expressions (LPEs) to output our Diffuse, Specular, Indirect Lighting, etc, as secondary passes.

LPEs can be creating via the Render Settings -> Passes -> Outputs.

To create Matte ID for objects, RenderMan provides the PxrMatteID node. On each of our bxdfs we can add an extra RenderMan attribute for Matte ID and then connect it to PxrMatteID node. This will create flat color output, which can be used to composite and color correct specific areas. Each MatteID node can support upto 6 color IDs.

Once we have all our passes rendered as a 32-bit exr, we can import it into Photoshop and layer those elements on top of each other. This allows us to control individual render elements and do any color correction and minor tweaks to get the final look. At this point we can also add little bit of chromatic aberration and additional post effects to give it photographic qualities.


As we can see it is a simple recipe to create realistic image. With RenderMan 21 we get physically correct lighting and shading at our fingertips. Using straightforward workflows we are able to create a realistic image within a week's time. RenderMan 21 makes this cookie making process a breeze.

I hope you enjoy these cookies and milk at home and share your own version of this recipe.

About the Artist

Harsh Agrawal is a CG Generalist, specializing in shading, texturing and look development. I love watercoloring in my free time.

LinkedIn : https://in.linkedin.com/in/harsh2art



  • Changed Subsurface to use Burley Normalized instead of single scatter to take advantage of SSS noise optimizations for 21.2.
  • Reduction of polycount by up to 80%
  • Removed stuck turtle, mental ray and vray nodes
  • Optimized render settings
  • Shrunk all maps to 2k
  • RenderMan subD attributes added
  • Reimport of resulting scene into a fresh RenderMan 21 scene

Project Assets
  • {{tag.name}}

Log in to post a comment

{{ commentBody.length || "0"}} / 10 characters

No Comments, Yet