Notifications
Clear all

[Closed] CgTalk Maxscript Challenge 003: "Foot Prints"

CgTalk Maxscript Challenge 003: “Foot Prints”

DESCRIPTION: Set up an object that leaves a foot print every time it touches another surface. This can be a texture footprint or an object.
If you have time, set up a simple scene that shows a person walking around making footprints.

INTERMEDIATE SCRIPTERS: Make the footprint actually embed into the surface.

ADVANCED SCRIPTERS: Give the surface two different properties; mud and concrete. Embed into the mud, and leave surface footprints on the concrete. (For extras, make the surface footprint the color of whatever the mud is!)
   
   RULES:  

[ul]
[li]You can set up scenes and textures for this one as you see fit. If you can code it all, even better![/li][li]Code from scratch. Try not to use pre-exisitng functions or plugins.[/li][li]Show your script references, if any (eg. Looking at another script to assist you).[/li][li]You are encouraged to ask for help where needed, but try to do it on your own. The maxscript reference is an invaluable resource.[/li][li]Post your final script inside [/li]“`
tags (located on your posting toolbar).
[li]Post all code into THIS thread.[/li][li]NEW RULE: Post the max version you coded in, plus any maxscript extensions you used. (Thanks galagast!)[/li][li]Try to finish the challenge in a week. There is no definite time limit. [/li][li]Voting will occur at the end of each ‘month’ (every 4 challenges). [/li][/ul]NOTES: I think this one will be slightly harder than the last two. Please remember to give feedback as to the ease or difficulty of the challenges. Think about using different methods, such as deformers or even displacement maps.

20 Replies

Awesome, I’ve been meaning to do this anyway. PFlow, here I come!

1 Reply
(@aearon)
Joined: 11 months ago

Posts: 0

Great Challenge, don’t have the time to do something myself, but i’m excited to see what people come up with

is pflow allowed?

There’s definitely going to be some scripting involved in the pflow part of it. The only other way I can think of to do this is using script controllers. It’ll be interesting to see the different solutions to this one.

Sure, it’s the first rule of this weeks challenge:

You can set up scenes and textures for this one as you see fit. If you can code it all, even better!

Remember, the challenge is here to make you think creatively about tackling problems!

What is the time limit?

-RyanT
Pipeworks Software
Foundation 9

1 Reply
(@erilaz)
Joined: 11 months ago

Posts: 0

You should try and complete the challenge in a week (I put up a new challenge every monday), but there isn’t really a time limit as such. We’ll be voting on the best scripts every month.

Okay, I’ve got something here that sort of works, but not nearly as good as I would like. There’s a couple issues with scripting pFlow that I’m trying to work out.

So here we go:
Open Max and run the script. All objects, animation, and pFlow system are created from the script. When you see the particle view window pop up, you need to manually delete the connection (if there is one) from PF_Source 01 to Event01, and then reconnect it. For some reason, it doesn’t always connect correctly when done from a script. Also, you can delete the extra floating events that aren’t connected to anything.

From there, just play the animation. There’s another issue that you’ll notice after the animation plays, and is that the mesh isn’t getting pushed down consistently under the boxes. The collision test seems to randomly ignore some particles.

I’ll keep working on it though and post updates as I complete them. The next step is to try and get the area around the footsteps to push up as though sand were getting displaced by the feet.

-- start with a fresh scene
 resetMaxFile #noPrompt
 -- maximize the viewport
 actionMan.executeAction 0 "50026"
 -- turn off real time playback
 realTimePlayback = false
 
 -- create the template object, which is a plane with a noise modifier to make it bumpy
 templateObj = plane length:150 width:50 pos:[0,85,0] lengthSegs:150 widthSegs:50
 -- define the noise modifier
 noiseMod = noiseModifier()
 -- add it to the template object
 addModifier templateObj noiseMod
 -- change the settings of the noise modifier
 noiseMod.strength = [0,0,1]
 noiseMod.scale = 5
 -- hide the template object because we don't need to see it
 hide templateObj
 
 -- make a new mesh object that will inherit it's mesh from the template object
 deformObj = mesh pos:[0,85,0]
 -- get the template object's mesh and replace the deform object's mesh with it
 deformObj.mesh = templateObj.mesh
 -- update the deform object
 update deformObj
 
 -- make a couple boxes to use as feet
 b1 = box length:10 width:5 height:3 pos:[7,-20,-1]
 b2 = box length:10 width:5 height:3 pos:[-7,0,-1]
 
 -- make a couple deflector to act as the soles of the "feet"
 d1 = deflector length:10 width:5 pos:b1.pos
 d2 = deflector length:10 width:5 pos:b2.pos
 -- link them to the boxes
 d1.parent = b1
 d2.parent = b2
 
 -- animate the feet "walking" forward
 for i = 10 to 100 by 20 do (with animate on (at time i (b1.pos += [0,40,0])))
 for i = 20 to 100 by 20 do (with animate on (at time i (b1.pos = (at time (i - 10) b1.pos))))
 for i = 5 to 100 by 20 do (with animate on (at time i (b1.pos += [0,0,10])))
 
 with animate on (at time 10 (b2.pos = b2.pos))
 for i = 20 to 100 by 20 do (with animate on (at time i (b2.pos += [0,40,0])))
 for i = 30 to 100 by 20 do (with animate on (at time i (b2.pos = (at time (i - 10) b2.pos))))
 for i = 15 to 100 by 20 do (with animate on (at time i (b2.pos += [0,0,10])))
 
 -- define the text for the Birth Script operator
 s1 = stringstream ""
 format "on ChannelsUsed pCont do (
" to:s1
 format "	pCont.usePosition = true
" to:s1
 format "	)
" to:s1
 format "
" to:s1
 format "on Init pCont do ()
" to:s1
 format "
" to:s1
 format "on Proceed pCont do (
" to:s1
 format "	t = pCont.getTimeStart() as float
" to:s1
 format "	if t < 0 then (
" to:s1
 format "		obj = $%
" deformObj.name to:s1
 format "		-- revert the plane's geometry back to it's original state by copying the mesh from the template object
" to:s1
 format "		obj.mesh = $%.mesh
" templateObj.name to:s1
 format "		-- get the number of verts in the plane
" to:s1
 format "		n = getNumVerts obj
" to:s1
 format "		-- create one particle per vert and place the particle at the vert's position
" to:s1
 format "		-- also set the particle's age to zero
" to:s1
 format "		for i = 1 to n do (
" to:s1
 format "			pCont.addParticle()
" to:s1
 format "			pCont.particleIndex = i
" to:s1
 format "			pCont.particleAge = 0
" to:s1
 format "			pCont.particlePosition = getVert obj i
" to:s1
 format "			)
" to:s1
 format "		)
" to:s1
 format "	)
" to:s1
 format "on Release pCont do ()" to:s1
 s1 = s1 as string
 
 -- define the text for the "vertsFollowParticles" Script Operator
 s2 = stringstream ""
 format "on ChannelsUsed pCont do (
" to:s2
 format "	pCont.usePosition = true
" to:s2
 format "	)
" to:s2
 format "
" to:s2
 format "on Init pCont do ()
" to:s2
 format "
" to:s2
 format "on Proceed pCont do 
" to:s2
 format "(
" to:s2
 format "	obj = $%
" deformObj.name to:s2
 format "	n = pCont.NumParticles()
" to:s2
 format "	for i in 1 to n do
" to:s2
 format "	(
" to:s2
 format "		pCont.particleIndex = i
" to:s2
 format "		x = pCont.particleID
" to:s2
 format "		setVert obj x (pCont.getParticlePositionByID x)	
" to:s2
 format "	)
" to:s2
 format "	update obj
" to:s2
 format ")
" to:s2
 format "on Release pCont do ()" to:s2
 s2 = s2 as string
 
 -- begin editing pFlow
 particleFlow.beginEdit()
 -- create new particle flow
 newPF = PF_Source X_Coord:0 Y_Coord:0 isSelected:on Logo_Size:5 Emitter_Length:10 Emitter_Width:10 Emitter_Height:10 pos:templateObj.center
 newPF.quantity_viewport = 100
 newPF.particle_amount_limit = 10000000
 -- add the Render and Dispaly operators to PF Source 01
 newPF.appendAction (renderParticles())
 newPF.appendAction (displayParticles type:1)
 -- turn off display of particles and PF object
 newPF.show_logo = off
 newPF.show_emitter = off
 newPF.baseObject.activateAction 2 0
 -- hook Event 01 to PF Source 01
 newPF.appendInitialActionList event01
 
 -- create Event01
 event01 = event()
 -- add the Birth Script operator and add the script
 event01.appendAction (Birth_Script Proceed_Script:s1)
 -- add a collision test and change some settings
 co = collision()
 event01.appendAction co
 co.Collision_Nodes = #(d1,d2)
 co.Speed_Option = 1
 -- get PF Source position in particle view window
 newPF_X = newPF_Y = 0
 newPF.getPViewLocation &newPF_X &newPF_Y
 -- reposition Event 01
 event01.setPViewLocation newPF_X (newPF_Y + 100)
 -- create Event02
 event02 = event()
 event02.setPViewLocation newPF_X (newPF_Y + 200)
 -- hook Event 02 to the collision test
 co.setNextActionList event02 co
 
 -- add the script operator that will deform the mesh using the particles
 event02.appendAction (Script_Operator proceed_script:s2 name:"vertsFollowParticles")
 
 -- add the two feet script operators
 for i = 1 to 2 do (
 	if i == 1 then objName = d1.name
 	if i == 2 then objName = d2.name
 	local s = stringStream ""
 	format "on ChannelsUsed pCont do (pCont.usePosition = true)
" to:s
 	format "on Init pCont do ()
" to:s
 	format "on Proceed pCont do (
" to:s
 	format "	obj = $%
" objName to:s
 	format "	n = pCont.NumParticles()
" to:s
 	format "	if obj.pos.z < (at time (sliderTime - 1) obj.pos.z) then (
" to:s
 	format "		for i in 1 to n do (
" to:s
 	format "			pCont.particleIndex = i
" to:s
     format "			if pCont.isParticleNew i then (
" to:s
 	format "			 x = pCont.particleID
" to:s
 	format "			 pPos = pCont.getParticlePositionByID x
" to:s
 format "			 pCont.setParticlePositionByID x [pPos.x,pPos.y,obj.pos.z]
" to:s
 	format "				)
" to:s
 	format "			)
" to:s
 	format "		)
" to:s
 	format "	)
" to:s
 	format "on Release pCont do ()
" to:s
 	s = s as string
 	
 	event02.appendAction (Script_Operator proceed_script:s name:("foot0" + i as string))
 	)
 
 -- end pFlow edit
 particleFlow.endEdit()
 
 -- open the Particle View window
 particleFlow.openParticleView()

Have fun!

Hey James,

that’s great! well done it works really well. no time for me this week so I’ll be in the next one.

J.

Wow, cool script there James … and very imaginative use of pflow … This challange was a big one (too big in this timeframe for me) so I only got very short way – investigating possiblities and noting a few ideas, but hopefully I can join in some time in the future.

Btw. I found that Peter Watje did a plugin (written in C++) doing something similar to this challange, but in a totally different way that yours:

http://www.max3dstuff.com/max4/objectDeform/help.html

Lars

Thanks for the link. That Peter Watje sure knows what he’s doing.

I’ve run into a bit of a road block trying to make the surface not only go down under the foot, but up around it as well. At this point, I’m thinking maybe a displacement modifier with some sort of procedurally generated bitmap might work out better. But, yeah, this is a big one, but I’ll keep working at it and post any updates here.

Okay, I had a Eureka moment and figured out how to write the pFlow script operator much simpler. It actually works faster and better than before, plus I’ve got my sand effect with the area around the feet raising up as the foot presses down into the ground.

Remember to manually link Even01 to PF_Source01 after running the script. You might even have to delete the link, then relink it. It’s weird.

-- start with a fresh scene
   resetMaxFile #noPrompt
   -- maximize the viewport
   actionMan.executeAction 0 "50026"
   -- turn off real time playback
   realTimePlayback = false
   
   -- create the template object, which is a plane with a noise modifier to make it bumpy
   templateObj = plane length:150 width:50 pos:[0,85,0] lengthSegs:150 widthSegs:50
   -- define the noise modifier
   noiseMod = noiseModifier()
   -- add it to the template object
   addModifier templateObj noiseMod
   -- change the settings of the noise modifier
   noiseMod.strength = [0,0,1]
   noiseMod.scale = 5
   -- hide the template object because we don't need to see it
   hide templateObj
   
   -- make a new mesh object that will inherit it's mesh from the template object
   deformObj = mesh pos:[0,85,0]
   -- get the template object's mesh and replace the deform object's mesh with it
   deformObj.mesh = templateObj.mesh
   -- update the deform object
   update deformObj
   
   -- make a couple boxes to use as feet
   b1 = box length:10 width:5 height:3 pos:[7,-20,-1]
   b2 = box length:10 width:5 height:3 pos:[-7,0,-1]
   
   -- make a couple deflector to act as the soles of the "feet"
   d1 = deflector length:10 width:5 pos:b1.pos
   d2 = deflector length:10 width:5 pos:b2.pos
   -- link them to the boxes
   d1.parent = b1
   d2.parent = b2
   -- hide them
   hide d1
   hide d2
   
   -- animate the feet "walking" forward
   for i = 10 to 100 by 20 do (with animate on (at time i (b1.pos += [0,40,0])))
   for i = 20 to 100 by 20 do (with animate on (at time i (b1.pos = (at time (i - 10) b1.pos))))
   for i = 5 to 100 by 20 do (with animate on (at time i (b1.pos += [0,0,10])))
   
   with animate on (at time 10 (b2.pos = b2.pos))
   for i = 20 to 100 by 20 do (with animate on (at time i (b2.pos += [0,40,0])))
   for i = 30 to 100 by 20 do (with animate on (at time i (b2.pos = (at time (i - 10) b2.pos))))
   for i = 15 to 100 by 20 do (with animate on (at time i (b2.pos += [0,0,10])))
   
   -- define the text for the Birth Script operator
   s1 = stringstream ""
   format "on ChannelsUsed pCont do (
" to:s1
   format "	pCont.usePosition = true
" to:s1
   format "	)
" to:s1
   format "on Init pCont do (
" to:s1
   format "	)
" to:s1
   format "on Proceed pCont do (
" to:s1
   format "	t = pCont.getTimeStart() as float
" to:s1
   format "	if t < 0 then (
" to:s1
   format "		obj = $Object01
" to:s1
 format "		-- revert the plane's geometry back to it's original state by copying the mesh from the template object
" to:s1
   format "		obj.mesh = $Plane01.mesh
" to:s1
   format "		-- get the position of each vert
" to:s1
 format "		global bigArryOVertPositions = for i = 1 to getNumVerts obj collect getVert obj i
" to:s1
   format "		-- get the number of verts in the plane
" to:s1
   format "		n = getNumVerts obj
" to:s1
 format "		-- create one particle per vert and place the particle at the vert's position
" to:s1
   format "		-- also set the particle's age to zero
" to:s1
   format "		for i = 1 to n do (
" to:s1
   format "			pCont.addParticle()
" to:s1
   format "			pCont.particleIndex = i
" to:s1
   format "			pCont.particleAge = 0
" to:s1
 format "			pCont.particlePosition = getVert obj i
" to:s1
   format "			)
" to:s1
   format "		)
" to:s1
   format "	)
" to:s1
   format "on Release pCont do ()
" to:s1
   s1 = s1 as string
   
   -- define the text for the "footsteps" Script Operator
   s2 = stringstream ""
   format "on ChannelsUsed pCont do (pCont.usePosition = true)
" to:s2
   format "on Init pCont do ()
" to:s2
   format "on Proceed pCont do (
" to:s2
   format "	obj1 = $Deflector01
" to:s2
   format "	obj2 = $Deflector02
" to:s2
   format "	defMesh = $Object01
" to:s2
   format "	n = pCont.NumParticles()
" to:s2
   format "	vertArr = #{}
" to:s2
   format "	vertArr2 = #{}
" to:s2
 format "	if (obj1.pos.z < (at time (sliderTime - 1) obj1.pos.z)) or (obj2.pos.z < (at time (sliderTime - 1) obj2.pos.z)) then (
" to:s2
   format "		for i in 1 to n do (
" to:s2
   format "			pCont.particleIndex = i
" to:s2
   format "			if pCont.isParticleNew i then (
" to:s2
   format "			    vertNum = pCont.particleID
" to:s2
   format "			    append vertArr vertNum
" to:s2
   format "			    ) -- end if pCont.isParticleNew
" to:s2
   format "			) -- end for i in 1 to n
" to:s2
   format "		) -- end obj position test
" to:s2
   format "	for v in (vertArr as array) do (
" to:s2
   format "		bigArryOVertPositions[v].z -= random .5 1
" to:s2
   format "		)
" to:s2
   format "	edgeArr = meshop.getEdgesUsingVert defMesh vertArr
" to:s2
   format "	vertArr2 = (meshop.getVertsUsingEdge defMesh edgeArr)
" to:s2
   format "	for j = 1 to 4 do (
" to:s2
   format "		edgeArr2 = (meshop.getEdgesUsingVert defMesh vertArr2)
" to:s2
   format "		vertArr2 = (meshop.getVertsUsingEdge defMesh edgeArr2)
" to:s2
   format "		setVertSelection defMesh vertArr2
" to:s2
   format "		for k in ((vertArr2 - vertArr) as array) do (
" to:s2
 format "			bigArryOVertPositions[k].z += random .1 .2
" to:s2
   format "			) 
" to:s2
   format "		) -- end for j = 1 to 10 
" to:s2
   format "	-- apply new vert positions to mesh
" to:s2
   format "	for j = 1 to bigArryOVertPositions.count do (
" to:s2
   format "		setVert defMesh j bigArryOVertPositions[j]
" to:s2
   format "		)
" to:s2
   format "	update defMesh
" to:s2
   format "	) -- end on Proceed pCont
" to:s2
   format "on Release pCont do ()
" to:s2
   s2 = s2 as string
   
   -- begin editing pFlow
   particleFlow.beginEdit()
   -- create new particle flow
 newPF = PF_Source X_Coord:0 Y_Coord:0 isSelected:on Logo_Size:5 Emitter_Length:10 Emitter_Width:10 Emitter_Height:10 pos:templateObj.center
   newPF.quantity_viewport = 100
   newPF.particle_amount_limit = 10000000
   -- add the Render and Dispaly operators to PF Source 01
   newPF.appendAction (renderParticles())
   newPF.appendAction (displayParticles type:1)
   -- turn off display of particles and PF object
   newPF.show_logo = off
   newPF.show_emitter = off
   newPF.baseObject.activateAction 2 0
   -- hook Event 01 to PF Source 01
   newPF.appendInitialActionList event01
   
   -- create Event01
   event01 = event()
   -- add the Birth Script operator and add the script
   event01.appendAction (Birth_Script Proceed_Script:s1)
   -- add a collision test and change some settings
   co = collision()
   event01.appendAction co
   co.Collision_Nodes = #(d1,d2)
   co.Speed_Option = 1
   -- get PF Source position in particle view window
   newPF_X = newPF_Y = 0
   newPF.getPViewLocation &newPF_X &newPF_Y
   -- reposition Event 01
   event01.setPViewLocation newPF_X (newPF_Y + 100)
   -- create Event02
   event02 = event()
   event02.setPViewLocation newPF_X (newPF_Y + 200)
   -- hook Event 02 to the collision test
   co.setNextActionList event02 co
   -- add the script operator that will deform the mesh using the particles
   event02.appendAction (Script_Operator proceed_script:s2 name:"footsteps")
   
   -- end pFlow edit
   particleFlow.endEdit()
   
   -- open the Particle View window
   particleFlow.openParticleView()
Page 1 / 2