Converting morphs into CAMorphs



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 09/01/2012 at 06:25, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R12-R13 
    Platform:   Windows  ;   Mac OSX  ; 
    Language(s) :     C++  ;

    ---------
    While the documentation helps a bit, I am very confused about how to proceed with converting morphs from my plugin into the new Pose Morph tag (CAMorphTag, CAMorph, CAMorphNode).  Here is the skeletal code for how I think it should be working (untested, just coding it out) but am uncertain (e.g.: do you need to call UpdateMorphs() after each change or can it be called after all changes as I am showing? and so on).

        // Morph tag  
      CAPoseMorphTag*    mtag =        CAPoseMorphTag::Alloc();  
      if (!mtag)                    return ErrorException::OOMThrow(EE_DIALOG, GeLoadString(IPPERR_MEMORY_TEXT), "Morphs_Figure_R12.mtag");  
      mtag->SetName("Morphs");  
      mesh->InsertTag(mtag);  
      doc->AddUndo(UNDOTYPE_NEW, mtag);  
      // - Must be initialized prior to any use  
      mtag->InitMorphs();  
      // - Apply any edits before modifying (?)  
      mtag->ExitEdit(doc,TRUE);  
      
      // - For each bone, add its morphs and configure (CAMorphNode)  
      BaseObject*        bone =        NULL;  
      BaseContainer*    bbc =        NULL;  
      BaseTag*        tag =        NULL;  
      BaseContainer*    tbc =        NULL;  
      IPPDial*        ippd =        NULL;  
      CAMorph*        camorph =    NULL;  
      CAMorphNode*    camnode =    NULL;  
      String            prefix;  
      LONG            m, lbi =    bpidx+1L;  
      LONG            i =            0L;  
      for (m = FIRST_BPINDEX; m != lbi; ++m)  
      {  
          bone =                fbc->GetObjectLink(m, doc);  
          if (!bone)            continue;  
          bbc =                bone->GetDataInstance();  
          if (!bbc)            continue;  
          prefix =            bone->GetName()+".";  
          for (tag = bone->GetFirstTag(); tag; tag = tag->GetNext())  
          {  
              if (!tag->IsInstanceOf(ID_IPPDIALTAG))    continue;  
              ippd =                        (IPPDial* )tag->GetNodeData();  
              if (!ippd)                    continue;  
              if (!ippd->HasMorphs())        continue;  
              tbc =                        tag->GetDataInstance();  
              if (!tbc)                    continue;  
              // Add morph to the list  
              mtag->AddMorph();  
              camorph =                    mtag->GetMorph(i);  
              camnode =                    camorph->GetFirst();  
              // Expand morph data  
              camorph->SetMode(doc,mtag,CAMORPH_MODE_FLAGS_ALL|CAMORPH_MODE_FLAGS_EXPAND,CAMORPH_MODE_ABS);  
              if (!(camnode->GetInfo() & CAMORPH_DATA_FLAGS_POINTS))    continue;  
              // Access morph point data  
              // ...  
              // Compress morph data  
              camorph->SetMode(doc,mtag,CAMORPH_MODE_FLAGS_ALL|CAMORPH_MODE_FLAGS_COLLAPSE,CAMORPH_MODE_AUTO);  
              mtag->Message(MSG_UPDATE);  
              ++i;  
              break;  
          }  
      }  
      // Must be called after changes to tag  
      mtag->UpdateMorphs();  
      return TRUE;
    


  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 12/01/2012 at 05:47, xxxxxxxx wrote:

    Let me update my question a bit: Is it even possible to create morphs from scratch programmatically using the CAMorphTag, CAMorph, CAMorphNode system?  I'm hitting roadblocks, especially at CAMorphNode.GetInfo().  The tag itself has an 'Add Pose' button but CAMorphTag.AddMorph() doesn't seem to be resulting in the same thing.  Should I be using CAMorphTag.SetParameter() to trigger the creation of a new morph (Add Pose) and then use that?

    I'd appreciate some help here since there is not a single example, not a single topic here, nothing but what is in the documentation - and it is vague and doesn't specify this scenario.

    Thanks,



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 12/01/2012 at 06:46, xxxxxxxx wrote:

    Making a bit of headway.  It is extremely confusing and unintuitive.  Thanks.

    Is there ANY way to make folders (ITEMTREE - no information) and put the morphs into the folders?  I'd like to make a folder for each body part (polygon selection used for rigging on the polygon object).

    Thanks,



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 13/01/2012 at 01:44, xxxxxxxx wrote:

    Hi Robert,

    I contacted the developers.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 13/01/2012 at 07:14, xxxxxxxx wrote:

    Hi Robert,

    Here is the information I got on this:

    Much of the posted code seems correct.
    The problem is probably due to not having set what data the morph is storing and not creating the data in the morph itself.
    You can use the API to create morphs, this is used in VAMP for example.

    ExitEdit() is not needed as this is a new tag, calling this method is only required if making changes to an existing tag that could be in the middle of editing.

    You also need to enable what data the morph will hold, e.g. in the tags container ID_CA_POSE_POINTS needs to be TRUE for point data to be stored.

    After calling AddMorph() the morph is empty. It needs to be filled. You can use morph.Store() as a start point.
    A morph isn't just a single object, it could contain a hierarchy so you have to deal with each node within the morph. After calling  morph.Store(), which will fill in the morph, you can start to edit/set the data.
    UpdateMorphs() should be the last call. This updates the morph tag UI (morph list) and internal tables.

    And finally, the API currently has no way to add folders to the morph list.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 14/01/2012 at 05:24, xxxxxxxx wrote:

    Hi Yannick,

    Thank you and the developers!  This should get me to a reasonable point where I can test that the morphs are acting the same as my plugin.  Users will have to live with long lists of morphs for the time being. :)

    Take care,



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 15/01/2012 at 06:35, xxxxxxxx wrote:

    My morph data only stores the non-zero delta values and the index to the points that are non-zero. Does the CAMorphNode need to have the PointCount of the morphed polygon object or can it be sparse (though
    I don't see a way to index points sparsely)?  If each must have a PointCount equal to the polygon object it references then I will make sure to do this.

    Thanks,



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 16/01/2012 at 04:13, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    My morph data only stores the non-zero delta values and the index to the points that are non-zero. Does the CAMorphNode need to have the PointCount of the morphed polygon object or can it be sparse (though
    I don't see a way to index points sparsely)?  If each must have a PointCount equal to the polygon object it references then I will make sure to do this.

    From the morph API you have no access to the sparse data format, however, all you need to do is to copy the base points, change only those you need and then when you use SetMode() to restore the data (with CAMORPH_MODE_FLAGS_COLLAPSE) flag it will sort out the data itself from the base.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 16/01/2012 at 05:47, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Originally posted by xxxxxxxx

    My morph data only stores the non-zero delta values and the index to the points that are non-zero. Does the CAMorphNode need to have the PointCount of the morphed polygon object or can it be sparse (though
    I don't see a way to index points sparsely)?  If each must have a PointCount equal to the polygon object it references then I will make sure to do this.

    From the morph API you have no access to the sparse data format, however, all you need to do is to copy the base points, change only those you need and then when you use SetMode() to restore the data (with CAMORPH_MODE_FLAGS_COLLAPSE) flag it will sort out the data itself from the base.

    Excellent! :D

    Thanks again!!



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 17/01/2012 at 23:13, xxxxxxxx wrote:

    How do I go about setting the individual morph Strength settings?  Do the settings in Edit mode carry over to Animate mode (vice versa, does it matter)?  Currently, all CA morphs are initiated to 1.0 (100%) but I'd like to set them to the values from my morphs.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 18/01/2012 at 01:54, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    How do I go about setting the individual morph Strength settings?  Do the settings in Edit mode carry over to Animate mode (vice versa, does it matter)?  Currently, all CA morphs are initiated to 1.0 (100%) but I'd like to set them to the values from my morphs.

    The strength isn't currently in the API but can be accessed through SetParameter(), each morph (CAMorph) has an ID (GetID()) that can be used to set the strength.

    In tcaposemorph.h are the IDs, the animate data is stored using the DescID as:

    DescID(ID_CA_POSE_ANIMATE_DATA,morph->GetID()*ID_CA_POSE_ANIMATE_CNT+ID_CA_POSE_ANIMATE_OFFSET+ID_CA_POSE_ANIMATE_STRENGTH);
    

    e.g.

    CAPoseMorphTag *mtag=(CAPoseMorphTag* )doc->GetFirstObject()->GetTag(Tposemorph);
    CAMorph *morph=mtag->GetActiveMorph();
    DescID id=DescID(ID_CA_POSE_ANIMATE_DATA,morph->GetID()*ID_CA_POSE_ANIMATE_CNT+ID_CA_POSE_ANIMATE_OFFSET+ID_CA_POSE_ANIMATE_STRENGTH);
    mtag->SetParameter(id,0.5,DESCFLAGS_SET_USERINTERACTION);
    

    DESCFLAGS_SET_USERINTERACTION is needed when you set the parameter if not in Animate mode, when in Edit only a user action is allowed to change the strength.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 18/01/2012 at 03:31, xxxxxxxx wrote:

    Aha!  The DescID was what was not working for me.  I was using:

    camorph = mtag->GetMorph(i);  
    mtag->SetParameter(camorph->GetID(), value, DESCFLAGS_SET_0);  
    ++i;
    

    Now it works perfectly and IPP can convert IPP morphs to CA morphs and retain the strength values! Yay!

    Thank you very much,



  • On 06/09/2013 at 19:56, xxxxxxxx wrote:

    Sorry to bring up this old post. But I can't get the code posted here to work for me.
    I'm just trying to move the points of an object that has a posemorph tag on it. But it just won't work for me.
    No matter what I put in this thing. The morph tag prevents the point from moving.

        BaseObject *obj = doc->GetFirstObject();  
      PointObject *pobj = ToPoint(obj);            //Cast the BaseObject type to a PointObject type and assign it to a variable "pobj"  
      Vector *points = pobj->GetPointW();  
      
      CAPoseMorphTag *pmTag=(CAPoseMorphTag* )obj->GetTag(Tposemorph);   //Cast the tag to a type we can access the data from  
        
      pmTag->ExitEdit(doc,TRUE);                       //First exit any editing  
      CAMorph *morph = pmTag->GetMorph(1);             //Get the morph to be changed  
      GePrint(morph->GetName());  
      CAMorphNode *mnode = morph->GetFirst();          //The first will be the object with the morph tag  
      mnode->GetInfo() & CAMORPH_DATA_FLAGS_POINTS;    //Make sure the data exists  
      
      pmTag->SetParameter(DescID(ID_CA_POSE_POINTS), GeData(TRUE), DESCFLAGS_SET_0); //Set the points option  
      
      //Go into edit mode so we can alter the object's points  
      Bool edit = pmTag->SetParameter(DescID(ID_CA_POSE_MODE), GeData(ID_CA_POSE_MODE_EDIT), DESCFLAGS_SET_0);  
      
      //The data must be made editable before we change it  
      morph->SetMode(doc,pmTag,CAMORPH_MODE_FLAGS_ALL|CAMORPH_MODE_FLAGS_EXPAND,CAMORPH_MODE_ABS);  
      
      //Move the points around as desired  
      points[0] = Vector(0,400,0);           //<---Not Working!!  
      GePrint(RealToString(points[0].y));    //Point is changed in memory. But the morph tag is preventing it from moving  
      pobj->Message(MSG_UPDATE);  
      
      //Once finished put the data back to its original form.  
      morph->SetMode(doc,pmTag,CAMORPH_MODE_FLAGS_ALL|CAMORPH_MODE_FLAGS_COLLAPSE,CAMORPH_MODE_AUTO);  
        
      pmTag->UpdateMorphs();                      //Updates the tag  
      pmTag->Message(MSG_UPDATE);  
      EventAdd();
    

    What am I doing wrong?

    -ScottA



  • On 07/09/2013 at 11:55, xxxxxxxx wrote:

    Never mind. I found that I was missing the Store() function.

    Just in case anyone needs it.
    This is an example of how to edit an object's pose data(points).

        BaseObject *obj = doc->GetFirstObject();  
      PointObject *pobj = ToPoint(obj);          //Cast the BaseObject type to a PointObject type and assign it to a variable "pobj"  
      Vector *points = pobj->GetPointW();  
      
      //Cast the tag from a BaseTag type to a type we can access the data from  
      CAPoseMorphTag *pmTag=(CAPoseMorphTag* )obj->GetTag(Tposemorph);  
       
      //Get the morph to you want to be changed    
      CAMorph *morph = pmTag->GetMorph(1);    //The first pose in the list of poses  
      
      //Move the object's points around as desired  
      points[0] = Vector(0,400,0);    
      pobj->Message(MSG_UPDATE);  
      
      //VERY IMPORTANT!!! Store the moved point positions  
      morph->Store(doc,pmTag,CAMORPH_DATA_FLAGS_POINTS);  
      
      EventAdd();
    

    -ScottA


Log in to reply