Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Register
    • Register
    • Login
    1. Maxon Developers Forum
    2. ferdinand
    3. Posts
    • Profile
    • Following 0
    • Followers 15
    • Topics 53
    • Posts 3,073
    • Best 746
    • Controversial 1
    • Groups 2

    Posts made by ferdinand

    • RE: [GeUserArea] Click detection selects wrong item when clicking on lower part of cell (image + text area)

      Hey,

      thanks for the extended code, but I still cannot run this, as it is only a fragment 😉 So, I only have a very rough understanding of what is going wrong.

      A likely issue apart from you just having a bug in your hit logic, is that you use the wrong coordinate system.

      if msg[c4d.BFM_INPUT_DEVICE] == c4d.BFM_INPUT_MOUSE \
          and msg[c4d.BFM_INPUT_CHANNEL] == c4d.BFM_INPUT_MOUSELEFT \
          and msg[c4d.BFM_INPUT_VALUE]:
      
          local_x = msg[c4d.BFM_INPUT_X]
          local_y = msg[c4d.BFM_INPUT_Y]
      
          scroll_y = self.dialog.get_scroll_offset()
      

      I would have to check myself, but there is some inconsistency with which dialogs send mouse input messages regarding the used coordinate system. Sometimes they send messages in the coordinate system of the dialog and sometimes messages in the coordinate system of the gadget. Just print out your (local_x and local_y) and check if the values make sense as local coordinates as you seem to treat them. On GeUserArea are multiple coordinate conversion methods. I think BFM_INPUT in this context is in local user area coordinates but I am not sure, it could also be that you have to convert them.

      The other thing is of course that you add this self.dialog.get_scroll_offset() on top of things. I assume this is sourced by something like GeDialog.GetVisibleArea? There you could also unintentionally mix coordinate systems.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: [GeUserArea] Click detection selects wrong item when clicking on lower part of cell (image + text area)

      Hey @Amazing_iKe,

      thank you for reaching out to us. I cannot execute your code example like this. Please provide an executable example. And as far as I can see, that also seems to be your own code which fails there and not one of our API calls? We cannot debug your code for you. Or is there a specific API call which is failing for you?

      My recommendation would be more abstraction, all this function shuffling especially in the context of GUIs gets really confusing really quick. I would write myself a Grid and a GridItem class which encapsulate the items and their hit logic. What matters also is how you feed def on_click(self, x, y). There are local (e.g. within a user area) and global (e.g., within a dialog or screen) coordinate systems.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Finding, Renaming, and Updating all References to Assets

      Hey @d_keith,

      Thank you for reaching out to us. Please file this request (which I assume is not private) internally, the forum is not the right place for this.

      I am not quite sure what the exact question of yours is :D. GetAllAssets(New) is the middleware for the Project Asset Inspector (PAI) and the backend messages MSG_GETALLASSETS and MSG_RENAMETEXTURES. The latter is not wrapped at all for Python and the former only as an outgoing message. So, GetAllAssets is the 'helper' method used by the PAI to realize all its functionalities you are looking for.

      There was once the thread Get all textures for a material which was in scope very similar to yours. We very recently also had this thread where we talked about how you can abstract away some stuff.

      As always, we cannot debug code for users, so I did not run your code to find potential problems. At first glance it looks okay. I would however recommend to use the flag ASSETDATA_FLAG_MULTIPLEUSE as you will otherwise step over nodes using an already yielded asset. Which you probably do not want to do in your case.

      You are also very broad in your terminology - ' finding & updating all references to assets in a Cinema 4D document'. The rest of your posting seems to be however very focused on textures, while your code then again does not really make an attempt to distinguish what kind of asset you are handling. Documents can contain media (textures, movies, audio), scene data (documents, volumes, xrefs, substances, ies, ...) and font assets. There is also some super exotic internal data you sometimes come along. Not filtering at all what asset data you handle does not seem to be a good idea.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: [API Question] How to List All Parameters in RS Shader Graph Material?

      Hello @writing-qi,

      Welcome to the Maxon developers forum and its community, it is great to have you with us!

      Getting Started

      Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.

      • Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
      • Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
      • Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

      It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: How to Ask Questions.

      About your First Question

      Please familiarize yourself with our support guidelines, your first question is composed out of multiple explicit and implicit questions and also lacks executable code, which makes it rather hard to answer.

      GetDescription() returns parameters but all show "Access Failed"

      There is no such error in our API. I assume you mean an error like this instead: AttributeError: Parameter value not accessible (object unknown in Python).

      The Cinema 4D API is primarily a C++ API and therefore exist data types that simply have not been ported to Python. For example, many objects have the parameters ID_BASELIST_ICON_PRESET_BUTTONS and ID_BASELIST_NODESPACE_ADD_REMOVE_BUTTONS (which are usually hidden) and when you try to access them, it will raise an error, because the respective data types simply have not been wrapped, so the Python API has no idea what to do with the data held by these parameters.

      In Redshift, which started out as a third party plugin and is still an optional feature of Cinema 4D, many data types have never been ported to Python which makes them simply inaccessible. But Redshift usually decomposes their data via channel decomposition. I.e., the parameter for a "Texture" (CUSTOMDATATYPE_RSFILE) itself is not exposed, but its sub channels such as the path, tiling, etc. are. This has been discussed quite a few times before on the forum, for example here.

      What is the correct API to enumerate all parameters in RS Shader Graph?

      Well, descriptions are the tool for that, but descriptions also contain things where you cannot get/set a parameter, either because the data type is not exposed to Python or simply because there is nothing to get and set. The next SDK release will also contain a function called mxutils.GetParameterTreeString which allows you to visualize the sensible parameters of a scene element. But neither it nor c4d.Description.__iter__ will automatically unfold sub-channels. E.g., when you come along a node which has a parameter of type DYTPE_VECTOR at ID_MY_VECTOR_PRAM, the description will yield you a parameter at ID_MY_VECTOR_PRAM but not its sub-channels (ID_MY_VECTOR_PRAM, VECTOR_X), (ID_MY_VECTOR_PRAM, VECTOR_Y), and (ID_MY_VECTOR_PRAM, VECTOR_Z). The same goes for Redshift datatypes, when you come across a parameter of type CUSTOMDATATYPE_RSFILE, e.g., for the 'Image > File' (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0) parameter of an RS Texture node. The description will list the parameter for REDSHIFT_SHADER_TEXTURESAMPLER_TEX0 for that node but not its nested parameters, such as [c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0,c4d.REDSHIFT_FILE_PATH], [..,c4d.REDSHIFT_FILE_LAYER], [...,c4d.REDSHIFT_FILE_COLORSPACE], etc. will not be listed.

      I am afraid there is no abstracted way to solve this in Python. You would need access to the datatype registries which you do not have in Python. And even in the public C++ API, I currently do not see a way to do this. You need access to our internal API to be able to query a data type for the sub-channels it does register.

      But you could of course just hardcode the cases, I have given a small example below for CUSTOMDATATYPE_RSFILE, it is not that much work for one data type. But Redshift did use a lot of custom data types in its old Xpresso system, so wrapping them all could be a bit of work (but should still be doable).

      Cheers,
      Ferdinand

      Output

      For this graph:
      72414249-863b-4c13-8acd-5247941e64b3-image.png

      RS Xpresso Material: <c4d.BaseMaterial object called RS C4D Shader/RS Shader Graph with ID 1036224 at 1819322820416>
      	Found Xpresso node: <c4d.modules.graphview.GvNode object called Shader Graph/XGroup with ID 1001102 at 1818547015360>
      		Parameter 'Icon File / ID'(c4d.ID_BASELIST_ICON_FILE) =
      		Parameter 'Icon Color'(c4d.None) = 0
      		Parameter 'Color'(c4d.ID_BASELIST_ICON_COLOR) = Vector(0, 0, 0)
      		Parameter ''(c4d.ID_BASELIST_ICON_PRESET_BUTTONS) = Inaccessible in Python
      		Parameter 'Name'(c4d.ID_BASELIST_NAME) = Shader Graph
      		Parameter 'Layer'(c4d.ID_LAYER_LINK) = None
      		Parameter ''(c4d.ID_BASELIST_NODESPACE_ADD_REMOVE_BUTTONS) = Inaccessible in Python
      		Parameter 'Enabled'(c4d.ID_GVBASE_ENABLE) = 1
      		Parameter 'Title Color'(c4d.ID_GVBASE_COLOR) = Vector(0.38, 0.384, 0.392)
      		Parameter 'Remark'(c4d.ID_GVBASE_REMARK) =
      		Parameter 'Inputs First'(c4d.GV_GROUP_INPUTS_FIRST) = 0
      		Parameter 'Active'(c4d.GV_GROUP_ACTIVE) = 0
      	Found Xpresso node: <c4d.modules.graphview.GvNode object called Output/Output with ID 1001101 at 1819032444352>
      		Parameter 'Icon File / ID'(c4d.ID_BASELIST_ICON_FILE) =
      		Parameter 'Icon Color'(c4d.None) = 0
      		Parameter 'Color'(c4d.ID_BASELIST_ICON_COLOR) = Vector(0, 0, 0)
      		Parameter ''(c4d.ID_BASELIST_ICON_PRESET_BUTTONS) = Inaccessible in Python
      		Parameter 'Name'(c4d.ID_BASELIST_NAME) = Output
      		Parameter 'Layer'(c4d.ID_LAYER_LINK) = None
      		Parameter ''(c4d.ID_BASELIST_NODESPACE_ADD_REMOVE_BUTTONS) = Inaccessible in Python
      		Parameter 'Enabled'(c4d.ID_GVBASE_ENABLE) = 1
      		Parameter 'Title Color'(c4d.ID_GVBASE_COLOR) = Vector(0.286, 0.329, 0.463)
      		Parameter 'Remark'(c4d.ID_GVBASE_REMARK) =
      		Parameter 'Material ID'(c4d.GV_REDSHIFT_OUTPUT_MATERIAL_ID) = 0
      	Found Xpresso node: <c4d.modules.graphview.GvNode object called RS Material/RS Shader with ID 1001101 at 1819032542400>
      		Parameter 'Icon File / ID'(c4d.ID_BASELIST_ICON_FILE) =
      		Parameter 'Icon Color'(c4d.None) = 0
      		Parameter 'Color'(c4d.ID_BASELIST_ICON_COLOR) = Vector(0, 0, 0)
      		Parameter ''(c4d.ID_BASELIST_ICON_PRESET_BUTTONS) = Inaccessible in Python
      		Parameter 'Name'(c4d.ID_BASELIST_NAME) = RS Material
      		Parameter 'Layer'(c4d.ID_LAYER_LINK) = None
      		Parameter ''(c4d.ID_BASELIST_NODESPACE_ADD_REMOVE_BUTTONS) = Inaccessible in Python
      		Parameter 'Enabled'(c4d.ID_GVBASE_ENABLE) = 1
      		Parameter 'Title Color'(c4d.ID_GVBASE_COLOR) = Vector(0.529, 0.345, 0.333)
      		Parameter 'Remark'(c4d.ID_GVBASE_REMARK) =
      		Parameter 'Version'(c4d.GV_REDSHIFT_SHADER_META_VERSION) = 17
      		Parameter 'Shader Class'(c4d.GV_REDSHIFT_SHADER_META_CLASSNAME) = Material
      		Parameter 'preset'(c4d.REDSHIFT_SHADER_MATERIAL_PRESET) = 65536
      		Parameter 'diffuse_color'(c4d.REDSHIFT_SHADER_MATERIAL_DIFFUSE_COLOR) = Vector(0.5, 0.5, 0.5)
      		Parameter 'diffuse_weight'(c4d.REDSHIFT_SHADER_MATERIAL_DIFFUSE_WEIGHT) = 1.0
      		Parameter 'diffuse_roughness'(c4d.REDSHIFT_SHADER_MATERIAL_DIFFUSE_ROUGHNESS) = 0.0
      		Parameter 'transl_color'(c4d.REDSHIFT_SHADER_MATERIAL_TRANSL_COLOR) = Vector(0.5, 0.5, 0.5)
      		Parameter 'transl_weight'(c4d.REDSHIFT_SHADER_MATERIAL_TRANSL_WEIGHT) = 0.0
      		Parameter 'refl_color'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_COLOR) = Vector(1, 1, 1)
      		Parameter 'refl_weight'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_WEIGHT) = 1.0
      		Parameter 'refl_roughness'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_ROUGHNESS) = 0.0
      		Parameter 'refl_samples'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_SAMPLES) = 16
      		Parameter 'refl_brdf'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_BRDF) = 0
      		Parameter 'refl_aniso'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_ANISO) = 0.0
      		Parameter 'refl_aniso_rotation'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_ANISO_ROTATION) = 0.0
      		Parameter 'refl_fresnel_mode'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_FRESNEL_MODE) = 3
      		Parameter 'refl_reflectivity'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_REFLECTIVITY) = Vector(0.04, 0.04, 0.04)
      		Parameter 'refl_edge_tint'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_EDGE_TINT) = Vector(0, 0, 0)
      		Parameter 'refl_ior3'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_IOR3) = Vector(1.5, 1.5, 1.5)
      		Parameter 'refl_k3'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_K3) = Vector(0, 0, 0)
      		Parameter 'refl_metalness'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_METALNESS) = 0.0
      		Parameter 'refl_ior'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_IOR) = 1.5
      		Parameter 'sheen_color'(c4d.REDSHIFT_SHADER_MATERIAL_SHEEN_COLOR) = Vector(1, 1, 1)
      		Parameter 'sheen_weight'(c4d.REDSHIFT_SHADER_MATERIAL_SHEEN_WEIGHT) = 0.0
      		Parameter 'sheen_roughness'(c4d.REDSHIFT_SHADER_MATERIAL_SHEEN_ROUGHNESS) = 0.30000001192092896
      		Parameter 'sheen_samples'(c4d.REDSHIFT_SHADER_MATERIAL_SHEEN_SAMPLES) = 64
      		Parameter 'refr_color'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_COLOR) = Vector(1, 1, 1)
      		Parameter 'refr_weight'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_WEIGHT) = 0.0
      		Parameter 'refr_roughness'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_ROUGHNESS) = 0.0
      		Parameter 'refr_samples'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_SAMPLES) = 8
      		Parameter 'refr_ior'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_IOR) = 1.5
      		Parameter 'refr_use_base_IOR'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_USE_BASE_IOR) = 1
      		Parameter 'refr_abbe'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_ABBE) = 0.0
      		Parameter 'refr_thin_walled'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_THIN_WALLED) = 0
      		Parameter 'ss_unitsMode'(c4d.REDSHIFT_SHADER_MATERIAL_SS_UNITSMODE) = 0
      		Parameter 'refr_transmittance'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_TRANSMITTANCE) = Vector(1, 1, 1)
      		Parameter 'refr_absorption_scale'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_ABSORPTION_SCALE) = 0.009999999776482582
      		Parameter 'ss_extinction_coeff'(c4d.REDSHIFT_SHADER_MATERIAL_SS_EXTINCTION_COEFF) = Vector(0, 0, 0)
      		Parameter 'ss_extinction_scale'(c4d.REDSHIFT_SHADER_MATERIAL_SS_EXTINCTION_SCALE) = 0.009999999776482582
      		Parameter 'ss_scatter_coeff'(c4d.REDSHIFT_SHADER_MATERIAL_SS_SCATTER_COEFF) = Vector(1, 1, 1)
      		Parameter 'ss_amount'(c4d.REDSHIFT_SHADER_MATERIAL_SS_AMOUNT) = 0.0
      		Parameter 'ss_phase'(c4d.REDSHIFT_SHADER_MATERIAL_SS_PHASE) = 0.0
      		Parameter 'ss_samples'(c4d.REDSHIFT_SHADER_MATERIAL_SS_SAMPLES) = 16
      		Parameter 'ms_amount'(c4d.REDSHIFT_SHADER_MATERIAL_MS_AMOUNT) = 0.0
      		Parameter 'ms_radius_scale'(c4d.REDSHIFT_SHADER_MATERIAL_MS_RADIUS_SCALE) = 100.0
      		Parameter 'ms_mode'(c4d.REDSHIFT_SHADER_MATERIAL_MS_MODE) = 1
      		Parameter 'ms_samples'(c4d.REDSHIFT_SHADER_MATERIAL_MS_SAMPLES) = 64
      		Parameter 'ms_include_mode'(c4d.REDSHIFT_SHADER_MATERIAL_MS_INCLUDE_MODE) = 1
      		Parameter 'ms_color0'(c4d.REDSHIFT_SHADER_MATERIAL_MS_COLOR0) = Vector(1, 0.9, 0.7)
      		Parameter 'ms_weight0'(c4d.REDSHIFT_SHADER_MATERIAL_MS_WEIGHT0) = 1.0
      		Parameter 'ms_radius0'(c4d.REDSHIFT_SHADER_MATERIAL_MS_RADIUS0) = 1.0
      		Parameter 'ms_color1'(c4d.REDSHIFT_SHADER_MATERIAL_MS_COLOR1) = Vector(1, 0.9, 0.7)
      		Parameter 'ms_weight1'(c4d.REDSHIFT_SHADER_MATERIAL_MS_WEIGHT1) = 0.0
      		Parameter 'ms_radius1'(c4d.REDSHIFT_SHADER_MATERIAL_MS_RADIUS1) = 1.0
      		Parameter 'ms_color2'(c4d.REDSHIFT_SHADER_MATERIAL_MS_COLOR2) = Vector(1, 0.9, 0.7)
      		Parameter 'ms_weight2'(c4d.REDSHIFT_SHADER_MATERIAL_MS_WEIGHT2) = 0.0
      		Parameter 'ms_radius2'(c4d.REDSHIFT_SHADER_MATERIAL_MS_RADIUS2) = 1.0
      		Parameter 'coat_color'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_COLOR) = Vector(1, 1, 1)
      		Parameter 'coat_weight'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_WEIGHT) = 0.0
      		Parameter 'coat_roughness'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_ROUGHNESS) = 0.0
      		Parameter 'coat_samples'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_SAMPLES) = 16
      		Parameter 'coat_brdf'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_BRDF) = 0
      		Parameter 'coat_fresnel_mode'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_FRESNEL_MODE) = 3
      		Parameter 'coat_reflectivity'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_REFLECTIVITY) = Vector(0.027, 0.027, 0.027)
      		Parameter 'coat_ior3'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_IOR3) = Vector(1.4, 1.4, 1.4)
      		Parameter 'coat_ior'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_IOR) = 1.399999976158142
      		Parameter 'coat_transmittance'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_TRANSMITTANCE) = Vector(1, 1, 1)
      		Parameter 'coat_thickness'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_THICKNESS) = 0.10000000149011612
      		Parameter 'coat_bump_input'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_BUMP_INPUT) = Vector(0, 0, 0)
      		Parameter 'overall_color'(c4d.REDSHIFT_SHADER_MATERIAL_OVERALL_COLOR) = Vector(1, 1, 1)
      		Parameter 'opacity_color'(c4d.REDSHIFT_SHADER_MATERIAL_OPACITY_COLOR) = Vector(1, 1, 1)
      		Parameter 'emission_color'(c4d.REDSHIFT_SHADER_MATERIAL_EMISSION_COLOR) = Vector(0, 0, 0)
      		Parameter 'emission_weight'(c4d.REDSHIFT_SHADER_MATERIAL_EMISSION_WEIGHT) = 0.0
      		Parameter 'bump_input'(c4d.REDSHIFT_SHADER_MATERIAL_BUMP_INPUT) = Vector(0, 0, 0)
      		Parameter 'depth_override'(c4d.REDSHIFT_SHADER_MATERIAL_DEPTH_OVERRIDE) = 0
      		Parameter 'refl_depth'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_DEPTH) = 3
      		Parameter 'refl_enablecutoff'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_ENABLECUTOFF) = 0
      		Parameter 'refl_cutoff'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_CUTOFF) = 0.009999999776482582
      		Parameter 'skip_inside_refl'(c4d.REDSHIFT_SHADER_MATERIAL_SKIP_INSIDE_REFL) = 1
      		Parameter 'refr_depth'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_DEPTH) = 5
      		Parameter 'refr_enablecutoff'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_ENABLECUTOFF) = 0
      		Parameter 'refr_cutoff'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_CUTOFF) = 0.009999999776482582
      		Parameter 'combined_depth'(c4d.REDSHIFT_SHADER_MATERIAL_COMBINED_DEPTH) = 6
      		Parameter 'diffuse_direct'(c4d.REDSHIFT_SHADER_MATERIAL_DIFFUSE_DIRECT) = 1.0
      		Parameter 'diffuse_indirect'(c4d.REDSHIFT_SHADER_MATERIAL_DIFFUSE_INDIRECT) = 1.0
      		Parameter 'refl_direct'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_DIRECT) = 1.0
      		Parameter 'refl_indirect'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_INDIRECT) = 1.0
      		Parameter 'refl_isGlossiness'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_ISGLOSSINESS) = 0
      		Parameter 'coat_direct'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_DIRECT) = 1.0
      		Parameter 'coat_indirect'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_INDIRECT) = 1.0
      		Parameter 'coat_isGlossiness'(c4d.REDSHIFT_SHADER_MATERIAL_COAT_ISGLOSSINESS) = 0
      		Parameter 'sheen_direct'(c4d.REDSHIFT_SHADER_MATERIAL_SHEEN_DIRECT) = 1.0
      		Parameter 'sheen_indirect'(c4d.REDSHIFT_SHADER_MATERIAL_SHEEN_INDIRECT) = 1.0
      		Parameter 'sheen_isGlossiness'(c4d.REDSHIFT_SHADER_MATERIAL_SHEEN_ISGLOSSINESS) = 0
      		Parameter 'refr_isGlossiness'(c4d.REDSHIFT_SHADER_MATERIAL_REFR_ISGLOSSINESS) = 0
      		Parameter 'decoupleIORFromRoughness'(c4d.REDSHIFT_SHADER_MATERIAL_DECOUPLEIORFROMROUGHNESS) = 0
      		Parameter 'shadow_opacity'(c4d.REDSHIFT_SHADER_MATERIAL_SHADOW_OPACITY) = 0.0
      		Parameter 'affects_alpha'(c4d.REDSHIFT_SHADER_MATERIAL_AFFECTS_ALPHA) = 1
      		Parameter 'block_volumes'(c4d.REDSHIFT_SHADER_MATERIAL_BLOCK_VOLUMES) = 1
      		Parameter 'energyCompMode'(c4d.REDSHIFT_SHADER_MATERIAL_ENERGYCOMPMODE) = 1
      		Parameter 'overallAffectsEmission'(c4d.REDSHIFT_SHADER_MATERIAL_OVERALLAFFECTSEMISSION) = 0
      		Parameter 'refl_endmode'(c4d.REDSHIFT_SHADER_MATERIAL_REFL_ENDMODE) = 1
      		Parameter 'anisotropy_orientation'(c4d.REDSHIFT_SHADER_MATERIAL_ANISOTROPY_ORIENTATION) = 2
      		Parameter 'anisotropy_uvChannel'(c4d.REDSHIFT_SHADER_MATERIAL_ANISOTROPY_UVCHANNEL) =
      		Parameter 'anisotropy_tangentChannel'(c4d.REDSHIFT_SHADER_MATERIAL_ANISOTROPY_TANGENTCHANNEL) =
      	Found Xpresso node: <c4d.modules.graphview.GvNode object called Baked Texture/RS Shader with ID 1001101 at 1819592565952>
      		Parameter 'Icon File / ID'(c4d.ID_BASELIST_ICON_FILE) =
      		Parameter 'Icon Color'(c4d.None) = 0
      		Parameter 'Color'(c4d.ID_BASELIST_ICON_COLOR) = Vector(0, 0, 0)
      		Parameter ''(c4d.ID_BASELIST_ICON_PRESET_BUTTONS) = Inaccessible in Python
      		Parameter 'Name'(c4d.ID_BASELIST_NAME) = Baked Texture
      		Parameter 'Layer'(c4d.ID_LAYER_LINK) = None
      		Parameter ''(c4d.ID_BASELIST_NODESPACE_ADD_REMOVE_BUTTONS) = Inaccessible in Python
      		Parameter 'Enabled'(c4d.ID_GVBASE_ENABLE) = 1
      		Parameter 'Title Color'(c4d.ID_GVBASE_COLOR) = Vector(0.663, 0.624, 0.424)
      		Parameter 'Remark'(c4d.ID_GVBASE_REMARK) =
      		Parameter 'Version'(c4d.GV_REDSHIFT_SHADER_META_VERSION) = 17
      		Parameter 'Shader Class'(c4d.GV_REDSHIFT_SHADER_META_CLASSNAME) = TextureSampler
      		Parameter 'tex0'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0) = Inaccessible in Python
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1000) =
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1010) =
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1011) =
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1001) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1006) = <c4d.BaseTime object at 0x000001A85FC0EDC0>
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1007) = <c4d.BaseTime object at 0x000001A85FC1F440>
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1009) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1003) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1004) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1005) = 30
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1008) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1002) = 0
      		Parameter 'tex0_layername'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0_LAYERNAME) =
      		Parameter 'tex0_colorSpace'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0_COLORSPACE) =
      		Parameter 'tex0_gamma'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0_GAMMA) = 1.0
      		Parameter 'tspace_id'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TSPACE_ID) =
      		Parameter 'mirrorU'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_MIRRORU) = 0
      		Parameter 'mirrorV'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_MIRRORV) = 0
      		Parameter 'wrapU'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_WRAPU) = 1
      		Parameter 'wrapV'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_WRAPV) = 1
      		Parameter 'scale'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_SCALE) = Vector(1, 1, 0)
      		Parameter 'offset'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_OFFSET) = Vector(0, 0, 0)
      		Parameter 'rotate'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_ROTATE) = 0.0
      		Parameter 'color_multiplier'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_COLOR_MULTIPLIER) = Vector(1, 1, 1)
      		Parameter 'color_offset'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_COLOR_OFFSET) = Vector(0, 0, 0)
      		Parameter 'alpha_multiplier'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_ALPHA_MULTIPLIER) = 1.0
      		Parameter 'alpha_offset'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_ALPHA_OFFSET) = 0.0
      		Parameter 'alpha_is_luminance'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_ALPHA_IS_LUMINANCE) = 0
      		Parameter 'invalid_color'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_INVALID_COLOR) = Inaccessible in Python
      		Parameter 'filter_enable_type'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_FILTER_ENABLE_TYPE) = 2
      		Parameter 'filter_bicubic'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_FILTER_BICUBIC) = 0
      		Parameter 'prefer_sharp'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_PREFER_SHARP) = 1
      		Parameter 'mip_bias'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_MIP_BIAS) = 0.0
      		Parameter 'tone_map_enable'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TONE_MAP_ENABLE) = 0
      		Parameter 'default_uv_if_invalid'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_DEFAULT_UV_IF_INVALID) = 1
      	Found Xpresso node: <c4d.modules.graphview.GvNode object called C4D Brick Shader/C4D Shader with ID 1001101 at 1819592570688>
      		Parameter 'Icon File / ID'(c4d.ID_BASELIST_ICON_FILE) =
      		Parameter 'Icon Color'(c4d.None) = 0
      		Parameter 'Color'(c4d.ID_BASELIST_ICON_COLOR) = Vector(0, 0, 0)
      		Parameter ''(c4d.ID_BASELIST_ICON_PRESET_BUTTONS) = Inaccessible in Python
      		Parameter 'Name'(c4d.ID_BASELIST_NAME) = C4D Brick Shader
      		Parameter 'Layer'(c4d.ID_LAYER_LINK) = None
      		Parameter ''(c4d.ID_BASELIST_NODESPACE_ADD_REMOVE_BUTTONS) = Inaccessible in Python
      		Parameter 'Enabled'(c4d.ID_GVBASE_ENABLE) = 1
      		Parameter 'Title Color'(c4d.ID_GVBASE_COLOR) = Vector(0.424, 0.392, 0.541)
      		Parameter 'Remark'(c4d.ID_GVBASE_REMARK) =
      		Parameter 'Width'(c4d.GV_REDSHIFT_BAKER_TEXTURE_WIDTH) = 128
      		Parameter 'Height'(c4d.GV_REDSHIFT_BAKER_TEXTURE_HEIGHT) = 128
      		Parameter 'Depth'(c4d.GV_REDSHIFT_BAKER_TEXTURE_DEPTH) = 0
      		Parameter 'Shader'(c4d.GV_REDSHIFT_BAKER_SHADER) = <c4d.BaseShader object called Brick/Brick with ID 5804 at 1822672588480>
      	Found Xpresso node: <c4d.modules.graphview.GvNode object called file_730884e9656be535~/RS Shader with ID 1001101 at 1819592599488>
      		Parameter 'Icon File / ID'(c4d.ID_BASELIST_ICON_FILE) =
      		Parameter 'Icon Color'(c4d.None) = 0
      		Parameter 'Color'(c4d.ID_BASELIST_ICON_COLOR) = Vector(0, 0, 0)
      		Parameter ''(c4d.ID_BASELIST_ICON_PRESET_BUTTONS) = Inaccessible in Python
      		Parameter 'Name'(c4d.ID_BASELIST_NAME) = file_730884e9656be535~
      		Parameter 'Layer'(c4d.ID_LAYER_LINK) = None
      		Parameter ''(c4d.ID_BASELIST_NODESPACE_ADD_REMOVE_BUTTONS) = Inaccessible in Python
      		Parameter 'Enabled'(c4d.ID_GVBASE_ENABLE) = 1
      		Parameter 'Title Color'(c4d.ID_GVBASE_COLOR) = Vector(0.663, 0.624, 0.424)
      		Parameter 'Remark'(c4d.ID_GVBASE_REMARK) =
      		Parameter 'Version'(c4d.GV_REDSHIFT_SHADER_META_VERSION) = 17
      		Parameter 'Shader Class'(c4d.GV_REDSHIFT_SHADER_META_CLASSNAME) = TextureSampler
      		Parameter 'tex0'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0) = Inaccessible in Python
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1000) = asset:///file_730884e9656be535~.jpg?name=back-2.jpg&db=MaxonAssets.db (assets.maxon.net)
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1010) =
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1011) =
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1001) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1006) = <c4d.BaseTime object at 0x000001A797214AC0>
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1007) = <c4d.BaseTime object at 0x000001A79721BFC0>
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1009) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1003) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1004) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1005) = 30
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1008) = 0
      			Sub-channel parameter (REDSHIFT_SHADER_TEXTURESAMPLER_TEX0, 1002) = 0
      		Parameter 'tex0_layername'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0_LAYERNAME) =
      		Parameter 'tex0_colorSpace'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0_COLORSPACE) =
      		Parameter 'tex0_gamma'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TEX0_GAMMA) = 1.0
      		Parameter 'tspace_id'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TSPACE_ID) =
      		Parameter 'mirrorU'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_MIRRORU) = 0
      		Parameter 'mirrorV'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_MIRRORV) = 0
      		Parameter 'wrapU'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_WRAPU) = 1
      		Parameter 'wrapV'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_WRAPV) = 1
      		Parameter 'scale'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_SCALE) = Vector(1, 1, 0)
      		Parameter 'offset'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_OFFSET) = Vector(0, 0, 0)
      		Parameter 'rotate'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_ROTATE) = 0.0
      		Parameter 'color_multiplier'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_COLOR_MULTIPLIER) = Vector(1, 1, 1)
      		Parameter 'color_offset'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_COLOR_OFFSET) = Vector(0, 0, 0)
      		Parameter 'alpha_multiplier'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_ALPHA_MULTIPLIER) = 1.0
      		Parameter 'alpha_offset'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_ALPHA_OFFSET) = 0.0
      		Parameter 'alpha_is_luminance'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_ALPHA_IS_LUMINANCE) = 0
      		Parameter 'invalid_color'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_INVALID_COLOR) = Inaccessible in Python
      		Parameter 'filter_enable_type'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_FILTER_ENABLE_TYPE) = 2
      		Parameter 'filter_bicubic'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_FILTER_BICUBIC) = 0
      		Parameter 'prefer_sharp'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_PREFER_SHARP) = 1
      		Parameter 'mip_bias'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_MIP_BIAS) = 0.0
      		Parameter 'tone_map_enable'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_TONE_MAP_ENABLE) = 0
      		Parameter 'default_uv_if_invalid'(c4d.REDSHIFT_SHADER_TEXTURESAMPLER_DEFAULT_UV_IF_INVALID) = 1
      

      Code

      """Prints the parameter values of all Xpresso nodes attached to the materials of a document.
      
      Adds custom handling for the Redshift data type `CUSTOMDATATYPE_RSFILE` to unfold its sub-channels.
      
      Note:
          This script requires Cinema 4D 2025.0.0 or higher to run because it uses mxutils.RecurseGraph to
          find all Xpresso nodes in a material. The general approach of this script can however be applied
          to much older versions of Cinema 4D (up to R21 guaranteed, maybe even older versions).
      """
      
      import c4d
      import mxutils
      
      doc: c4d.documents.BaseDocument  # The currently active document.
      op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
      
      # A bunch of data types to step over in descriptions because we do not care about them.
      NO_VALUE_TYPES: list[int] = [
              c4d.DTYPE_BUTTON, c4d.DTYPE_CHILDREN, c4d.DTYPE_CHILDS, c4d.DTYPE_DYNAMIC,
              c4d.DTYPE_GROUP, c4d.DTYPE_MULTIPLEDATA, c4d.DTYPE_NONE,
              c4d.DTYPE_SEPARATOR, c4d.DTYPE_SUBCONTAINER, c4d.DTYPE_POPUP
      ]
      
      def main() -> None:
          """Called by Cinema 4D when the script is being executed.
          """
          # Iterate over all materials in the document, stepping over everything that is not an
           # RS Xpresso material.
          for material in doc.GetMaterials():
              if not material.CheckType(c4d.Mrsgraph):
                  continue
              
              # Iterate over all Xpresso nodes owned by this material. #RecurseGraph is a 2025.0.0+ feature. 
              # You can achieve the same effect with the Redshift API in earlier versions of Cinema 4D. But
              # since you did not share your code, I took this shortcut instead of writing some lengthy code 
              # to find all RS Xpresso nodes for this material.
              print(f"RS Xpresso Material: {material}")
              for node in mxutils.RecurseGraph(material, yieldBranches=True, nodeFilter=[c4d.GVbase]):
                  print(f"\tFound Xpresso node: {node}")
      
                  # Iterate over the description of the node, stepping over all irrelevant data types.
                  description: c4d.Description = node.GetDescription(c4d.DESCFLAGS_DESC_0)
                  data: c4d.BaseContainer
                  pid: c4d.DescID
                  for data, pid, _ in description:
                      if pid[0].dtype in NO_VALUE_TYPES:
                          continue
      
                      # Now we try to access the data at #pid. This can fail because the data type of #pid
                      # might not be accessible in Python.
                      value: any | None = None
                      try:
                          value = node[pid]
                      except:
                          value = "Inaccessible in Python"
                      
                      print(f"\t\tParameter '{data[c4d.DESC_NAME]}'(c4d.{data[c4d.DESC_IDENT]}) = {value}")
      
                      # Hardcode one of the data types (CUSTOMDATATYPE_RSFILE) and unfold its sub-channels.
                      if pid[0].dtype == c4d.CUSTOMDATATYPE_RSFILE and len(pid) == 1:
                          for subChannel in  (c4d.REDSHIFT_FILE_PATH, 
                                              c4d.REDSHIFT_FILE_LAYER, 
                                              c4d.REDSHIFT_FILE_COLORSPACE,
                                              c4d.REDSHIFT_FILE_ANIMATION_MODE, 
                                              c4d.REDSHIFT_FILE_ANIMATION_RANGE_START,
                                              c4d.REDSHIFT_FILE_ANIMATION_RANGE_END, 
                                              c4d.REDSHIFT_FILE_ANIMATION_LOOP_COUNT,
                                              c4d.REDSHIFT_FILE_ANIMATION_FRAME_START,
                                              c4d.REDSHIFT_FILE_ANIMATION_FRAME_END,
                                              c4d.REDSHIFT_FILE_ANIMATION_FRAME_RATE,
                                              c4d.REDSHIFT_FILE_ANIMATION_FRAME_OFFSET,
                                              c4d.REDSHIFT_FILE_ANIMATION_TIMING_MODE):
                              try:
                                  value = node[pid[0].id, subChannel]
                              except:
                                  # This, that the sub-chanel is inaccessible too, can also happen, as the 
                                  # sub-channel could be as much an unwrapped data type as its parent 
                                  # parameter. Technically, a DescID can be composed out of three 
                                  # DescLevel, i.e., you could have a parameter X with N sub-channels
                                  # where each of the sub-channels could also have N sub-channels, e.g.,
                                  # (ID_FOO, ID_SUB_1, ID_SUB_1_1). None of these sub-channels has to use
                                  # a data type that is wrapped in Python. But something like this is 
                                  # rather rare. Parameters where the first desc level is not some kind of
                                  # container (e.g., DTYPE_SUBCONTAINER), usually only decomposes into 
                                  # atomic data types that can also be read from Python. But there is no
                                  # hard guarantee that this is the case.
                                  value = "Sub-channel is inaccessible in Python"
      
                              print(f"\t\t\tSub-channel parameter ({data[c4d.DESC_IDENT]}, "
                                    f"{subChannel}) = {value}")
      
      if __name__ == '__main__':
          main()
      
      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Motion Blur, ExecutePasses in VideoPostData

      Hello @Aaron,

      Thank you for reaching out to us. Please follow our support procedures.

      • You should consolidate your postings until we answer, i.e., update your last posting instead of creating new ones. I have consolidated your postings for you.
      • You should also spend more time on making your problems reproducible for us. I know it can be easy to overlook in the heat of the battle but your question(s) are not as obvious to me as you probably think they are. As lined out in our support procedures, example code and/or scene data is usually required.

      I cannot answer every possible angle and interpretation this topic of yours could take, but I can state three things which come to mind when reading your two postings.

      What's the way to get several steps of motion blur transformation matrices for BaseObjects of the BaseDocument.

      That is simply not possible. A document has no notion of motion blur as it is a render effects implemented by a render engine, not something documents implement. Cinema's time system BaseTime allows for sub-frame accuracy, e.g., you could set a 10fps document to BaseTime(i, 30) and with that step with three sub-frames through the document. Simple things like position animations or other interpolated values will also work doing this. But simulations might yield different results than stepping with the natural frame rate through the document.

      And the most important thing is that there is absolutely no guarantee that this approach will result in 'matrices', i.e., transforms, that will match with what a render engine produces when you add some kind of sub-frame-based motion blur. Using this BaseTime approach is one way how the render engine could do it, but since render engines always have their own scene format, they could also do the calculation there, yielding different results than what Cinema's animation system would yield.

      When we want to add Motion Blur and call document->ExecutePasses(...) for some time then this POC is flushed and has no polygons or vertices, so it's not collected and can't be rendered

      It is too opaque for me what you are doing there to give a real answer, but:

      • There is no guarantee that the caches of an object are built at any point except for when a render engine gets a scene state to render or inside GetVirtualsObjects when you manually build your dependent objcts. Usually, caches are built but depending on where you are, the cache of another object might not have been built or updated yet, resulting in either an empty cache or you looking at the cache output from the previous scene update.
      • ExecutePasses has become a bit too popular tool recently. I guess that is partially my fault, because I have shown its usage in some examples. But executing the passes on a document is a very expensive operation and should only be carried out when absolutely necessary.
      • I would absolutely not be surprised if something like liquids do not support stepping through a document with a frame rate lower than the documents frame rate. But without concrete data and example code I am just guessing.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: How to Modify Button Parameters?

      Hey @Ross,

      Thank you for reaching out to us. You are right, we cannot support third party APIs, but questions about our API do not automatically become moot or out of scope of support, just because they happen in the context of a plugin. We will of course still answer such questions. We will just never write code for a third-party API or test user code that requires a plugin.

      Your question '[I] need help modifying the "Import Type" button parameters of an ImageTexture node' is however ambiguous. A parameter is Cinema 4D slang for an element in a description, one of the ways of how Cinema 4D defines UIs. This includes things that users would naturally call a parameter such as a textbox holding a string, a number edit holding a float, or a combo box holding a selection, i.e., things that hold a value. But it also includes things that are just part of the UI of a node that cannot hold a value, e.g., a group, a separator, or a button.

      • When someone talks about 'modifying' a parameter I would usually assume that they talk about changing the description of a node, specifically at that parameter. E.g., changing the label of a button, adding or removing elements to/from a drop down, disabling an element, etc. You can only do this for nodes you own, i.e., implement yourself. You cannot change the UI of alien elements, because for you their description is read only.
      • But I assume you are actually talking here about getting or setting the parameter of an element, e.g., set a float slider to the value '4.13'.

      What gets a bit in the way here in your case, is that Cinema 4D summarizes everything under the label of paramater, even things that do not naturally have a value which could be gotten or set. So, I assume you want to press this button, for that you have two options:

      • Call c4d.CallButton
      • Send the message c4d.MSG_DESCRIPTION_COMMAND

      Please note that both approaches are restricted to being called from the main thread only when the scene element upon which they are called is part of a loaded scene. E.g., calling one of them on a node in the active document from outside of the main thread: forbidden. Calling them from inside a GetVirtualObjects (or any other off-main thread context) on a scene element in a dummy document which has been constructed just for this purpose and is not loaded by Cinema 4D: absolutely fine.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Script to change parameters across all similar nodes material

      Hey @annoyedUser,

      Thank you for reaching out to us. Your code looks very much like generated by a chatbot or generated with the help of a chatbot. Please note our Support Procedures: Scope of Support regrading the usage of AI. Please also post into the correct forum for future topics, I have moved your topic into the Cinema 4D SDK forum.

      Your code does not make too much sense, I cannot dissect all the issues there. It is possible to do with the Nodes API what you want to do but it is more an API for experts. You can find here some code examples for it. Novice users should rather use graph descriptions which is a less powerful but also simpler API.

      Cheers,
      Ferdinand

      To change the external thickness of each Contour node in a document, you could write something like using a graph description query:

      """Sets the external thickness of all 'Contour' nodes in Redshift material graphs of the active 
      document to 2.
      """
      
      import c4d
      import maxon
      
      doc: c4d.documents.BaseDocument  # The currently active document.
      op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
      
      def main() -> None:
          """Called by Cinema 4D when the script is being executed.
          """
          # Iterate over the material graphs of all Redshift materials in the document.
          for graph in maxon.GraphDescription.GetMaterialGraphs(
              doc, maxon.NodeSpaceIdentifiers.RedshiftMaterial):
              # Apply a graph description to each of them which ...
              maxon.GraphDescription.ApplyDescription(graph, 
              {
                  # ... queries all nodes of type 'Contour' in the graph ...
                  "$query": {
                      "$qmode": maxon.GraphDescription.QUERY_FLAGS.MATCH_ALL | 
                                maxon.GraphDescription.QUERY_FLAGS.MATCH_MAYBE,
                      "$type": "Contour",
                  },
                  # ... so that we can set the thickness value of all matching nodes to 2.
                  "External/Thickness": 2
              })
      
      
      if __name__ == '__main__':
          main()
      
      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: How to get explicit import node space?

      Hey @Dunhou,

      Thank you for reaching out to us. This subject comes up from time to time, and the answer is that you have to eval the description at runtime. I probably should write a more prominent example for that. In case you have already considered this option and deemed it unsafe, there is no safer route.

      Cheers,
      Ferdinand

      """Demonstrates how to evaluate a dynamically built description at runtime.
      
      Things like cycles (Cinema slang for a combo box) are often built at runtime in Cinema 4D. I.e., 
      there is no resource where one could look up all the cycle elements in advance. And this of course
      makes sense, because something like all the installed render engines cannot be known in advance.
      
      The solution to this to evaluate the description of the item at runtime, to figure out what cycle
      index corresponds to which string label. This is of course a bit unsafe, but there is no better way
      for dynamic elements as their defining characteristics is that they do not have a static identifier.
      """
      
      import c4d
      import mxutils
      
      doc: c4d.documents.BaseDocument  # The currently active document.
      op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
      
      def main() -> None:
          """Called by Cinema 4D when the script is being executed.
          """
          # Get the import/export preferences plugin.
          pref: c4d.plugins.BasePlugin = mxutils.CheckType(
              c4d.plugins.FindPlugin(c4d.PREFS_IMPORTEXPORT, c4d.PLUGINTYPE_PREFS))
          
          # Get its description and there the container for `PREF_IMEXPORT_NODESPACE`.
          desc: c4d.Description = pref.GetDescription(c4d.DESCFLAGS_DESC_NONE)
          param: c4d.BaseContainer = mxutils.CheckType(desc.GetParameter(c4d.PREF_IMEXPORT_NODESPACE))
      
          # Get the cycle element in the parameter container and print all values.
          cycle: c4d.BaseContainer = mxutils.CheckType(param[c4d.DESC_CYCLE])
          for i, v in cycle:
              print(f"Cycle element {i}: {v}")
      
          # Build a translation map from string labels to indices. This assumes that there are no exactly
          # identical render engine labels in the cycle. Which is reasonable but not a hard guarantee.
          engineMap: dict[str, int] = {v: i for i, v in cycle}
      
          # Now set the render engine in the settings using a string and a fallback value in case an
          # engine with our string is not present.
          pref[c4d.PREF_IMEXPORT_NODESPACE] = engineMap.get("CentiLeo", 0)
      
      if __name__ == '__main__':
          main()
      
      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Graph Description Explicit Connections can not work in 3rd-renderer (Arnold).

      Hey DunHou,

      the error is a bit different one as I would have expected. It also seems to treat '>output.r' as a reference and not as an ID. I will have to take a look what is going wrong there, this does not look right.

      This could be an edge case of what is also happening for standard. Vectors are not actually exposed data types for which you could find data descriptions in a data description database. So, the information the data type Vector has there components x, y, and z and the datatype ColorA has the components r, g, b, and a cannot be evaluated in this manner. But the Standard renderer has add custom code which decomposes all its color ports into color port bundles of the form Color {r, g, b}. When then the API is caching the graph description lookup, it only sees that outer Color port parent, but not its bundle children {r, g, b} which are added at runtime. Which is exactly why I added validateAbsolutePaths, so that you can forcibly side step the cache. Because even if you use explicit IDs, graph descriptions check under the hood if what you wrote makes sense (to avoid cryptic errors or worse - something failing silently).

      But what is Arnold is doing there is not a port bundle but just four ports next to each other. But maybe they do something similar like Standard where they dynamically create ports at runtime outside of the 'normal' bounds of a variadic port (where dynamic ports are expected and somewhat predictable).

      I will have a look when I have time. What you could do, is check the resource of the Arnold image node in the resource editor. When you cannot see there the r output port, it means it is irregularly added at runtime, and therefore cannot be cached or predicted. Maybe @peter_horvath knows more?

      Or there could of course also just be a bug in how graph descriptions handle explicit output port references.


      Regarding the forum, the errors you have there are 'normal', it is just the emoji plugin of NoddeBB. And you have no notifications at all? I.e., this here?

      ebb40f5a-9ae9-491d-aba9-f3bf641f3213-image.png

      My daily driver is Edge, and there it works on Win, MacOS, and Linux for me. I also checked on Safari and FF and it seems to work there too.

      But these broken notifications are a common NodeBB problem, and are usually tied to dangling sessions. But I have not seen a case as persistent as yours before. You could try to go User Icon > Settings > Three Dots > Login Sessions and there manually revoke all your sessions.

      On top of that you can try to either completely delete the browser cache for developers.maxon.net or just force the site rebuilding it py pressing CTRL + F5 or similar key combos.

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Updated Redshift node material examples

      Hey @Dunhou,

      without having run your script, the answer lies probably in the posting above. The Nodes API allows you to manipulate the undo stack in a special way with the settings for the transaction (there is also a maxon.nodes.UNDO_MODE.NONE). And Graph descriptions do not expose these settings, I agree however that it would be a nice feature for experts to expose them. I added a little task to expose them.

      Currently there is probably not much you can do about it in an elegant way. What you could try to do, is just carry out the description, then call BaseDocument.GetUndoPtr, copy it, undo things, then open your own undo item, do the stuff you want, and replace the material with the result from BaseDocument.GetUndoPtr, and close the undo item. So that 'your stuff' and the graph transaction are consolidated in one undo item. But there is a lot which could go wrong here, especially with the Nodes API which does quite a bit of dark magic under the hood.

      Cheers,
      Ferdinand

      posted in Bugs
      ferdinandF
      ferdinand
    • RE: Graph Description Explicit Connections can not work in 3rd-renderer (Arnold).

      Hey @Dunhou,

      You are talking about the "#<multiply -> #>output.r" part, right? What is the error output of the ApplyDescription call? Graph descriptions are usually very verbose in what is going wrong and tell you why something is not working.

      Have you tried absolute (i.e., non-lazy) paths and turning off validateAbsolutePaths with that you can basically force graph descriptions to always work in the addressing part, because it completely turns off all cache evaluation. I never tested graph descriptions with Arnold, it could be that they do something super unusual with their nodes, but at face value that image node looks pretty normal.

      As you know third party APIs are formally out of scope of support, and checking this will take some time. But I will try to give it a look, but this will only be post release, as I currently absolutely blasted with work, and I would first also have to request a license, as we do not have Arnold licenses out of the box in our SDK software pool. So, this would probably happen around end of September. Please tell me explicitly if you will need help or not with this.

      btw: The notification and sorting of the forum have not been fixed yet. I have also tested it on a new computer and browser

      In what capacity? Have you tried resetting your browser cache? That sounds all bit mysterious. What happend with the forum rollback, is that all the nodebb sessions were invalidated. But that should have rectified itself the latest after seven days. Can you show us your console output?

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: BaseBitmap.Init("somefile.exr") crashes with multiple std::thread

      @Aaron said in BaseBitmap.Init("somefile.exr") crashes with multiple std::thread:

      When I replace std::thread to omp #parallel for the result is the same

      I am not quite sure what 'omp #parallel' is supposed to be? maxon::ParallelFor? Unless it was unclear, there is of course the possibility that BaseBimtap::Init is in principle not thread safe, at least in the context for the EXR bitmap loader (as a general statement that is for sure not true). But gereally without having had a closer look, that strikes me as less likely.

      I honestly think that BaseBitmap.Init() should be local and independent function from any other C4D infrastructure.

      We do not support std and this unfortunately cannot change. That we do not support std is a not a 'oops, now it is like this' thing but a deliberate decision. Because not all compilers always support the entirety of std and std does not always behave the same with all compilers. So, we will never deliberately move towards std.

      When you do not want to drop your std thread, you can try to assimilate it as I linked to in my first posting. But there is then still no guarantee that this will work. BaseBimtap is also a Cinema API entity, and just an adapter for ImageInterface from the Maxon API. You can always access the underlying ImageRef for a BaseBitmap, but without copying data, you cannot construct a BaseBitmap for an existing ImageRef.

      Our Image API is very abstracted and aimed at parallelization under the hood. So, what you are trying to do, should be possible in principle, unless there is somewhere a bug or design decision in the EXR loader that makes it not thread safe.

      You seem insistent on using std::thread and possibly std in general. As lined out before, I understand that there can be scenarios where it is at least not so easy to move away from std for third parties, but it is simply not supported in our API. When you do not absolutely need std, you will do not do yourself any favours by keep using it. When you still have issues with this, please provide a short compileable code example. I will then have a look (but it might take some time, as we are in the midst of release preparations, and I am quite busy).

      Cheers,
      Ferdinand

      edit: please also provide some sample images then, because there is no guarantee that this will happen with all images.

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Knowing if a font exists

      Hey @datamilch,

      Thank you for reaching out to us. We recently had a very similar topic, where I gave an answer which is probably also relevant for you.

      In short, GetFontDescription is one of the ways to do this. What I would absolutely advise against, is browsing all font data to look for your font, because that can be very slow.

      The approach I showed in the linked topic requires that you can accurately predict the name of a font. E.g., predict that the font you are looking for will have the postscript name "ArialMT-Regular". This stands in contrast to just browsing all font data - for example via EnumerateFonts - and then checking one by one if one of the font labels contains the string "Arial". This latter approach will be very slow, because these browse functions all load the actual fonts to access their meta data.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: BaseBitmap.Init("somefile.exr") crashes with multiple std::thread

      Hey @Aaron,

      I appreciate efforts to keep example code short. I just point out things where I see them. The memory leak is only a minor aspect, which is why I brought it up last. More problematic is that you lean so much into the std library. That will always cause issues when you are not very careful. I short, you can effectively only use parts of std that are noexcept, and even then you can run into problems, as things might work on one OS but not another.

      MISC_ERROR is unfortunately a very generic error, as it gets generated like this:
      5878aa52-d066-42bd-9be6-7602445c21fd-image.png

      So, this hints at a more fundamental issue, as for example a locked file handle or the OS somehow intervening. You should keep in mind that not all file IO operations are thread safe. E.g., read access to the same file form multiple threads can be non-thread safe. But an SSD can still only read things one by one, so unless your data is already cached, the pure reading cannot be threaded. When you are loading many 8k 32bit EXRs (~570 MB a piece), then you could look easily at multiple seconds of disk IO with a modern NVMe SSD (Gen 4 or 5).

      What can be of course threaded and makes sense, is the deserialization of the data on disk, which I assume is your goal here. But does the actual deserialization of EXR images really take that long?

      But without concrete code of what you are doing and example data I cannot help you. From what I understand, you currently have multiple threads and just make them wait for each other by using a semaphore? Which probably means that you do not want to use threads to speed up reading, but just happen to have to read from multiple threads?

      C4DThread is a very ancient threading mechanism in our API (which is in fact deprecated). The Maxon API has more modern threading mechanisms. You could for example use a jobs group to read your images one by one in a job group and do this from one to many threads.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: BaseBitmap.Init("somefile.exr") crashes with multiple std::thread

      Hey @Aaron,

      Thank you for reaching out to us. You cannot use std in Cinema 4D projects, it is at least is strongly discouraged. All modules (i.e., plugin binaries) have by default exception handling disabled, so std code can easily lead to undefined behaviour. Your code is very non-conformant to the Cinema API (raw arrays, printf, manual heap allocation, std). Unless I am overlooking something, I would also say that your code leaks, because you heap allocate t[i] but never free it.

      You can technically turn exceptions on again in our project configurations, but there is a reason why Cinema 4D avoids this (primarily - exceptions are slow). There are some modules/frameworks which have exceptions enabled and which use std (e.g., the misc.framework). But we are then usually very particular in how we use std.

      It is also important that you use our threading system, or at least wrap alien threads. When you want to use our types such as BaseBitmap or functions like IO, you must use our threads.

      ... however some bitmaps are not read correctly and return err codes ...

      Well, without the errors and the concrete code I cannot help you much. I would probably also need the exact files which fail.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: String to Spline (cast)

      Hey @Kantronin,

      Thank you for reaching out to us. Unfortunately, I do not understand your question. The print out you provided, <c4d.SplineObject object ..., already indicates that the object is a c4d.SplineObject. So, I do not really understand what you mean with 'get a spline-type variable'. To get the underlying editable spline object for a spline generator, e.g., get a spline with editable vertices and tangents for a Flower Spline generator, you should use BaseObject.GetRealSpline. But that is only necessary when you have a BaseObject which under the hood represents a spline. It does not apply when you already have a SplineObject as you do.

      Cheers,
      Ferdinand

      posted in General Talk
      ferdinandF
      ferdinand
    • RE: Bundle fonts with Cinema 4D submissions

      Hey @karthikbp,

      that is because other than in C++, the documentation of some symbols is not automated in Python (the definition is). So, we simply forgot to update the doc file for this flag when it was introduced. I already fixed that when I wrote the answer above, in the next doc update it will be included.

      And as I said, the symbol is a 2024.0.0 feature, you can always check the C++ docs to confirm something like this. So, in 2023.2 and lower, neither the flag nor the feature will exist. To use this flag client sided, you would have to check the Cinema 4D version the user is running.

      ⚠ Work on the Project Asset Inspector (PAI) spanned over a good part of 2024. I do not think that we would add symbols without them being functional. But to be sure, I would grab a 2024.0.0 release and check if it does what you expect it to do, when using that symbol.


      While I understand the direction you are coming from, I still think you are heading a bit in the wrong direction. And I understand that you want and have to solve that problem, but the angle you are taking is in my opinion not the right one.

      When I wrote my first answer here, my first reaction was like yours - 'why is this not working?'. But then I realized the technical complexity of grabbing a font from one system and providing it - possibly over OS boundaries - on another system. I also briefly talked with one of the PAI developers and one concern they also seem to have is copyright issues (as fonts are often licensed). But there is a complex discussion to be had if we still plan to add features there and what the recommended workflows are right now. You can only answer these with end user support and the beta community.

      I personally would just go the route I hinted at above. Just scan the scene for missing fonts and then emit a warning. You could then give the user the option to use a replacement font, upload a font, or to discretize the font object (at the risk of losing animation, mograph, or simulation data). When you absolutely have to work client sided, you would either have to limit the feature to 2024+ clients or write something yourself which abstractly searches for such scene elements (note that the mxutils scene traversal tools are a 2025.0.0 feature, so you cannot use them too - but you could use something inspired by their code). You then would have to provide a hardcoded list of fonts supported by your server/render node. The middle ground would be something more complex where you evaluate client sided, and then ask the server if 'these' fonts are supported.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Bundle fonts with Cinema 4D submissions

      Hey @karthikbp,

      Which leads me to wonder if we can convert all the text objects into editable before submission through code [...]

      In general, I would say that this is not a feasible route. First, collapsing ('current state to object' in Cinema slang) things destroys animations. I.e., if a Text Object had an animated height, you would lose that data. And secondly collapsing things can also mess with your scene structure as text objects and splines can be influenced on a by character basis by fields, effectors, and materials.

      The article mentioned that if we need to keep the text objects "procedural" we need to install the fonts.

      I am sorry, I cannot read and answer end user articles. As I said, this is an end user question not an API question. Please contact end user support about their material. My hunch would be that they just misspoke here, were a bit informal, and meant that when you want to keep the objects as generators (the proper term for procedural geometry in Cinema 4D), you must install the font for the scene to work.

      An alternative route could be to bring up this subject in our beta community (I assume you already have access). This is an end user subject, and how to handle this or if we plan on adding features there, would have to be solved by customer support or our beta community.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Bundle fonts with Cinema 4D submissions

      Hey @karthikbp,

      Thank you for reaching out to us. Here are sort of two questions layered into one.

      Could c4d.documents.GetAllAssetsNew() help with this?

      Yes, fonts are also recognized as assets (a relatively new feature). You need the flag ASSETDATA_FLAG_WITHFONTS to get them yielded as assets.

      How to export scenes with fonts as assets?

      This is effectively not SDK domain but an end-user question. But you are right, when I export my scene from above as 'Save Project with assets ...'. I end up with a folder that holds my scene but not the font.

      But for me this makes sense, as fonts are often deeply integrated into systems and not fully transferable between OS's. In my case, Cinema 4D would have to rip the Roboto Condensed font out of my /Windows/Fonts directory (where the actual Roboto Condensed.ttf is then buried in the Roboto font collection). On the other side, on a target system, Cinema 4D would have to install that font with OS appropriate system. That strikes me as asking for quite a bit to be automated.

      What you can do, is use GetAllAssetsNew to scan the scene for font data and then try to match that with system data, to either reject a scene (when there are missing fonts) or overwrite that parameter with a new font.

      Cheers,
      Ferdinand

      Output

      d6e854ab-2ffd-4580-967d-1ba6685f2a9b-image.png

      You need beta access and have to uncomment the mxutils.GetContainerTreeString calls to get this exact output. The general approach will work in all versions of Cinema 4D.

      Code

      """Scans the active document for font assets and prints their details, and tries to find a matching
      installed system font.
      """
      
      import c4d
      import mxutils
      
      doc: c4d.documents.BaseDocument  # The currently active document.
      op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
      
      def main() -> None:
          """Called by Cinema 4D when the script is being executed.
          """
          assets: list[dict[str, any]]=[]
          c4d.documents.GetAllAssetsNew(doc, False, "", c4d.ASSETDATA_FLAG_WITHFONTS, assets)
      
          for asset in assets:
              pid: int = asset.get("paramId", c4d.NOTOK)
              owner: c4d.BaseList2D | None = asset.get("owner", None)
              if pid == c4d.NOTOK or owner is None:
                  continue
              
              # There is no super good way to check if an asset is a font asset, so we check the type of 
              # the parameter value. If it is a FontData, we assume it is a font asset.
              value: any = owner.GetParameter(pid, c4d.DESCFLAGS_GET_NONE)
              if not isinstance(value, c4d.FontData):
                  continue
              
              name: str = asset.get("assetname", "")
              font: c4d.BaseContainer = value.GetFont()
              print(f"Font asset: {name} (ID: {pid})")
      
              # mxutils.GetContainerTreeString is a beta feature not available in 2025.3.1 or lower. When
              # you have beta access, you can uncomment the next line to print the font container.
      
              # print(f"Font data found in scene:\n{mxutils.GetContainerTreeString(font)}")
              
              # There is quite a bit of hand-wavy stuff going on here. I figured out the font data 
              # container ID 508 by using the 2026.0.0 feature mxutils.GetContainerTreeString. There seem
              # to be no symbols for these IDs, at least I couldn't find any. 508 is where the container
              # stores the PostScript name of the font, e.g. "ArialMT-Regular".
      
              # Try to get a system font with the PostScript name of the font asset. When we find a match,
              # it means the font is installed on the system.
              bc: c4d.BaseContainer | None = c4d.bitmaps.GeClipMap.GetFontDescription(
                  font[508], c4d.GE_FONT_NAME_POSTSCRIPT)
              if not bc:
                  print(f"{font[508]} is not a system font.")
                  continue
              
              # print(f"Matched with system data:\n{mxutils.GetContainerTreeString(bc)}")
      
      if __name__ == '__main__':
          main()
      
      posted in Cinema 4D SDK
      ferdinandF
      ferdinand
    • RE: Is There a Python API Equivalent to "Make Preview" for Batch Animation Previews with Custom Output Path?

      Hey @Amazing_iKe,

      Thank you for reaching out to us. That RenderDocument does not support animations is only partially true. Effectively it does not for users, but that is more a regression than the lack of an actual feature. When you look into its documentation, you will see that many symbols and arguments are animation related. And when you send it a document which holds an animation, you are paying the price for rendering the full animation. The regressed state is however that you effectively only have access to the bitmap of the last frame of that animation. There is also the issue that the OCIO workflow with RenderDocument is a bit clunky at the moment. We have these issues in our backlog by I unfortunately cannot make any guarantees as to when we will fix them.

      You have two options:

      • Render the document frame by frame yourself with RenderDocument and then assemble the animation yourself.
      • Use the BatchRender, i.e., what is shown to the user as the render queue. You can use this in a fully programmatic manner, but you are restricted to rendering documents that have been saved to disk, and the output will also be put to disk. I.e., you do not have the 'memory only'-aspect of RenderDocument. There are many topics about this subject on this forum, for example here where I showed how you abstract some of the disc-only limitations aways. Maxime also recently added some features to the batch render like switching cameras and takes, which makes it less likely that you have to modify the file.

      I cannot write examples for all possible routes here. You have to decide yourself which route you want to go, and when you are then stuck there, I will help you. What to pick depends on your goals. When you expect the renderings to be quick, doing it manually with RenderDocument could be a solution. For more complex animations, the batch renderer is probably the better route.

      Cheers,
      Ferdinand

      posted in Cinema 4D SDK
      ferdinandF
      ferdinand