Notifications
Clear all

[Closed] How to check whether a node is a copy, instance or reference?

I wouldn’t use MaxPlus for python scripting, at least not only MaxPlus. You should use the pymxs dynamic module, which is a bridge between maxscript to python.

MaxPlus is very incomplete, it was meant to replace Autodesk.Max, that was the .NET api for 3dsmax. But that never happened, it took a boost with MCG, but is still miles away from what you can do with maxscript (or the C++ SDK).

Cheers,
Daniel

 bpl

Thanks for the advice, although the only thing I can complain about embedded python in 3dsmax is basically:

  • Modern python (ie:>=3.6 at least) not supported
  • Autogenerated documentation of maxplus where you’ll be guessing mostly of the time even after you’ve read the counterpart c++ wrapped stuff
  • Max should detect somehow whether your python has made something nasty and allow to break the process instead crashing, starting max over and over till you catch the bug is really time consuming

That said… so far I’m pretty happy with maxplus+python and everything I’ve wanted to implement so far has been implemented, although it’s true it took quite a lot of time effort… about pymxs, yeah, I’ve used slightly and it’s really handy for certain tasks.

Anyway, please let’s try to no go offtopic here, does anyone know how to tweak my above pasted code to detect copies/instances/references?

Thanks in advance!

Something like this, if I got what you wanted.

from collections import defaultdict
from pymxs import runtime as rt

def node_key(n):
    return str(n).split()[-1]

def traverse():
    nodes = []
    root_node = rt.rootNode

    def _traverse(node):
        if node != root_node:
            nodes.append(node)
        for c in node.children:
            _traverse(c)
    _traverse(root_node)
    return nodes

instances_and_references = defaultdict(list)

for node in traverse():
	clones = []
	rt.instancemgr.getinstances(node, pymxs.mxsreference(clones))
	instances_and_references[node_key(node.name)] = clones

print('-' * 80)
for k, v in instances_and_references.items():
    print(k, len(v))

don’t tell MAX what to do. It doesn’t listen to you anyway

 bpl

First of all, thank you very much for your attempt, which btw is much nicer and lighter than mine.

Unfortunately the outcome of that script is similar to the one I’ve pasted above, it doesn’t distinguish between instances & references.

Why is this important, imagine I’m dumping the topological information of all nodes from the scene, now, let’s say there are 3 boxes instantiated and 2 boxes references (and with some modifiers applied on top of it). Now, let’s say I dump the information of 1 of the instances and then I cache the other ones… as a result, the information of the referenced boxes would be lost… That’s why I’m interested to distinguish between copy/instance/referenced objects.

Does it make sense?

i’m looking now in MaxPlus documentation and see INode method GetObject
i guess that two instances have to have the same Object returned by this method
this Object as I guess is equivalent of c++ SDK:

Object* osobj = node->GetObjectRef()->Eval(t).obj;

which must be same for instances.

if they are different for two objects, the nodes can still be references but it’s not your case

returns (same for MXS) both instances and references

what is the HASH?

1 Reply
 bpl
(@bpl)
Joined: 1 year ago

Posts: 0

@denisT Imagine this case:

If I use GetObject as suggested:

instances_and_references = defaultdict(list)

for node in traverse():
    instances_and_references[node.GetObject()].append(node)

The final dictionary will be something like:

 (<MaxPlus.Object; proxy of <Swig Object of type 'Autodesk::Max::Object *' at 0x00000000509CF480> >, 1)
(<MaxPlus.Object; proxy of <Swig Object of type 'Autodesk::Max::Object *' at 0x00000000509CF4B0> >, 1)
(<MaxPlus.Object; proxy of <Swig Object of type 'Autodesk::Max::Object *' at 0x00000000509CF3C0> >, 1)

Why? Cos those MaxPlus.Object returned by GetObject are not “equal”.

When I said “… wasn’t giving me the same hash between two instances” I meant the objects weren’t equal (__eq__), to use object as keys in dictionary they must be hashable and to retrieve their values (__getitem__) they must be equal, for more info check this out, and here’s a little snippet to clarify these concepts:

from collections import defaultdict


class foo():

    def __init__(self, n):
        self.number = n

    def __hash__(self):
        return self.number % 2

    def __eq__(self, other):
        return self.__hash__() == other.__hash__()

instances = defaultdict(list)

instances[foo(2)].append(2)
instances[foo(4)].append(4)
instances[foo(6)].append(6)
print(dict(instances))
 bpl

@denisT , @dgsantana Guys, ok, let’s forget for a moment about python-maxplus as using maxscript from python is straightforward, now, consider this mcve:

tp_original = Teapot()
$Teapot:Teapot001 @ [0.000000,0.000000,0.000000]
tpi1 = instance tp_original
$Teapot:Teapot002 @ [0.000000,0.000000,0.000000]
tpi2 = instance tp_original
$Teapot:Teapot003 @ [0.000000,0.000000,0.000000]
tpi3 = reference tp_original
$Teapot:Teapot004 @ [0.000000,0.000000,0.000000]
InstanceMgr.GetInstances tp_original &instances
4
instances
#($Teapot:Teapot004 @ [0.000000,0.000000,0.000000], $Teapot:Teapot003 @ [0.000000,0.000000,0.000000], $Teapot:Teapot002 @ [0.000000,0.000000,0.000000], $Teapot:Teapot001 @ [0.000000,0.000000,0.000000])

In this case, my point is perfectly clear, as you can see InstanceMgr.GetInstances will return both instances & references but that’s still not good enough… how would you check which elements from that array instances are references?

Ok, now I see what you want. But it’s a bit difficult to check (at least I’m not recalled of any way in maxscript/maxplus, only in the SDK) to see if it’s a ref or an instance. Since a reference is an instance, but with a “new” modifier stack (Derived Object with a ref to another Derived Object). You can check this here, maybe it will shed some light or give you some other idea.

https://help.autodesk.com/view/3DSMAX/2018/ENU/?guid=__developer_3ds_max_sdk_features_modeling_geometry_pipeline_system_pipeline_overview_html

Page 2 / 4