• Vertex Map Tag not in sync error

    python 2024 windows
    3
    1
    0 Votes
    3 Posts
    600 Views
    D
    Hi Ilia, Thank you very much, I was not aware of that! Cheers!
  • Global static classes?

    c++
    4
    0 Votes
    4 Posts
    617 Views
    ferdinandF
    As I said, you will run into access violations when you instantiate your fields on the class instead of the Init function. And as I also said, in your concrete case it would probably even be fine if you would directly do it in the class scope. But I would advise against breaking this rule. There is nothing to optimize here, either return a new instance when this is only called once in a blue moon and you do not want to bother with initializing a field. Or define a field and initialize it up in NodeData::Init. And no, scene elements (NodeData) should not share data on their class. We have types in the Maxon API to deal with this when you really want some heavy data structure which shall be initialized exactly once, but that is total overkill in this case. Cheers, Ferdinand
  • Refresh viewport after updating RenderData width and height

    windows python
    8
    0 Votes
    8 Posts
    1k Views
    S
    Hello @ferdinand ! Thanks for answer it is very clear, i will use virtual resolution from now on
  • Correct OCIO Color Value Conversion via Python?

    windows python 2024
    3
    0 Votes
    3 Posts
    539 Views
    B
    Hey Ferdinand, Thank you for the quick response! Ah ok I see. Thank you for the provided information, I will have a look at it. But I can also wait for the moment. My work arround for now would be to simply set everything up / import the parameters and colors with color management set to 'Basic' and manually doing the conversion via 'Convert to OCIO' in the Project settings. Thats giving me the correct result. But thanks again! Cheers, Ben
  • Programing a Tabulated BRDF Node / Shader - possible ?

    2024
    6
    1
    0 Votes
    6 Posts
    948 Views
    ferdinandF
    Hey, Out of curiosity, I did some poking in Redshift, and what I forgot, is that you are in principle unable to escape the current shading context of a sample in Redshift. I.e., you cannot just say, "screw the current UV coordinate, please sample my texture 'there'" due to the closure thing which Redshift has going. With the Standard Renderer, you can do the following, which is pretty close. I compute the v (i.e., view angle coordinate) as described above. Standard also does not give you directly light ray angles, but you can get the light contribution where I use the diffuse component of the light(s) as a faksimile: High diffuse = high angle of incident/light contribution. [image: 1730128355045-82ee51e1-15a9-487b-8cb0-91eec633352e-image-resized.png] Fig. I: A crude iridescence setup in Standard. test.png is your texture from above, I forgot to take the inverse of values as 1 - x. view_angle.zip In Redshift you cannot do the same light contribution hack, and I currently do not see how you could set the sampling coordinate of the texture in the first place. Maybe the Redshift pro's know more. Cheers, Ferdinand
  • Hide Items (Object Plugin)

    2024 python
    3
    0 Votes
    3 Posts
    589 Views
    R
    @m_adam Thanks, I await your info. Have a nice weekend
  • Get MODATA_SIZE of Mograph Particles to Build Stacks of Geometry

    python sdk
    13
    1
    0 Votes
    13 Posts
    2k Views
    ferdinandF
    No worries, everything is fine, that is what we are here for, to clear up things. When you have questions I encourage you to open a new thread so that we can see what we can do. And this is also an open forum, so you can ask questions to the community if you want to. But unless pointed out specifically otherwise, we assume things to be support requests. Cheers, Ferdinand
  • MacOS C4D Python app questions

    python macos
    4
    0 Votes
    4 Posts
    704 Views
    ferdinandF
    Good to hear. When you want to know more about how to expose libraries, I would recommend reading the Python Libraries Manual, as there are quite a few differences to a vanilla CPython. The guide is a little bit dated, I haven't updated it yet to the pip support Maxime is adding, and I also did not yet cover there mxutils.LocalImportPath. Cheers, ferdinand
  • Development requirements for C4D 2025

    c++ macos
    10
    0 Votes
    10 Posts
    3k Views
    ferdinandF
    Dear development community, just as a clarification, as I was not very clear about that above. We are working on a solution for the build system for the SDK (as I hinted at before in other postings). But for 2025 we will stay with this a bit cumbersome legacy build system solution for macOS. Please excuse the inconvenience but there are a few more moving parts in the background than it is obvious from the outside (to fix this, we must move away from the project tool). Cheers, Ferdinand
  • BaseBitmap Save TIF with LZW and save EXR using ZIP

    2024 c++ windows
    4
    0 Votes
    4 Posts
    650 Views
    ferdinandF
    Hey Kent, it depends a bit on the context. Generally, yes, flags and parameters passed to a BaseBitmap are piped through to the underlying ImageRef. But as I hinted at with the TIF settings for BaseBitmap::Save, some stuff is also ignored. For fundamental stuff like initializing a bitmap with a channel depth, color format, etc., I am not aware of cases where flags are being ignored. But as I wrote in my pseudocode example, the exact nature of the BaseBitmap::GetImageRef is also quite important. My very high level advice would be, use the Maxon Image API directly for simple things like loading, color converting, or saving an image, but avoiding it for complex tasks like for example assembling a multi layer image or drawing (not possible at all in the public API apart from 'dumb' pixel by pixel drawing). The problem with this is that when you must have a BaseBitmap output. Because while you can get an ImageRef from a BaseBitmap instance, there is no 'sane' public way to construct a BaseBitmap from an ImageRef you can of course copy over the buffer manually (not so sane) and there is a private way to do this but has its pitfalls (but is possible to do with the public API). As I said, I would invite you to reach out to us with some code and a concrete use case when you get stuck, I will then be able able to help you specifically. Cheers, Ferdinand PS: We recently dropped the term 'classic API' in favour of 'Cinema API'. We also capitalize now 'Maxon API'. Just saying this for clarity.
  • Help with C4D Preferences Plugin Installation/

    python 2024 2023
    2
    0 Votes
    2 Posts
    596 Views
    ferdinandF
    Hello @qq475519905, Thank you for reaching out to us. Your question is very ambiguous. But given your posting history, I assume this is a development question and not an end user question. I.e., you are a developer who struggles with setting up a plugin which is being loaded, and you are not a user struggling with installing someone else's plugin (the latter would be out of scope of support for the developer forum). We have plenty of Python plugin examples on Github, for anything more concrete, we will need a more concrete question from you. Most importantly executable example code which highlights your problem. Please have a look at Support Procedures: How to Ask Questions. Cheers, Ferdinand
  • Dissipating fog volume

    python
    2
    0 Votes
    2 Posts
    410 Views
    ferdinandF
    Hey @ops, Thank you for reaching out to us. Please excuse the delayed reply. You must use the c4d.modules.volume.VolumeBuilder interface for what you want to do, specifically its GetInputObject method. You have to understand that a volume builder is not a singular object, but a virtual tree of objects, and most parameters are located on one of these child objects. Cinema 4D then only displays the parameters of the child objects inline in the GUI (i.e., description) of the Volume Builder object. [image: 1729163133931-5b76e06e-da90-4205-9e68-3e0ca7d14e8f-image.png] Fig.I: The internal makeup of a Volume Builder object. The virtual hierarchy in form of Volume Filter is inaccessible both via the Object Manager and things like GeListNode.GetChildren(). Instead we must use the dedicate UI and API interface to access them. Cheers, Ferdinand Code """Sets the new min and max values of a Volume Builder fog range object. Must be run as a Script Manager script with a Volume Builder object selected. """ import c4d doc: c4d.documents.BaseDocument # The currently active document. op: c4d.BaseObject | None # The primary selected object in `doc`. Can be `None`. #: The volume builder fog range object type. We currently do not expose a symbol for this. c4d.Ofograngemap = 1039862 def main() -> None: """Called by Cinema 4D when the script is being executed. """ if not isinstance(op, c4d.modules.volume.VolumeBuilder): raise ValueError("The selected object is not a Volume Builder.") # Iterate over the objects in the Volume Builder 'Objects' parameter list. for i in range(op.GetInputObjectCount()): node: c4d.BaseList2D | None = op.GetInputObject(i) # Can happen for folders and on failure, there is no good way to distinguish between the two. if node is None: continue # This is a fog range object, we could do here further checks to ensure it is the correct one. if node.GetType() == c4d.Ofograngemap: print(f"{node[c4d.ID_VOLUMEFILTER_SDF_REMAP_NEW_MIN] = }") print(f"{node[c4d.ID_VOLUMEFILTER_SDF_REMAP_NEW_MAX] = }") # Set new values. node[c4d.ID_VOLUMEFILTER_SDF_REMAP_NEW_MIN] = 0.5 node[c4d.ID_VOLUMEFILTER_SDF_REMAP_NEW_MAX] = 2.0 # Push an update event to Cinema 4D to refresh the user interface. c4d.EventAdd() if __name__ == '__main__': main()
  • 0 Votes
    4 Posts
    814 Views
    ferdinandF
    Oh, my bad, I did overlook that you flagged this as S26. Yes, mxutils is a 2024+ feature. I used it here to carry out type checks, e.g., that a document or bitmap are not null/none. The code will run without them, but it will fail more gracefully with these checks. You could replace these calls with manual checks: bmp: c4d.bitmaps.BaseBitmap = c4d.bitmaps.MultipassBitmap( int(rData[c4d.RDATA_XRES]), int(rData[c4d.RDATA_YRES]), c4d.COLORMODE_RGB)) if bmp is None: # or more precise: if not isinstance(bmp, c4d.bitmaps.BaseBitmap) ... raise MemoryError("Failed to allocate bitmap.") Cheers, Ferdinand
  • Hide port from input menu in the Node Editor

    c++
    3
    1
    0 Votes
    3 Posts
    658 Views
    P
    Thanks for looking into it @m_adam. Maybe this is specific to Arnold, but there are shader parameters that are not linkable. It's a flag on the parameter. Typically, boolean and enum type parameters are not linkable, like the ones highlighted in the screenshot below. But could be any parameters really, depending on the shader code. [image: 1728997153428-7fe9bc40-5f47-4e10-aede-a7fe0fb0331e-image.png]
  • How to compare a port value has been changed?

    windows python 2024
    8
    0 Votes
    8 Posts
    1k Views
    DunhouD
    Wow @m_adam , thanks for that, I'll check this after work!
  • GeUserArea.GetDragObject() for xpresso node

    python
    4
    0 Votes
    4 Posts
    642 Views
    ferdinandF
    Hey everyone, Just as an FYI: cinema::GvCopyBuffer is not a public type. Just saying this so that future C++ users do not run against a wall here. One might be able to wiggle through with a forward/dummy deceleration of GvCopyBuffer, but officially this is not supported in the public C++ API either. And we therefore cannot provide forum support for this in C++ either. Cheers, Ferdinand
  • 0 Votes
    4 Posts
    822 Views
    O
    And that's good to know about using GetMl() over Get Mg(), mainly for the performance reasons if I understood correctly.
  • SetPortValue for Texture node ColorSpace

    python 2024 windows
    3
    0 Votes
    3 Posts
    675 Views
    M
    Thank you so much, this was very helpful to learn. All the best.
  • Render depth map using python

    python
    3
    0 Votes
    3 Posts
    521 Views
    G
    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() )
  • Input port menu in Node Editor does not respect order index

    c++
    4
    1
    0 Votes
    4 Posts
    656 Views
    ferdinandF
    Hey Peter, you can reach out directly to us via mail. While there is some end-user aspect in this, I think it is best handled by SDK. But thanks for asking and caring about submitting to the right place! I will forward your mail/request to the right places. But as hinted at above, I do not see the Node team being all thrilled about this. Maybe also make the case why this is needed as making the case for something usually increases your chances compared to a "I want X"! Maybe also line out how you envision for this to work. E.g., request to introduce an attribute which can be set on port bundles. As for example maxon::DESCRIPTION::UI:NOSORT which is then respected by BuildPopupMenuForDescription. What we very likely will not do, is that we completely turn this off, as both Scene Nodes and Redshift have a lot of data types with many sub ports where it will be hard to find things without alpha-numerical sorting. I could be wrong about all this as I am neither in the Nodes nor Redshift team, but that is the hunch I have when I look at this system. Cheers, Ferdinand