Keep up-to-date with Free tutorials!!


Sign up to our twice-monthly newsletter today for the latest tutorials, interviews and product information.

Sign me up to receive third-party emails from 3dtotal's partners, too!

- Latest news
- Exclusive Shop Offers
- Preview early content
- Plus much more


Not Ready to take that step? OK, Why not just Subscribe to the RSS Feed

submit tutorial
1 | 2 | 3 | 4 | 5
Advanced Baking - Baking Next-Gen lighting with Turtle

| Your Rating:
rating star fullrating star fullrating star fullrating star fullrating star full
(Score 4.75 out of 5 after 4 Votes)
| Comments 0
Date Added: 9th December 2009
Software used:

Let's look at how you would bake an ordinary PTM texture with Lua, so you'll get an overview of the parts comprising a Lua Bake Script. We're going to use the ArmorBaking.mb scene again, so prep Source and Target Surfaces for a Surface Transfer if they are not already. Switch everything but the Lua baking off in the Outputs. All Lua Baking Scripts must implement one or more of the following functions:

setup - configure Turtle, run once before the baking task

basis - define a custom basis, will be evaluated by Turtle during rendering

bake - process samples and other data, run once for every surface sample

Let's take a look at a simple Lua Bake Script.

function setup()
bset("gather.sampletype", "direct dynamic illumination")
bset("", "tangent space")
bset("gather.distribution", "equiareal")
bset("gather.minsamples", 100)
bset("gather.maxsamples", 200)
bset("gather.coneangle", 180)
bset("gather.cosweighdynamic", true)
bset("output.size", 6)
bset("basis.type", "custom")
bset("basis.rgb", false)

function basis(x, y, z)
values = {x*x, y*y, x*y, x, y, 1}
return values


function bake()
ci = getBasisCoefficients(0)
return ci


The function setup() contains a series of bset statements, which set the options for the Turtle baking. The Turtle Reference Manual will be your best friend here, since you'll probably not be able to remember all the options from memory. The gather.sampletype attribute controls the type of illumination that Turtle will sample; it's currently set to sample direct dynamic illumination. Dynamic illumination means that we wish to consider any possible lighting direction, which is suitable if we wish to bake down a PTM, for example. We can also bake down indirect dynamic lighting, but this requires us to correctly setup a Dynamic Photon Map in the Render tab, which will generate an emission of photons down onto your scene from all directions.

You can also specify indirect illumination, which will bake down the static indirect illumination in the scene, which is what you'd want for baking an RNM. The attribute defines the coordinate system in which you want Turtle to sample in. It's currently set to the tangent space defined by the low-res mesh, but it can also be set to object space or a coordinate system based on the sampled source surface. The gather.distribution attribute controls how the samples are spread out over the sphere, the equiareal option samples equally in all directions, but you can choose to use a cosine weighted distribution as well, which can be useful if you are baking occlusion maps. Turtle will automatically make an adaptive sampling between the gather.minsamples and gather.maxsamples, so be sure to set both in your Lua scripts, otherwise the default values will kick in, which might give you unexpected results. The gather.coneangle attribute will restrict the sampling to a subset of the sphere, so setting it to 180 will result in hemisphere sampling in the chosen coordinate system. You can weigh the actual sample data by a cosine weight by enabling the gather.cosweighdynamic property. You have to manually set the output.size property for your baking script, because in many cases Turtle will not know how many texture components you want to write out. You select a basis for your sampled information through the basis.type property. We've specified that we want to use a custom basis, but there are also predefined basis for PTMs and Spherical Harmonics. If you are only interested in the intensity of the illumination, basis.rgb should be set to false, otherwise you could have triple the amount of output components to deal with.

The basis(x, y, z) function is really very simple. Turtle will call your basis function with a given vector v = [x, y, z] that defines a point on the sampling sphere, asking you what values this vector will produce in your custom basis. All you have to do is plug the values into your function and return the number of coefficients set by the output.size property. The sampled data will automagically be fitted to your basis during rendering, so there's really nothing much to it. Recognize the basis by the way? It's the standard PTM basis!

The bake() function is where most of your custom work is done, although it is very basic in this script. We get the coefficients for the intensity by using the getBasisCoefficients(0) function, and pass them right out for Turtle to write out. Passing a value of 1-3 to the getBasisCoefficients(...) function gets you the respective color channel coefficients. For such a simple case as this, we don't actually need to implement the bake() function, so it could have been skipped completely.

With Model View Hardware Visualization enabled, Lua baked textures are automatically connected to the Color property of the Hardware Shader. Go ahead and switch this off and render out a frame using the PTM Lua Bake Script. You will have to manually connect EXR channels 0-2 to Light ABC, and EXR channels 3-5 to Light DEF. With Hardware Shading on, you should now get something you recognize.

Just having duplicated PTM baking through a Lua Bake Script isn't much fun, but we can do some interesting things now that we have the base script going. There's a nice trick in the original PTM whitepaper called Diffuse Gain that is quite easy to implement. It essentially boosts the effect of the PTM by scaling the PTM coefficients appropriately. Change the bake() function to:

function bake()

ci = getBasisCoefficients(0)

fMaxX = (ci[3]*ci[5] - 2.0*ci[2]*ci[4]) / (4.0*ci[1]*ci[2] -
fMaxY = (ci[3]*ci[5] - 2.0*ci[1]*ci[5]) / (4.0*ci[1]*ci[2] -

diffuseGain = 1.4
co = {}
co[1] = diffuseGain * ci[1]
co[2] = diffuseGain * ci[2]
co[3] = diffuseGain * ci[3]
co[4] = (1.0 - diffuseGain) * (2.0*ci[1]*fMaxX + ci[3]*fMaxY) + ci[4]
co[5] = (1.0 - diffuseGain) * (2.0*ci[2]*fMaxX + ci[3]*fMaxY) + ci[5]
co[6] = (1.0 - diffuseGain) * (ci[1]*fMaxX*fMaxX + ci[2]*fMaxY*fMaxY +
ci[3]*fMaxX*fMaxY + (ci[4] - co[4])*fMaxX + (ci[5] -
co[5])*fMaxY + ci[6]

return co


The diffuseGain property controls the amount of boosting; a value of 1 will give standard PTM, unboosted, so try out some different values. Render out a frame and compare to the old PTM without boost to see the effect.You start to see artifacts if you go as high as 1.4, as this is only a rescaling of the effect, but at least you'll get the basic idea at least.

Taking full advantage of Turtle using Lua Bake Scripts will require you to spend some time on the theory and details of newer computer graphics concepts such as Spherical Harmonics, Wavelets or other applicable mathematical tools. For your everyday needs you might be better off using the preset baking passes, but you never know, the need to develop your own custom illumination model might arise sooner than you think! The Lua Bake Scripts will allow you to experiment way faster than when having to write your own proprietary tools.

More Lua Baking

Let's look at one final example of how to bake down indirect lighting with the Lua Baking Scripts. We're going to check out the school-book example of baking an RNM using a custom Lua script. We don't need to use the Surface Transfer tool for an RNM, as we will take any possible normal into account anyway, so let's switch the Render Type to Texture Baking, and head over to that tab.

Check out the RNM baking script

function setup()

bset("gather.sampletype", "indirect illumination")
bset("", "tangent space")
bset("gather.distribution", "equiareal")
bset("gather.minsamples", 200)
bset("gather.maxsamples", 300)
bset("gather.coneangle", 180)
bset("output.size", 12)


function bake()

-- RNM basis vectors
basis1 = vec3(0.8165, 0.0, 0.577)
basis2 = vec3(-0.408, 0.707, 0.577)
basis3 = vec3(-0.408, -0.707, 0.577)

-- Project indirect light onto our RNM basis vectors
rgb1 = getSampleProjectedSum(basis1, false)
rgb2 = getSampleProjectedSum(basis2, false)
rgb3 = getSampleProjectedSum(basis3, false)

-- Weigh the indirect contribution
n = getSampleCount()
rgb1 = (rgb1 * 2.0) / n
rgb2 = (rgb2 * 2.0) / n
rgb3 = (rgb3 * 2.0) / n

-- Add direct light contribution

nlights = getLights()
for i = 1, nlights do

col = getLightCol(i)

if (getLightAmb(i)) then
rgb1 = rgb1 + col
rgb2 = rgb2 + col
rgb3 = rgb3 + col
localLightDir =

weight = dot3(basis1, localLightDir)
if (weight > 0) then
rgb1 = rgb1 + col * weight
weight = dot3(basis2, localLightDir)
if (weight > 0) then
rgb2 = rgb2 + col * weight
weight = dot3(basis3, localLightDir)
if (weight > 0) then
rgb3 = rgb3 + col * weight



array = {rgb1[1], rgb1[2], rgb1[3], 1.0,
rgb2[1], rgb2[2], rgb2[3], 1.0,
rgb3[1], rgb3[2], rgb3[3], 1.0}

return array


< previous page continued on next page >

1 | 2 | 3 | 4 | 5
Related Tutorials

3D Still Life – Breakdown

by Zeno Pelgrims
published on 2015-09-24

Keywords: Zeno Pelgrims, Maya, ZBrush, tutorial

rating star fullrating star fullrating star fullrating star fullrating star half (18)
Comments 2 Views 32710

Using Substitute Geometry in Maya

by Guru Vaidya
published on 2009-12-09

Keywords: maya, substitute, geometry, modeling,

rating star fullrating star fullrating star fullrating star fullrating star half (3)
Comments 2 Views 29490

How to Render in Less Time

by Jaime Casanova
published on 2009-06-16

Keywords: render, less, time, model, lighting,

rating star fullrating star fullrating star fullrating star fullrating star full (3)
Comments 2 Views 36831

Mudbox 2009 Quick Start Series: Baking Ambient Occlusion Maps In Mudbox

by Wayne Robson
published on 2010-12-30

Keywords: baking, ambient occlusion, ao, creature, head,

rating star fullrating star fullrating star fullrating star nonerating star none (2)
Comments 0 Views 10471
Readers Comments (Newest on Top)
no comments!
No comments yet. Be the first to comment!
Add Your Comment..