AWS Thinkbox Discussion Forums

MagmaFlow Editor - Love And Hate Thread

If there are two BLOPs at the top level and a nested BLOP inside the first BLOP, you should be able to open all 3 in separate editors while keeping the main view open, too. But closing the main view should also close all dependent “children”. This would be useful when in Debug mode showing all values in the top level while you tweak the BLOPS underneath.

Aye ok, BLOPS in BLOPS, I have dared not venture that deep…yet, the constraints of my thought process usually restricts me to no more than +1 deep, gets too confusing for me without being able to easily track type and value. LOL if on the other hand the pipe out type/average value were listed somewhere on the BLOP… sorry probably getting a little carried away :blush: I guess debug kinda does this anway.

But what if I have 8 KCM’s all using one BLOP? I should be able to edit the BLOP in one window and have it affect 8 KCM’s without having them open. Or am I confusion who’s dependent on whom?

Ohhh I see what your saying now, so where/how does the dependency lie. Can you do this as is though? Honestly, I have never tried it. I would think that unless writing to a channel (that is accessed via other KCMs) that a BLOP is only available to its parent KCM. Is that not correct?

Your thinking like an instantiated BLOP across multiple KCM’s, right?

In the current (and future) implementations of MagmaFlow, a BLOP is stored in the flow itself and does NOT keep a live connection to an eventual source on disk (but I guess it could if desired). So if you have a, say, Phong Shading BLOP stored on disk and load it into 3 KCMs, then you modify one BLOP in one KCM, the other two as well as the disk definition will not change automatically (you do “local edit”). If you re-save the modified BLOP to disk, the definition will be updated, but the other two KCMs won’t be updated automatically because they are not hot-linked to the disk definition. Only if you re-load the disk definition into each one of them will they get the change you made.

We could talk about mechanisms to allow that propagation / hot linking to happen automatically, but I would imagine it could be confusing to the end user. Or we could have a color indicator that shows green when the disk def. matches the current def, red when it doesn’t, or blue when the definition does not exist on disk. A button could force a refresh with a single click or something…

So, yes, I was actually asking earnestly :laughing:

That sounds weird; I mean the current way. Guess it’s a matter of expectations (and mine were wrong). If a BLOP is just a “group” that the user can tidy up a flow with (we don’t have any other way of tidying, really), that’s a big conceptual difference than a “black box” which is more like a plugin (often made by someone else) that they expect to perform a certain process over and over again. If the BLOP is stored in the KCM (as opposed to a reference to it on disk) that would explain why we don’t have network locations for BLOPS.

Maybe a compromise? A HOTBLOP (or HotBlOp?) could be referenced (meaning if you couldn’t find it on disk, the render would fail), while the current BLOPs would would maintain the current embedded nature? HOTBLOPS would be stored at a network location and would be cached like a bitmap (or PRT) is.

Maybe you would colorcode them so that HOTBLOPS are easily differentiated from BLOPS? Have a button in the HOTBLOP that converts it (embedding it to the KCM) to a BLOP?

  • Chad

A HOTBLOP don’t you mean a Betty BLOP? :smiley:

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

You are right, BLOPs are a mixture of a group and a compound. Here are the reasons why we did what we did:

  1. The BLOP lets you save a definition to disk and load a definition from disk, creating a new node that does some operations encapsulated in it.
  2. Once loaded in the flow, the BLOP can be modified to serve the task at hand without affecting 100 other flows out there that might use the same definition.
  3. Once loaded in the flow, the BLOP will live in the MAX scene and the MAX file can be sent to other users without the need to also pack and send external references (I would HATE to do that, but I guess it is not too bad in a production environment if all BLOPs were on the network).
  4. The BLOP can be exploded at any time, and any group of interconnected nodes can be collapsed to a BLOP even without saving a definition to disk (because of 3.) This is kind of like Collapsing/Grouping.

So we have created something that is more like a Group that can be saved and loaded than a real Compound, as you correctly noted.
In Magma 2.0, the management of BLOPs, as well as saving and loading of flows and compounds is handled by the C++ code.
The editor simply calls a Push() and Pop() function for any existing BLOP and all query methods switch to operating to the current BLOP level, which makes the Editor’s design much simpler.

So we might look into using the same technology for two types of BLOPs - a Group node that can be used inline to collapse/explode groups of nodes as needed (and optionally saved to disk/loaded from disk - in other words, the current system), and a real Compound node (we can keep on calling it BLOP) which can keep a reference to a file. Here are some things to discuss:

*The Compound BLOP will be still stored in the flow and when you open the MAX scene, should try to update from the network to ensure the latest version of the saved definition is being used. If that definition is not found, for example because the scene was sent to another office that doesn’t have the definitions on disk, it would still work (which sounds good).

*The Compound BLOP could be modified by a user within the context of the flow. We now come into the realm of the Max Containers management where we could decide whether to make these changes in place and publish them to the disk definition which would potentially affect all other scenes using that BLOP, or keep them local.

*The Compound BLOP could also be switched not to update automatically from disk even if the definition is there and is changing, for example if the user is happy with v1.23 of the BLOP and does not want someone updating it to v1.24 to screw up his results…

As you can see, we are moving into the area of cooperative editing of flows which I totally DISLIKE because one moron can ruin the whole pipeline by changing a BLOP in a test scene that propagates to any number of scenes, some probably already rendering on Deadline (we could suppress updates in slave mode, but this is getting ridiculously complicated already).

I am open for discussion, but I believe that a system that requires manual intervention to trigger updates is safer and will cause less havoc.

I’d say :cry:
So simply put:
Localize - all BLOP nodes are integrated to scene, each BLOP is singular in nature

Global - BLOP is saved on disk, edit one edit them all. Manual Update trigger, needs BLOP Locks, saving automatically saves an increment copy instead of overwriting to keep morons from completely breaking something. Sounds fine to me, Safety First.

Gees, I just wanted to open a BLOP in a child window.

You don’t need to suppress updates on the slave, you “embed” the HotBLOPs at submission.

And morons updating stuff happens with stuff now anyway. Could be a texture map, or a PRT, or a PointCache or whatever. You’d manage it the same way.

I’m not against manual updates, of course. But I’d hate to be asking people to periodically update their BLOPs. They won’t know they were updated unless they open the KCM and check? Hmmm…

You would have to serialize them something like Bobo mentioned earlier. Scene open, scan BLOP directory, sees newer BLOP, use newer?, confirm yes/no

No matter what, you cannot foolproof everything, gees people still wonder why FumeFX crashes their machine when the grid is too dense, old hat.

My gut feeling is that a BLOP is an entity that is saved to disk as a template and does certain operation. It is typically not as complex as a plugin to require updates many times a week - it either works or it doesn’t. If it does work well the first time it is inserted in a flow, I don’t see a reason to update it automatically. If the user feels the BLOP is more of a template and decides to tweak it to match the current requirements of his flow, these changes should never propagate to the template on disk because they are probably irrelevant to all other 99% of the cases. And if a TD updates the definition on disk, I would hate it if my customizations to the in-flow BLOP would be lost due to automatic updating.

In short, I would prefer the current workflow to be the default, and provide means to automatically replace all instances of a specific BLOP via some sort of tool like a “BLOP Manager” or something with full control over what is being updated, what is the old flow vs. the new one, full undo and logging support etc.

If you can convince me that your HotBLOP workflow is what your company would use more than 50% of the time when working with MagmaFlow, then we can look into separating the BLOP into two types - a Hot one and a Cold (Local, old style) one to satisfy both demands. But right now I believe the current implementation makes more sense.

I would like say that I appreciate the naming schemes you guys suggest though. HotBLOP seems like a name that will stick to something, even if it’s not this particular idea.

Yeah, you’re probably right. So the real sticky point would be how does one make one BLOP affect 12 KCM’s in one file. I can see where whatever tweaks you wanted to do would do on scene specific basis would likely need to be applied to multiple objects.

What we could think about (but I am not promising anything) would be if a BLOP was actually a ReferenceTarget or some other kind of MAX object. In that case, a BLOP would be its own flow and could be instanced within the MAX scene in many flows and any change to one instance could be propagated automatically to all others. But this would be quite difficult to implement and I don’t think Darcy intended to go that way.

So what we could do is have an option in the UI of the BLOP that lets you open a Manager that searches the scene for all other BLOPs from the same source and lets you update any or all of them. This would be relatively easy to script, and we could also add a property in all BLOPs that flags them for modification. For example, if you load a BLOP from disk, it would set the flag to “I am OK for updates”. If you open the BLOP and make any changes vs. the source, it would set the property to “custom modifications, don’t update me”. Then the Manager could show these flags and you could easily filter out and update all occurrences of a specific BLOP that have not been touched since insertion, or override that flag and replace them all no matter what. But this all will affect only the current scene and not other people’s scenes which I find safer.

If other people’s scenes need updating, we could think of other UI-level ways to trigger the BLOP Manager and ensure everybody is using the latest and greatest “Phong Shading BLOP” for example without destroying anything. Or a filePostOpen callback could check the scene against the sources on the network and prompt the user to update the unmodified occurrences of a BLOP that might have been resaved on disk with the latest version without affecting the ones with the “don’t update me” flag set…

Let’s wait until I have the basic BLOP handling working again like it did before, and I will see how far we can go with the automation…

Time to revisit the list and see where we stand as of beginning of July:

Done. Currently, MAXScript code emission is used to perform Copy&Paste, Save/Load/Merge and even Undo/Redo. Totally index-independent, and since you can now have more than one output node, it is even possible to paste or merge multiple flows into the same modifier. The Windows Clipboard can be used to paste into forum posts and copy back into flows. This also means that the creation of MagmaFlows using MAXScript is very simplified.

Here a quick example:

[code](–MAGMAFLOW2–
global MagmaFlowEditor_EditBLOPHistory = #()
node0 = magmaNode.createNode “Output”
magmaNode.setNumNodeInputs node0 1
magmaNode.setNumNodeOutputs node0 0
magmaNode.setNodeProperty node0 “enabled” true
magmaNode.setNodeProperty node0 “channelName” “Position”
magmaNode.setNodeProperty node0 “channelType” “float32[3]”
magmaNode.DeclareExtensionProperty node0 “Collapsed”
magmaNode.SetNodeProperty node0 “Collapsed” false
magmaNode.DeclareExtensionProperty node0 “OrderX”
magmaNode.SetNodeProperty node0 “OrderX” 1
magmaNode.DeclareExtensionProperty node0 “OrderY”
magmaNode.SetNodeProperty node0 “OrderY” 1
magmaNode.DeclareExtensionProperty node0 “Position”
magmaNode.SetNodeProperty node0 “Position” [100,100]
magmaNode.DeclareExtensionProperty node0 “Position2”
magmaNode.SetNodeProperty node0 “Position2” [100,100]
magmaNode.DeclareExtensionProperty node0 “Selected”
magmaNode.SetNodeProperty node0 “Selected” true

node1 = magmaNode.createNode “InputChannel”
magmaNode.setNumNodeInputs node1 0
magmaNode.setNumNodeOutputs node1 1
magmaNode.setNodeProperty node1 “enabled” true
magmaNode.setNodeProperty node1 “channelName” “Position”
magmaNode.setNodeProperty node1 “channelType” “”
magmaNode.DeclareExtensionProperty node1 “Collapsed”
magmaNode.SetNodeProperty node1 “Collapsed” false
magmaNode.DeclareExtensionProperty node1 “OrderX”
magmaNode.SetNodeProperty node1 “OrderX” 8
magmaNode.DeclareExtensionProperty node1 “OrderY”
magmaNode.SetNodeProperty node1 “OrderY” 2
magmaNode.DeclareExtensionProperty node1 “Position”
magmaNode.SetNodeProperty node1 “Position” [-70,150]
magmaNode.DeclareExtensionProperty node1 “Position2”
magmaNode.SetNodeProperty node1 “Position2” [-160,378]
magmaNode.DeclareExtensionProperty node1 “Selected”
magmaNode.SetNodeProperty node1 “Selected” true

node2 = magmaNode.createNode “IntersectRay”
magmaNode.setNumNodeInputs node2 3
magmaNode.setNumNodeOutputs node2 6
magmaNode.setNodeProperty node2 “enabled” true
magmaNode.DeclareExtensionProperty node2 “Collapsed”
magmaNode.SetNodeProperty node2 “Collapsed” false
magmaNode.DeclareExtensionProperty node2 “HideUnconnectedOutputs”
magmaNode.SetNodeProperty node2 “HideUnconnectedOutputs” false
magmaNode.DeclareExtensionProperty node2 “OrderX”
magmaNode.SetNodeProperty node2 “OrderX” 6
magmaNode.DeclareExtensionProperty node2 “OrderY”
magmaNode.SetNodeProperty node2 “OrderY” 1
magmaNode.DeclareExtensionProperty node2 “Position”
magmaNode.SetNodeProperty node2 “Position” [220,-20]
magmaNode.DeclareExtensionProperty node2 “Position2”
magmaNode.SetNodeProperty node2 “Position2” [100,277]
magmaNode.DeclareExtensionProperty node2 “Selected”
magmaNode.SetNodeProperty node2 “Selected” true

node3 = magmaNode.createNode “InputValue”
magmaNode.setNumNodeInputs node3 0
magmaNode.setNumNodeOutputs node3 1
magmaNode.setNodeProperty node3 “enabled” true
magmaNode.setNodeProperty node3 “forceInteger” false
ctrl=Point3_XYZ(); ctrl.value = [0,0,-1]
magmaNode.setNodeProperty node3 “controller” ctrl
magmaNode.DeclareExtensionProperty node3 “Collapsed”
magmaNode.SetNodeProperty node3 “Collapsed” false
magmaNode.DeclareExtensionProperty node3 “OrderX”
magmaNode.SetNodeProperty node3 “OrderX” 7
magmaNode.DeclareExtensionProperty node3 “OrderY”
magmaNode.SetNodeProperty node3 “OrderY” 2
magmaNode.DeclareExtensionProperty node3 “Position”
magmaNode.SetNodeProperty node3 “Position” [70,220]
magmaNode.DeclareExtensionProperty node3 “Position2”
magmaNode.SetNodeProperty node3 “Position2” [-30,425]
magmaNode.DeclareExtensionProperty node3 “Selected”
magmaNode.SetNodeProperty node3 “Selected” true

node4 = magmaNode.createNode “InputGeometry”
magmaNode.setNumNodeInputs node4 0
magmaNode.setNumNodeOutputs node4 1
magmaNode.setNodeProperty node4 “enabled” true
magmaNode.setNodeProperty node4 “node” (getNodeByName “Torus Knot001”)
magmaNode.DeclareExtensionProperty node4 “Collapsed”
magmaNode.SetNodeProperty node4 “Collapsed” false
magmaNode.DeclareExtensionProperty node4 “OrderX”
magmaNode.SetNodeProperty node4 “OrderX” 7
magmaNode.DeclareExtensionProperty node4 “OrderY”
magmaNode.SetNodeProperty node4 “OrderY” 1
magmaNode.DeclareExtensionProperty node4 “Position”
magmaNode.SetNodeProperty node4 “Position” [70,90]
magmaNode.DeclareExtensionProperty node4 “Position2”
magmaNode.SetNodeProperty node4 “Position2” [-30,470]
magmaNode.DeclareExtensionProperty node4 “Selected”
magmaNode.SetNodeProperty node4 “Selected” true

node5 = magmaNode.createNode “Switch”
magmaNode.setNumNodeInputs node5 3
magmaNode.setNumNodeOutputs node5 1
magmaNode.setNodeProperty node5 “enabled” true
magmaNode.DeclareExtensionProperty node5 “Collapsed”
magmaNode.SetNodeProperty node5 “Collapsed” false
magmaNode.DeclareExtensionProperty node5 “OrderX”
magmaNode.SetNodeProperty node5 “OrderX” 2
magmaNode.DeclareExtensionProperty node5 “OrderY”
magmaNode.SetNodeProperty node5 “OrderY” 1
magmaNode.DeclareExtensionProperty node5 “Position”
magmaNode.SetNodeProperty node5 “Position” [500,-20]
magmaNode.DeclareExtensionProperty node5 “Position2”
magmaNode.SetNodeProperty node5 “Position2” [620,0]
magmaNode.DeclareExtensionProperty node5 “Selected”
magmaNode.SetNodeProperty node5 “Selected” true

node6 = magmaNode.createNode “FromWorld”
magmaNode.setNumNodeInputs node6 1
magmaNode.setNumNodeOutputs node6 1
magmaNode.setNodeProperty node6 “enabled” true
magmaNode.setNodeProperty node6 “inputType” “Point”
magmaNode.DeclareExtensionProperty node6 “Collapsed”
magmaNode.SetNodeProperty node6 “Collapsed” false
magmaNode.DeclareExtensionProperty node6 “OrderX”
magmaNode.SetNodeProperty node6 “OrderX” 3
magmaNode.DeclareExtensionProperty node6 “OrderY”
magmaNode.SetNodeProperty node6 “OrderY” 1
magmaNode.DeclareExtensionProperty node6 “Position”
magmaNode.SetNodeProperty node6 “Position” [370,-20]
magmaNode.DeclareExtensionProperty node6 “Position2”
magmaNode.SetNodeProperty node6 “Position2” [490,13]
magmaNode.DeclareExtensionProperty node6 “Selected”
magmaNode.SetNodeProperty node6 “Selected” true

node7 = magmaNode.createNode “ToWorld”
magmaNode.setNumNodeInputs node7 1
magmaNode.setNumNodeOutputs node7 1
magmaNode.setNodeProperty node7 “enabled” true
magmaNode.setNodeProperty node7 “inputType” “Point”
magmaNode.DeclareExtensionProperty node7 “Collapsed”
magmaNode.SetNodeProperty node7 “Collapsed” false
magmaNode.DeclareExtensionProperty node7 “OrderX”
magmaNode.SetNodeProperty node7 “OrderX” 7
magmaNode.DeclareExtensionProperty node7 “OrderY”
magmaNode.SetNodeProperty node7 “OrderY” 2
magmaNode.DeclareExtensionProperty node7 “Position”
magmaNode.SetNodeProperty node7 “Position” [70,150]
magmaNode.DeclareExtensionProperty node7 “Position2”
magmaNode.SetNodeProperty node7 “Position2” [-30,365]
magmaNode.DeclareExtensionProperty node7 “Selected”
magmaNode.SetNodeProperty node7 “Selected” true

node8 = magmaNode.createNode “IntersectRay”
magmaNode.setNumNodeInputs node8 3
magmaNode.setNumNodeOutputs node8 6
magmaNode.setNodeProperty node8 “enabled” true
magmaNode.DeclareExtensionProperty node8 “Collapsed”
magmaNode.SetNodeProperty node8 “Collapsed” false
magmaNode.DeclareExtensionProperty node8 “HideUnconnectedOutputs”
magmaNode.SetNodeProperty node8 “HideUnconnectedOutputs” false
magmaNode.DeclareExtensionProperty node8 “OrderX”
magmaNode.SetNodeProperty node8 “OrderX” 4
magmaNode.DeclareExtensionProperty node8 “OrderY”
magmaNode.SetNodeProperty node8 “OrderY” 2
magmaNode.DeclareExtensionProperty node8 “Position”
magmaNode.SetNodeProperty node8 “Position” [220,150]
magmaNode.DeclareExtensionProperty node8 “Position2”
magmaNode.SetNodeProperty node8 “Position2” [360,86]
magmaNode.DeclareExtensionProperty node8 “Selected”
magmaNode.SetNodeProperty node8 “Selected” true

node9 = magmaNode.createNode “InputGeometry”
magmaNode.setNumNodeInputs node9 0
magmaNode.setNumNodeOutputs node9 1
magmaNode.setNodeProperty node9 “enabled” true
magmaNode.setNodeProperty node9 “node” (getNodeByName “Cylinder001”)
magmaNode.DeclareExtensionProperty node9 “Collapsed”
magmaNode.SetNodeProperty node9 “Collapsed” false
magmaNode.DeclareExtensionProperty node9 “OrderX”
magmaNode.SetNodeProperty node9 “OrderX” 5
magmaNode.DeclareExtensionProperty node9 “OrderY”
magmaNode.SetNodeProperty node9 “OrderY” 2
magmaNode.DeclareExtensionProperty node9 “Position”
magmaNode.SetNodeProperty node9 “Position” [70,270]
magmaNode.DeclareExtensionProperty node9 “Position2”
magmaNode.SetNodeProperty node9 “Position2” [230,204]
magmaNode.DeclareExtensionProperty node9 “Selected”
magmaNode.SetNodeProperty node9 “Selected” true

node10 = magmaNode.createNode “FromWorld”
magmaNode.setNumNodeInputs node10 1
magmaNode.setNumNodeOutputs node10 1
magmaNode.setNodeProperty node10 “enabled” true
magmaNode.setNodeProperty node10 “inputType” “Point”
magmaNode.DeclareExtensionProperty node10 “Collapsed”
magmaNode.SetNodeProperty node10 “Collapsed” false
magmaNode.DeclareExtensionProperty node10 “OrderX”
magmaNode.SetNodeProperty node10 “OrderX” 3
magmaNode.DeclareExtensionProperty node10 “OrderY”
magmaNode.SetNodeProperty node10 “OrderY” 1
magmaNode.DeclareExtensionProperty node10 “Position”
magmaNode.SetNodeProperty node10 “Position” [370,40]
magmaNode.DeclareExtensionProperty node10 “Position2”
magmaNode.SetNodeProperty node10 “Position2” [490,73]
magmaNode.DeclareExtensionProperty node10 “Selected”
magmaNode.SetNodeProperty node10 “Selected” true

node11 = magmaNode.createNode “LogicalAnd”
magmaNode.setNumNodeInputs node11 2
magmaNode.setNumNodeOutputs node11 1
magmaNode.setNodeProperty node11 “enabled” true
magmaNode.DeclareExtensionProperty node11 “Collapsed”
magmaNode.SetNodeProperty node11 “Collapsed” false
magmaNode.DeclareExtensionProperty node11 “OrderX”
magmaNode.SetNodeProperty node11 “OrderX” 3
magmaNode.DeclareExtensionProperty node11 “OrderY”
magmaNode.SetNodeProperty node11 “OrderY” 1
magmaNode.DeclareExtensionProperty node11 “Position”
magmaNode.SetNodeProperty node11 “Position” [370,100]
magmaNode.DeclareExtensionProperty node11 “Position2”
magmaNode.SetNodeProperty node11 “Position2” [490,133]
magmaNode.DeclareExtensionProperty node11 “Selected”
magmaNode.SetNodeProperty node11 “Selected” true

node12 = magmaNode.createNode “VectorDot”
magmaNode.setNumNodeInputs node12 2
magmaNode.setNumNodeOutputs node12 1
magmaNode.setNodeProperty node12 “enabled” true
magmaNode.DeclareExtensionProperty node12 “Collapsed”
magmaNode.SetNodeProperty node12 “Collapsed” false
magmaNode.DeclareExtensionProperty node12 “OrderX”
magmaNode.SetNodeProperty node12 “OrderX” 5
magmaNode.DeclareExtensionProperty node12 “OrderY”
magmaNode.SetNodeProperty node12 “OrderY” 1
magmaNode.DeclareExtensionProperty node12 “Position”
magmaNode.SetNodeProperty node12 “Position” [370,290]
magmaNode.DeclareExtensionProperty node12 “Position2”
magmaNode.SetNodeProperty node12 “Position2” [230,264]
magmaNode.DeclareExtensionProperty node12 “Selected”
magmaNode.SetNodeProperty node12 “Selected” true

node13 = magmaNode.createNode “InputValue”
magmaNode.setNumNodeInputs node13 0
magmaNode.setNumNodeOutputs node13 1
magmaNode.setNodeProperty node13 “enabled” true
magmaNode.setNodeProperty node13 “forceInteger” false
ctrl=Point3_XYZ(); ctrl.value = [0,0,1]
magmaNode.setNodeProperty node13 “controller” ctrl
magmaNode.DeclareExtensionProperty node13 “Collapsed”
magmaNode.SetNodeProperty node13 “Collapsed” false
magmaNode.DeclareExtensionProperty node13 “OrderX”
magmaNode.SetNodeProperty node13 “OrderX” 6
magmaNode.DeclareExtensionProperty node13 “OrderY”
magmaNode.SetNodeProperty node13 “OrderY” 1
magmaNode.DeclareExtensionProperty node13 “Position”
magmaNode.SetNodeProperty node13 “Position” [220,320]
magmaNode.DeclareExtensionProperty node13 “Position2”
magmaNode.SetNodeProperty node13 “Position2” [100,442]
magmaNode.DeclareExtensionProperty node13 “Selected”
magmaNode.SetNodeProperty node13 “Selected” true

node14 = magmaNode.createNode “Greater”
magmaNode.setNumNodeInputs node14 2
magmaNode.setNumNodeOutputs node14 1
magmaNode.setNodeInputDefaultValue node14 2 0.5
magmaNode.setNodeProperty node14 “enabled” true
magmaNode.DeclareExtensionProperty node14 “Collapsed”
magmaNode.SetNodeProperty node14 “Collapsed” false
magmaNode.DeclareExtensionProperty node14 “HideUnconnectedOutputs”
magmaNode.SetNodeProperty node14 “HideUnconnectedOutputs” false
magmaNode.DeclareExtensionProperty node14 “Name”
magmaNode.SetNodeProperty node14 “Name” “Greater”
magmaNode.DeclareExtensionProperty node14 “OrderX”
magmaNode.SetNodeProperty node14 “OrderX” 4
magmaNode.DeclareExtensionProperty node14 “OrderY”
magmaNode.SetNodeProperty node14 “OrderY” 1
magmaNode.DeclareExtensionProperty node14 “Position”
magmaNode.SetNodeProperty node14 “Position” [370,220]
magmaNode.DeclareExtensionProperty node14 “Position2”
magmaNode.SetNodeProperty node14 “Position2” [360,251]
magmaNode.DeclareExtensionProperty node14 “Selected”
magmaNode.SetNodeProperty node14 “Selected” true

node15 = magmaNode.createNode “Output”
magmaNode.setNumNodeInputs node15 1
magmaNode.setNumNodeOutputs node15 0
magmaNode.setNodeProperty node15 “enabled” true
magmaNode.setNodeProperty node15 “channelName” “Selection”
magmaNode.setNodeProperty node15 “channelType” “float32”
magmaNode.DeclareExtensionProperty node15 “Collapsed”
magmaNode.SetNodeProperty node15 “Collapsed” false
magmaNode.DeclareExtensionProperty node15 “OrderX”
magmaNode.SetNodeProperty node15 “OrderX” 1
magmaNode.DeclareExtensionProperty node15 “OrderY”
magmaNode.SetNodeProperty node15 “OrderY” 2
magmaNode.DeclareExtensionProperty node15 “Position”
magmaNode.SetNodeProperty node15 “Position” [640,80]
magmaNode.DeclareExtensionProperty node15 “Selected”
magmaNode.SetNodeProperty node15 “Selected” true

node16 = magmaNode.createNode “ToFloat”
magmaNode.setNumNodeInputs node16 1
magmaNode.setNumNodeOutputs node16 1
magmaNode.setNodeProperty node16 “enabled” true
magmaNode.DeclareExtensionProperty node16 “Collapsed”
magmaNode.SetNodeProperty node16 “Collapsed” false
magmaNode.DeclareExtensionProperty node16 “OrderX”
magmaNode.SetNodeProperty node16 “OrderX” 2
magmaNode.DeclareExtensionProperty node16 “OrderY”
magmaNode.SetNodeProperty node16 “OrderY” 2
magmaNode.DeclareExtensionProperty node16 “Position”
magmaNode.SetNodeProperty node16 “Position” [500,100]
magmaNode.DeclareExtensionProperty node16 “Position2”
magmaNode.SetNodeProperty node16 “Position2” [620,130]
magmaNode.DeclareExtensionProperty node16 “Selected”
magmaNode.SetNodeProperty node16 “Selected” true

node17 = magmaNode.createNode “LogicalNot”
magmaNode.setNumNodeInputs node17 1
magmaNode.setNumNodeOutputs node17 1
magmaNode.setNodeProperty node17 “enabled” true
magmaNode.DeclareExtensionProperty node17 “Collapsed”
magmaNode.SetNodeProperty node17 “Collapsed” false
magmaNode.DeclareExtensionProperty node17 “OrderX”
magmaNode.SetNodeProperty node17 “OrderX” 3
magmaNode.DeclareExtensionProperty node17 “OrderY”
magmaNode.SetNodeProperty node17 “OrderY” 2
magmaNode.DeclareExtensionProperty node17 “Position”
magmaNode.SetNodeProperty node17 “Position” [500,160]
magmaNode.DeclareExtensionProperty node17 “Position2”
magmaNode.SetNodeProperty node17 “Position2” [490,208]
magmaNode.DeclareExtensionProperty node17 “Selected”
magmaNode.SetNodeProperty node17 “Selected” true

try(magmaNode.setNodeInput node0 1 node5 1)catch()
try(magmaNode.setNodeInput node2 1 node7 1)catch()
try(magmaNode.setNodeInput node2 2 node3 1)catch()
try(magmaNode.setNodeInput node2 3 node4 1)catch()
try(magmaNode.setNodeInput node5 1 node6 1)catch()
try(magmaNode.setNodeInput node5 2 node10 1)catch()
try(magmaNode.setNodeInput node5 3 node11 1)catch()
try(magmaNode.setNodeInput node6 1 node2 1)catch()
try(magmaNode.setNodeInput node7 1 node1 1)catch()
try(magmaNode.setNodeInput node8 1 node7 1)catch()
try(magmaNode.setNodeInput node8 2 node3 1)catch()
try(magmaNode.setNodeInput node8 3 node9 1)catch()
try(magmaNode.setNodeInput node10 1 node8 1)catch()
try(magmaNode.setNodeInput node11 1 node2 2)catch()
try(magmaNode.setNodeInput node11 2 node14 1)catch()
try(magmaNode.setNodeInput node12 1 node2 5)catch()
try(magmaNode.setNodeInput node12 2 node13 1)catch()
try(magmaNode.setNodeInput node14 1 node12 1)catch()
magmaNode.setNodeInput node14 2 -1 1
try(magmaNode.setNodeInput node15 1 node16 1)catch()
try(magmaNode.setNodeInput node16 1 node17 1)catch()
try(magmaNode.setNodeInput node17 1 node8 2)catch()

)
[/code]
It produces the following flow:

Going to revisit collapsing this month, or remove the option to hide branches of collapsed nodes if I fail.
EDIT: Done, it seems to work in all cases I could test, will let you confirm whether it works or not when we post a build. Also allowing the collapsing of Output Nodes now to hide whole sub-flows when more than one Output is created within the same modifier.

Done.

We made the first step to solve this by licensing the Helium code, but no actual code changes are planned for 2.0.

Fixed, SignedDistance is now actually signed.
Normals issue still open.

Done.
EDIT: The InputTexmap node now has explicit input sockets to define position and optional Normal, Vertex Color and Texture Coordinate channels. Thus you can sample the texture map at any point and provide alternative shading context values to allow the evaluation in UVW space, evaluation of Falloff maps using custom Normal vectors etc. On the flipside, Magma 1.x was easier to set up since all channels were provided implicitly, in Magma 2.0 you have to provide them explicitly if they are required, or it won’t work right.

Made Reorder a mode instead of an action. In other words, you can now toggle between reordered and free (user-defined) flow, with two sets of positions stored per node. An option to copy the automatic order into the free order buffer was also added. Right now, only a right to left dot_order sorting has been implemented. Might add more time permitting.

Done. New Breakout node exposes the components of the value as multiple output sockets. To extract X, just connect the first socket. To Swizzle, connect the three outputs of a Vector to a ToVector in any desired order. Two operations in one operator!

Does not apply to 2.0 yet…

Done. The Min. and Max. values of the input range can be specified at any time without touching the actual curve.
Also, the curve editor is now a modeless floating dialog, with arbitrary number of such floaters supported at the same time.

W.I.P.
We added one level of smart connecting rules to allow sockets with matching names to find each-other. We are discussing some more metadata to define the accepted input value types. This can be tricky since our operators can work on varying types. Box #3 requires the user to specify the type explicitly, and disconnects if the type does not match, something I dislike a lot. I don’t agree that MagmaFlow does not report errors for wrong value types, it complains pretty clearly.

W.I.P.
-Dragging a node from the Depot onto another, existing but unselected node will connect the new node to the existing node as if it were selected. If a node is pre-selected, the new node will be connected anyway (supported since 1.5.0)
-Selecting two or more nodes and hitting Spacebar will now sort the nodes from left to right and attempt to auto-connect by socket name (see previous point). This allows for some amazing actions like creating and selecting InputGeometry, IntersectRay, InputChannel:Position and InputValue:Vector and connect them to a working flow with a single Spacebar click!
-Given the arbitrary number of output sockets in Magma 2.0, Insert key will now cycle through the connected sockets for insertion first, then through all sockets for branching, with the active socket highlighted in yellow.
-Exploring the potential to drag into the editor’s background a la Slate to create and auto-connect a new node, with some filter logic (e.g. if dragging from a socket expecting Geometry, create GeometryInput automagically instead of popping up a menu with node types) EDIT: Done, dragging from an input or output socket will now pop up a mega-menu with all categories and nodes installed. The same menu can be opened using the [~] key, or via the right-click editor menu.
-Added support for socket defaults. Some nodes support optional sockets - if no node is connected, the socket uses a default static value. The result is a lot less nodes and connections to achieve the same flow. E.g. to multiply a vector by 2.0 does not require a second InputValue node with value 2.0 unless the value needs to be keyframed over time.

Done. Arbitrary number of editors are now be opened at the same time.

Made even better. In 1.x Magma, an Input node could not be turned into an Operator and vice-verse. Magma 2.0 does not care anymore and lets you make an InputChannel node out of an Add operator, if necessary.

The assignment of Keyboard Shortcuts used to be completely hard-coded in 1.x Magma. In 2.0, the two-stroke keyboard shortcuts are partially automated and the menus are built dynamically. This means that if a new node is implemented by replacing the DLR, the scripted UI will still work and assign a plausible second keystroke based on the available letters within the menu and some other rules.

Done. As mentioned above, it is now large. Very large. Might look into making it resizable, but it is probably not necessary.

Selecting a wire and creating a node is the next thing I intend to try.

Done. Debug is now using the incoming data from the bottom the stack and lists all flow nodes in a spreadsheet not unlike Particle Data Viewer, with the ability to see the values of each node for each particle (currently first 100 shown, need to add controls a la PDV to specify ranges and steps)

Done. See screenshot above. Right-clicking the navigator provides the Zoom/Pan menu for zoom selected, zoom extents, reset pan and zoom etc.

LOL, I thought you were on vacation!

Some yummy stuff!

So how is the multi output order defined? Up-Down, Down-Up, by integer order?

Top to bottom.

In the example above, the Normal channel is read, modified and saved back into the Normal channel of the PRT object’s stack.
The second sub-flow reads the modified Normal channel, modifies it a bit and outputs as Color.

If you wanted to read the unmodified Normal, modify it and output into both Normal and Color channel, just connect the original Normal (#1) node instead of the modified Normal (#5).

Muy bien ! Thread logic, I like it

Congrats on the “new” job :slight_smile:

Privacy | Site terms | Cookie preferences