Switching lights within a volume

I’ve created a script to switch lights on and off depending on their position inside or outside of a volume. This volume can be animated if needed. The clever part is taken from the cgtalk forums. The calculation to determine if an object is within a specific volume is done by casting rays in an arbitrary direction.

The interface has a few options, setting the multiplier for the current frame or the active framerange.

This is the pseudocode by Matan Halberstadt

1. add a normal modifier to the volume object, with the flip option turned ON 
2. loop through all verts 
 2.1. p = position of current vert 
 2.2. fire a ray from p in an arbitrary direction like [0,0,1] at the volume object 
 2.3. if the ray missed then you are out side the volume else 
  2.3.1 turn the normal modifier on the volume object OFF 
  2.3.2 fire another ray from p in the same direction at the volume object 
  2.3.3 if the 2nd ray missed or distance from p to hit1 < distance from p to hit2 then you are inside the volume else you are outside the volume 
  2.3.4 turn the normal modifier on the volume object ON

I’ve taken this idea and incorporated it in a script to manipulate lights. The volume-detection however can be used to do many other things. Here are my examples.

An array of lights
The lights light a displaced plane
A volume encloses some of the lights
Only the lights within the volume are switched on

Insanto posted an alternative method on scriptspot. I’ve compared both methods of determining if a point is within a specific volume for speed. I’ve had to adjust my method, but it came out a bit faster. I’ve used the following maxscene and testscript to compare the speed. The scene is in max 2010. Download them here: CompareSpeed, or as fbx2009 format: TestVol_fbx2009.

This is the testscene
fn isPointInVol obj pos = --checks if supplied position is inside supplied mesh object( 
    if superclassOf obj == geometryClass do
        local tMesh = obj.mesh; local nVerts=tMesh.numverts; 
        local isInVol = true for v = 1 to nVerts while isInVol do
            if asin (dot (getNormal tMesh v) (normalize(((getVert tMesh v)*obj.transform) - pos))) <= 0.0 do isInVol = false
        tMesh = nVerts = vPos = undefined 
        return isInVol 
)--END isPointInVol FN

this is the method by Insanto the test results Average of ten iterations running on a bunch of points and a single volume 10 points check insanto: 20ms mine: 28ms 100 point check insanto: 199ms mine: 144ms 500 point check insanto: 934ms mine: 558ms


david charles

Great work and dedication Klass.

Cant get the lights working though. What is the set min and set max buttons for?

Doesnt the min and max multiplier do the same thing?

Hi David, thanks for stopping by. The set min and set max buttons are meant to control all selected lights independently from any volume. The buttons use the values from the min and max spinners. I found it handy to have a tool at hand to quickly set all lights to a specific value when I was experimenting with the script.
What isn’t working for you? Could you describe your problem with the script?

david charles

Its working fine now, really amazing to see. I am using an inverted cone to slowly turn an array of lights on starting at a central point and blossoming outward.

Last part of the puzzle is figuring out a way to get the lights to gradually turn on (fade in) instead of just going for on to off.

Any ideas?

david charles

Klass, will the falloff work with Vray lights?

It’ll work with any light which has a multiplier-property. I’ve tested with vraylights and it worked for me.

david charles

I am away for a couple days, will get back on it next week. Thank you so much. I will be in touch.


david charles


Getting this error…
Error scanning macroscript file: C:Program FilesAutodesk3ds Max Design 2012UIMacroScriptsvraymtlPresets_v06.mcr, macroscript: will; No macroscript body found
Note: PhysX SDK initialized
Note: PhysX Plugin initialized
Max to Physcs Geometry Scale = 1.0
Max to Physcs Geometry Scale = 1.0
— Error occurred in fn_createLightingLag(); filename: C:Program FilesAutodesk3ds Max Design 2012ScriptsSwitchlightbyvolume_003.ms; position: 4110; line: 132
— Frame:
— arrValue: undefined
— arrLowKey: undefined
— arrIndex: undefined
— theLight: $VRayLight001
— inDelay: 5
— outDelay: 10
— arrKey: undefined
— minValue: undefined
— called in l loop; filename: C:Program FilesAutodesk3ds Max Design 2012ScriptsSwitchlightbyvolume_003.ms; position: 6478; line: 176
— Frame:
— l: $VRayLight001
— called in btn_lag.pressed(); filename: C:Program FilesAutodesk3ds Max Design 2012ScriptsSwitchlightbyvolume_003.ms; position: 6504; line: 177
— Frame:
>> MAXScript Rollout Handler Exception:
— Unknown property: “keys” in undefined <<

and also an error about keys when i try the faloff option

this error probably means that you try to add the fades to a light without any animation on it’s multiplier. Fading a light with a constant multiplier doesn’t do anything. I’ve added some error trapping there. Now it shouldn’t crap out when this happens.
To avoid this, you first should add some animation to the multiplier with the script. After that you can add the fading to the light. I’ve also “officially” confirmed that a vray-light will work with the script.
So: download the latest version to get the more robust script.

david charles

Klaas, really seems to be working great.

One strange thing is that when i apply script to lights, there is a cycle for each light that says “reducing keys” When it does this the listener window comes up and is redrawn with every cycle.

Each cycle takes about 1.5 seconds and that is alot when there are >1000 lights. Any idea how to supress the listener window or “reducing keys” notifiaction to speed things up? It takes about 15 minutes to run the script on 1000 lights with pretty powerful workstation.

Also, would be great to get your email so i can send you some clips when i am finished.


David, it’s great to hear the script fits in your workflow.

Reducing keys is needed because the volume-function creates a keyframe on every frame. To make the fading work I need to have keyframes on only the positions where they make sense. Reducing keyframes in the script is actually the same function as the one in the trackview: the progressbar and cancel-button can’t be deactivated.. I also noticed it’s not the fastest thing in the world but it speeds up the rest of the script (the fading part).

I’m not really sure I can do something about that. Writing a custom reduction-algorithm might do the trick but that’s a bit out of my league.

Leave a Reply

* Will not be published