SOLVED External Compositing Tag not working with generated objects by ObjectData Plugin

Hi All,
I'm on my first plugin, and by no means a true Python developer.
my plugin is relatively simple : it gets a cloner from a LINK box in the GUI, and creates a null for each clone, with a compositing tag attached, and gets the matrix of each clone from the GetCache() and applies it to each null, making them follow the clones.

It all works fine on the viewport, but if i export an AEC file, the nulls are all static, and not following changes caused by effectors, like position or rotation etc. it DOES work on the viewport as you scrub the timeline in C4D though.

i'm creating the Nulls during the GetVirtualObjects() function, and changing their Matrix on the Execute() function.

Any ideas?

Cheers,
Eddie

Hi Eddy, welcome for the Forum and thanks for reaching out us.

With regard to your issue, I think the problem is how you handle your ObjectData cache and when if update it during the scene evaluation. In the code below beside checking for my object cache existence and for my object's parameters changes I also check if the cloner's cache has changed when the ObjectData::GetVirtualObjects is called.

class PC_12764 (plugins.ObjectData):
	_clonerDirty = 0

	def Init(self, node):
		return True

	def GetVirtualObjects(self, op, hh):
		cloner = op[1002]
		res = c4d.BaseObject(c4d.Onull)
		if cloner is None:
			return res

		clonerCache = cloner.GetCache()
		if clonerCache is None:
			return res

		firstClonerItem = clonerCache.GetDown()
		if firstClonerItem is None:
			return res

		# check cloner cache dirty count
		clonerDirty = False
		if self._clonerDirty != cloner.GetDirty(c4d.DIRTYFLAGS_CACHE):
			clonerDirty = True
			self._clonerDirty = cloner.GetDirty(c4d.DIRTYFLAGS_CACHE)
		
		# return object cache taking in account cloner cache
		dirty = op.CheckCache(hh) or op.IsDirty(c4d.DIRTY_DATA) or clonerDirty
		if not dirty :
			return op.GetCache(hh)
		
		while firstClonerItem is not None:
			child = c4d.BaseObject(c4d.Onull)
			child.SetMg(firstClonerItem.GetMg())
			child.InsertUnder(res)
			firstClonerItem = firstClonerItem.GetNext()

		return res

This approach, without using the ObjectData::Execute() gives ,in the end, consistent results when exporting a .aec file using a External Compositing Tag as in the scene attached.

AEC file except

...
...

NULL2 "Null"
{
  NULLTYPE 1
  SIZEX 200
  SIZEY 100
  ANCHOR 3
  ORIENTATION 1
  COLOR 1 0 0 
  SHOWFROM 1
  SHOWTO 10
  KEY 1 200 200 200 0 0 0 0 0 0
  KEY 2 202.036 195.61 204.755 0 0 0 0 0 0
  KEY 3 206.929 185.058 216.184 0 0 0 0 0 0
  KEY 4 212.786 172.427 229.866 0 0 0 0 0 0
  KEY 5 217.679 161.875 241.295 0 0 0 0 0 0
  KEY 6 219.714 157.485 246.051 0 0 0 0 0 0
  KEY 7 217.679 161.875 241.295 0 0 0 0 0 0
  KEY 8 212.786 172.427 229.866 0 0 0 0 0 0
  KEY 9 206.929 185.058 216.184 0 0 0 0 0 0
  KEY 10 202.036 195.61 204.755 0 0 0 0 0 0
}

NULL2 "Null"
{
  NULLTYPE 1
  SIZEX 200
  SIZEY 100
  ANCHOR 3
  ORIENTATION 1
  COLOR 1 0 0 
  SHOWFROM 1
  SHOWTO 10
  KEY 1 0 200 200 0 0 0 0 0 0
  KEY 2 0.427 201.541 196.343 0 0 0 0 0 0
  KEY 3 1.453 205.246 187.554 0 0 0 0 0 0
  KEY 4 2.681 209.681 177.032 0 0 0 0 0 0
  KEY 5 3.707 213.385 168.242 0 0 0 0 0 0
  KEY 6 4.134 214.927 164.585 0 0 0 0 0 0
  KEY 7 3.707 213.385 168.242 0 0 0 0 0 0
  KEY 8 2.681 209.681 177.032 0 0 0 0 0 0
  KEY 9 1.453 205.246 187.554 0 0 0 0 0 0
  KEY 10 0.427 201.541 196.343 0 0 0 0 0 0
...
...
}

Scene file

PC_12764.c4d

Hi Eddy, welcome for the Forum and thanks for reaching out us.

With regard to your issue, I think the problem is how you handle your ObjectData cache and when if update it during the scene evaluation. In the code below beside checking for my object cache existence and for my object's parameters changes I also check if the cloner's cache has changed when the ObjectData::GetVirtualObjects is called.

class PC_12764 (plugins.ObjectData):
	_clonerDirty = 0

	def Init(self, node):
		return True

	def GetVirtualObjects(self, op, hh):
		cloner = op[1002]
		res = c4d.BaseObject(c4d.Onull)
		if cloner is None:
			return res

		clonerCache = cloner.GetCache()
		if clonerCache is None:
			return res

		firstClonerItem = clonerCache.GetDown()
		if firstClonerItem is None:
			return res

		# check cloner cache dirty count
		clonerDirty = False
		if self._clonerDirty != cloner.GetDirty(c4d.DIRTYFLAGS_CACHE):
			clonerDirty = True
			self._clonerDirty = cloner.GetDirty(c4d.DIRTYFLAGS_CACHE)
		
		# return object cache taking in account cloner cache
		dirty = op.CheckCache(hh) or op.IsDirty(c4d.DIRTY_DATA) or clonerDirty
		if not dirty :
			return op.GetCache(hh)
		
		while firstClonerItem is not None:
			child = c4d.BaseObject(c4d.Onull)
			child.SetMg(firstClonerItem.GetMg())
			child.InsertUnder(res)
			firstClonerItem = firstClonerItem.GetNext()

		return res

This approach, without using the ObjectData::Execute() gives ,in the end, consistent results when exporting a .aec file using a External Compositing Tag as in the scene attached.

AEC file except

...
...

NULL2 "Null"
{
  NULLTYPE 1
  SIZEX 200
  SIZEY 100
  ANCHOR 3
  ORIENTATION 1
  COLOR 1 0 0 
  SHOWFROM 1
  SHOWTO 10
  KEY 1 200 200 200 0 0 0 0 0 0
  KEY 2 202.036 195.61 204.755 0 0 0 0 0 0
  KEY 3 206.929 185.058 216.184 0 0 0 0 0 0
  KEY 4 212.786 172.427 229.866 0 0 0 0 0 0
  KEY 5 217.679 161.875 241.295 0 0 0 0 0 0
  KEY 6 219.714 157.485 246.051 0 0 0 0 0 0
  KEY 7 217.679 161.875 241.295 0 0 0 0 0 0
  KEY 8 212.786 172.427 229.866 0 0 0 0 0 0
  KEY 9 206.929 185.058 216.184 0 0 0 0 0 0
  KEY 10 202.036 195.61 204.755 0 0 0 0 0 0
}

NULL2 "Null"
{
  NULLTYPE 1
  SIZEX 200
  SIZEY 100
  ANCHOR 3
  ORIENTATION 1
  COLOR 1 0 0 
  SHOWFROM 1
  SHOWTO 10
  KEY 1 0 200 200 0 0 0 0 0 0
  KEY 2 0.427 201.541 196.343 0 0 0 0 0 0
  KEY 3 1.453 205.246 187.554 0 0 0 0 0 0
  KEY 4 2.681 209.681 177.032 0 0 0 0 0 0
  KEY 5 3.707 213.385 168.242 0 0 0 0 0 0
  KEY 6 4.134 214.927 164.585 0 0 0 0 0 0
  KEY 7 3.707 213.385 168.242 0 0 0 0 0 0
  KEY 8 2.681 209.681 177.032 0 0 0 0 0 0
  KEY 9 1.453 205.246 187.554 0 0 0 0 0 0
  KEY 10 0.427 201.541 196.343 0 0 0 0 0 0
...
...
}

Scene file

PC_12764.c4d