Stoke Genome - Inflate > Iterative Limited Push By Element

Hello,

In the wonderful world of iterative looping Genome flows, I am wondering if it is possible to iteration through a routine that runs sequentially through an objects elements?
Can an element interrogate/be affected by neighboring elements in the same object?

For example (check out the attached screengrab) I want to create a explicit element Inflate mod:

Say I have an object with 7 elements – Can Genome select the first element and apply something akin to the limited push flow checking against all of the un-selected geometry?
In the second iteration, the second element runs the same deformation against a slightly different shaped object (the first element has been limited pushed against the remaining element).
So on and so fourth until it has cycled through all the elements.

Does this sound do-able? Or perhaps there is another way to accomplish the same effect?
In the attached screengrab, I basically did what I am describing ‘manually’ - I am hoping we could build a Genome mod that automates it.

Thanks,
Bob Dyce

This ALMOST works, but right now it is missing one detail.
If you create a flow that pushes by a small step and stops if it reaches another part of the mesh, then clone that Genome N times on the stack (similar to N iterations, but using independent cloned modifiers), it works nicely.

If you try to do a single modifier and set N iterations, it does not produce the correct result because the CurrentMesh node does not update between iterations in the current version of Genome. I have logged it as a bug/WishList item since it would be quite powerful. I think it should be optional so you can switch between updating once in the beginning and updating once per iteration (rebuilding the kd-tree with a very heavy mesh would be slow).

[attachment=0]STK_GNM_LimitedPushInOneMesh_v001.png[/attachment]

Very cool! Could you save back to max 2013 and post a scene file? Multiple iterations / versions of the genome mod in the stack woks better than the manual method I was using.

B

Here is the scene in Max 2013 format…
STK_GNM_LimitedPushSameMesh_Max2013_v001.zip (66.7 KB)

That is really cool. Can this same style of setup be used to soft-select when elements intersect? Bulge?
I’ve always thought that genome needed a separate object to test against - this opens some doors for sure!

Check out the attached video clip:
I took your flow and applied to a mesher pointing at a massFX Pflow with some spherical gravity and a little turbulence for churn.
This has 3 instances of that Genome Mod in the stack - Works like a charm!

B
STK_GNM_LimitedPushSameMesh_testPB.mp4 (2.88 MB)

Looks awesome!

In theory, anything you could do with multiple Genome instances on the stack should be doable with one modifier + iterations. CurrentMesh is, I think, and exception because it relies on a kd-tree of the mesh which is built only once in the beginning. Anything operating on actual channels though (Position, Selection etc.) would work. So soft-selection would probably work (but I am not sure what you are trying to do). This setup works because the vertices are NOT intersecting before we start. If they were already intersecting, it would be quite difficult to figure out what is where because it is hard to do a nearest point to a Vertex - it would find itself. IntersectRay works because I offset the initial ray position slightly off-surface along the normal to avoid self-intersection false positives.

Here is another example of how Stoke Genome Limited Push Same Mesh can do some pretty cool stuff to elements. Using massFX, I sim’d some shapes to get them packed together, then pushed them back against the current mesh. Very cool modeling tool for organic surfaces.

Try adding a Relax modifier on top to smooth it out a bit.
We are considering the inability to update the kd-tree between Iterations a bug and will try to fix it before release (which is scheduled for next week!)

Looks like intestines! Cool use of Genome!

I’m ‘Stoked’ to hear that the ability to update the dk-tree between iteration is on the short list. Sounds like it could open up some powerful possibilities!

B

I’m trying to build a flow that checks and selects verts that are ‘inside’ the volume of other elements within that same mesh. If you attached 2 geospheres that intersected, I want Genome to select (soft select) all of the verts that are inside/within the volume of another element.

Can Genome access or create a bounding box around elements - and then check if elements intersect?
Could you then test with intersectRay shooting from the normal and see if it crosses one vs. two faces on a neighboring element? (one meaning that vert is inside the other element -two meaning that it’s outside?)

Thanks,
Bob Dyce

If you shoot an IntersectRay and the Distance value has a negative sign, it means you hit a surface from the inside. So no need to shoot twice - just use < 0.0 on the Distance. There is also the InVolume operator that was meant to figure that out (but it does more tests and is thus slower).

Don’t forget to offset the Lookup Point slightly along the Normal, otherwise the vertex might find itself…

[code](–MAGMAFLOW2–
global MagmaFlowEditor_EditBLOPHistory = #()
global MagmaFlowEditor_Genome_Properties = #(#(#removeDegenerateFaces, false), #(#clampVertexSelection, true), #(#IterationCount, 1))
global MagmaFlowEditor_Genome_MeshIterationMode = #vertex
node0 = magmaNode.createNode “Output”
magmaNode.setNumNodeInputs node0 1
magmaNode.setNumNodeOutputs node0 0
magmaNode.setNodeProperty node0 “channelName” “Selection”
magmaNode.setNodeProperty node0 “channelType” “float16”
magmaNode.DeclareExtensionProperty node0 “Position”
magmaNode.SetNodeProperty node0 “Position” [331.05,90.2625]
magmaNode.DeclareExtensionProperty node0 “Selected”
magmaNode.SetNodeProperty node0 “Selected” true

node1 = magmaNode.createNode “IntersectRay”
magmaNode.setNumNodeInputs node1 3
magmaNode.setNumNodeOutputs node1 7
magmaNode.DeclareExtensionProperty node1 “Position”
magmaNode.SetNodeProperty node1 “Position” [413,15]
magmaNode.DeclareExtensionProperty node1 “Selected”
magmaNode.SetNodeProperty node1 “Selected” true

node2 = magmaNode.createNode “CurrentMesh”
magmaNode.setNumNodeInputs node2 0
magmaNode.setNumNodeOutputs node2 1
magmaNode.DeclareExtensionProperty node2 “Name”
magmaNode.SetNodeProperty node2 “Name” “CurrentMesh”
magmaNode.DeclareExtensionProperty node2 “Position”
magmaNode.SetNodeProperty node2 “Position” [273,120]
magmaNode.DeclareExtensionProperty node2 “Selected”
magmaNode.SetNodeProperty node2 “Selected” true

node3 = magmaNode.createNode “InputChannel”
magmaNode.setNumNodeInputs node3 0
magmaNode.setNumNodeOutputs node3 1
magmaNode.setNodeProperty node3 “channelName” “Position”
magmaNode.setNodeProperty node3 “channelType” “”
magmaNode.DeclareExtensionProperty node3 “Position”
magmaNode.SetNodeProperty node3 “Position” [-7,205]
magmaNode.DeclareExtensionProperty node3 “Selected”
magmaNode.SetNodeProperty node3 “Selected” true

node4 = magmaNode.createNode “ToWorld”
magmaNode.setNumNodeInputs node4 1
magmaNode.setNumNodeOutputs node4 1
magmaNode.setNodeProperty node4 “inputType” “Point”
magmaNode.DeclareExtensionProperty node4 “Position”
magmaNode.SetNodeProperty node4 “Position” [133,190]
magmaNode.DeclareExtensionProperty node4 “Selected”
magmaNode.SetNodeProperty node4 “Selected” true

node5 = magmaNode.createNode “InputChannel”
magmaNode.setNumNodeInputs node5 0
magmaNode.setNumNodeOutputs node5 1
magmaNode.setNodeProperty node5 “channelName” “Normal”
magmaNode.setNodeProperty node5 “channelType” “”
magmaNode.DeclareExtensionProperty node5 “Position”
magmaNode.SetNodeProperty node5 “Position” [-147,290]
magmaNode.DeclareExtensionProperty node5 “Selected”
magmaNode.SetNodeProperty node5 “Selected” true

node6 = magmaNode.createNode “ToWorld”
magmaNode.setNumNodeInputs node6 1
magmaNode.setNumNodeOutputs node6 1
magmaNode.setNodeProperty node6 “inputType” “Normal”
magmaNode.DeclareExtensionProperty node6 “Position”
magmaNode.SetNodeProperty node6 “Position” [-7,275]
magmaNode.DeclareExtensionProperty node6 “Selected”
magmaNode.SetNodeProperty node6 “Selected” true

node7 = magmaNode.createNode “Less”
magmaNode.setNumNodeInputs node7 2
magmaNode.setNumNodeOutputs node7 1
magmaNode.setNodeProperty node7 “useTolerance” false
magmaNode.setNodeProperty node7 “toleranceExp” 4
magmaNode.setNodeInputDefaultValue node7 2 0.0
magmaNode.DeclareExtensionProperty node7 “Position”
magmaNode.SetNodeProperty node7 “Position” [553,0]
magmaNode.DeclareExtensionProperty node7 “Selected”
magmaNode.SetNodeProperty node7 “Selected” true

node8 = magmaNode.createNode “Add”
magmaNode.setNumNodeInputs node8 2
magmaNode.setNumNodeOutputs node8 1
magmaNode.setNodeInputDefaultValue node8 1 0.0
magmaNode.setNodeInputDefaultValue node8 2 0.0
magmaNode.DeclareExtensionProperty node8 “Position”
magmaNode.SetNodeProperty node8 “Position” [273,175]
magmaNode.DeclareExtensionProperty node8 “Selected”
magmaNode.SetNodeProperty node8 “Selected” true

node9 = magmaNode.createNode “Multiply”
magmaNode.setNumNodeInputs node9 2
magmaNode.setNumNodeOutputs node9 1
magmaNode.setNodeInputDefaultValue node9 1 1.0
magmaNode.setNodeInputDefaultValue node9 2 0.001
magmaNode.DeclareExtensionProperty node9 “Position”
magmaNode.SetNodeProperty node9 “Position” [133,260]
magmaNode.DeclareExtensionProperty node9 “Selected”
magmaNode.SetNodeProperty node9 “Selected” true

try(magmaNode.setNodeInput node0 1 node7 1)catch()
try(magmaNode.setNodeInput node1 1 node2 1)catch()
try(magmaNode.setNodeInput node1 2 node8 1)catch()
try(magmaNode.setNodeInput node1 3 node6 1)catch()
try(magmaNode.setNodeInput node4 1 node3 1)catch()
try(magmaNode.setNodeInput node6 1 node5 1)catch()
try(magmaNode.setNodeInput node7 1 node1 5)catch()
magmaNode.setNodeInput node7 2 -1 1
try(magmaNode.setNodeInput node8 1 node4 1)catch()
try(magmaNode.setNodeInput node8 2 node9 1)catch()
try(magmaNode.setNodeInput node9 1 node6 1)catch()
magmaNode.setNodeInput node9 2 -1 1

)
[/code]

And here is the SoftSelection version:

(--MAGMAFLOW2--
global MagmaFlowEditor_EditBLOPHistory = #()
global MagmaFlowEditor_Genome_Properties = #(#(#removeDegenerateFaces, false), #(#clampVertexSelection, true), #(#IterationCount, 1))
global MagmaFlowEditor_Genome_MeshIterationMode = #vertex
node0 = magmaNode.createNode "Output" 
magmaNode.setNumNodeInputs node0 1 
magmaNode.setNumNodeOutputs node0 0 
magmaNode.setNodeProperty node0 "channelName" "Selection"
magmaNode.setNodeProperty node0 "channelType" "float16"
magmaNode.DeclareExtensionProperty node0 "Position"
magmaNode.SetNodeProperty node0 "Position" [100,100]
magmaNode.DeclareExtensionProperty node0 "Selected"
magmaNode.SetNodeProperty node0 "Selected" true
--------------------------------------------
node1 = magmaNode.createNode "IntersectRay" 
magmaNode.setNumNodeInputs node1 3 
magmaNode.setNumNodeOutputs node1 7 
magmaNode.DeclareExtensionProperty node1 "Position"
magmaNode.SetNodeProperty node1 "Position" [133,45]
magmaNode.DeclareExtensionProperty node1 "Selected"
magmaNode.SetNodeProperty node1 "Selected" true
--------------------------------------------
node2 = magmaNode.createNode "CurrentMesh" 
magmaNode.setNumNodeInputs node2 0 
magmaNode.setNumNodeOutputs node2 1 
magmaNode.DeclareExtensionProperty node2 "Name"
magmaNode.SetNodeProperty node2 "Name" "CurrentMesh"
magmaNode.DeclareExtensionProperty node2 "Position"
magmaNode.SetNodeProperty node2 "Position" [-7,150]
magmaNode.DeclareExtensionProperty node2 "Selected"
magmaNode.SetNodeProperty node2 "Selected" true
--------------------------------------------
node3 = magmaNode.createNode "InputChannel" 
magmaNode.setNumNodeInputs node3 0 
magmaNode.setNumNodeOutputs node3 1 
magmaNode.setNodeProperty node3 "channelName" "Position"
magmaNode.setNodeProperty node3 "channelType" ""
magmaNode.DeclareExtensionProperty node3 "Position"
magmaNode.SetNodeProperty node3 "Position" [-287,235]
magmaNode.DeclareExtensionProperty node3 "Selected"
magmaNode.SetNodeProperty node3 "Selected" true
--------------------------------------------
node4 = magmaNode.createNode "ToWorld" 
magmaNode.setNumNodeInputs node4 1 
magmaNode.setNumNodeOutputs node4 1 
magmaNode.setNodeProperty node4 "inputType" "Point"
magmaNode.DeclareExtensionProperty node4 "Position"
magmaNode.SetNodeProperty node4 "Position" [-147,220]
magmaNode.DeclareExtensionProperty node4 "Selected"
magmaNode.SetNodeProperty node4 "Selected" true
--------------------------------------------
node5 = magmaNode.createNode "InputChannel" 
magmaNode.setNumNodeInputs node5 0 
magmaNode.setNumNodeOutputs node5 1 
magmaNode.setNodeProperty node5 "channelName" "Normal"
magmaNode.setNodeProperty node5 "channelType" ""
magmaNode.DeclareExtensionProperty node5 "Position"
magmaNode.SetNodeProperty node5 "Position" [-427,320]
magmaNode.DeclareExtensionProperty node5 "Selected"
magmaNode.SetNodeProperty node5 "Selected" true
--------------------------------------------
node6 = magmaNode.createNode "ToWorld" 
magmaNode.setNumNodeInputs node6 1 
magmaNode.setNumNodeOutputs node6 1 
magmaNode.setNodeProperty node6 "inputType" "Normal"
magmaNode.DeclareExtensionProperty node6 "Position"
magmaNode.SetNodeProperty node6 "Position" [-287,305]
magmaNode.DeclareExtensionProperty node6 "Selected"
magmaNode.SetNodeProperty node6 "Selected" true
--------------------------------------------
node7 = magmaNode.createNode "Less" 
magmaNode.setNumNodeInputs node7 2 
magmaNode.setNumNodeOutputs node7 1 
magmaNode.setNodeProperty node7 "useTolerance" false
magmaNode.setNodeProperty node7 "toleranceExp" 4
magmaNode.setNodeInputDefaultValue node7 2 0.0
magmaNode.DeclareExtensionProperty node7 "Position"
magmaNode.SetNodeProperty node7 "Position" [413,155]
magmaNode.DeclareExtensionProperty node7 "Selected"
magmaNode.SetNodeProperty node7 "Selected" true
--------------------------------------------
node8 = magmaNode.createNode "Add" 
magmaNode.setNumNodeInputs node8 2 
magmaNode.setNumNodeOutputs node8 1 
magmaNode.setNodeInputDefaultValue node8 1 0.0
magmaNode.setNodeInputDefaultValue node8 2 0.0
magmaNode.DeclareExtensionProperty node8 "Position"
magmaNode.SetNodeProperty node8 "Position" [-7,205]
magmaNode.DeclareExtensionProperty node8 "Selected"
magmaNode.SetNodeProperty node8 "Selected" true
--------------------------------------------
node9 = magmaNode.createNode "Multiply" 
magmaNode.setNumNodeInputs node9 2 
magmaNode.setNumNodeOutputs node9 1 
magmaNode.setNodeInputDefaultValue node9 1 1.0
magmaNode.setNodeInputDefaultValue node9 2 0.001
magmaNode.DeclareExtensionProperty node9 "Position"
magmaNode.SetNodeProperty node9 "Position" [-147,290]
magmaNode.DeclareExtensionProperty node9 "Selected"
magmaNode.SetNodeProperty node9 "Selected" true
--------------------------------------------
node10 = magmaNode.createNode "Switch" 
magmaNode.setNumNodeInputs node10 3 
magmaNode.setNumNodeOutputs node10 1 
magmaNode.setNodeInputDefaultValue node10 3 1
magmaNode.DeclareExtensionProperty node10 "Position"
magmaNode.SetNodeProperty node10 "Position" [553,0]
magmaNode.DeclareExtensionProperty node10 "Selected"
magmaNode.SetNodeProperty node10 "Selected" true
--------------------------------------------
node11 = magmaNode.createNode "Abs" 
magmaNode.setNumNodeInputs node11 1 
magmaNode.setNumNodeOutputs node11 1 
magmaNode.DeclareExtensionProperty node11 "Position"
magmaNode.SetNodeProperty node11 "Position" [273,30]
magmaNode.DeclareExtensionProperty node11 "Selected"
magmaNode.SetNodeProperty node11 "Selected" true
--------------------------------------------
node12 = magmaNode.createNode "Divide" 
magmaNode.setNumNodeInputs node12 2 
magmaNode.setNumNodeOutputs node12 1 
magmaNode.setNodeInputDefaultValue node12 1 1.0
magmaNode.setNodeInputDefaultValue node12 2 1.0
magmaNode.DeclareExtensionProperty node12 "Position"
magmaNode.SetNodeProperty node12 "Position" [413,15]
magmaNode.DeclareExtensionProperty node12 "Selected"
magmaNode.SetNodeProperty node12 "Selected" true
--------------------------------------------
node13 = magmaNode.createNode "InputValue" 
magmaNode.setNumNodeInputs node13 0 
magmaNode.setNumNodeOutputs node13 1 
magmaNode.setNodeProperty node13 "forceInteger" false
ctrl=bezier_float(); ctrl.value = 50.0
magmaNode.setNodeProperty node13 "controller" ctrl
magmaNode.DeclareExtensionProperty node13 "Exposed"
magmaNode.SetNodeProperty node13 "Exposed" true
magmaNode.DeclareExtensionProperty node13 "Name"
magmaNode.SetNodeProperty node13 "Name" "Falloff Dist."
magmaNode.DeclareExtensionProperty node13 "Position"
magmaNode.SetNodeProperty node13 "Position" [270,100]
magmaNode.DeclareExtensionProperty node13 "Selected"
magmaNode.SetNodeProperty node13 "Selected" true
--------------------------------------------
node14 = magmaNode.createNode "InputValue" 
magmaNode.setNumNodeInputs node14 0 
magmaNode.setNumNodeOutputs node14 1 
magmaNode.setNodeProperty node14 "forceInteger" false
ctrl=bezier_float(); ctrl.value = 0.0
magmaNode.setNodeProperty node14 "controller" ctrl
magmaNode.DeclareExtensionProperty node14 "Position"
magmaNode.SetNodeProperty node14 "Position" [413,100]
magmaNode.DeclareExtensionProperty node14 "Selected"
magmaNode.SetNodeProperty node14 "Selected" true
--------------------------------------------
try(magmaNode.setNodeInput node0 1 node10 1)catch()
try(magmaNode.setNodeInput node1 1 node2 1)catch()
try(magmaNode.setNodeInput node1 2 node8 1)catch()
try(magmaNode.setNodeInput node1 3 node6 1)catch()
try(magmaNode.setNodeInput node4 1 node3 1)catch()
try(magmaNode.setNodeInput node6 1 node5 1)catch()
try(magmaNode.setNodeInput node7 1 node1 5)catch()
magmaNode.setNodeInput node7 2 -1 1 
try(magmaNode.setNodeInput node8 1 node4 1)catch()
try(magmaNode.setNodeInput node8 2 node9 1)catch()
try(magmaNode.setNodeInput node9 1 node6 1)catch()
magmaNode.setNodeInput node9 2 -1 1 
try(magmaNode.setNodeInput node10 1 node12 1)catch()
try(magmaNode.setNodeInput node10 2 node14 1)catch()
try(magmaNode.setNodeInput node10 3 node7 1)catch()
try(magmaNode.setNodeInput node11 1 node1 5)catch()
try(magmaNode.setNodeInput node12 1 node11 1)catch()
try(magmaNode.setNodeInput node12 2 node13 1)catch()
--------------------------------------------
)

Right on - Thanks! I really appreciate you taking the time to make these flows.

Question - Could a loop be added to these flows that would ‘grow’ the selection outward? Would you put that loop at the very end of the flow, right before the output?
I’ve created a face growing flow from your tutorial, but have not tried it on the vertex level. Basically the same loop with a VertexLoopByFace?

Thanks,
Bob Dyce

Do you mean growing on vertices that are NOT inside the intersection?

Growing selections is possible with a separate Genome on top of your current Genome. Basically you iterate over the neighbor vertices with a VertexLoopByEdge and propagate the selection as needed. Then increase the modifier’s iterations to define how far you want to grow. Making it fall off as a soft-selection is slightly tricky, but doable.

I mean growing the vertices that are being selected by the element intersection flow.
So you’re suggesting that I add a second Genome mod to grow the selection rather than trying to pack it all into a single flow?

Check the attached vertex ‘grow’ flow - what am I doing wrong here?

Also - Could a flow be made to take an existing vert (or face) selection and add controllable / animate-able softselection from that selection?
It would be cool to have a flow that could grow/shrink selections that it receives from the stack AND you could turn on and adjust soft selections.

Yes, I don’t think you can do it in one flow because the flow you have does the selection, and you cannot have two different passes within the same iteration. You have an explicit loop over all vertices in the Genome modifier. If you would try to grow a selection, the intersection selection data wouldn’t be there yet to grow when you try to grow it. Thus the requirement for a separate “GrowSelection” modifier on top.

When inside a Loop, you MUST use the LoopChannel input node instead of the InputChannel node. The LoopChannel node explicitly looks at the data of the neighbor element being looped over as opposed to the vertex that initiated the loop.

Yes, it would be possible, and I am pretty sure I have posted that example before. Will see if I can post it again.

LoopChannel Selection input node! Thanks Bobo, that fixed it.

Really cool, Bob! I will certainly be using this technique.

Hi Bobo - Was the ability to update the kd-tree between iterations ever fixed? I have been playing with the ‘limited push same mesh’ flow using Frost to place instanced geo at vert point and I’d love to have a limited push same mesh that could be set to a small about, then looped a few iterations.

B