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 end
This 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 end
This 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 end
This 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