View Full Version : Optimizing my script & Assign Controller to materials?

06 June 2008, 01:44 PM
What’s up guys, created a thread a couple days ago for creating a script that would automatically luminate brake lights depending on the “speed” along a path constraint. With a lot of help from Zeboxx2 I was able to get that script working; but now I have a follow up question regarding the optimal implementation of the script.

The script is assigned to a material, specifically the Self Illumination Amount. It looks for an object (which you specify within the script) and adjusts the self illumination value based on that objects progression along the path, when it slows down the brake lights light up…

The problem is that I still have to apply this script to each unique texture; that looks for each unique car. Even when I have a duplicate car model, I have to duplicate the material as well and assign the script to that specific “tandom”. If I have 30 cars, I have 30 materials and 30 scripts to assign.

So the issue is; can I optimize the script somehow to expedite this process? Either way I’ll need a unique texture for each car, as that’s what controlling the brake lights…so maybe I’m stuck?

Also, one part of the process that feels more time consuming than it should be is how to assign the script to my material. Each car uses a Multi Sub-Object texture, so I have to scroll through endless materials, and sub-materials in the Curve Editor to find the right one, then scroll through that one to find the Self Illumination Amount. Is there another place in the 3dsmax GUI that I can use to assign a Float Script to a specific material? I tried filters on the Curve Editor but it still displays all the materials…

Thanks guys,

06 June 2008, 02:21 PM
Can you not just make one multimaterial with an "off" and an "on" material, then animate a MaterialModifier on the object? That way you switch the material off and on by animating the MaterialID value from 1 to 2.

06 June 2008, 03:03 PM
That sounds like an idea; let me make sure I understand correctly. So I simplify the brake light texture to just a color, no bitmap...Then I make 1 material with a maroon (off), and bright red (on). Apply this material to all 30 brake lights, then use the script to animate the polygons' Material ID, therefore turning the lights on and off...

So then the real change is too modify my script to alter the Material ID state of the object. Which is something I'm not sure how to do...

So if I add a Material Modifier I can add the script there, but what in my script (below) needs to change?

Here's the parts of the script that would need to change:

braking = .96

theCar = $Box01
PositionNext = at time (currentTime + 1) theCar.position.controller.percent
PositionCurrent = at time currentTime ( theCar.position.controller.percent )
PositionPrevious = at time (currentTime - 1) ( theCar.position.controller.percent )

travel = abs (PositionNext - PositionCurrent)
travelPrev = abs (PositionCurrent - PositionPrevious)

material ID = 1 (however that's accomplished in script)

if (travel == 0) then ( change to material ID = 1 ) -- standing still
else (

if ((travel / travelPrev) < braking) then ( change to material ID = 2 ) -- braking
else ( change to material ID = 1 ) -- coasting


06 June 2008, 03:08 PM
That's the best way to go about it if you don't want a ton of extra materials, yep :)

Select one of your cars, then follow the code:

myMaterialModifier = MaterialModifier() -- create a material modifier (need to reference it later)
addModifier $ myMaterialModifier -- this applies the Material modifier[code]

With the modifier applied, we can assign that a Float_Script controller:

myMaterialModifier.materialID.controller = Float_Script()

By default, that script will just contain the value of the controller at the point in time that you assigned it:


So let's modify that script to change the material ID between 1 and 10 randomly. Scrub the timeslider to see this:
myMaterialModifier.materialID.controller.script = "random 1 10"

So at this point, you can substitute "random 1 10" with the script from our other thread. But let's make it a little nicer; assuming you have at least 3ds Max 8.

We can refer to the path controller's percentage using a variable. That way, if you should ever change the name of your car, the script won't break (as $Car01 always refers to the object with the name "Car01", not to a specific object).

myMaterialModifier.materialID.controller.addObject "pathPercent" $.position.controller[#percent] -- [#percent] must be specified this way, as addObject requires a subAnim track.

myMaterialModifier.materialID.controller.script = "pathPercent.value / 100.0"
"pathPercent.value / 100.0"

( Note that I'm using addObject. We could also use addTarget, which allows us to specify a time offset as well; something we're using in the brakelight function. However, I'm not a fan of this, as it requires you to look at the actual variable to see that it has a time offset; this is not immediately obvious in the 3ds Max user interface. )

So, scrub the timeline again, and you should see that the material ID being changed to fits the percentage along the path.

You can now adjust the original script function to reference "pathPercent.value" within the "at time (t) ( pathPercent.value )" structures.

And, of course, you'll want to change the braking "0.6" (self-illumination value) to, say, '5' for MaterialID 5, while the coasting value would be, say, '4' for Material ID 4.

Now, obviously, you have more than 1 car - but that's no biggie, we can loop over all cars, and perform the same code on all of them:

Select all your cars (as I don't know what they're named!)

myCars = getCurrentSelection() -- gets all the selected cars into an array
for car in myCars do ( -- loop over each of the cars
myMaterialModifier = MaterialModifier()

addModifier car myMaterialModifier

myMaterialModifier.materialID.controller.addObject "pathPercent" car.position.controller[#percent]

myMaterialModifier.materialID.controller.script = "pathPercent / 100.0"

And that is all there should be to it :)

06 June 2008, 03:37 PM
So I simplify the brake light texture to just a color, no bitmap...

Hey up,
Well, you can have whatever material you like, really. If you want a bitmap, have one (as long as your mapping coords are correct)

The material modifier is just telling the selection (face or object) to display a sub material.

The choice is yours...

06 June 2008, 04:48 PM
Alright, now we're talking although I'm noticing an issue now that I hadn't in my simple testing scene.

In my full scene cars will come to a full stop, then start again (like a stop sign) and while they're stopped the lights blink on and off a couple times. (It doesn't happen one the car is stopped for good.) But if it's stopped stopped in between a couple keyframes they start blinking...

I also made sure that my tangents were Linear while it was stopped, to make sure it was truly stopped; which had no effect.

Turns out I have to detach the tail-light polygons, so that just those Material ID's can be adjusted, not the whole car. (when I first tried it the whole car was being set to ID 1 & 2...perhaps theres a way to specifiy which ID's to adjust?). So here's the script I'm applying to each cars' Material Modifier:

braking = .96

theCar = $MaroonSedan
PositionNext = at time (currentTime + 1) theCar.position.controller.percent
PositionCurrent = at time currentTime ( theCar.position.controller.percent )
PositionPrevious = at time (currentTime - 1) ( theCar.position.controller.percent )

travel = abs (PositionNext - PositionCurrent)
travelPrev = abs (PositionCurrent - PositionPrevious)

ID = 1

if (travel == 0) then (ID = 2 ) -- standing still
else (

if ((travel / travelPrev) < braking) then ( ID = 2 ) -- braking
else( ID = 1 ) -- coasting


EDIT: Attached file

06 June 2008, 04:55 PM
Without looking at the script, you just need to apply a volume select modifier first, then you can adjust the lights on their own

06 June 2008, 06:56 PM
That method works dave, infact I just used an Edit Poly Modifier to select the polygons, than applied the Material modifier on top of that.

Thanks man. :D

Unfortunately I'm still getting the blinking on & off thing. I've tried editing some of those values in the script and nothing seems to fix it. The percentage stays at exactly 35.389 for the 20 frames it's stopped. So (PositionNext - PositionCurrent) should always stay at 0, which should always be standing still...:hmm:

06 June 2008, 10:38 AM
Do you need to round off the input to MaterialID to have it be effective?

fn round n = (floor (n + 0.5))

EDIT: just checked, and that doesn't look like the case...

06 June 2008, 12:15 PM
nope - you're just hitting a maxscript accuracy issue. I shouldn't have made the standing still check "== 0.0"; change that to "<= 0.0001" or so; should do the trick.

Edit: Added some print statements myself to check on just how inaccurate the thing was:

travel: 1.14441e-005 (positionNext(35.389) - positionCurrent(35.389))
positionNext: 3.5389038085937500e+001 (format:".16e")
positionCurrent: 3.5389049530029297e+001 (format:".16e")

So yes, 0.0001 (changed from 0.001) should be safe in your current scene, but you might want to change that to just 0.01 or so; that's practically standing still anyway ;)

06 June 2008, 01:18 PM
Yup, that does the trick!

Where did you learn all this stuff ZeBoxx2? In hitting these hurdles I've done a good deal of Google searching and never found anything other than a tutorial on wiring, or a super simple script.

Kudos ZeBoxx2; I really appreciate all the time and effort.:thumbsup:

06 June 2008, 02:02 PM
help file, lots of playing about with code and not being afraid to ask* :)

* though don't ask too quickly, and be wary of where you ask and how you ask it, or you won't really learn anything.. just get spoonfed the solution. That's why I try to help with scripts here with some explanation of what I'm doing, step by step. Judging from your adaptation of the original code, I'd say you're doing well - so if this scripting stuff is of interest to you, just keep going the way you are :)

'd love to see the end-result of this, by the way.. should be pretty cool to see a bunch of cars driven (no pun intended) by this stuff :)

CGTalk Moderation
06 June 2008, 02:02 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.