Community
3ds Max Forum
Welcome to Autodesk’s 3ds Max Forums. Share your knowledge, ask questions, and explore popular 3ds Max topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

I want to maintain state, have loops, how are these done in MCG?

11 REPLIES 11
Reply
Message 1 of 12
programmer.pilot
1005 Views, 11 Replies

I want to maintain state, have loops, how are these done in MCG?

 

I'e been coding for 20 years, but MCG has me stumped, and I'm finding the documentation doesn't appear to cater to C++/C#/Java types and many nodes don't have examples or are named very strangely, making it hard to find a node that does what I want.

 

 

Here is how my brain works, in a C like language:

 

Declare some stuff to hold onto: "variables" / state.

 

Loop some number of times while applying function arguments/parameters to current state to generate new data.

 

"loop doing work"  in MCG seems to be tied up in making arrays, but I have so many other things I want to input besides one or two types. For example.

 

I want a point 'P' to be initialized with the location of a node.

I want 'V' a vector3 to be initialized to some parameter.

A is a constant parameter.

 

Loop 15 times doing the following:  P = P + V   AND V = V + A

 

Each time in the loop, I append P to an array.

 

So, for this case, I suppose I can make an array of V first, then shove that into something that takes that array, and does the addition to P, and it generates a array of P's. 

 

However, this next bit is where I get stuck.

 

I want P+V to be a ray, and that does a hit check against a mesh. If it collides, it 'bounces'. So now  there is a conditional( which can change both P and V), and the two values are interconnected and can no longer be separate arrays. I need to maintain P and V as 'state', but this node stuff doesn't make that easy to do.  

 

The whole idea is to have a simple particle system that 'traces' the particles as they go. I just set a starting point, iterations, and direction and this geometry tool would spit out a path (a ribbon made of quads). 

Eventually I want to be able to do that some 'n' number of times and get particle traces for a set of particles, who's start is along a spline defined by the user.

 

I can use python or write a C++/C# plugin for this of course, and it would be super simple, but I'd like to be able to learn how MCG would handle this.

 

 

in C++/C# psuedo code:

 

List<Vector3> PathOfParticle(Vector3 startPosition, Vector3 initialVelocity, Vector3 acceleration, TriMesh mesh, unsigned int iterations)

{

 

Vector3 position = startPosition;

Vector3 velocity = initialVelocity;

 

List<Vector3> pointStorage;

 

unsigned int i;

for(i=0;i<iterations;i++)

{

   v = v+ acceleration; // apply 'gravity', etc

   Ray r(p,v);

   Vector3 hitPoint;

   Vector3 hitNormal;

   bool hit =mesh.RayIntersect(r, hitPoint, hitNormal);

   if (hit)

   { 

      p = hitPoint;  // move to intersect point.

      v = Reflect(v, hitNormal);  // bounce perfectly from normal

      v *= 0.9;  // lose some energy

   }

    p = p + v; // update position from velocity.

    pointStorage.append(p);   // store position this 'tick'. 

}

 

 return pointStorage;

}

 

 

This is also compromising on iterations, as what I really want is to keep the particle moving until it moves out of the bounding box for example, or hits a triangle of a certain color, or any other reason.

 

in MCG however, If, While, Repeat, don't operate like C#/C++.

 

What would be helpful is if I can learn to 'write' MCG as perhaps a C#/C++ program so I can map the concepts in my old befuddled brain. It appears there are no variables, no state, only function arguments (which are immutable)?

 

so in kinda C++ I'm guessing:

 

<template T>

typedef (void)(*)RepeatFuncPtr(int, T);           // not even sure if this is correct!

T Repeat(T init, int n, RepeatFuncPtr* ptr)

{

     int i;

     T val = init;

     for(i=0;i<n;i++)

     {

         val = RepeatFuncPtr(n, val);

     }

     return val;
}

 

 

Of course any function I then make has to be made up of only other functions, returns only one 'item', and has read only arguments.

 

Is this anywhere close? Any resources to help make this transition?

 

 

 

11 REPLIES 11
Message 2 of 12

Ok, gonna end up answering this myself as I got some help from a friend of mine.

 

 

So, for C#/C++/Java coders out there:

 

No state or variables exist, imagine everything must be passed in as arguments.

No pointers, no references.

Pass by value.

Effectively arguments/parameters are immutable, const or final.

 

A tuple is a type than can hold other types, sort of like a struct or class with only data in it. The most a tuple can have is 3 items, but tuples can hold tuples. 

 

Only one item is returned from a function/node. However, this can be an array or a tuple object.

 

MCG Nodes that take functions an iterate on them have internal loops or recursion to complete the task. Many of these iterate over arrays automatically. Array count or index is rarely available to the 'work' function for the node. (MapWithIndex does it, and it's a compound that uses Combine, so this is not a native ability)

 

Pro-tip, copy the text from the 'help' window in the lower corner, and "Paste as HTML" into a text editor, then remove the style="" attributes, throw a html/body tag around the whole thing and save to disk.  Its much easier to search and navigate using a webbrowser. Everything is anchored, so the table of contents still works.

 

 

So to handle my position and velocity together, I made a tuple. (an Array2 would have also worked as they are both Vector3). This tuple ends up being an argument to a function that iterates on an array. The input array is the vertices of a spline, so I get my 'start position' passed in as the initial value.  Inside the function chain(I use Groups for functions and other concepts in my graph), I pick apart the tuple with 'pair1, pair2', and each one follows the velocity or position path, only to be recombined into a tuple at the end, so it can be thrown back at itself for the next run.

 

 

I was able to make a SimpleQuadMesh that traced a simple newtonian particle path out, and now I'm trying to figure out how to do ray intersections.

 

 

Message 3 of 12

Some results:

particle-trace.PNG

 

Important thing to get this working was to get all points into world space first, but use the inverse to get back to object space (this is a modifer after all).  Once I did this, collisions happened correctly and the geo lined up.

 

 

Tip: Spline vertices can be read using Modifier:Trimesh. Though I doubt they have anything but position valid, though that's all I needed.

 

Debugging is bit of a pain, using 'print' is annoying since it has to be inline with other data. It would be great to have a single step mode and a data inspector for each node that is separate.  When i used print for arrays, the output scrolling on the listener window really slowed down max. The errors it gives are by node number, but not which compound! It's also hard to find 'node 54' amidst my current complex graph when it throws an error.

 

I can get the MCG to 'do nothing', where the prints don't even fire off, and no geo is generated, even though the validate and evaluate report no errors. I don't have early out cases yet, so I'm not sure how it gets into this state.

 

Ray intersection tests are infinite rays, not a line segment, the length of 'direction' is irrelevant.  So to get a hit location, this formula works:  hitPos = normalize(direction) * hitDistance + rayPosition.

 

I've attached the progress so far. (maxtool/ms/txt)

 

Array:Map is the primary workhorse for most operations.

 

The outer loop is a Map function that converts input spline positions to an array of trimeshes.

 

This array is then combined and a final mesh is spat out on the modifier output.

 

GenerateN is my primary loop that ticks the particle and lays down positions.

 

 

Message 4 of 12
vusta
in reply to: programmer.pilot

This looks really interesting !!!

Message 5 of 12
vusta
in reply to: vusta

howdy,

 

have you any chance to make further progress with this ? I swear I log in everyday looking for any update on this post coz I think it's fantastic...I'm trying very hard to understand your graph but making very slow progress...

 

Vu.

Message 6 of 12
Steve_Curley
in reply to: vusta

Subscribing to the thread would be easier (automatic email when there's a new reply) 😉

Max 2016 (SP1/EXT1)
Win7Pro x64 (SP1). i5-3570K @ 4.4GHz, 8Gb Ram, DX11.
nVidia GTX760 (2GB) (Driver 430.86).

Message 7 of 12
vusta
in reply to: Steve_Curley

haha thanks Steve...but I'm old fashioned and I believe in real 'effort' rather than everything being 'automated' these days...

yeah yeah you can call me an old fart, a fossil...but I don't subscribe to the subscribe theory, I even made a video about it...:)

 

https://www.youtube.com/watch?v=_Y_jso_EPbk

 

Cheers.

Vu.

 

ps: done with Max + MassFX

Message 8 of 12
programmer.pilot
in reply to: vusta

I did this as my primary learning case for MCG. It won't be developed further. I didn't know you were looking for updates.

 

What in particular would you like to know about?

Message 9 of 12
vusta
in reply to: programmer.pilot

Everything :)....

 

no seriously, it's different to all the other mcgs out there, including mine. But I need to get a grip on 'dynamics', 'sims', 'collisions'.

 

Stuff like DeltaPosSquared, dot/cross product, yeah you eat these for breakfast but me I looked at it and it's like a primitive tribesman seeing a rocketman for the first time...

 

Anyway, I'm goping thru your graph slowly everyday...absorbing it bit by bit

 

The ox is slow but the earth is patient...

 

 

Message 10 of 12
programmer.pilot
in reply to: vusta

one thing at a time then.

 

DeltaPosSquared =   x > y  = x^2 > y ^2    

since this holds true, we can compare squared distances, instead of going through the whole square root process. It's a math shortcut.

 

Since a dot product of (start - end) gives me the 'squared length', I can use that for a distance check, as long as I compared the squared distance.

 

 

So you really need to know algerbra, but some linear geometry, and trigonometry,  otherwise lots of this stuff won't make any sense.

 

You seem to know about offseting objects (like your blinds), so instead of  myZ = myIndex * 5meters, a simulation is iterative.

instead of a single equation to get to a final position, it must iterate.  myZ = myZ + deltaZ.  This means the 'old' value is rolled into the new position with a delta applied to it. In my case, it's the force of gravity.

 

Before I blindly move the virtual particle however, I check for a collision against the 'ground'. and if found, it bounces. 

A bounce is a loss of energy and usually a reflection across the surface normal. 

 

 

 

 

 

Message 11 of 12
vusta
in reply to: programmer.pilot

Thanks very much, I have more clues to digest now...if I look at one tiny section with a couple of ops, sure it's not too hard, you know what each op does...like you see a gear, a lever inside a clock...individually, they're simple.

 

It's when I look at the whole clock made up of a hundred different gears, levers of all sorts and sizes ticking like mad,

that's when it becomes bewildering. But anyway, it's good now that I have more materials to go on with...

 

Trying to sink in the tuple concept. Is the crucial thing in your graph that at any time, you must know the pos + velocity (ie. a tuple)

of the object ?

 

Thanks again.

Vu.

Message 12 of 12
programmer.pilot
in reply to: vusta

Correct, tuples hold packets of data together so it can flow down the graph.

 

This is because most nodes only operate on 'one' piece of data, and the tuple counts as one. This is why there nodes that set and get bits of data from tuples.

 

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report