Cloning Materials for Generator Plugin



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

    On 12/02/2004 at 17:04, xxxxxxxx wrote:

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

    ---------
    Hi,

    I'm trying to write a Generator plugin that changes some material
    properties for each object instance.

    As the material isn't cloned when the objects are cloned, I clone the
    material, and set each object-clone's TextureTag to point to its
    corresponding material-clone.

    This works. Sort of. However:

    1. The most significant problem is that C4D will often crash when I
    delete the materials in Free() :-|. I don't have any good ideas as to
    why. I'm wondering whether something like the object cloning pattern
    needs to be used (ie: first clone: use GetHierarchyClone(), subsequent
    clones: clone cloneone with GetClone()). I still don't understand
    *why* we need to make object clones in different ways.

    2. A secondary problem is that there doesn't seem to be any way to
    hide the created materials, as they must be inserted in the current
    document for the TextureTag links to be followed, and once inserted in
    the document, they are visible to the user. Is there any way to add
    the materials to the document, yet hide them?

    3. There's also a need to keep track of the original material's
    "dirty" status, which I'm not so clear on how to do.

    4. Also, when 'make editable' is invoked, the materials are of course
    deleted, leaving a bunch of TextureTags pointing to nowhere... is
    there any way to detect this?

    Any input welcome!
    Thanks.

    .angus.

    An outline of my code follows:

      
    class MyPlugin : public ObjectData  
    {  
        // ...  
        void freeMaterials();  
        std::vector<BaseObject*> materials;  
    };  
      
    void  
    MyPlugin::Free(GeListNode* /*node*/)  
    {  
        // ...  
        freeMaterials(); // this will cause CRASH  
    }  
      
    void  
    MyPlugin::freeMaterials()  
    {  
        std::vector<BaseMaterial*>::iterator it;  
        for (it = materials.begin(); it != materials.end(); ++it)  
        {  
            (*it)->Remove(); // remove material from document  
            BaseMaterial::Free(*it); // free material  
        }  
    }  
      
    BaseObject*  
    MyPlugin::GetVirtualObjects(PluginObject* op, HierarchyHelp* hh)  
    {  
        BaseDocument* bdoc = hh->GetDocument();  
        BaseObject* childone = op->GetDown();  
        // ... check dirt  
        // ... update dependence  
        if (!dirty) return op->GetCache(hh);  
      
        // root of returned tree  
        BaseObject* instroot = BaseObject::Alloc(Onull);  
        std::vector<BaseObject*> clones(numInsts);  
      
        // get first object clone  
        BaseObject* cloneone = op->GetHierarchyClone  
            (hh, childone, HCLONE_ASIS, 0, 0);  
        // ... touch dependence  
        cloneone->InsertUnderLast(instroot);  
        clones[0] = cloneone;  
      
        // make subsequent object clones  
        BaseObject* clone;  
        for (int i = 1; i < numInsts; ++i)  
        {  
            clone = cloneone->GetClone(CLONE_FLAGS, 0);  
            clone->InsertUnderLast(instroot);  
            clones _= clone;  
        }  
      
        freeMaterials();  
        materials.resize(numInsts);  
      
        // find material (eg, ignoring IsInstanceOf, casts, etc)  
        BaseMaterial* matone = childone->GetFirstTag()->GetMaterial();  
      
        // make material clones  
        BaseMaterial* mclone;  
        for (int i = 0; i < numInsts; ++i)  
        {  
            mclone = matone->GetClone(CLONE_FLAGS, 0);  
            materials _= mclone;  
            bdoc->InsertMaterial(mclone);  
        }  
      
        // update TextureTags (ignoring casts, etc)  
        for (int i = 0; i < numInsts; ++i)  
            clones _- >GetFirstTag()->SetMaterial(materials _);  
      
        // ... manipulate cloned objects and materials  
      
        return instroot;  
    }  
    


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

    On 15/02/2004 at 16:32, xxxxxxxx wrote:

    First of all, this question has arisen before and unfortunately it's forbidden to add "virtual" materials in GetVirtualObjects() of a generator. As you've noticed it will lead to crashes, and the answer I got from the programmers the last time I asked about it was that this wouldn't be easy to resolve.
    So you need to insert the materials you need into the real document, even if many are needed, and there's unfortunately no way to hide them. Perhaps you could reduce the number of materials needed by making your own shader that reads parameters stored in the cloned objects?



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

    On 16/02/2004 at 00:24, xxxxxxxx wrote:

    Thanks for clearing up the possibility of "virtual" or hidden
    materials. I couldn't (and still can't) find previous discussion on
    the subject -- could you give me a link to the thread? And thanks for
    the suggestion to create my own shader. I need to think about that
    before I can say whether that will work for me or not...

    However, some questions remain unanswered :-(

    1. can you see anything I'm doing wrong that would cause C4D to crash
        when the materials are deleted? any hints?

    It seems that I only get a crash when freeMaterials() is called
        via Free() (ie: when the plugin is being deleted). I'm not yet
        sure what preconditions apply, as some Free's are OK.

    2. (you've answered)

    3. how do I keep track of the "dirty" status of an object not
        actually "owned" by the Generator plugin? ie: how do I track
        changes in the original material?

    4. how do I know when *not* to delete the materials I've created?
        ie: how can I tell when "make editable" has been invoked, and I
        shouldn't be deleting the materials?

    Thanks again.

    .angus.



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

    On 16/02/2004 at 20:23, xxxxxxxx wrote:

    0. Hm, the discussion might have been over email only. But at least I've got a definite response from the developers in the past on this.
    1. Generally it's very dangerous to do things in Free(). C4D will allocate all sorts of copies of your object, outside of your control, for example for the undo buffer. Free() should only free resource allocated by the plugin itself that noone else has seen.
    3. You should be able to use GetDirty() to get a checksum (or rather a value that's incremented when something changes). If you store this number you can check it later to see if an object has changed. (I haven't verified that this is actually implemented for materials. It should be since they are BaseList2D.)
    4. I don't think you can actually, hence the recommendation from the programmers to only create objects and let the user delete them as necessary. (Quite easy with "remove unused materials".)



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

    On 16/02/2004 at 21:46, xxxxxxxx wrote:

    1. Ah? Thanks.
    3. Ok. Thanks.
    4. Hm. Thanks.

    Thanks!

    .angus.


Log in to reply