SOLVED How can I update custom tokens when rendering with the Takes System?

Hello,

I'm working on creating custom tokens and they work perfectly when I'm just rendering straight to Picture Viewer with what's actively set up in my viewport.

However, I haven't been able to figure out how to get the custom tokens to update correctly when rendering with the Takes System—whether it's multiple takes or even just one take that has different settings than the currently active take in the viewport.

Basically, my code as currently written is only able to grab the currently active settings in the document the moment I hit render, rather than applying the selected Take first and updating the custom token with the Take's settings and re-updating with each Take if there's multiple takes.

Any guidance here would be greatly appreciated. Thank you!

I've attached a C4D example file set up with multiple takes with different cameras and width x height output sizes to test the tokens, if you need it to understand what I'm talking about with these custom tokens when rendering straight to Picture Viewer vs. rendering multiple takes at the same time.

C4D Example File:
customTokens_takesTest.c4d

Python Script:
customTokens_takesTest.pyp

Full script below as well if you don't want to download the Python script file:

import c4d
import maxon

def GetCameraName(data):
	"""
	A token that looks for the active camera name and reformats the name
	to be all uppercase for the filename.

	Works with single render when just rendering straight to viewport with
	current active settings, but does not work when rendering with
	Takes that have different settings than the currently active settings.
	"""
	doc = c4d.documents.GetActiveDocument()
	bd = doc.GetRenderBaseDraw()
	sceneCam = bd.GetSceneCamera(doc)
	camName = sceneCam.GetName()
	return camName.upper()


def GetResolutionActive(data):
	"""
	A token that looks for the active rendering setting's output width
	and determines whether the filename should be "highRes"or "lowRes"
	based on the width.

	Works with single render when just rendering straight to viewport
	with current active settings, but does not work when rendering with
	Takes that have different settings than the currently active settings.
	"""
	doc = c4d.documents.GetActiveDocument()
	renderData = doc.GetActiveRenderData()
	renderResX = round(renderData[c4d.RDATA_XRES])
	if renderResX >= 1920:
		return "activeDocHighRes"
	else:
		return "activeDocLowRes"


def GetResolutionTakes(data):
	"""
	An alternate version of the GetResolutionActive(data) above with an
	attempt to use Take Data, but seems I might not be writing this correctly?
	Still doesn't update correctly when rendering with Takes.
	"""
	doc = c4d.documents.GetActiveDocument()

	takeData = doc.GetTakeData()
	if takeData is None:
		return

	take = takeData.GetCurrentTake()
	if take is None:
		return

	renderData = take.GetRenderData(takeData)
	renderResX = round(renderData[c4d.RDATA_XRES])

	c4d.EventAdd()

	if renderResX >= 1920:
		return "takeHighRes"
	else:
		return "takeLowRes"

#----------------------------------------------------------------------------------------------------------------------------------------
# Register Tokens
#----------------------------------------------------------------------------------------------------------------------------------------
if __name__=="__main__":
	for registeredToken in c4d.modules.tokensystem.GetAllTokenEntries():
		if registeredToken.get("_token") in ["camUppercase", "lowHighResActive", "lowHighResTakes"]:
			exit()

	# Filename Parsed Tokens
	c4d.plugins.RegisterToken("camUppercase","[TEST] Uppercase Cam Name", "CAMNAME", GetCameraName)
	c4d.plugins.RegisterToken("lowHighResActive","[TEST] Low/High Resolution [Active Doc]", "lowRes / highRes", GetResolutionActive)
	c4d.plugins.RegisterToken("lowHighResTakes","[TEST] Low/High Resolution [Current Take]", "lowRes / highRes", GetResolutionTakes)

Hello @nullobject,

ah okay, I do understand now. The reason why this is happening, is because your token callbacks all rely on the active document, e.g., this GetCameraName callback:

def GetCameraName(data):
	...
	doc = c4d.documents.GetActiveDocument()
	...
	return sceneCam.GetName().upper()

So, you return a upper case form of the active camera in the active document. But when you invoke the "batch take rendering functionality" of the Take manager, the active take of the active document will not change. Which then also means that the active camera will not change, leading to your problem.

This is a common trap in the Cinema 4D API to rely on the active document, as documents can be evaluated without being loaded into the editor or being the active document. In this case the solution is simple, just use the callback data argument provided by Cinema 4D which will also contain the correct document state. For details see the RegisterToken Documentation. So, your GetCameraName should probably look like this:

def GetCameraName(data):
	...
	doc = data[0]
	...
	return sceneCam.GetName().upper()

Cheers,
Ferdinand

Hello @nullobject,

welcome to the forum and the Cinema 4D community! Thank you for reaching out to us. You did make a nice posting for your first question, but it is missing some information, most importantly the version of Cinema 4D you are using and the tags we require users to use. To learn more about support procedures on Plugin Café, I would recommend reading our Forum Guidelines.

However, I haven't been able to figure out how to get the custom tokens to update correctly when rendering with the Takes System

I have installed your plugin and tried your file, and it is not immediately obvious to me what you would consider going wrong with your plugin. I had to deactivate Octane as the render engine though, since I do not have Octane here. I did activate different Takes in the Take Manger in your file and then did render the document as shown below.

f7487fdb-aecb-4009-8beb-33322f51e2fe-image.png

The resulting file names are what I would expect them to be. I was specifically looking for you camera name token. This was the output of three renderings. Could you please point out what you would consider wrong about them?

0fddbe14-ff01-498c-87c1-5ecde129eabe-image.png

The take system lives in a matter of speaking outside of the parameter access of C4DAtom. So, when you change a take, the parameters of node actually do change, no extra steps required when accessing them. The only thing I could think of, is that Octane might not implement the integration of the Take System correctly with their rendering interface. But that is all very speculative. It would be better if you could describe more precisely what you do consider going wrong on your side.

Cheers,
Ferdinand

Hi @ferdinand,

Thank you for taking the time to installing to take a look and reply. Sorry that I didn't provide the proper amount of information in the original post.

I'm using Cinema 4D R23.110 on Windows 10.

Were you rendering one take at a time or multiple takes at the same time with "Render Marked Takes to PV"?

However, I haven't been able to figure out how to get the custom tokens to update correctly when rendering with the Takes System—whether it's multiple takes or even just one take that has different settings than the currently active take in the viewport.

I should have specified when I mentioned rendering multiple takes with the Takes System, I meant rendering using the "Render All Takes to PV" and/or "Render Marked Takes to PV" buttons rather than rendering multiple takes by manually activating one take at a time. Apologies if that wasn't clear originally.

Screen Recording:

To make it even more clear, here's a screen recording of what happens when I activate each individual take at a time and render each one individually (getting the correct filenames) vs. rendering all marked takes at the same time (getting incorrect filenames):
https://drive.google.com/file/d/1rRGYZ_-yEjxo29TBiiJXLjq9vt1HPXRU/view

If there's any issues playing the video, you should be able to download the video from the link with the download button in the top-right.

Filenames Comparison:
For easier comparison, here is a screenshot of the two list of filenames side-by-side below:

Tokens_Not_Updating_With_Multiple_Takes-Screenshots-v001.jpg

Notice that on the left, when rendering one take at a time, the tokens update correctly. The camera name changes and the low/high resolution token changes to match the correct camera and resolution for each take.

On the right, when rendering with multiple takes all at once, the tokens do not update correctly. The camera name and low/high resolution tokens are exactly the same for every single file—which is the token names for the document's active take (the 2000px take) and not updating accordingly with each take.

Correct names (rendering one take at a time):

customtokens_takestest-400px-CAM400PX-activeDocLowRes-takeLowRes.jpg
customtokens_takestest-1024px-CAM1024PX-activeDocLowRes-takeLowRes.jpg
customtokens_takestest-1920px-CAM1920PX-activeDocHighRes-takeHighRes.jpg
customtokens_takestest-2000px-CAM2000PX-activeDocHighRes-takeHighRes.jpg
customtokens_takestest-Main-CAMMAIN-activeDocLowRes-takeLowRes.jpg

Incorrect names (rendering multiple/all takes at the same time with "Render All/Marked Takes to PV"):

customtokens_takestest-400px-CAM2000PX-activeDocHighRes-takeHighRes.jpg
customtokens_takestest-1024px-CAM2000PX-activeDocHighRes-takeHighRes.jpg
customtokens_takestest-1920px-CAM2000PX-activeDocHighRes-takeHighRes.jpg
customtokens_takestest-2000px-CAM2000PX-activeDocHighRes-takeHighRes.jpg
customtokens_takestest-Main-CAM2000PX-activeDocHighRes-takeHighRes.jpg

Hope that all makes sense.

Let me know if you did in fact render multiple takes at the same time with "Render All/Marked Takes to PV" and it worked for you.

RE: Octane

I had to deactivate Octane as the render engine though, since I do not have Octane here.
[...]
The only thing I could think of, is that Octane might not implement the integration of the Take System correctly with their rendering interface.

That is strange since the render settings in the file I've provided only use "Standard Renderer" and doesn't contain any Octane. I do have Octane installed so it may have accidentally got its way into the file somehow, but I've only I've only been testing with "Standard Renderer." The video recording above was using the C4D file downloaded from my original post in this thread and the renderer is already set to "Standard" when I opened the re-downloaded the file. In any case, I'm not using or concerned with Octane renderer in particular with this issue as long as it works with the Standard renderer.

Thanks again for any help.

Hello @nullobject,

ah okay, I do understand now. The reason why this is happening, is because your token callbacks all rely on the active document, e.g., this GetCameraName callback:

def GetCameraName(data):
	...
	doc = c4d.documents.GetActiveDocument()
	...
	return sceneCam.GetName().upper()

So, you return a upper case form of the active camera in the active document. But when you invoke the "batch take rendering functionality" of the Take manager, the active take of the active document will not change. Which then also means that the active camera will not change, leading to your problem.

This is a common trap in the Cinema 4D API to rely on the active document, as documents can be evaluated without being loaded into the editor or being the active document. In this case the solution is simple, just use the callback data argument provided by Cinema 4D which will also contain the correct document state. For details see the RegisterToken Documentation. So, your GetCameraName should probably look like this:

def GetCameraName(data):
	...
	doc = data[0]
	...
	return sceneCam.GetName().upper()

Cheers,
Ferdinand

Amazing, thank you @ferdinand!

I figured GetActiveDocument() was the issue, so I was attempting to use takeData.GetCurrentTake() instead in the GetResolutionTakes callback but it still was exactly the same issue where the active take does not change. I didn't know about the callback data argument that already contains the correct document state in data[0], so thank you for letting me know to use that instead and pointing me to further details in the RegisterToken Documentation.

Replacing:

  • doc = c4d.documents.GetActiveDocument() with doc = data[0]
  • renderData = doc.GetRenderData(takeData) with renderData = data[1]

to get the following code below worked perfectly:

def GetCameraName(data):
	doc = data[0]
	bd = doc.GetRenderBaseDraw()
	sceneCam = bd.GetSceneCamera(doc)
	camName = sceneCam.GetName()
	return camName.upper()


def GetResolutionActive(data):
	renderData = data[1]
	renderResX = round(renderData[c4d.RDATA_XRES])
	if renderResX >= 1920:
		return "highRes"
	else:
		return "lowRes"

Thank you again very much for the help! Really appreciate it.