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.
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 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], obj.name)
"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
else
(
append classes (classOf mat)
append counts 1
)
)
for i = 1 to classes.count do
append result (classes[i] as string + ":" + counts[i] as string + " ")
result
)
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 (objects.center)
)
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!
Leave a Comment