jameswhitaker Posted March 31, 2017 Share Posted March 31, 2017 Hello, This is my first foray into maxscript, and I have nearly achieved what I'm after. If only I could do this one simple thing! Any help would be much appreciated. I've written a short script that creates a particle system and a rectangular poly. I then want to bind the newly created PF_Source to the newly created poly with a Particle Skinner. The end result will be a script that emits sheets of paper every n frames that will then swirl around my scene. Here is the portion of script for creating the rectangular poly and it all works, except the bit that tries to attach/define the Particle_Flow_Systems Rectangle length:280 width:210 cornerRadius:0 pos:position isSelected:on $.name = "Paper" + (progressString) modPanel.addModToSelection (Garment_Maker ()) ui:on $.modifiers[#Garment_Maker].density = 0.02 macros.run "Modifier Stack" "Convert_to_Poly" modPanel.addModToSelection (Particle_Skinner ()) ui:on $.modifiers[#Particle_Skinner].Particle_Flow_Systems = #("pFlow" + (progressString)) $.modifiers[#Particle_Skinner].activateSkinning() modPanel.addModToSelection (TurboSmooth ()) ui:on modPanel.addModToSelection (UVWMap ()) ui:on $.modifiers[#UVW_Map].realWorldMapSize = off Like I say, this is my first go at maxscript so I'm still learning how the syntax works etc which will hopefully explain any howling errors. Thanks in advance, James Link to comment Share on other sites More sharing options...
jameswhitaker Posted March 31, 2017 Author Share Posted March 31, 2017 And here's the script in its entirety, progress = 5 while progress ( progressString = progress as string position = [0,0,0] sliderTime = progress pfSource = PF_Source() pfSource.SetPViewLocation -343 634 pfSource.Quantity_Viewport = 100 pfSource.Integration_for_Viewport = 1 pfSource.name = "pFlow" + (progressString) particleFlow.BeginEdit() op1 = BirthGrid() op1.Grid_Size = 70 op1.Icon_Length = 280 op1.Icon_Width = 210 op1.Icon_Height = 20 op1.Icon_Height = 20 op1.pos = position op1.Emit_Time = (160 * progress) op2 = ShapeLibrary() op2.Type_3d = 14 op2.size = 68 op3 = mP_Shape() op3.Collide_Type = 3 op3.Mass_Type = 0 op3.mass = 0.001 pw = PhysXWorld() pw.Apply_Gravity = on pw.Ground_Collision_Plane = on pw.Icon_Length = 50 pw.Icon_Width = 50 pw.Icon_Height = 50 op5 = PhysX_World() op5.PhysX_World_Driver = pw --op6 = RenderParticles() op7 = DisplayParticles() op7.color = pfSource.wireColor op7.type = 6 ev1 = Event() ev1.name = "Event" + (progressString) ev1.SetPViewLocation -343 734 op8 = mP_Glue() op8.type = 2 op8.Bind_Distance = 100 op9 = mP_Force() op9.Force_Space_Warps.count = 0 op9.Force_Space_Warps = #($'Wind001') particleFlow.EndEdit() ev1.AppendAction op1 ev1.AppendAction op2 ev1.AppendAction op3 --ev1.AppendAction op4 ev1.AppendAction op5 ev1.AppendAction op9 ev1.AppendAction op8 ev1.AppendAction op7 --pfSource.AppendAction op6 pfSource.AppendInitialActionList ev1 realTimePlayback = off Rectangle length:280 width:210 cornerRadius:0 pos:position isSelected:on $.name = "Paper" + (progressString) modPanel.addModToSelection (Garment_Maker ()) ui:on $.modifiers[#Garment_Maker].density = 0.02 macros.run "Modifier Stack" "Convert_to_Poly" modPanel.addModToSelection (Particle_Skinner ()) ui:on $.modifiers[#Particle_Skinner].Particle_Flow_Systems = #("pFlow" + (progressString)) $.modifiers[#Particle_Skinner].activateSkinning() modPanel.addModToSelection (TurboSmooth ()) ui:on modPanel.addModToSelection (UVWMap ()) ui:on $.modifiers[#UVW_Map].realWorldMapSize = off progress = progress + 5 ) Link to comment Share on other sites More sharing options...
jackbird Posted March 31, 2017 Share Posted March 31, 2017 (edited) That looks like output from the macro recorder, which tends to emit code that doesn't work beyond one line scripts. Once you get into scripts that you are running from an .ms or .mcr (as opposed to executing individual lines in the listener), you want to stop using $ (which means "current selection," and therefore can either be a reference to an object with all its properties, or an array of objects with limited things you can do without drilling down). Instead, assign the object, modifier, or whatever to a variable and then reference the variable. For example, here's a rewrite of your section that creates a piece of paper: r = rectangle length:280 width:210 pos:position r.name = "Paper" + (progressString) --this has to be on another line, as creation parameters can only be explicit values or simple variable references gm = garment_maker() gm.density = .02 --we could have done this in one line as we did with the rectangle's size parameters, but this is to show you need () if you are creating a class instance without any parameters addmodifier r gm convertToPoly r ps = Particle_skinner all_particle_Flow_Events:false addmodifier r ps ps.particle_flow.systems += pfSource --we are in the same scope where you built the particle system, so pfSource is still a defined variable. No need for string manipulation. ps.activateskinning() addmodifier r turbosmooth() --we don't need to bother with variables if we 're not doing anything complex. addmodifier r (UVWMap realWorldMapsize:false) Also, your use of a while loop for program flow is a little odd, especially as it's set up to only execute once. I would think you'd want to use a for loop that counts up by 5, and uses at time to do things rather than actually moving the time slider (any maxscript that makes the UI update is going to be slower than Maxscript that doesn't.) If I were writing this, I'd break out the particle system creation and paper creation to functions (assuming one pflow per page?) and have a very small for loop to iterate the creation: fn makePflow = --functions have to be declared at the beginning so they exist in scope when they're called ( mypFlow = PF_Source() --etc return myPflow ) fn makePaper pflowToUse= ( myPaper = rectangle() --etc --but note that: ps = Particle_skinner all_particle_Flow_Events:false addmodifier myPaper ps ps.particle_flow.systems += pFlowToUse --since the function is a different scope than the one creating the particle system, we had to pass the function the right system as a parameter return myPaper ) --art directors will ask for the unexpected every time. Hard-code as few values as possible startFrame = 5 stopFrame = 6 paperInterval= 5 for f in startFrame to stopFrame by paperInterval do ( at time f thisPFlow = makePFlow() thisPaper = makePaper thisPFlow ) Edited March 31, 2017 by jackbird Link to comment Share on other sites More sharing options...
jameswhitaker Posted March 31, 2017 Author Share Posted March 31, 2017 That's great, thanks very much Jackbird. I'll put that all to good use on Monday. The short loop was just for testing purposes. The idea is that a new piece of paper will be blown away every nth frame (currently every 5th frame) until there are 100 pieces of paper floating around Link to comment Share on other sites More sharing options...
jackbird Posted March 31, 2017 Share Posted March 31, 2017 Is there a reason not to set that up as a single pflow that emits a particle every 5 frames? I don't like max's odds to survive evaluating 100 flows at once. Link to comment Share on other sites More sharing options...
jameswhitaker Posted March 31, 2017 Author Share Posted March 31, 2017 I'll make a rough animation on Monday to show you what I'm trying to achieve. I think the final solution might be to do some of the sheets using the method I'm following and then some of the more distant sheets with a single emitter and one sheet per particle as per your suggestion. Thanks again for your help Jon. It's much appreciated Link to comment Share on other sites More sharing options...
jameswhitaker Posted April 5, 2017 Author Share Posted April 5, 2017 Hi Jon, Sorry for the delay replying. From what you've written I'm now getting a better feel for how to write maxscript (ish). I'm still running into the buffers though when trying to assign the pfSource to the Particle Skinner. Having followed my nose a little I'm finding: ps.Particle_Flow_Systems += pfSource returns the error - No ""+"" function for #() ps.Particle_Flow_Systems = pfSource returns error: array parameter assignment requires Array, got: $pFlow5 ps.Particle_Flow_Systems = #(pfSource) returns the error - Invalid value for property: $pFlow5 Essentially I'm fishing for the right answer without quite knowing what I'm doing :-) It did occur to me though that is the problem that until the script completes the new pfSource doesn't exist so can't be assigned? Link to comment Share on other sites More sharing options...
jackbird Posted April 5, 2017 Share Posted April 5, 2017 Your third attempt (setting the value to a 1-element array) should work. The fact that it doesnt could mean the object creatino hasn't finished (as you intuited) or a host of other things. you could try append instead of +=. at that moment, ps.particle_Flow_systems is an empty array, and pfSource refers to the scene node $pFlow5. In a quick test, I was able to add a scene node to an array with +=, but append ps.Particle_Flow_Systems pfsource might work. You could also try using one script to create the PF sources, then another to loop through them and attach them, to particle skinners if the creation sync thingf is an issue. It's ugly, but might work. Hang in there; every script you write gets easier. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now