PDA

View Full Version : Scripted material change when objects touch


sconlogue
03-31-2008, 06:07 PM
Total MaxScript n00b just starting to dig through the Max reference and my MAXscript Essentials book. Here's what I'm trying to do.

-Detect for intersection of objects (in my case I have a large array of small instanced geometry objects that will be intersected by another larger mesh object)
-If intersecting, change material of the small object to that of the larger object
-Once not intersecting anymore, change material back to the original material

Another way to think of it is like this:
I want to control the color and or material of individual LEDS that together make up a large LED array. I want to control the colors by using mesh objects that pass through the array causing the colors to be temporarily inhereted. This would allow me to simple create complex patterns and displays. Keep in mind the LED things is an example, my actual geometry is not as simple as that so calling intersection of bounding boxes is out.

Or maybe there is another way to go about the whole thing.

Bobo
03-31-2008, 06:31 PM
If I were to do this, I would have used Particle Flow for the LED array or at least for the testing. Checking whether an object is inside a complex mesh is not as trivial as you might think, but the upcoming Krakatoa 1.1 update which is supposed to be released tomorrow (not an April Fools joke!) will provide a bonus Krakatoa Geometry Test which does this very very fast using a kdtree acceleration structure. You can use Krakatoa in Evaluation mode for free and employ its PFlow operators as bonus tools inside of PFlow even if you don't need the volumetric rendering features.

Using a simple Birth Script, you could place one particle at the pivot of every real LED instance, then use the new Krakatoa Geometry test to detect whether a particle is inside the control mesh and send to another event. A Script Operator would then take the Particle ID and change the material of the corresponding scene object accordingly. Alternatively, you could BUILD the LED array from particles and just switch the particle material, unless there is a specific reason you want to use instanced objects instead of particles.

These are just some ideas, and the Geometry Test operator is still not available, but if you feel this might be a good solution, you could probably wait 24 hours... ;)


(EDIT: Tested it, worked like a charm after less than 5 minutes. I used an array of 100x20 particles for the leds and an extruded text shape for the control mesh.)

Bobo
03-31-2008, 06:35 PM
Another cool way would be to simply use a bitmap to control the lighting of the LEDs via PFlow. That would work with the simplest version of PFlow that ships with Max and a very little bit of Scripted Operators. Will see if I can prepare a quick example...

EDIT: I tested it and it sort of works with the bitmap approach, but it is not as precise as I expected. Also, if the control object is moved away, the particles will still try to find the closest point on the surface, thus acquiring the edge pixels. I used a checkerboard map so I got an extended tiling, but with a black border it might work well...

See attached Max 9 file.

ZeBoxx2
03-31-2008, 07:11 PM
another option is to abuse the Volume Select modifier, but you have to take care that it does, in fact, select your object correctly.

I can't for the life of me remember how to get around the self-reference issue in script controllers nicely (would be good if that could get dropped, implosions of the max space/time-continuum through infinite self-references be darned), so the attached file (3ds Maxx 2008) uses a clone of the object for reference.

That clone has its faces selected by the intersecting volume by picking it as the geometry volume, and setting the selection method to 'crossing'.

The clone is hidden as we won't be using that.

The original object has a Material modifier added. The Material ID property of that modifier has a script controller that basically sets the Material ID as follows:
if no faces in the clone are selected, then Material ID 1 - grey
if some faces in the clone are selected, then Material ID 2 - blue
if all of the faces in the clone are selected, then Material ID 3 - green
if something went wrong in the script (it's in a try/catch), then Material ID 4 - red

Not sure if it does what you'd need, though

sconlogue
03-31-2008, 07:32 PM
Wow, thanks Bobo and ZeBoxx! I will check out your examples and report back. Two very different approaches but both looking promising. Thanks!

JHN
03-31-2008, 11:57 PM
Well a completely different approach could also be taken and that is a distance based approach... Animate your intersection plane the way you'd like. Get the time per object where the intersection plane is closest to the object... that's your toggle time.

Now if you have a blend material you could preset keyframes to animate on/off on frame 0 and further... now with the new found time you offset the keyframes of your objects. My approach does involve a bit more work (I think) but you have total control over how the animated textures should behave and not a constantly looping script in the background (which also means it doesn't update automaticly!)

My 2 cents,
-Johan

Bobo
04-02-2008, 12:17 AM
...the upcoming Krakatoa 1.1 update which is supposed to be released tomorrow (not an April Fools joke!) will provide a bonus Krakatoa Geometry Test which does this very very fast using a kdtree acceleration structure. You can use Krakatoa in Evaluation mode for free and employ its PFlow operators as bonus tools inside of PFlow even if you don't need the volumetric rendering features.


Ok, here is a tutorial which explains how the Krakatoa Geometry Test can be used to create the effect.
http://www.franticfilms.com/software/support/krakatoa/using_krakatoa_geometry_test_operator.php

An evaluation version of Krakatoa 1.1 including the Krakatoa Geometry Test operator can be downloaded from our web page (http://www.franticfilms.com/software/products/krakatoa/download/).

We just introduced an improvement to our algorithm which removes any leaking - in Krakatoa 1.0, a very small percent of particles could be left behind. I tested today with hundred million particles culled by various geometry objects including misformed ones and got ZERO leaks :)

sconlogue
04-02-2008, 06:28 PM
Ok, here is a tutorial which explains how the Krakatoa Geometry Test can be used to create the effect.


:eek: Bobo is the master. That is exactly what I'm looking for! I'll give this a try. You example using PFlow was impressive and simple, I just wish it was more accurate and didn't bog down in the upper frame numbers.

ZeBoox,

Your solution is clever as well. I plan to mess with it some more and see if I can script up a dynamic array of objects using the Vol select to control the intersections. I like that there is different material for when inside the volume! Cool.

Bobo
04-02-2008, 07:43 PM
:eek: Bobo is the master. That is exactly what I'm looking for! I'll give this a try. You example using PFlow was impressive and simple, I just wish it was more accurate and didn't bog down in the upper frame numbers.

I updated the tutorial once again a minute ago to show what happens if you do 5 million particles inside the volume. I am not sure what you mean with accurate, if the center of a particle is inside the volume, it will be detected. (PFlow does not deal with the meshes of the particles, just with their pivots). Of course, being history-dependent, going to higher frame counts will cause slowdowns, but you can drop a Cache operator in the global event, add one more zero to the memory limit and you will be able to scrub back and forth once pre-cached. If you are doing interactive updates like moving the volume, either go to frame 0 or disable the PFlow until ready.

sconlogue
04-02-2008, 10:26 PM
Hey ZeBoxx,

I was playing some more with your example. At first I was trying out weak ref to get around the Self-Ref issue but then it dawned on me that I could use the referenced geometry as a proxy object for the Vol Selection. That being said. I am now realizing that I am in over my head when It comes to scripting this all up. So what I am going to try to do is create a script that creates an array of objects+ their proxies that have multiple Vol Selects so I can have a fixed number of "control" objects for them to interact with. Each Vol Select is assign a different control object in a user defined list via a gui.

So pick your control objects from the scene -- Set the number of objects to create along the X and Y axis (no z needed at this point) -- the script loops through creating the reqeusted number of objects and bingo.. they can detect multiple control objects.

Sound good in theory anyway. I have some tuts to try before digging into this though. As I have yet to create a fully functioning script of any value by myself.

ZeBoxx2
04-03-2008, 03:35 PM
sounds pretty cool :) Good luck with it, if you need help, we'll be here; Bobo's approach is definitely worth a look as well if you don't need the distinction between an intersection and an encapsulation; it should run much faster for these cases and be easier to set up :)

sconlogue
04-08-2008, 03:50 AM
The script is getting there. So far you can pick a source object, it's proxy and create a user defined 2d array on the x and y axis. I also have the material and volselect modifiers being applied to the appropriate objects.

Problem I am having at the moment is I can't seem to add a foat_script controller to the material modifier on the copies of the source object. The modifier is there but I must be getting the syntax wrong for adding the scripted controller.

Here's kinda what I was trying

$yourObject.material.materalID.controller = float_script()

is that totally off? I can't seem to find any clear help in the MaxScript Reference on adding controllers beyond your basic position or what have you.

JHN
04-08-2008, 10:31 AM
It's because you are trying to assign the class float_script to the controller, not an instance of the class.. I think...

So

$yourObject.material.materalID.controller = (float_script())


or my prefered way


fs = float_script()
$yourObject.material.materalID.controller = fs
fs.script = "etc"


-Johan

ZeBoxx2
04-08-2008, 11:22 AM
woo... this is where bells and whistles should go off :)

I've seen this done by scripters before, and I wish the powers that be would be more vocal in discouraging it, but here we go...

Do not access modifiers based on their name by referencing them as a property of the node. Your post is a good example of why you shouldn't.

If you have a node with a Bend modifier on top, named "Bend" (you can change the name by right-clicking on the modifier in the stack), you -can- access it as follows:
<node>.bend

However, imagine what happens if A. you rename it to &quot;myBend&quot;. That code will fail.

Imagine what happens if B. you add another modifier named &quot;Bend&quot;. That code will simply return the first modifier named &quot;Bend&quot; that it finds from the top of the stack down.

Now imagine what happens if C. the modifier's name conflicts with an existing node property. It will use the node's property. That's what you're running into.

This code...
<node>.material
...does not refer to the Material modifier on the node, but rather refers to the node's actual material (i.e. a Standard material, Multi/Sub, etc.).

If you do have unique modifier names, then using...
<node>.modifiers[&quot;<name>&quot;] -- e.g. <node>.modifiers[&quot;material&quot;]
...will at least prevent situation C. It will do nothing for situations A and B, however.

Edit: Bugger keeps changing my "'s into &quot;'s, even though it's fine in the preview. The above is supposed to read: <node>.modifiers["<name>"] -- e.g. <node>.modifiers["material"]

The only way to uniquely identify a modifier is to make sure it has a unique identifier, and then 'searching' for that modifier in the node's stack. I'll leave that as an excercise :)

JHN
04-08-2008, 12:45 PM
I do agree with Zeboxx2, but I do think it depends on who is going to use your tools... If I am the only one using them, I definetly take shortcuts like these, and also skip class testing or whatever I can and will speed up writing the script. If its for general use for your artists or even the whole world, thourough testing is definitly advised.

But I think a distinction can be made for personal (TD only like) use or general use.

-Johan

ZeBoxx2
04-08-2008, 01:06 PM
oh absolutely - but if you do take shortcuts, eventually you'll hit a problem like this, even if it -is- only for internal use :)

More importantly, if you don't -know- that a particular method is a shortcut with caveats, then you'll be stuck wondering why it's not working when it has always worked in the past and on similar-but-different tests.

JHN
04-08-2008, 02:33 PM
Yeah, and that's when you whip out the manual, and learn something new ;)

-johan

sconlogue
04-08-2008, 09:31 PM
Thanks for the help. Here's how I'm doing it now and it seems to work fine.

fs = float_script()
refy.modifiers["MaterialMod"].materialID.controller = fs
fs.script = "try ( \n case (volume.selectedFaces.count) of ( \n 0: 1 \n (volume.numFaces): 3 \n default: 2 \n ) \n ) \n catch ( 4 )"

CGTalk Moderation
04-08-2008, 09:31 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.