This page provides some examples of Lua bake scripts that can be provided to a Lua render pass in order to achieve some commonly used effects.
This example shows a very simple use of occlusion. It bakes red for surfaces that are in occlusion relative to the first light source, and green otherwise.
This example shows a typical setup for baking indirect illumination to Radiosity Normal Maps. Note that there are multiple different standard definitions in existence for the three RNM basis vectors.
function setup()
-- Sampling hemispherically in tangent space.
bset("gather.sampletype", "indirect illumination")
bset("gather.space", "tangent space")
bset("gather.distribution", "equiareal")
bset("gather.minsamples", 300)
bset("gather.maxsamples", 600)
bset("gather.coneangle", 180)
bset("output.size", 9)
end
function bake()
-- Basis definition.
basis1 = vec3(0.8165, 0.0, 0.577)
basis2 = vec3(-0.408, 0.707, 0.577)
basis3 = vec3(-0.408, -0.707, 0.577)
rgb1 = getSampleProjectedSum(basis1, false)
rgb2 = getSampleProjectedSum(basis2, false)
rgb3 = getSampleProjectedSum(basis3, false)
n = getSampleCount()
rgb1 = (rgb1 * 2.0) / n
rgb2 = (rgb2 * 2.0) / n
rgb3 = (rgb3 * 2.0) / n
result = {rgb1[1], rgb1[2], rgb1[3],
rgb2[1], rgb2[2], rgb2[3],
rgb3[1], rgb3[2], rgb3[3]}
return result
endThis example shows a typical setup for baking indirect illumination to Spherical Harmonics. It uses three SH, one for each color channel. Each SH has two bands. This makes a total of 12 components. The bake() function here is actually implicit. Unless you want to rearrange the components or perform other operations, then removing the bake() function completely will render the same result.
shbands = 2;
shbasiscount = shbands*shbands;
function setup()
-- Sampling spherically in world space.
bset("gather.sampletype", "indirect illumination")
bset("gather.space", "world space")
bset("gather.distribution", "equiareal")
bset("gather.minsamples", 700)
bset("gather.maxsamples", 1000)
bset("gather.coneangle", 360)
bset("basis.type", "sh")
bset("basis.rgb", true)
bset("basis.sh.bands", shbands)
bset("output.size", 3 * shbasiscount)
end
function bake()
red = getBasisCoefficients(1)
grn = getBasisCoefficients(2)
blu = getBasisCoefficients(3)
result = {}
for i = 1, shbasiscount do
result[i] = red[i]
end
for i = 1, shbasiscount do
result[i + shbasiscount] = grn[i]
end
for i = 1, shbasiscount do
result[i + 2*shbasiscount] = blu[i]
end
return result
endThis example demonstrates a Dominant Light Direction pass. Unlike the fixed RNM basis vectors, it projects lighting onto the normal direction and the direction of the most incoming lighting. The dominant light direction is derived from the second SH band. Note that the example is working in tangent space, taking only the upper hemisphere into account.
function setup()
-- Sampling hemispherically in tangent space.
bset("gather.sampletype", "indirect illumination")
bset("gather.space", "tangent space")
bset("gather.distribution", "equiareal")
bset("gather.minsamples", 300)
bset("gather.maxsamples", 600)
bset("gather.coneangle", 180)
bset("basis.type", "sh")
bset("basis.rgb", true)
bset("basis.sh.bands", 4)
bset("output.size", 8)
end
function bake()
-- Tangent space directions to get illumination from.
normal = vec3(0.0, 0.0, 1.0)
lightDir = dominantLight()
-- Project indirect light onto those directions.
if lightDir == vec3(0.0, 0.0, 0.0) then
rgb1 = {0.0, 0.0, 0.0} -- No dominant light direction, no light.
else
rgb1 = getSampleProjectedSum(lightDir, false)
end
rgb2 = getSampleProjectedSum(normal, false)
n = getSampleCount()
rgb1 = (rgb1 * 2.0) / n
rgb2 = (rgb2 * 2.0) / n
-- Output indirect lighting projected on normal and dominant light direction.
-- Dominant light direction stored in LDR alpha channel.
result = {rgb1[1], rgb1[2], rgb1[3], lightDir[1]/2+0.5,
rgb2[1], rgb2[2], rgb2[3], lightDir[2]/2+0.5}
return result
end
function dominantLight()
coefficients = getBasisCoefficients(0)
-- Get dominant light direction from second band sh coefficients.
dir = vec3(coefficients[4], coefficients[2], math.max(0.0, coefficients[3]))
if length(dir) > 0.000001 then
return normalize(dir)
else
-- Can't find a proper direction, at least not in this hemisphere.
return vec3(0.0, 0.0, 0.0)
end
endThis example demonstrates how to include direct lighting from certain light sources. You can add a light loop in the bake() function that projects the direct light contribution onto the basis. This example shows how it can be done with RNM, but the same principle applies to other basis types like SH.
function setup()
-- Sampling hemispherically in tangent space.
bset("gather.sampletype", "indirect illumination")
bset("gather.space", "tangent space")
bset("gather.distribution", "equiareal")
bset("gather.minsamples", 300)
bset("gather.maxsamples", 600)
bset("gather.coneangle", 180)
bset("output.size", 9)
end
function bake()
-- Basis definition.
basis1 = vec3(0.8165, 0.0, 0.577)
basis2 = vec3(-0.408, 0.707, 0.577)
basis3 = vec3(-0.408, -0.707, 0.577)
rgb1 = getSampleProjectedSum(basis1, false)
rgb2 = getSampleProjectedSum(basis2, false)
rgb3 = getSampleProjectedSum(basis3, false)
n = getSampleCount()
rgb1 = (rgb1 * 2.0) / n
rgb2 = (rgb2 * 2.0) / n
rgb3 = (rgb3 * 2.0) / n
-- Direct light loop.
nlights = getLights()
for i = 1, nlights do
if not (getLightInd(i)) then
-- Add lambert shaded light source contibution for each basis vector.
col = getLightCol(i)
weight = getLightLambertianReflectance(i, gatherToWorld(basis1))
if (weight > 0) then
rgb1 = rgb1 + col * weight
end
weight = getLightLambertianReflectance(i, gatherToWorld(basis2))
if (weight > 0) then
rgb2 = rgb2 + col * weight
end
weight = getLightLambertianReflectance(i, gatherToWorld(basis3))
if (weight > 0) then
rgb3 = rgb3 + col * weight
end
end
end
result = {rgb1[1], rgb1[2], rgb1[3],
rgb2[1], rgb2[2], rgb2[3],
rgb3[1], rgb3[2], rgb3[3]}
return result
end