GetVirtualObjects and Target Tag

On 13/10/2017 at 07:50, xxxxxxxx wrote:

I have a object plugin with GetVirtualObjects().
There I create a area light with a Target Tag.
I fill the target with user data and that is all working.

Except the light does not follow the target.
When I convert the object plugin to an object (C command), it is working!

What am I missing?

    def GetVirtualObjects(self, op, hierarchyhelp) :
        if not(op.IsDirty(c4d.DIRTY_MATRIX | c4d.DIRTY_DATA)) :
            return op.GetCache(hierarchyhelp)
        #get and set parameters 
        data = op.GetDataInstance()
        targetLink = data.GetLink(LOOKAT)
        moveableLight = c4d.BaseObject(c4d.Olight)
        moveableLight[c4d.LIGHT_TYPE] = c4d.LIGHT_TYPE_AREA
        targetTag = moveableLight.MakeTag(c4d.Ttargetexpression)
        targetTag[c4d.TARGETEXPRESSIONTAG_LINK] = targetLink
        return moveableLight

On 13/10/2017 at 09:10, xxxxxxxx wrote:

Could it be that the target is not 'working' because it is on a virtual object?

When I add a target tag to the object plugin, it is working.
It is a workaround, but I like to understand why it is not working.


On 13/10/2017 at 10:25, xxxxxxxx wrote:

Is not very clear in python since HierarchyHelp class is not implemented. But take a look at this class in c++.
So you will understand a virtual object is on a virtual document. That mean the link of your target is not valid.

On 13/10/2017 at 10:32, xxxxxxxx wrote:

Ok, an explanation I can follow.
It is all virtual, so the 'real' document and the 'virtual' document are not the same.

But the object plugin, will insert the 'virtual' objects in the 'real' document?
Ok, I am confused, I have to read the class documentation in C++.


On 15/10/2017 at 09:56, xxxxxxxx wrote:

Yes but basicly in you Virtual document you create your tag and set your link to a c4d.BaseList2D which is inside another document then your target tag.
So this assignation fail (it's logicalbecause that would mean you can open two documents, and in one of two set a target object wich is into the other document.)
So your target is actually None.

Then when c4d "convert" everythings to the No virtual document he simply copy your value (which is None)

For finnish it's just my guess, I Have no proof, or tested anything but that's seem to me pretty logical.

On 16/10/2017 at 02:52, xxxxxxxx wrote:


this time I need to object gr4ph0s. There is no virtual document in that situation and the link of the "LOOKAT" parameter actually points to the desired object in the correct document.
The problem is rather creating this tag on a cache object (that's what the generated virtual object actually is) and that there are priority issues in this constellation.

Not sure there is a good way to work around this. We'd suggest to additionally implement Execute() to mimic the functionality of the Target tag and alter the generators PSR. Of course this works only nicely if there is only one light generated by the generator.

If there are multiple lights generated you would need to change the PSR of all of them separately. While this is easy on generation in GetVirtualObjects() you would then run into issues, when the target changes/moves around, as the dirty check in GetVirtualObjects() would prevent regeneration. This to get right, can be a pain and you may very well end up in having your generator always dirty (which could have quite negative effects depending on scene hierarchy).

On 16/10/2017 at 05:55, xxxxxxxx wrote:

Thanks for the answer.
I do  not completely understand what you mean with "Execute() to mimic the functionality of the Target tag and alter the generators PSR". I assume you mean changing the local/global matrix of the generator, but that cannot be done with an Execute();

Edit: I now realize you mean the generators function Execute().

Do you have a small example?

As a workaround, I solved it by adding a target to the generator object.


On 17/10/2017 at 01:26, xxxxxxxx wrote:

Thanks for correcting me.
I also do not understand what "priority issues in this constellation" mean.

Execute() to mimic the functionality of the Target tag and alter the generators PSR
Target code is pretty easy to do here a sample that align op to a given obj

import c4d
def target(SrcObj, DestObj, RightNormalized=c4d.Vector(0,1,0)) :
    if not SrcObj or not DestObj:
    #Get global pos
    srcPos = SrcObj.GetMg().off
    destPos = DestObj.GetMg().off
    #Build front axis
    forward = srcPos - destPos
    #Build right axis
    right = RightNormalized.GetNormalized().Cross(forward)
    #Build up axis
    up = forward.Cross(right)
    #Build the final matrice
    m = SrcObj.GetMg()
    m.v1 = right
    m.v2 = up
    m.v3 = forward
def main() :
    obj = doc.GetFirstObject()
    target(obj, obj.GetNext())
if __name__=='__main__':

On 17/10/2017 at 01:55, xxxxxxxx wrote:

The only thing with the script is, that the scale of the source object is sometimes scaled.


On 17/10/2017 at 02:00, xxxxxxxx wrote:

Then simply add

    scale = SrcObj.GetRelScale()

On 17/10/2017 at 02:47, xxxxxxxx wrote:

Thanks again.

On 17/10/2017 at 07:22, xxxxxxxx wrote:

@gr4ph0s: See for example here:
Usually expressions (aka tags) get executed before generators. So it's getting a bit weird, if a expression gets created by a generator.

On 17/10/2017 at 07:49, xxxxxxxx wrote:

You changed my day....