Render To Texture Using MAXScript

Render To Texture (also known as Texture Baking) is a procedure for capturing various aspects of 3ds Max geometry scene objects' surfaces to bitmaps using the production renderer. The Default Scanline renderer supports this functionality.

The actual 3ds Max Render To Texture tool available through the Main Menu>Rendering>Render To Texture menu item is implemented as a scripted tool.Its source code can be found in the following subfolder of the 3ds Max installation:

..\ui\macroscripts\Macro_BakeTextures.mcr

In addition, some Render To Texture methods used by the network version of the tool can be found in the file

..\stdplugs\stdscripts\RTT_methods.ms

Render To Texture Components

Here is a short overview of the MAXScript classes, interfaces, properties and methods used in the process and how to use them to create your own texture baking tools:

Bake Elements

The main object class involved in the texture baking process is the Bake Element.

It implements an object capable of capturing a specific channel out of the production renderer, for example Diffuse, Lighting, Ambient Occlusion, Normals, Shadows and so on.

INodeBakeProperties Interface

The geometry objects whose surfaces will be baked have to be set up for the process using the INodeBakeProperties Interface exposed by all scene nodes.

This interface is used to add one or more Bake Elements to specific nodes, enable the baking and control some other related parameters.

Production Renderer

The production renderer, including the Default Scanline renderer, has to be called via MAXScript in a special mode invoked via

render rendertype:#bakeSelected

Unwrap UVW

For the baked texture to be usable, the object being rendered has to provide good texture coordinates without any overlapping.

The Render To Texture script shipping with 3ds Max provides controls over the automatic application and setup of Unwrap_UVW Modifiers to ensure the texture coordinates are usable for baking. You might have to ensure the same in your own script, unless your object has good UV coordinates to work with.

Projection Mapping

In some cases, especially when generating Normal Maps, the surface being rendered is a high-resolution version of an object, while the target object being mapped is a lower-resolution version. In this case, the texture coordinates of the low-resolution object have to be generated by projecting from the high-resolution one.

The Interface: INodeBakeProjProperties, the Projection Modifier and the Project_Mapping ReferenceTarget are the main elements of the Projection Mapping system of 3ds Max.

Shell Material

The Shell Material has been specifically designed to be used together with the Render To Texture tools. It can hold two different materials, typically the original material and the baked material. Either one can be used in the Viewport or in the Renderer.

Developing a Simple Render To Texture Script

The following example shows the basic steps to create a custom Render To Texture script.

The script creates a simple scene containing a textured sphere on a textured plane lit by a shadow-casting omni light.

Then it bakes the Diffuse and Lighting Elements of both objects to TGA files on disk and creates a Shell Material containing the old material in the one slot and the baked material in the other.

The Baked material uses a Composite map to combine the diffuse and the lighting information into a single diffuse map.

In this simple case, the texture coordinates of both objects are procedurally generated by the geometry primitives and are usable for baking. Also, no projection mapping is required in this simple case.

SCRIPT

fn BakeDiffuseAndLighting obj size =
(
--Clear all render elements 
obj.iNodeBakeProperties.removeAllBakeElements() 
--Preparing the Bake Elements:
be1 = diffusemap() --instance of the bake element class
be1.outputSzX = be1.outputSzY = size --set the size of the baked map
--specifythe full file path, name and type:
be1.fileType = (getDir #image+"\\"+obj.name+"_diffuse.tga")
be1.fileName = filenameFromPath be1.fileType
be1.filterOn = true --enable filtering
be1.shadowsOn = false --disable shadows
be1.lightingOn = false --disable lighting
be1.enabled = true --enable baking
be2 = LightingMap() -- instance of the bake element class
be2.outputSzX =be2.outputSzY = size --set the size of the baked map
--specifythe full file path, name and type:
be2.fileType = (getDir #image+"\\"+obj.name+"_lighting.tga")
be2.fileName = filenameFromPath be2.fileType
be2.filterOn = true --enable filtering
be2.shadowsOn =true --enable shadows
be2.enabled = true --enable baking
--Preparing theobjectfor baking:
obj.INodeBakeProperties.addBakeElement be1 --add first element
obj.INodeBakeProperties.addBakeElement be2 --add second element
obj.INodeBakeProperties.bakeEnabled = true --enabling baking
obj.INodeBakeProperties.bakeChannel = 1 --channel to bake
obj.INodeBakeProperties.nDilations = 1 --expand the texturea bit
select obj --we are baking the selection, so we select the object
--Call the renderer to bake both elements:
render rendertype:#bakeSelected vfb:off progressBar:true outputSize:[size,size]
theComp = CompositeTextureMap() --create a composite map
theComp.add() --add a second layer
theComp.blendMode = #(0,5) --set second layer to Multiply 
--Create two maps, one with the diffuse, one with the lighting map
theMap1 =bitmaptexture filename:be1.fileType
theMap2=bitmaptexture filename:be2.fileType
theComp.mapList = #(theMap1,theMap2) --composite the two maps
theComp.opacity = #(100,70) --set the lighting map to 70% opacity
--Create a standard self-illum material using the Composite map
bakedMat = standard diffusemap:theComp selfIllumAmount:100
--Assign a Shell Material to the object,
--keep the old material as original material,
--set the new bakedMat as the baked material:
obj.material = Shell_Material originalMaterial:obj.material\
bakedMaterial:bakedMat viewportMtlIndex:1 renderMtlIndex:1
--Show the textures of the baked material in the viewport
showTextureMap obj.material obj.material.bakedMaterial true
)--end fn
resetMaxFile #noprompt--reset the scene to start from scratch
--Create a shadow casting white Omni light
theLight = omniLight pos:[0,-60,100] rgb:white
theLight.baseobject.castshadows = true
--Create a mapped sphere object above the ground plane
theObject = Sphere segs:32 mapcoords:true pos:[0,0,25]
--Create a Cellular map and assign via Standard material to object
theMap = cellular cellColor:blue divColor1:red divColor2:yellow size:15
theObject.material = standard diffusemap:theMap
--Call the Bake function with the object and the desired size
BakeDiffuseAndLighting theObject 256
--Create a mappedplaneobjecton theground plane
theObject = Plane width:200 length:200 mapcoords:true
--Create a checker map and set the tiling to 4x4, then assign to object
theMap = checker Color1:green Color2:orange
theMap.coordinates.uTiling = theMap.coordinates.vTiling = 4
theObject.material = standard diffusemap:theMap
--Call the Bake function with the object and the desired size
BakeDiffuseAndLighting theObject 256
--Delete the light from the scene and deselect everything
delete theLight
max select none

RESULTS

After running the script, the following four baked textures will be written to the Images folder and will appear on the scene objects in the viewports:

 

See Also