Thank you for the quick answer.
Unfortunately this approach was quite destructive for my workflow, so i found a workaround using materials and 3d gradients. For anyone who want to render z-depth in python from c4d scene, this may be the approach. There may be some tweaks considering color space.
It would be nice to get access to this kind of data inside cinema 4d's python without crazy workarounds.
import c4d
from c4d import gui, plugins, storage
import os
PLUGIN_ID = 1234567 # Replace this ID with your unique plugin ID from Maxon
def GetFilterTypeFromFilename(filename):
ext = os.path.splitext(filename)[1].lower()
if ext == '.bmp':
return c4d.FILTER_BMP
elif ext == '.jpg' or ext == '.jpeg':
return c4d.FILTER_JPG
elif ext == '.png':
return c4d.FILTER_PNG
elif ext == '.tif' or ext == '.tiff':
return c4d.FILTER_TIF
elif ext == '.exr':
return c4d.FILTER_EXR
else:
return c4d.FILTER_PNG # Default to PNG if extension is unrecognized
class RenderDialog(gui.GeDialog):
DESTINATION_FILE = 1001
BROWSE_BUTTON = 1002
RENDER_BUTTON = 2000
def CreateLayout(self):
self.SetTitle("External Render Plugin")
# Add Destination File Field
self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT, cols=2)
self.AddStaticText(id=0, flags=c4d.BFH_LEFT, name="Destination File:")
self.AddEditText(id=self.DESTINATION_FILE, flags=c4d.BFH_SCALEFIT)
self.GroupEnd()
# Add Browse Button
self.AddButton(id=self.BROWSE_BUTTON, flags=c4d.BFH_LEFT, name="Browse")
# Add Render Button
self.AddButton(id=self.RENDER_BUTTON, flags=c4d.BFH_CENTER, name="Render")
return True
def Command(self, id, msg):
if id == self.BROWSE_BUTTON:
path = storage.SaveDialog(title="Select Destination File")
if path:
self.SetString(self.DESTINATION_FILE, path)
return True
elif id == self.RENDER_BUTTON:
path = self.GetString(self.DESTINATION_FILE)
if not path:
gui.MessageDialog("Please specify a destination file.")
return True
# Get the active document
doc = c4d.documents.GetActiveDocument()
# Create a large sphere object
sphere = c4d.BaseObject(c4d.Osphere)
sphere[c4d.PRIM_SPHERE_RAD] = 10000000 # Set radius to 10,000,000 m
doc.InsertObject(sphere)
c4d.EventAdd()
# Check if a material named "LuminanceMaterial" already exists
material = doc.SearchMaterial("LuminanceMaterial")
if not material:
# Create new material and set its parameters
material = c4d.BaseMaterial(c4d.Mmaterial)
material.SetName("LuminanceMaterial")
material[c4d.MATERIAL_USE_COLOR] = False
material[c4d.MATERIAL_USE_REFLECTION] = False
material[c4d.MATERIAL_USE_LUMINANCE] = True
# Create gradient shader and set it as luminance
gradient_shader = c4d.BaseShader(c4d.Xgradient)
if gradient_shader:
gradient_shader[c4d.SLA_GRADIENT_TYPE] = c4d.SLA_GRADIENT_TYPE_3D_LINEAR # 3D Linear Gradient
gradient_shader[c4d.SLA_GRADIENT_SPACE] = c4d.SLA_GRADIENT_SPACE_WORLD # World space
gradient_shader[c4d.SLA_GRADIENT_CYCLE] = False
material[c4d.MATERIAL_LUMINANCE_SHADER] = gradient_shader
material.InsertShader(gradient_shader)
# Insert material into the document
doc.InsertMaterial(material)
# Update gradient start and end points for the current camera
gradient_shader = material[c4d.MATERIAL_LUMINANCE_SHADER]
if gradient_shader:
camera = doc.GetActiveObject()
if not camera or camera.GetType() != c4d.Ocamera:
camera = doc.GetRenderBaseDraw().GetSceneCamera(doc)
if not camera:
camera = doc.GetRenderBaseDraw().GetEditorCamera()
if camera:
start_position = camera.GetMg().off
focus_distance = camera[c4d.CAMERAOBJECT_TARGETDISTANCE]
end_position = start_position + (camera.GetMg().v3 * focus_distance) # Use v3 for z-axis direction
gradient_shader[c4d.SLA_GRADIENT_START] = start_position
gradient_shader[c4d.SLA_GRADIENT_END] = end_position
# Enable material override in render settings
rd = doc.GetActiveRenderData()
rd[c4d.RDATA_MATERIAL_OVERRIDE] = True
rd[c4d.RDATA_MATERIAL_OVERRIDE_LINK] = material
# Set render settings
rdata = rd.GetDataInstance().GetClone(c4d.COPYFLAGS_NONE)
rdata[c4d.RDATA_PATH] = path
rdata[c4d.RDATA_RENDERENGINE] = c4d.RDATA_RENDERENGINE_STANDARD
# Create a bitmap to render into
width = int(rdata[c4d.RDATA_XRES])
height = int(rdata[c4d.RDATA_YRES])
bmp = c4d.bitmaps.BaseBitmap()
result = bmp.Init(width, height)
if result != c4d.IMAGERESULT_OK:
gui.MessageDialog("Failed to initialize bitmap.")
return True
# Trigger render
render_result = c4d.documents.RenderDocument(
doc, # Document to render
rdata, # Render settings
bmp, # Bitmap to render into
c4d.RENDERFLAGS_EXTERNAL | c4d.RENDERFLAGS_DONTANIMATE # Flags
)
if render_result != c4d.RENDERRESULT_OK:
gui.MessageDialog("Render failed.")
else:
# Determine the appropriate file format filter
filter_type = GetFilterTypeFromFilename(path)
# Save the rendered image
save_result = bmp.Save(path, filter_type, c4d.BaseContainer())
if save_result != c4d.IMAGERESULT_OK:
gui.MessageDialog("Failed to save image.")
else:
gui.MessageDialog("Render completed and saved.")
# Turn off material override after rendering
rd[c4d.RDATA_MATERIAL_OVERRIDE] = False
rd[c4d.RDATA_MATERIAL_OVERRIDE_LINK] = None
# Delete the large sphere after rendering
sphere.Remove()
c4d.EventAdd()
# Delete the material after rendering
if material:
material.Remove()
c4d.EventAdd()
# Refresh the document
c4d.EventAdd()
return True
return False
class ExternalRenderPlugin(plugins.CommandData):
def __init__(self):
self.dlg = None
def Execute(self, doc):
if not self.dlg:
self.dlg = RenderDialog()
self.dlg.Open(c4d.DLG_TYPE_ASYNC, defaultw=400, defaulth=100)
return True
if __name__ == "__main__":
plugins.RegisterCommandPlugin(
id=PLUGIN_ID,
str="External Render Plugin",
info=0,
icon=None,
help="Render current frame to a specified file",
dat=ExternalRenderPlugin()
)