[Closed] Optimizing my script & Assign Controller to materials?
Whats 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 Ill need a unique texture for each car, as thats what controlling the brake lights
so maybe Im 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,
Ryan
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.
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)
[b]material ID = 1 (however that's accomplished in script)[/b]
if (travel == 0) then ( [b]change to material ID = 1[/b] ) -- standing still
else (
if ((travel / travelPrev) < braking) then ( [b]change to material ID = 2[/b] ) -- braking
else ( [b]change to material ID = 1 [/b]) -- coasting
)
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
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:
myMaterialModifier.materialID.controller.script
“1”
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.
true
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 :)
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…
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
Without looking at the script, you just need to apply a volume select modifier first, then you can adjust the lights on their own
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.
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:
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…
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:
@40f
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