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.
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 ?
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.
yes. you have to return 0 if you want (really you have to) keep the original object class
If I return 0 it’s really only as an optimization. I don’t need to keep the original object class.
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
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
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