Instance object and ObjectData,GetVirtualObjects
-
On 25/04/2016 at 14:58, xxxxxxxx wrote:
Update: It appears that this works great... until rendering. Probably loses the link during document cloning because the linked object isn't in the document. Worth a trial and now I know the error.
-
On 25/04/2016 at 22:03, xxxxxxxx wrote:
Hello Robert,
no, it is not a good idea to have a linked object outside of a scene (the singular instance part of your question), as you may have found out yourself by now.
Not only in rendering context, but on many other occasions, C4D needs to clone objects and documents. And usually links are evaluated only within a single document.
On the second part your question, it should be perfectly fine to have the object in your GVO result, as it "will" be in the document, when other instances of C4D evaluate the links. And you may also hide the real_op from the user. Let me know, when your second post already relates to this solution.
In C++ one way to go would be a SceneHook, which can hold the object (without having it inserted into the Object Manager). But still, you'd need to make sure, that the links would be reworked after your generator is being copied into a new scene to avoid cross-scene links.
-
On 26/04/2016 at 09:47, xxxxxxxx wrote:
Another way would be to insert all the clone masters under a main null in GVO (and not directly into the document). Once they are inserted, you can use them as instance masters, and it would work in both viewport and render.
The user would not see anything different as everything is parented under the main null. -
On 26/04/2016 at 10:29, xxxxxxxx wrote:
If you don't want the link to break, you can implement NodeData::GetBranchInfo() with your own
branch that contains the object(s) that you need, but don't want to appear anywhere in the scene.
(it's still linked into the document though, but no manager/plugin implements displaying your branchCheers,
Niklas -
On 26/04/2016 at 10:36, xxxxxxxx wrote:
That is exactly what I was doing.
The master object is created uniquely per Object plugin instance in the document (not one for all instances of the Object plugin in all documents). If I put this master object under the main null in GVO and link all of the instances (under the same main null in GVO) to it, it works until I render. Then the instances do not show up.
-
On 26/04/2016 at 11:07, xxxxxxxx wrote:
I can confirm that adding the master object under the GVO main null does not work. When I render, none of the instances linking to the master are rendered - but they show in the viewport.
How would one go about implementing the GetBranchInfo() in this case? In my one plugin, Greebler, the 'nurnies' (objects) exist or are added to the document for Instance references (the simple way). For GetBranchInfo(), should I store the master object in a BaseLink (in the description resource) or would that be redundant with GetBranchInfo()? Not many examples except an old one from 2006 (presented again by Scott in 2011). This master object will need to be persistent (between saves and loads of the document).
-
On 26/04/2016 at 11:40, xxxxxxxx wrote:
Not sure about the saving part. I do not think that it will be saved automatically, so I do think that
you might need to save it yourself from NodeData::Write() somehow. Hopefully the SDK Support Team
can shed some light on this.Your implementation could look something like what you see below. After you did this, the Instance
Object should keep the link to the object even when you render.GeListHead* myListHead = nullptr; String* myListHeadName = nullptr; virtual Int32 GetBranchInfo(GeListNode* node, BranchInfo* info, Int32 max, GETBRANCHINFO flags) override { // Allocate the head and name for the branch. You probably want to do this // from something like Init() instead. And free it in Free()! if (!myListHead) { myListHead = GeListHead::Alloc(); if (myListHead) { myListHead->SetParent(node); BaseObject* test = BaseObject::Alloc(Ocube); if (test) myListHead->InsertFirst(test); } } if (!myListHeadName) { myListHeadName = NewObjClear(String); if (myListHeadName) *myListHeadName = "myListHead"; } Int32 count = 0; if (myListHead && myListHeadName && count < max) { BranchInfo& branch = info[count++]; branch.flags = BRANCHINFOFLAGS_0; branch.head = myListHead; branch.name = myListHeadName; } return count; }
This is how it would look like in the C++ SDK ActiveObjectManager dialog.
Cheers,
Niklas -
On 26/04/2016 at 11:45, xxxxxxxx wrote:
Still not seeing the objects in render:
Header:
// CLASS: V4DObject class V4DObject : public ObjectData { INSTANCEOF(V4DObject,ObjectData) private: // Data // --- This is the list head were the plugin node will be inserted to AutoAlloc<GeListHead> m_pBranchHead; String m_String_BranchName; //pointer to an instance of the plugin node BaseList2D* m_pBranchNode; ...
CPP File
// NodeData.Init //*---------------------------------------------------------------------------* Bool V4DObject::Init(GeListNode* node) //*---------------------------------------------------------------------------* { if (node == nullptr) return MessageSystem::Throw(GeLoadString(KDZS_ERR_MEMORY), "V4DObject.Init.node"); // Allocate V4DPlant m_pPlant = NewObjClear(V4DPlant, static_cast<BaseObject*>(node)); if (m_pPlant == nullptr) return ErrPrt("V4DPlant allocation failed!"); if (!m_pPlant->Init()) return ErrPrt("V4DPlant initialization failed!"); // Establish GeListHead and Node to store Leaf Object (??) if (m_pBranchHead == nullptr) return ErrPrt("V4DObject.Init.m_pBranchHead"); if (m_pBranchNode == nullptr) { // - Create Master Leaf Object for Render Instances m_pBranchNode = m_pPlant->CreateLeafObject(); if (m_pBranchNode == nullptr) return ErrPrt("V4DObject.Init.m_pPlant.CreateLeafObject"); } // Needed to save the node list m_pBranchHead->SetParent(node); // Insert the plugin node into the list m_pBranchHead->Insert(m_pBranchNode, nullptr, nullptr); // Allocate dialog to impart and stop growth m_pDialog = NewObjClear(V4DGrowthDialog); if (m_pDialog == nullptr) return ErrPrt("V4DGrowthDialog allocation failed!"); // Set default values SetDefaults(static_cast<BaseObject*>(node)); m_Bool_RebuildCache = TRUE; return TRUE; } // NodeData.GetBranchInfo //*---------------------------------------------------------------------------* Int32 V4DObject::GetBranchInfo(GeListNode* node, BranchInfo* info, Int32 max, GETBRANCHINFO flags) //*---------------------------------------------------------------------------* { // Fill the info structure array; only one element is saved in this example info[0].head = m_pBranchHead; info[0].name = &m_String_BranchName; info[0].id = ID_VINEMA4D_OBJECT; info[0].flags = BRANCHINFOFLAGS_0; // Return the number of filled BranchInfo elements return 1; } // NodeData.Copy - Copy data to copied BaseObject //*---------------------------------------------------------------------------* Bool V4DObject::CopyTo(NodeData* dest, GeListNode* snode, GeListNode* dnode, COPYFLAGS flags, AliasTrans* trn) //*---------------------------------------------------------------------------* { if (snode == nullptr) return MessageSystem::Throw(GeLoadString(KDZS_ERR_MEMORY), "V4DObject.CopyTo.snode"); if (m_pBranchHead == nullptr) return MessageSystem::Throw(GeLoadString(KDZS_ERR_MEMORY), "V4DObject.CopyTo.m_pBranchHead"); if (m_pPlant == nullptr) return MessageSystem::Throw(GeLoadString(KDZS_ERR_MEMORY), "V4DObject.CopyTo.m_pPlant"); // Get Destination V4DObject and its V4DPlant V4DObject* dobj = (V4DObject* )dest; if (dobj == nullptr) return MessageSystem::Throw(GeLoadString(KDZS_ERR_MEMORY), "V4DObject.CopyTo.dobj"); if (dobj->m_pPlant == nullptr) return MessageSystem::Throw(GeLoadString(KDZS_ERR_MEMORY), "V4DObject.CopyTo.dobj.m_pPlant"); if (!m_pBranchHead->CopyTo(dobj->m_pBranchHead, COPYFLAGS_0, trn)) return MessageSystem::Throw(GeLoadString(KDZS_ERR_MEMORY), "V4DObject.CopyTo.m_pBranchHead.CopyTo"); return m_pPlant->CopyTo(dobj->m_pPlant); }
m_pBranchNode is being passed to be set as the link in the Render Instance objects.
-
On 26/04/2016 at 12:11, xxxxxxxx wrote:
Yes, it does exist. And just for completeness, my first attempt was with an object underneath my Object plugin object used to link to the GVO Render Instance objects and that worked perfectly. So, something about having it stored 'internally' isn't working for me. A pointer to the object (m_pBranchNode) is being passed to be set in the Render Instances. (???)
-
On 26/04/2016 at 12:24, xxxxxxxx wrote:
It just appeared to me that the object won't get all the object routines if it is in a separate branch.
So it's GetVirtualObjects() method will not be called, thus the cache will not be filled etc. And that will make
the Instance Objects actually instance nothing..Sorry
-
On 26/04/2016 at 12:36, xxxxxxxx wrote:
What is weird is that if I look at the CACHE, the instances are there and they are pointing to that Leaf object. When I render *OR* when I MakeEditable, the link to the Leaf object is lost.
Unless anyone has any code tricks that work, the master object is going into the document I suppose.
-
On 26/04/2016 at 14:03, xxxxxxxx wrote:
This code, added in GVO, works for me in both viewport and render
BaseObject* cube = BaseObject::Alloc(Ocube); LONG count = 10; BaseObject* main = BaseObject::Alloc(Onull); cube->InsertUnder(main); for (LONG i=0; i<count; i++) { BaseObject* iop = BaseObject::Alloc(Oinstance); BaseContainer* ibc = iop->GetDataInstance(); ibc->SetLink(INSTANCEOBJECT_LINK, cube); ibc->SetBool(INSTANCEOBJECT_RENDERINSTANCE, TRUE); iop->SetAbsPos(Vector(300*i, 0,0)); iop->InsertUnderLast(main); } return main;
If it works for you, you can then substitute the cube for whatever objects you have in your plugin.
-
On 26/04/2016 at 14:10, xxxxxxxx wrote:
Now, even with the master object in the document, I still don't get anything even with MakeEditable (???). So, the master object is in the document. The Instances point to it. And they still won't render. That is strange. It is almost as if something is broken somewhere (but I can't find it). Maybe it is my master object. I will try with another object to see the results.
Note: Since my first similar test, I have implemented multi-processing threads to break up the work for GVO. That works when I create the objects as objects (instead of instances). It is very fast - but since it is creating thousands of objects, it gets slow (say, in render or running animation in the viewport). Thus, the reason to use instances instead of geometry.
UPDATE NOTE!!!!!
Yeah, it helps when none of the scale values are 0.0. Do not ask how that got passed into the viewport and displayed at all. Once scales were properly set on the instances, they are working with the master under the GVO null. Oye vay!Thanks for your help and patience, everyone!!!!!
Have a beer on me. I am going to have a few on you guys!