Render Info-strip Customization

I have recently published an info-strip script that allows custom information to be displayed in the rendered image, just like the v-ray frame stamp, but this one supports all renderers using the VFB (most notably mental ray and scanline). Together with user defined font size, style, colors and opacity of the strip background the user can define expressions to include things like photon count, diffuse bounces number etc. in the displayed information. There are five custom fields for simple expression and one field for custom script if you need some more elaborate way to get the desired result. In this tutorial I will show how these fields can be used to their full potential.

Render Info-strip UI

Among the default values you will notice renderers.current.FinalGatherAccuracy and similar parameters of the current renderer. There are many more that can be useful to record, like .GlobalIllumAccuracy, .GlobalIllumRadius or .GIPhotonMergeDistance. To get the complete list of render settings for mental ray, have a look at mental_ray_renderer : RendererClass section of maxscript help – wherever it says <mental_ray_renderer> you'd replace it with renderers.current. To get a list of properties for a different renderer run showProperties renderers.current in the maxscript listener (press F11 to open it).

The same procedure applies for exposure control and virtually any single property that you can access via maxscript or .NET. In the case of mental ray Photographic Exposure Control the example usage is sceneExposureControl.exposureControl.exposure_value and the exposure_value can be likewise replaced with .shutter_speed, .saturation, .gamma etc. The list of all the properties for this exposure control can be found in chapter mr_Photographic_Exposure_Control : ToneOperator.

Other simple expressions that might be noteworthy are listed here:

  objects.count -- number of objects

  sceneMaterials.count -- number of scene materials

  displayGamma -- main gamma correction value

  fileInGamma -- input gamma

  fileOutGamma -- output gamma

  numEffects -- number of current render effects

  rendOutputFilename -- preset rendered image file name

  sliderTime -- current slider time position

  units.systemType -- current system unit type

The custom script entry offers the possibility to get more information at once, the only requirement for the script is it has to return a value – either a string or a value that can be converted to one. Also, the resulting string cannot contain any line-breaks and should be short enough to fit in the strip lenght. To combine multiple values into one result, there are a few options. The first one is string concatenation:

  "Ten: " + 10 as string + " that's all, folks!"

The second one is formatting the values to a stringStream. Each percent character works as a placeholder for the argument following the string. For each percent metacharacter you have to add one argument:

  sstream = "" as stringStream
  format "Ten: % %" 10 "that's all, folks!" to:sstream

To show some possible uses, here are some ready-made snippets. If you use temporary variables, it's always better to enclose the code in braces and declare the variables as locals. To test the output of the script you can copy it to maxscript editor in 3ds max (located under New Script.. menu entry) and evaluate it (CTRL+E). If you'd need a piece of code or would like to share one that you find useful and is not listed here, use the comments section under the article.

Anti-aliasing (default value of the script field):

    local s = "" as stringStream
    local r = renderers.current

    format "AA Min: % | AA Max: % | AA Spatial Contrast: % % % %" \
        r.MinimumSamples \
        r.MaximumSamples \
        r.RedSpatialContrast \
        r.GreenSpatialContrast \
        r.BlueSpatialContrast \
        r.AlphaSpatialContrast to:s

    s as string -- returned value 

The highest number of glossy subdivisions of Arch&Design material in scene:

    local highestGlossy = 0

    for mat in sceneMaterials
        where isProperty mat #refl_samples AND
        (local newGlossy = getProperty mat #refl_samples) > highestGlossy do
            highestGlossy = newGlossy

    "Highest Glossy Subdivs: " + highestGlossy as string

Snippet to get the heaviest mesh in scene:

    local heaviestMesh = #(0,"none")

    for obj in geometry
        where (getPolygonCount obj)[1] > heaviestMesh[1] do
            heaviestMesh = #((getPolygonCount obj)[1],

    "Heaviest mesh: " + heaviestMesh[2] + ", poly count: " + heaviestMesh[1] as string

Scene poly count and vertex count – this one depends on another factor which is whether or not the file had been saved since the last change in scene that would influence the poly and vertex count (even saveNodes command or scene hold updates scene information). If it has already been saved, we can use (fileProperties.getItems "Mesh Totals")[1] to get the vertex count and (fileProperties.getItems "Mesh Totals")[2] to get the face count. If not, something like this would work:

    local faceTotal = 0
    local vertTotal = 0

    for obj in objects do
        local meshTotal = getPolygonCount obj
        vertTotal += meshTotal[1]
        faceTotal += meshTotal[2]

    "Vertices: " + vertTotal as string + " | Faces: " + faceTotal as string

Number of materials and their types:

    local classes = #()
    local counts = #()
    local result = ""

    for mat in sceneMaterials do
        if (local index = findItem classes (classOf mat)) > 0 then
            counts[index] += 1
            append classes (classOf mat)
            append counts 1

    for i = 1 to classes.count do
        append result (classes[i] as string + ":" + counts[i] as string + " ")


Scene dimensions (bounding box dimensions, bounding box center position):

    fn formatPoint3 p3 = "x:" + p3.x as string + ", y:" + p3.y as string + ", z:" + p3.z as string

    "Dimensions: " + formatPoint3 (objects.max - objects.min) + "; Center:" + formatPoint3 (

For yet more ideas be sure to have a look at the Maxscript Oneliners for Artists article.

All the custom expressions together with the script part are evaluated after the rendering is done. If you'd need to take into consideration some information you could only get before the rendering starts, you can register your own preRender callback that would save the desired value(s) to a global variable, and then access it from the script.

DISCLAIMER: All scripts and snippets are provided as is under Creative Commons Zero (public domain, no restrictions) license. The author and this blog cannot be held liable for any loss caused as a result of inaccuracy or error within these web pages. Use at your own risk.

This Post needs Your Comment!

Return to top