Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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
    • Recent
    • Tags
    • Users
    • Register
    • Login
    1. Maxon Developers Forum
    2. Popular
    Log in to post
    • All Time
    • Day
    • Week
    • Month
    • All Topics
    • New Topics
    • Watched Topics
    • Unreplied Topics

    • All categories
    • ThomasBT

      Thread safety when handling CTrack in TagData.Message() on button click

      Watching Ignoring Scheduled Pinned Locked Moved Cinema 4D SDK 2026 python windows
      13
      0 Votes
      13 Posts
      184 Views
      ferdinandF
      @ThomasB Reproduction steps just refers to what you do in the GUI as an end user (switch to modeling layout, press play, ...). Do not include any API information, imagine you are someone who knows nothing about our APIs. And if we have or have not your plugin is irrelevant for the report, just state what you do.
    • DunhouD

      How to export icons of asset

      Watching Ignoring Scheduled Pinned Locked Moved Cinema 4D SDK python 2026 2024
      8
      0 Votes
      8 Posts
      151 Views
      DunhouD
      Hey @ferdinand , Sorry I forgot click Submit button well, that is the info I need, I use same tech to get icons for CMD, and now waiting for svg part in the future. Cheers~ DunHou
    • T

      Reverse direction of multi-segment splines

      Watching Ignoring Scheduled Pinned Locked Moved Cinema 4D SDK windows 2024 python
      6
      0 Votes
      6 Posts
      115 Views
      ferdinandF
      Okay, I think I was a bit overly cautious in my answer here. You gave my a very broad question, or to be precise, you gave me a video and a scene file, and did not really ask a precise question. I understand that asking good questions can be hard, especially with a language barrier. But when I have nothing to go by, I of course assume the worst case possible. The scene you have there is a trivial case, even the best case possible. You have there spline segments which lie in a perfect plane and which have no self intersections. You can treat them just like polygons (in the CG sense, not in the mathematical sense) and simply compute their normal over the first three vertices of each segment. Due to the fundamental property of a polygon - reversing the order of the vertices reverses the normal - you can then easily determine if two segments have opposite or equal winding. But all this starts to fall apart, as soon as you cannot make these assumptions. And I cannot help you to write the code for this, as this is then more than just a few lines. Hope this helps, and that I my answer was now less 'overly cautious'. Cheers, Ferdinand Result [image: 1780950951310-85f415e7-7f45-4c00-9651-b4091ee543e2-image.png] The code correctly identifies that in this six segment spline are four segments of one winding direction (clockwise in this case) and two of the other winding direction. winding_direction.c4d Code """Treats spline segments as polygons and compares their plane normals to find segments with reversed winding order. """ import c4d op: c4d.SplineObject # The currently active object in the scene. def main() -> None: """Called by Cinema 4D when the script is being executed. """ if not isinstance(op, c4d.SplineObject): return c4d.gui.MessageDialog("Please select a spline object.") # Get all points in the spline and organize them into their segments. points: list[c4d.Vector] = op.GetAllPoints() segments: list[list[c4d.Vector]] = [] j: int = 0 for i in [op.GetSegment(i)["cnt"] for i in range(op.GetSegmentCount())]: segments.append(points[j:j+i]) j += i if len(segments) < 2: return c4d.gui.MessageDialog("Please select a spline object with at least 2 segments.") # Now build normal data for the spline segments. This assumes: # # - A spline where all points lie in a single plane, a '2D' spline in 3D space. # - No self intersections in the spline. # - A piecewise linear spline, i.e., what Cinema 4D calls a 'Linear' spline. When we have a # 'Cubic' or 'Bezier' spline, we would have make it linear with 'Current State to Object' # first. # # We build the normal for each segment over its three first vertices. The reason why we are doing # this is because of the fundamental identity of a polygon (in a computer graphics sense), # reversing the order of the vertices of a polygon will reverse the normal. So if we have a # spline with two segments with reversed winding order, they will have antiparallel normals (normals # pointing in opposite directions). segmentNormals: list[c4d.Vector] = [] for segment in segments: if len(segment) < 3: print("Segment has less than 3 points, skipping normal calculation.") continue a, b, c = segment[0], segment[1], segment[2] edge1: c4d.Vector = b - a edge2: c4d.Vector = c - b normal: c4d.Vector = edge1.Cross(edge2).GetNormalized() segmentNormals.append(normal) # Now we just declare one segment as 'ground truth' and check if the other segments have normals # that are parallel or antiparallel to it. When we found a segment with an antiparallel normal, we # know we found a segment with reversed winding order. To check if two normals are parallel or # antiparallel, we just compute their dot product (i.e., spanned angle). When the dot product is # negative, the normals are antiparallel. print(f"Establishing the first segment normal {segmentNormals[0]} as ground truth.") baseNormal: c4d.Vector = segmentNormals[0] for i, normal in enumerate(segmentNormals[1:], start=1): isAntiparallel: bool = baseNormal.Dot(normal) < 0 print(f"Segment {i} normal: {normal} is {'antiparallel' if isAntiparallel else 'parallel'} " f"to the base normal {baseNormal}.") if __name__ == '__main__': main()
    • chuanzhenC

      TimeLine DopeSheet not update

      Watching Ignoring Scheduled Pinned Locked Moved Bugs 2026 python
      4
      0 Votes
      4 Posts
      40 Views
      chuanzhenC
      @ferdinand Thanks for help
    • A

      Copy res folder without shortcut

      Watching Ignoring Scheduled Pinned Locked Moved Cinema 4D SDK c++ windows
      4
      0 Votes
      4 Posts
      97 Views
      ferdinandF
      That is of course also a valid option, just pick the scripting language you are most comfortable with.
    • DunhouD

      How to draw svg to bitmaps?

      Watching Ignoring Scheduled Pinned Locked Moved Cinema 4D SDK windows python 2026
      4
      0 Votes
      4 Posts
      140 Views
      ferdinandF
      I started to work last Friday on a BaseBitmap.InitWithVectorImage. It will for sure not make it into the next release of Cinema 4D, as we are too close to that, and I cannot make any promises when or if it will arrive. But I see value in this especially since I realized that you cannot even really use this in C++, as VectorImageInterface requires access to some internal components to be rasterized.
    • E

      How to get selected DescId and BaseList2D at the same time

      Watching Ignoring Scheduled Pinned Locked Moved Cinema 4D SDK c++
      2
      0 Votes
      2 Posts
      51 Views
      ferdinandF
      Hey @ECHekman, well, when a node displays an embedded description (what you exemplify at the case of a BaseLink), it uses a DescriptionCustomGui too. Other parameter types aside from a BaseLink which can do this are for example field lists. I am quite frankly a bit surprised that this even bubbles up in the form you report it, that you get a DescID which is selected inside a DescriptionCustomGui that is shown by the node in the DescriptionCustomGui you opened yourself. Attribute Manger selection states (and by extension DescriptionCustomGui) are not a public API feature, as we usually keep our GUIs sealed, i.e., inaccessible to third parties. DescriptionCustomGui is here a bit in a grey area, but I am afraid there is no way to do what you want to do. To do what you want to do, you would need access to internal systems. And other than in some other cases, where we do not always had the time to expose something (and are open to the idea of changing something), this is for GUIs not the case; they are intentionally sealed as we do not want third parties to change basic UX concepts. My general advice would also be to not to try to overcome this boundary (that a plugin reacts to which parameter in a node is being highlighted by the user), as you break UX conventions of Cinema 4D with that. Cheers, Ferdinand You can do this, but it is very hacky: Get the description of the node(s) you are currently displaying in the your DescriptionCustomGui. Check if desc is a member via CheckDescID (I think GetParameter would also work and return an empty container when the ID does not exist). When the ID does not exist, start browsing the container for parameters that are of a DTYPE that implies an underlying node, such as DTYPE_BASELINK. When you find such parameter, get the node node, and check there. Rinse and repeat recursively. Issues: You cannot distinguish the case where an object A has two BaseLink parameters which both hold an object of type T, but not the same instances. You will run into issues with DescID translations which some nodes might do. This is a really big point, which is probably already overlooked in your current code. Nested node relations can get REALLY complicated. BaseLink is trivial, but stuff like field lists, volume lists, or some special shader stuff can get really complicated. You would probably only have to worry about base links and field lists in your case, as other renderers are irrelevant for you, but field list alone are already complex enough that I would strongly advise against 'just implementing it'.
    • ferdinandF

      GeDialog::GetFilename currently broken in 2026.3.0

      Watching Ignoring Scheduled Pinned Locked Moved Bugs 2026 python cpp bug windows macos
      1
      0 Votes
      1 Posts
      26 Views
      No one has replied
    • ferdinandF

      Maxon Cinema 4D 2026.3 SDK Release

      Watching Ignoring Scheduled Pinned Locked Moved News & Information news cinema 4d c++ python sdk information
      1
      0 Votes
      1 Posts
      2k Views
      No one has replied
    • rndm_cgR

      [Python] Best practice for creating multiple custom tabs in a .res file (ObjectData)

      Watching Ignoring Scheduled Pinned Locked Moved Cinema 4D SDK python 2026 windows
      3
      0 Votes
      3 Posts
      124 Views
      rndm_cgR
      @ferdinand thanks so much, problem solved!