3D Still Life – Breakdown
NCCA student Zeno Pelgrims takes us through an in-depth tutorial of how he created 3D Still Life in Maya and ZBrush
I recently finished my still life image, so decided to do a quick breakdown of what's going on in the scene! I will go over the whole pipeline, from shooting the backplate and capturing the lighting information all the way through to compositing.
Shooting the backplate and capturing the lighting information
After I knew what I was going to do, it was time to shoot backplate and capture all the lighting information.
For this I used:
- Canon 5D Mark II
- 50mm 1.4f
- 8mm 3.5f fisheye
- Tripod with a panoramic head (One that clicks every # of degrees. Very useful when creating HDRs)
- Chrome & grey sphere (to check my lighting)
- Macbeth chart (to calibrate my colors)
The first thing I did was to try and make a composition that was less or more pleasing to the eye in real life, maybe trying to get some happy accidents in that occur MUCH more often in real life than in 3D. I also used it as my main big reference to shade objects. All in all, this is a very useful thing to do even if you're not using any of it in your 3D scene.
Shooting the backplate was very straightforward. I shot: a clean one, one with lighting checkers and one with a color checker. Something to note is that your camera has to be on manual mode. You do not want to have different settings for each of these shots. They all need to match!
Also ALWAYS shoot in RAW for these kinds of things. You don't want to have a compressed .jpg before you've even started.
The following pictures are shot in a really bright sunny environment, even though they don't really look like it. They're just as raw as it comes out of my camera sensor, and need some grading work to make them pretty again.
These days I try to use Nuke as much as possible, steering away from Photoshop as much as I can. This gave me a problem – by default Nuke doesn't read Canon's .cr2 raw files. I turned to DCRAW, an open source piece of software that you can access from the command line once installed. It reads ALL raw formats and converts it the input into a 16bit tiff.
Later on I learned that also NUKE can use DCRAWs code. Just put the DCRAW files into your nuke directory in your home folder, and enjoy reading in .cr2 files in Nuke! You even get an argument line in your read node where you can enter your options for DCRAW. Super sweet!
Shooting the HDR
Once the backplate had been shot, it was time to capture the lighting information in the room. This is most commonly done by using a fisheye lens (because of the extreme wide angle), and shooting at least three exposures for every angle, for the full 360 degrees. You can shoot every 120°, 90°, and 60° – it's entirely up to you! Just keep in mind that you do not want your lighting to change or your objects to move during the shoot. I personally went for 6 angles because I was the only one in the room and there were no clouds. Probably as easy as shooting an HDR gets!
Once again, I made sure my camera was set as manual as possible. I even chose a white balance setting just to be consistent across all my images, even though it makes absolutely no difference for raw images.
Using the panoramic head of my tripod, I shot three exposures (called exposure bracketing) for every angle. I did this using a little two second timer. Three Exposures really is the bare minimum, you should shoot more if you can. The camera I used with the default OS just can't do more than three.
I placed my Macbeth chart within a sunny area of my environment, so I can color calibrate the HDR to my photographed backplate (explained later on).
After the shoot I ended up with 18 .cr2 images. I stitched them together with an incredibly neat piece of software called PTGui.
PTGui outputted me the following 32bit EXR. Great – but not there yet. The highest floating point value within the image was only 4 (keep in mind that 8 bit images can only store values between 0 and 1). I used a Nuke gizmo called mmColorTarget to match the values of the Macbeth chart in the HDR to the values of the Macbeth chart in my backplate (read more about this on the renderblog), and this boosted my max floating point value up to about 240.
A high value like this is great; it gives you nice crisp shadows. No need to fake this using CG lights! After the calibration, I color graded it a bit more for artistic purposes.
So that's my HDR image sorted. Great! Just a couple more things and we can move into 3D space.
First thing I had to do is color grade my backplate a bit for artistic purposes. After that was done, I had to undistort the image. Real lenses always have their own lens distortion.
Undistorting this is easy because of the already available algorithms in Nuke. I just printed off this grid and snapped a picture of it at a 90° angle, then read it in Nuke and used a lensDistortion node to analyze this grid, copy pasted the node and plugged it into my main node network. Easy! Ready to be used in 3D.
Aligning the camera to the scene
There are a couple of tricks to keep in mind when trying to align your camera in 3D. It can be a pain, but if you have taken the right steps, your image should line up perfectly.
A couple of tips:
- Measure your real life objects with precision, always make notes of measurements when shooting
- Make sure your image has no lens distortion
- If you shoot with a cropped sensor camera, make sure you multiply your cropping factor with your lenses focal length, and then enter that value into your Maya cam. Maya doesn't know whether you shoot with a cropped frame sensor or a full frame sensor!
And then there's a really useful trick that I learned from a senior modeler at MPC:
? Create your camera and immediately group it. On your camera, lock the rotation channels. On your group, lock the translation ones. By doing this you can select your group, pan around with your camera and adjust the rotation values very precisely using the rotate tool.
I feel like this trick really helps a lot when trying to precisely match something. You can also undo every camera movement really easily like this.
It will take a couple of minutes of thinking "this is never going to match up", but you will get there eventually.
Setting up the scene
Wicked. So we've got all our photographic elements ready to go and our proxy geometry is modeled to match the objects in our photograph. Time to set up the scene.
We know that we will need both information from the HDR (direct illumination) and information from the environment (indirect illumination, because the light has already bounced once) to light our scene properly.
It's really easy to set this up in Arnold, but it did take me some initial figuring out.
I assigned a ShadowCatcher shader to all the modeled ‘shadow catching' geometry. Since the geometry also has to cast shadows, do not disable ‘opaque' in the Arnold tab – unlike specified in the documentation.
The ShadowCatcher shader has some cool attributes. The first one we'll look at is the most important one. Use background.
In this slot we will pipe in a projection. In your node editor, just create a File [projection] node. It's pretty straightforward, plug in both your projection camera and image you want to project and make sure you have your UVs laid out for the objects you are projecting onto.
Important! Having it set up like this, your shadow catching geometry will also have a diffuse texture (the projection). This is NOT what we want, so we pipe the projection into an aiRaySwitch node, just not connecting the ‘camera rays' slider. This will essentially not return any camera rays, whilst still returning all the other rays – exactly what we want.
The rest is easy. Enable cast shadows, transparency and catch diffuse. Catch diffuse is one to play with – it affects the colors of the shadows depending on the diffuse color. I wonder why I didn't try piping in the projection into that. Might be worth testing out!
For the lighting, I just created a skydome light with the HDR attached, intensity kept at 1. With the help of a chrome sphere I matched the direction of the light.
Modeling the objects
I really enjoyed the modeling aspect of this project. I usually do bigger things, which means I don't get to model into this fine detail. Really fun when there's no cap on your polycount and you can try and get every nice little shape in there! I only box modeled the tape, the tin and one single tube.
I laid out the UVs and after that I took the tubes into ZBrush and sculpted them an individual ZDisp map. I also quaded up the geometry so I'd get an even distribution of resolution whilst sculpting. It's always a good idea to do this!
Usually whilst sculpting this I'd reach for the DamStandard brush – however, since it pinches the geometry and my UVs are already laid out, this is not ideal. I can't have the pinching. To work around this I simply took the alpha of the DamStandard brush and applied it to my regular Standard brush. Simple, problem solved. The whole time I watched closely that I was only working in the normal direction of the faces so not too much stretching would appear when they were textured.
A quick demonstration on how I approached sculpting the paint tubes can be seen here.
For both the paint tubes and the tin can I found that I also had to break up the surface with quite a bit of low level noise (which I sculpted, I did not do this procedurally). This really helped to sell the objects.
To create the paint splatters on the objects, I developed two ways – and switched halfway through the project! The first one was to get some Photoshop splatter brushes, import those into MARI, splash them onto my object and convert that layer's alpha into a mask. This gave me a clean mask regardless of the color of the paint. Then I imported this map as an alpha into ZBrush and under the masking submenu I clicked ‘Mask by Alpha‘. The only thing I then had to do is inflate certain parts and sculpt a bit of texture on top.
Halfway through the project I found that it was much easier to have all this paint as separate geometry. It allows for much greater control rather than having it at render time through a Displacement map. I used the same splatter maps, but converted the ZBrush masks into polygroups. Then I could split off all the faces that weren't ‘splatters', give it some thickness and DynaMesh that. It's pretty high res geo (although you generate the same amount of polygons with your disp map), but I found that it looks a lot better than having your actual object displaced.
The water droplets were created with the Waterdrop generator I made a while ago. It's free and it works fairly well, check it out here!
As always, I textured my objects in MARI. It was pretty easy – nothing like texturing something that is supposed to look alive! The first step is probably the most important one, and that is looking for good reference. Once you know what you have to paint, and take the guesswork out, it's just doing it.
The labels of the objects were created in Photoshop since MARI lacks a lot of 2D tools. I then exported the maps and imported those into MARI, where I painted the Isolation maps of the layered shaders (more on this later on), splatters, a dirt layer and a dust layer.
The way I paint my isolation maps is simple. I just paint them with the standard MARI brushes, but not in black and white. If I'm painting dust, I need it to look like dust to be able to properly judge its appearance. So when I'm done with it, I just convert the layer's alpha into a mask. By doing this I can easily export the color map and the mask, to use in my layered shaders.
Note that you can also export the colored version, and use the alpha channel of that image to drive the mask properties of the layered shader. It's just whatever you prefer!
If I could recap one thing about texturing, it would be reference. Reference reference and more reference!
I received some requests to dive a bit deeper into the shading of the objects, so I will try to do this!
If you've read about my previous work, you've probably noticed I like to use the alShader library instead of the standard Arnold library. It has many advantages, which you can read about over here.
At this moment in time I really like to think about shading as like thinking in layers, and I also build the networks this way. It gets pretty easy when doing this. I will go over three objects, the coffee tin, the paint tube and the tape.
As I mentioned earlier, everything begins with good reference. Life is pretty once you know what you've got to do, reach or accomplish. Then it's just doing it! Before I start, I always try to push myself to spend that extra bit of time on the internet, looking for that one picture that might push my idea that little bit further.
The first thing I do is inspect the object, and stare at it for a couple of minutes. How does the light react with the surfaces? What properties of the surface really leave a mark in my mind? Are there any noteworthy specialties? What are the material layers of this object?
For example, the coffee tin will have six main layers:
1. Base metal
2. The super thin tin coat over the metal
3. The label material
4. Paint layer
5. Dirt (wasn't needed for this asset in my image, but still worth noting that it is there!)
6. Dust (wasn't needed for this asset in my image, but still worth noting that it is there!)
Once we've got the layers figured out, it's playtime. All we have to do now is recreate them and paint masks to layer the shaders on top of each other.
The way I approach building the materials at the moment is still very much by eye. I would like to start using more scientifically correct values and numbers soon, it's something that I'm working on.
So, for now, eyeballing! Let's start with layer one – the metal.
In real life you'd have two layers for the base metal. The actual base metal that the coffee tin is made from, and then a tin layer on top. Because the underlying metal layer really is barely visible (just through some scratches), and if it would be visible, it wouldn't have had any crazy visual impact. So instead of building it this way, I decided to just create a tin material and use a spec map to emulate that metal layer underneath.
Because it's a metal, the Diffuse color should be black. Ideally you'd pipe a really dark breakup map into this, nothing is perfect in real life, but it just wasn't necessary in this case.
The Specular map is a simple tiling map with some scratches. I add a bit of color to this spec map by multiplying the tiling map on top of a color (light beige – metals have a colored Specular highlight!) through an alLayerColour node. No need to go and do this in another software package.
As you can see I use the two specular lobes provided by the alSurface shader in here. As I said before, I'm not going to lie; I haven't got any real values for these. Right now I'm trying to match the reflection by looking at my reference very, very closely! What I'm creating here is a combination of both a rougher reflection, and a sharper one.
The IOR value is pumped up to 5 to have it reflect like a metal. You can use values up to 100 or even 1000 to get a chrome like Fresnel falloff.
That's that for the tin layer. Now let's create an alLayer shader, another alSurface shader for the label shader and a file node to connect the mask that we painted into the layered shader.
TOP TIP 1: By default if you drag and drop the file node onto the mask attribute, it will connect out alpha to the input. This is NOT what we want! Make sure you switch the out alpha connection of the file node to out color. Since we've painted a black and white mask, all individual color channels will be identical. Connect it to either the red channel, blue channel or green channel depending on your favorite color.
TOP TIP 2: You can also work with just one texture file with transparency. In that case, obviously don't change the connection
Cool, let's move onto the label shader. Not that much special going on here, but definitely an important layer to get right. It's the shader that will dominate the biggest area of the image. All I did was connect my diffuse map that I painted, and set my spec parameters as the following:
Note that I used a slightly tinted Specular color. This is for artistic reasons – it gave me a much ‘fuller' feeling. It's hard to describe, but it worked. You should always remind yourself that you're an artist, not a scientist. It's good to base yourself on values that are proven to be correct, but there's no one saying you can't cheat if you know why you cheat.
The last layer for this object is the paint layer. Again, nothing special going on really! Just a diffuse color map and some tweaked spec values.
That's actually it for the tin can! Nothing special or over complicated, but still looks pretty sweet. Working in layers is easy!
The tape was fun to make; it's not something you shade every day! The main thing to note about this object is that I created two different shaders – one for the actual roll of tape, which is double sided geometry, and one for the torn off tape – which is single sided. This is an important feature to consider, because we have to shade single sided objects differently. For example, sub surface scattering effects that I would use on double sided geo don't make sense on single sided geo.
Anyway, let's start with the double sided geometry first.
As you can see, it's once again pretty simple. I loaded in both my painted diffuse map (really simple, flat colors with some really subtle value/color differences – I could have done this procedurally in Maya but happened to be in MARI) and a scratch/breakup map. I repeated the breakup map with a 2.5/1 UV ratio. (re-word this) It just needed to be squashed! This piped into both the bump slot and the spec slot of the alShader.
As you can see, it goes through an alRemapColor node before going into the spec slot. The reason for this is simple – it's way too ‘heavy', there's too much value difference. I only want this map to be subtle, so inside of the alRemapColor node I raised the gamma to a value of 8. If you'd test this out, you'd see that the values get flattened out a lot – exactly what I was looking for.
An important visual attribute this tape has is some subtle sub surface scattering, so we have to make sure we include this. The attributes are really simple I only used one SSS layer, which had the same color as the diffuse map.
That's it for the double sided geo; let's move onto the single sided geometry. It's a bit more interesting!
To quickly sum this up, we have a refractive ‘glue' shader, and a backlit ‘paper' shader layered on top of each other with the remapped scratch map from earlier acting as a mask. Once I figured this out, it was once again, pretty easy! Inside of the shaders nothing complicated or special is going on. It's all about the layering.
An important attribute for the paper shader was backlighting. With this I emulated the translucency of the paper, just like I did with the SSS on the actual tape model.
In retrospect, I should have added more rough reflections on the tape on the grazing angles. I tried to do this with through my spec, but it didn't really work strong enough. It's something I looked over – and should have faked this with my diffuse. It would have been a lot faster to render and easier to control.
Basically I would use a Sampler Info node to query my viewing angle, and map that into my U and V coordinates of a ramp node. Then in that ramp node I can plug in whatever I like and interpolate in between whatever I plugged in based on my viewing angle. Just like you would fake a cloth shader. It's explained pretty well over here.
Then I painted an opacity map for the edges of the tape, to give it a bit of a torn look. That's all, tape = done!
Creating and rendering dust
This was a tricky one. I had never encountered a piece that needed a bit of dust sprinkled on top! I weighed up my options and decided that I'd try to do it as it would occur in real life, meaning rendering curves as thin hairs.
So then my only problem was: how do I create all these curves?! I looked online, but couldn't find any tool for Maya that was even remotely suitable. I didn't want to spend an incredible amount of time on just creating some dust, so I decided to paint on curves with Maya's PaintFX, using the popcorn preset. Pretty strange, having popcorn scattered all over my scene, but the curves that are used as a base for the PaintFX are pretty good. I converted the PaintFX into curves and rendered these as thin hairs. You can find a lot of information on rendering curves (with sets) in the Arnold documentation.
For the shading of the curves, I didn't use a Hair shader. I just used a standard alSurface shader with a really light brown diffuse color. It gave me the look I wanted!
The dust, however, is something I'm not 100% happy with. The shading is OK but the shape of the little dust particles just doesn't work fully. Writing a little dust PaintFX preset might be a cool thing to do sometime in the future!
The final step of the process! For this image not much compositing work was needed – it came out pretty decent out of the render engine!
I added some colour corrections for some individual objects based on the ID masks that I rendered out, some overall grading, and a bit of grain and the depth of field.
With every project I do I try to learn new things, explore new techniques. In this project I wanted to try out Sony's SPI-ANIM OCIO profile instead of the default 2.2 gamma curve in Nuke. There's way too much to it to explain in this post, but with a quick Google you'll be reading about it in no time.
It's all about the maths behind going from your linear image to what you display on your monitor. The default is a 2.2 gamma curve, but there are many other options, which actually prove to look better. The highlights were not blown out, and everything had quite a film like look. Pretty cool! Try it yourself
Overall I learned A LOT whilst creating this image. I absolutely loved diving into all these mini details. I definitely think one of my next pieces will once again be a small scenery. It's just SO much fun! Hope this was a little bit useful, and don't hesitate to contact me if you have any questions or remarks. I'm always looking to learn!