Notifications
Clear all

[Closed] Adding and removing modifiers to nodes using the SDK

Hi, this is my first post on this forum, so Hello to everyone

I’m working on a plugin using the SDK, and I need to apply a modifier ( Edit Normals ) to Nodes. Until now I did this to add the modifier:

	Object *Obj = Node->GetObjectRef();
  	IDerivedObject *DerObj = NULL;
    	if ( Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID )  	
           {
  		DerObj = static_cast<IDerivedObject *> (Obj);  	
           }
  	else 
 	{ 
 		DerObj = CreateDerivedObject();  
		DerObj->TransferReferences(Obj);  
		DerObj->ReferenceObject(Obj);  
	}
    	EditNormalsMod = (Modifier*)MaxInterface->CreateInstance( OSM_CLASS_ID, EDIT_NORMALS_CLASS_ID );
    	EditNormalsModContext = new ModContext(new Matrix3(1), NULL, NULL );
    	DerObj->AddModifier( EditNormalsMod, EditNormalsModContext );  

And to remove this modifier I run this code:

	if ( Obj->SuperClassID() != GEN_DERIVOB_CLASS_ID ) 
 		return; 
  	DerObj = static_cast<IDerivedObject *> (Obj);
    	const int nMods = DerObj->NumModifiers();
    	for (int i=0;i<nMods;i++)
  	{  
		Modifier *Mod = DerObj->GetModifier(i);
  		if ( Mod->ClassID()==EDIT_NORMALS_CLASS_ID )
  		{
  			DerObj->DeleteModifier(i);
  			break;
  		}
  	}
    	if ( !DerObj->NumModifiers() )
  	{
  		Obj = DerObj->GetObjRef();
  		Obj->TransferReferences(DerObj, true );
  	}

This works well on normal objects, but if the object is Editable Poly, and I run this code, the object is not seen as a derived object before I add the modifier, so the above code creates a derived object which references the object, and to this derived object it applies the Edit Normals modifier.
The problem now is when I try to remove the modifier. All works fine until it executes Obj->TransferReferences( DerObj, true );. When this happens, max crashes!

I know I’m doing something wrong, but what? :banghead:

Any ideea is welcomed !

5 Replies

Hi,
I have quickly created a dlx a plugin to test it( which gives two maxscript functions AddNormal and removeNormal)…with the following block of code and get no such crash.


#include "MAXScrpt.h"
#include "modstack.h"

#define EDIT_NORMALS_CLASS_ID Class_ID(0x4aa52ae3, 0x35ca1cde)

void TestNormalInit()
{
}


#include "definsfn.h"
	def_visible_primitive(AddNormal, "AddNormal");
	def_visible_primitive(RemoveNormal, "RemoveNormal");
Value* AddNormal_cf(Value **arg_list, int count)
{
	check_arg_count(AddNormal, 1, count);
	one_typed_value_local(Ok* result);
	Value *vNode = arg_list[0];
	Interface* MaxInterface = GetCOREInterface();
	INode *Node = vNode->to_node();
	Object *Obj = Node->GetObjectRef();
	  IDerivedObject *DerObj = NULL;
	if ( Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID )	  
	 {
		DerObj = static_cast<IDerivedObject *> (Obj);	  
	}
	  else 
	 { 
		 DerObj = CreateDerivedObject();  
		DerObj->TransferReferences(Obj);  
		DerObj->ReferenceObject(Obj);  
	}
		Modifier *EditNormalsMod = (Modifier*)MaxInterface->CreateInstance( OSM_CLASS_ID, EDIT_NORMALS_CLASS_ID );
		ModContext *EditNormalsModContext = new ModContext(new Matrix3(1), NULL, NULL );
		DerObj->AddModifier( EditNormalsMod, EditNormalsModContext ); 
		vl.result = &ok;
		return_value(vl.result);	
}

Value* RemoveNormal_cf(Value **arg_list, int count)
{
	check_arg_count(RemoveNormal, 1, count);
	one_typed_value_local(Ok* result);
	Value *vNode = arg_list[0];
	Interface* MaxInterface = GetCOREInterface();
	INode *Node = vNode->to_node();
	Object *Obj = Node->GetObjectRef();

	if ( Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID ) 
	{
		  IDerivedObject *DerObj = static_cast<IDerivedObject *> (Obj);
			const int nMods = DerObj->NumModifiers();
			for (int i=0;i<nMods;i++)
		  {  
			Modifier *Mod = DerObj->GetModifier(i);
			  if ( Mod->ClassID()==EDIT_NORMALS_CLASS_ID )
			  {
				  DerObj->DeleteModifier(i);
				  break;
			  }
		  }
			if ( !DerObj->NumModifiers() )
		  {
			  Obj = DerObj->GetObjRef();
			  Obj->TransferReferences(DerObj, true );
		  }
	}
	return_value(vl.result);
}

Thank you, for your time susanta!
Yes, it seems to work when interfacing through maxscript, but if I run that code without the maxscript part, it crashes.

	ULONG Handle = Node->GetHandle();
    	Interface* MaxInterface = GetCOREInterface();
  	Object *Obj = Node->GetObjectRef();
  	IDerivedObject *DerObj = NULL;
 	if ( Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID )
    	{
  		DerObj = static_cast<IDerivedObject *> (Obj);	    				}
  	else
   	{
   		DerObj = CreateDerivedObject();
    		DerObj->TransferReferences(Obj);
    		DerObj->ReferenceObject(Obj);
    	}
  	Modifier *EditNormalsMod = (Modifier*)MaxInterface->CreateInstance( OSM_CLASS_ID, EDIT_NORMALS_CLASS_ID );
  	ModContext *EditNormalsModContext = new ModContext(new Matrix3(1), NULL, NULL );
  	DerObj->AddModifier( EditNormalsMod, EditNormalsModContext );



       	Obj = MaxInterface->GetINodeByHandle(Handle)->GetObjectRef();
    	if ( Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID )
   	{
  		DerObj = static_cast<IDerivedObject *> (Obj);
  		const int nMods = DerObj->NumModifiers();
  		for (int i=0;i<nMods;i++)
  		{
    			Modifier *Mod = DerObj->GetModifier(i);
  			if ( Mod->ClassID()==EDIT_NORMALS_CLASS_ID )
  			{
  				DerObj->DeleteModifier(i);
  				break;
  			}
  		}
  		if ( !DerObj->NumModifiers() )
  		{
  			Obj = DerObj->GetObjRef();
  			Obj->TransferReferences(DerObj, true );
  		}
  	}

For example when I run the above code, adding the modifier and right after that remove it, it crashes at Obj->TransferReferences(DerObj, true ) when the node references an editable poly.
I tought that maybe something in the Node changes and need to obtain the node again to work right, but I used the node’s handle to retrieve the node again, and the same thing happens.
It’s something fishy with this code !

Strange indeed! Now I have tried to merge them…but again failed to regenerate the problem…can you tell me please what maxSDk version are you using? I’m using Max9 one.


 def_visible_primitive(AddRemoveNormal, "AddRemoveNormal");
 
 bool NormalAddAndRemove(INode *Node)
 {
 	Interface* MaxInterface = GetCOREInterface();
 	Object *Obj = Node->GetObjectRef();
 	  IDerivedObject *DerObj = NULL;
 	if ( Obj->SuperClassID() == GEN_DERIVOB_CLASS_ID )	  
 	 {
 		DerObj = static_cast<IDerivedObject *> (Obj);	  
 	}
 	  else 
 	 { 
 		 DerObj = CreateDerivedObject();  
 		DerObj->TransferReferences(Obj);  
 		DerObj->ReferenceObject(Obj);  
 	}
 	Modifier *EditNormalsMod = (Modifier*)MaxInterface->CreateInstance( OSM_CLASS_ID, EDIT_NORMALS_CLASS_ID );
 	ModContext *EditNormalsModContext = new ModContext(new Matrix3(1), NULL, NULL );
 	DerObj->AddModifier( EditNormalsMod, EditNormalsModContext ); 
 	mputs("Normal modifier has been added
");
 
 	const int nMods = DerObj->NumModifiers();
 	for (int i=0;i<nMods;i++)
 	{  
 		Modifier *Mod = DerObj->GetModifier(i);
 		if ( Mod->ClassID()==EDIT_NORMALS_CLASS_ID )
 		{
 			DerObj->DeleteModifier(i);
 			mputs("Normal modifier has been removed
");
 			break;
 		}
 	}
 	if ( !DerObj->NumModifiers() )
 	{
 		Obj = DerObj->GetObjRef();
 		Obj->TransferReferences(DerObj, true );
 	}
 	return true;
 }
 
 Value* AddRemoveNormal_cf(Value **arg_list, int count)
 {
 	check_arg_count(AddNormal, 1, count);
 	one_typed_value_local(Ok* result);
 	Value *vNode = arg_list[0];
 	INode *Node = vNode->to_node();
 	NormalAddAndRemove(Node);
 	vl.result = &ok;
 	return_value(vl.result);
 }
 

Hi,

Yes, strange behaviour. I think the problem may come from the plugin type in which you’re using this code. This kind of operations are usually done in an utility.

Maybe you have to update the node after adding/removing the modifier :

// Update derived object
  DerObj->NotifyDependents(FOREVER,PART_ALL,REFMSG_CHANGE);
  // Make damn sure everything knows something has changed
  EditNormalsMod->NotifyDependents(FOREVER,PART_ALL,REFMSG_CHANGE);
  Node->NotifyDependents(FOREVER,PART_ALL,REFMSG_CHANGE);
  Node->NotifyDependents(FOREVER,0,REFMSG_SUBANIM_STRUCTURE_CHANGED);

Also, take a look at the 3ds Max SDK discussion board on the Modifiers / Geometry Pipeline section : http://discussion.autodesk.com/forum.jspa?forumID=270
For example : http://discussion.autodesk.com/thread.jspa?threadID=576022 and http://discussion.autodesk.com/thread.jspa?threadID=575955

Hope this help.

I too use Max9 and VS 2005, and this code is part of an exporter I work on! The Node is obtained traversing the scene graph from root using recursion, and the only processing on the node is

	ObjectState ObjState = Node->EvalWorldState(MaxInterface->GetTime());

I removed this, to see if has the same results, and yes, it still crashes.

Just now I’ve tried te folowing code, instead of Obj->TransferReferences( DerObj, true );

	Obj->TransferReferences(DerObj, false );
    	DerObj->DeleteMe();

and now it seems to work just fine!

I also tried your code, and works fine!

Maybe a Max bug ? :hmm:

LE: Thanks Yannick, I’ll have a look at that!

Another LE:
I’ve tried to update the derived object and the node, using those functions you suggested Yannick, but the result is the same!
Anyway, I’ll stick to

	Obj->TransferReferences(DerObj, false );
    	DerObj->DeleteMe();

as it seems to work fine!

Thanks for your time mates!