Arnold for 3ds max – Volumetric Fog and ‘God Rays’

3ds max 2019 | Arnold 5


Adding a ‘Volume Light’ effect in Arnold for 3ds max is fairly simple:

  1. In the Render Setup windows > Arnold Renderer tab, under Environment, Background & Atmosphere:
  2. Click the Scene Atmosphere material slot, add an Arnold Atmosphere Volume material to it,
    And drag it as an instance to the Material Editor to edit it’s parameters.
  3. Set the Density to a higher than 0.0 value, so the material will have an effect.
  4. You’ll probably need to significantly raise the number of samples in the Atmosphere Volume material, and also the number of Volume samples in the light settings in order to get a clean render.


Arnold for 3ds max Volume Shading

V-Ray for 3ds max Wood Floor Material

3ds max 2019 | V-Ray Next

An example of varnished wood floor material in V-Ray and 3ds max.
The material uses a VRayBlendMtl with 2 connected VRayMtl sub materials to simulate a natural wood base layer coated by a glossy varnish layer.


Explanation of the material node graph:50770279_2476404922388832_853261524695777280_o.jpg

  1. The wood color (Diffuse texture)
  2. The wood black and white detail texture (used to add reflection detail)
  3. The wood bump texture (actually the same as the reflection texture just color corrected to whiten most details except the lines separating the wood planks)
  4. The reflection texture is color corrected to to intensify it prior to it being connected to the base wood layer material:
  5. The reflection texture is color corrected to to decrease its intensity prior to it being connected to the varnish coat blend:
  6. The base layer natural wood material with the Diffuse, Reflect and Bump textures connected to it:
  7. The varnish coat material with the Bump texture connected to it:
    * Note the Fresnel Reflections is turned off because the Fresnel reflection is calculated by the Falloff map (8)
  8. The Falloff map that defines the amount with which the varnish coat material covers the base wood material,
    A combination of Fresnel reflection intensity/Angle with the pre-processed reflection detail map (5):
  9. The final VRayBlendMtl combining the base wood material with the varnish coat material using the Fresnel Falloff blend map:


Related posts:

  1. Fresnel Reflections

Simple Snow Material in VRay for 3ds max

3ds max 2019 | V-Ray Next

A simple way to create a snow material in V-Ray for 3ds max is to combine a VRayFastSSS2 material with a VRayFlakesMtl using a VRayBlendMtl.
The VRayFastSSS2 creates the soft translucent shading for the snow, and the VRayFlakesMtls adds sparkling highlights.

  • Note that depending on the scene and view scale,
    The VRayFlakesMtls ‘flake glossiness’, ‘flake density’ and ‘flake size’ have to be tweaked to achieve the wanted result.




3ds max Island / Seashore opacity underwater tip

3ds max 2016

When creating a surface submerged in sea water,
Theoretically, it’s the Volume Absorption or ‘Fog‘ of the water shader that should do cause the surface to disappear under water.
But in many cases that doesn’t work well because we don’t actually model enough extended surface under the water for it to completely disappear without seeing the surfaces geometric edges that spoil the result.

One of the oldest tricks in the book is to use a Gradient Ramp map in the surface’s Opacity channel to make it gradually disappear before the geometry ends.

This can be done in most  3d software and render engines, I’m demonstrating it here using 3ds max and V-Ray:



Python for 3ds max – Mesh manipulation

3ds max 2019

An example of creating a mesh ripple deformation using Python for 3ds max:


Script steps:

  1. Define the effect intensity and a helper point object that will serve as the effect center.
  2. Collapse the object to an Editable-Mesh so its vertices will be accessible by Python.
    Note that the Node‘s Object has to be cast as a TriObject, to access the object’s Mesh data.
  3.  Loop through the Mesh’s vertices, get their world position, and set a new Z position as a sine function of the distance from the effect center.
import math
from MaxPlus import Factory
from MaxPlus import ClassIds
from MaxPlus import INode
from MaxPlus import TriObject
from MaxPlus import Matrix3
from MaxPlus import Point3

# Intensity:
effecr_mult = 1.0

# Effect center:
effector = INode.GetINodeByName('Point001')
effect_pos = effector.GetWorldPosition()

# Prepare object and eccess it's mesh data:
node = INode.GetINodeByName('Teapot001')
new_edit_mesh_mod = Factory.CreateObjectModifier(ClassIds.Edit_Mesh)
node_tm = node.GetWorldTM()
node_pos = node.GetWorldPosition()
obj = node.GetObject()
triobj = TriObject._CastFrom(obj)
mesh = triobj.GetMesh()

# Process the object's vertices:
for i in range(mesh.GetNumVertices()):
     # Get vertex in world space
     vert_pos = mesh.GetVertex(i)
     vert_world_pos = node_tm.VectorTransform(vert_pos)
     vert_world_pos = vert_world_pos + node_pos
     # Get vertex distance from effect center:
     diff_vec = vert_world_pos - effect_pos 
     diff_vec.Z = 0
     dist = diff_vec.GetLength()
     # Set new vertex position:
     mesh.SetVert(i,vert_pos.X,vert_pos.Y,vert_pos.Z + math.sin(dist)*effecr_mult)

* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.

Related Post:
Python for 3ds max – Animated Mesh

Python for 3ds max – replace selected objects with a merged object

3ds max 2020


The following Python for 3ds max snippet replaces all selected objects with an object merged from an external 3ds max file.

Get this code on gist


  1. The ‘model_path’ string variable should be set to the path of the 3ds max file containing the replacement model.
  2. This example takes into account that the merged file contains only a single object, otherwise the first of the merged objects will be used.
  3. The script actually replaces the Object node of the selected objects with the Object node of the merged model (creating instances), assigning them the merged material giving them the merged object’s name appended with numbers.
from MaxPlus import FileManager
from MaxPlus import SelectionManager

model_path = r"D:\Models\Bar_Stool_A.max"

place_holders = []
for o in SelectionManager.Nodes:


model = SelectionManager.GetNode(0)

for i in range(len(place_holders)):
     place_holders[i].SetName(model.Name + "_" + str(i))


* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.

3ds max – Use the Particle-Flow Lock/Bond test to have particles move on a surface in

3ds max 2019

The Lock/Bond Particle Flow test can be used to have particle movement restricted to a surface.


This example shows a simple setup in which the particle teapots have a Speed operator set to Random 3D mode that causes them to move in random directions,
While at the same time the Lock/Bond test forces them to ‘stick’ to the surface:



Python for 3ds max – list scene objects

3ds max 2019

Iterating through a list of all of an object’s hierarchy or all of the objects in the scene is a very common requirement for scripted tools and utilities in 3D animation software.
Coming from a MaxScript background, I was used to just have to write the word ‘objects‘ to reference a list of all of the objects in the scene.

Unless I’m missing something obvious,
There isn’t a shortcut like this available in the 3ds max Python API.

In order to list all the objects in the scene you need to use a recursive function that will return a list of all of a node’s children, and children’s children, etc.

In the following example, the function ‘list_children()’ will return a list all of the objects in the supplied node’s hierarchy, and when given the scene’s root node via MaxPlus.Core.GetRootNode() it will return a list of all the objects in the scene.
Wrapping ‘list_children()’ within the ‘scene_objects()’ function, provides a convenient way get a list of all the objects in the scene just by calling ‘scene_objects()’.

def scene_objects():
    def list_children(node):
       list = []
       for c in node.Children:
           list = list + list_children(c)
       return list
    return list_children(MaxPlus.Core.GetRootNode())

for o in scene_objects():
    print o.Name

* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.


Python for 3ds max – Animated Mesh

3ds max 2019

This is an example of procedurally animating a mesh’s vertices via Python script.


1. The model has to be converted to Editable Mesh before the script is run.
* unless the scrip will be extended to do it.
2. The model must be selected for the script to work.

import MaxPlus
import math
from MaxPlus import INode
from MaxPlus import TriObject
from MaxPlus import SelectionManager
from MaxPlus import Factory
from MaxPlus import Animation
from MaxPlus import Point3
from MaxPlus import Control

ticks_frame = 160

sel = []
for n in SelectionManager.Nodes:
node = sel[0]

#Setup Controllers
obj = node.GetObject()
Tri = TriObject._CastFrom(obj)
mesh = Tri.GetMesh()
num_verts = mesh.GetNumVertices()
mesh_anim = obj.GetSubAnim(0)
pnt_ctrl = Factory.CreateDefaultMasterPointController()
for i in range(num_verts):
    bezp3 = Factory.CreateDefaultPoint3Controller()

for t in range(100):
    time = t * ticks_frame
    for i in range(num_verts):
        vert_anim = mesh_anim.GetSubAnim(i)
        vert_ctrl = Control._CastFrom(vert_anim)
        vert_val = mesh.GetVertex(i)
        vert_val.SetZ(vert_val.GetZ() + math.sin(((Animation.GetTime()*0.5)/(ticks_frame))+i))

* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.

Python for 3ds max – Mesh manipulation

Python for 3ds max – Create Objects

3ds Max 2019


from MaxPlus import ClassIds
from MaxPlus import Point3
import random

# Define Sphere geometry object:
sphere_obj = Factory.CreateGeomObject(ClassIds.Sphere)
sphere_obj.ParameterBlock.Radius.Value = 5
sphere_obj.ParameterBlock.Segs.Value = 64

# Create a list of 10 sphere instanced objects:
spheres = []
for i in range(10):

# Move spheres to random positions
for s in spheres:
    s.SetLocalPosition(Point3( random.randint(-50,50),
    scale = 5.0 * (random.randint(30,100)/100.0)

* note that when copying and pasting a script from this example, the indentation may not be pasted correctly.