Notifications
Clear all

[Closed] Prevent modifier collapse?

Thanks @denisT, will try that and report back here!

Hey @denisT, your snippet appears to work just fine, thanks a lot!

Out of curiosity, doesn’t the local variable ‘bo’ have the same value as the argument ‘obj’? Similarly, what’s the relationship (if any) between the local variable ‘derob’ and the argument ‘derObj’?

One of the last pieces of the puzzle that I can’t figure out is how to retrieve (if that’s even possible) the list of modifiers applied to an object such that I can then detect my special “Object Properties” modifier when scene objects gets translated to appleseed.

I realize that it might not be the right way to approach the problem. Maybe the stack of modifiers is systematically applied to (copies of) objects when a render begins, and that my “Object Properties” modifier should then somehow store its properties into the object copy, in which case I’m curious about the best way to achieve this.

For reference, my code is here:
https://github.com/appleseedhq/appleseed-max/tree/master/src/appleseed-max-impl/appleseedobjpropsmod

I think I’ve figured it out. Here’s my untested code:

asr::VisibilityFlags::Type get_visibility_flags(Object* object, const TimeValue time)
{
    if (object->SuperClassID() == GEN_DERIVOB_CLASS_ID)
    {
        IDerivedObject* derived_object = static_cast<IDerivedObject*>(object);
        for (int i = 0, e = derived_object->NumModifiers(); i < e; ++i)
        {
            Modifier* modifier = derived_object->GetModifier(i);
            if (modifier->ClassID() == AppleseedObjPropsMod::get_class_id())
            {
                const auto obj_props_mod = static_cast<const AppleseedObjPropsMod*>(modifier);
                return obj_props_mod->get_visibility_flags(time);
            }
        }
    }

    return asr::VisibilityFlags::AllRays;
}

find attached a link to a pared down modifier (which is from an export property manager) which shows how to use a modifier to edit appdata attached to nodes.

propmanlite

collapsing the stack will have no effect on the data stored on the node, any subsequent modifier will use the current data set attached to the node. Max will manage any saves though it’s worth noting that max doesn’t copy appdata when cloning nodes (you’ll need to add a NOTIFY_POST_NODES_CLONED handler via the RegisterNotification function for this). Also it’s not been compiled so there will be errors but you’ll get the gist

Hey @Klvnk, thanks a lot for the example code, it’s well written and a useful reference!

I ended up keeping all the information in the modifier, and making the modifier non-collapsable as discussed above. This way, I don’t need to store object properties anywhere else and the result is simple and robust.

In case it might help someone, the whole code for this modifier is available here (MIT license):
https://github.com/appleseedhq/appleseed-max/tree/master/src/appleseed-max-impl/appleseedobjpropsmod

Thanks all for the help!

I ended up keeping all the information in the modifier, and making the modifier non-collapsable as discussed above.

What happens when the user deletes the modifier ?

1 Reply
(@dictoon)
Joined: 10 months ago

Posts: 0

In that case, the object properties for that object are deleted, as expected.

there is a mistake in your code (check ChannelsChanged)

5 Replies
(@dictoon)
Joined: 10 months ago

Posts: 0

Hey, thanks for checking out my code, appreciated!

Should I return 0 instead of GEOM_CHANNEL?

EDIT: I guess I should also return 0 from ChannelsUsed(), like @Klvnk has done in propmanlite.

(@denist)
Joined: 11 months ago

Posts: 0

yes. you have to return 0 if you want (really you have to) keep the original object class

(@dictoon)
Joined: 10 months ago

Posts: 0

If I return 0 it’s really only as an optimization. I don’t need to keep the original object class.

(@denist)
Joined: 11 months ago

Posts: 0

i’m not sure you really understand the problem.

make an editable_poly object

apply your modifier

check vert selection as $.selectedverts

check the class of your object

(@dictoon)
Joined: 10 months ago

Posts: 0

I’m not sure I understand the problem either

Let’s just make sure we agree on the purpose and principle of operations of my modifier:

  • The purpose is to tag some objects with appleseed-specific properties. Properties apply to the whole object, never to a subset of it.

  • These appleseed-specific properties are not stored anywhere, really. They only exist in the paramblock of the modifier.

  • At render-time, when translating a given object, the appleseed renderer plugin inspects the stack of modifiers of that object and only considers the top-most ‘appleseed Object Properties’ modifier. It then retrieves the object properties from this modifier and apply them to the (appleseed) object being constructed. The “derived” Max object is not affected.

  • The modifier is such that it cannot be collapsed, i.e. if you try to collapse the whole modifier stack, it’ll remain there.

Does that make sense?

As far as I understand, this is also how the Arnold Properties Modifier works:
https://support.solidangle.com/display/A5AF3DSUG/Arnold+Properties+Modifier

Your plugin changes the type of the object, but should only store information about it. This is why many people don’t use the Attribute Holder.

For example, I put your plugin on Bones in my scene. Before I could filter them by type, after applying the I can’t

1 Reply
(@dictoon)
Joined: 10 months ago

Posts: 0

Ok, this is interesting. Pardon my ignorance but I’m relatively new to 3ds Max so I may have missed something.

Why would my modifier change the type of the object, as long as ChannelsUsed() and ChannelsChanged() return 0?

Editable_Poly and PolyMeshObject share many poly methods but not all of them. So I have to write a code that modifies the objects in two variants: without your modifier and with

Page 2 / 3