Jump to content

A paper canon in maxscript... Help me!


jameswhitaker
 Share

Recommended Posts

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

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

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 by jackbird
Link to comment
Share on other sites

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

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

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

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

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...