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
    • Login

    Spline Generator GetVirtualObjects() + GetContour()

    Cinema 4D SDK
    python 2025
    2
    4
    722
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • bacaB
      baca
      last edited by

      Hi team,

      I only recently noticed there's an issue with Spline Generators which utilized both GVO and GetContour, and this object has a Rope Dynamics tag.
      Spline simulates properly while timeline is playing, but once paused — returns to it's initial state because of GVO.
      If generator has only GetContour() method implemented then it's working fine, except source child object is not being hidden.

      If it's not a bug — are there workarounds?

      To replicate the issue — official example could be used https://github.com/Maxon-Computer/Cinema-4D-Python-API-Examples/blob/master/plugins/py-osffset_y_spline_r16/py-osffset_y_spline_r16.pyp

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @baca
        last edited by ferdinand

        Hey @baca,

        thank you for reaching out to us.

        Let me preface things by stating that mixing GetVirtualObjects and GetCountour is generally not a great idea. And I am fully aware that we do this ourself, point and case - the offset_y_spline_r16.pyp example.

        If generator has only GetContour() method implemented then it's working fine, except source child object is not being hidden.

        An object being hidden or not, is being determined by it having been BaseObject.Touched, resulting in its cache being deleted and BIT_CONTROLOBJECT being set. You can technically emulate/call this somewhere yourself, but this will then really stop all cache building, so the next time you want to build your spline, you will have no input data (unless the input has been rebuilt forcibly). In GVO you get passed in a HierachyHelp hh (which is not actually wrapped as a type in Python) with which you then call methods such as BaseObject.GetAndCheckHierarchyClone which will build the cache of the object for you and then touch it right away. So that you can have both, the hidden object and the most recent version of the cache. But in GetContour there is no hh and you also cannot construct it yourself (not even in C++). Which is the underlying reason for the design of this code example (and the Spline Mask object in Cinema 4D itself).

        The bottom line is that splines are simply not meant to have geometry inputs, rely on things that have a cache. When you want to develop something like the offset_y_spline_r16.pyp spline, it should rather be a deformer which deforms an existing spline. That code example is not a good code example, as it fishes in muddy waters.

        And just to be clear: The major draw-back of just using GetContour is not that the input object is not hidden, it is that there possibly will either be no input object cache (when no cache has ever been built yet) or that you possibly operate on the input object cache of the previous build event. This happens when your spline comes before the input spline in the object hierarchy (will be the case when you use the parent-child pattern).

        Spline simulates properly while timeline is playing, but once paused — returns to it's initial state because of GVO.

        This is happening because two rather unique systems - MoGraph (the Spline Mask generator which invented this GVO + GC workflow and is also the only user atm) and simulation - are meeting here. There is a fix for what you want to do, you must put this line into your code:
        1dd6aa40-b5e5-4cb0-82ea-bb96f0fb0404-image.png

        op.CopyTagsTo(resSpline, True, -2, False) will effectively copy the rope tag into the cache and for me this will then work as expected. But this call to CopyTagsTo is very non-conformant, as in Python it is documented to take three Boolean arguments at the end, not BaseObject, bool, int, bool. Its internal signature is actually BaseObject, int, int, int but even there this is non-standard, as in C++ this is meant to take NOTOK (-1), false (0), and true (1) as the last three arguments. But simulation uses here -2 for special purposes.

        All this indicates why this whole code example was never a good idea, as it publishes a hacky approach without making clear how hacky it is. And hacky things will always entail more hacky things, point and case the CopyTagsTo call to make it work with simulation. You can copy this 'fix' but I would suggest to use a deformer when possible. Splines that have input objects are not a good pattern, especially in this GVO + GC workflow.

        I might de-publish the code example, I have not decided yet.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        bacaB 1 Reply Last reply Reply Quote 1
        • bacaB
          baca @ferdinand
          last edited by

          Thanks @ferdinand

          I appreciate your explanation and solution.

          Honestly I also felt input based spline generators looks confusing because you'll need to implement both GVO and GC.
          But I already made quite a lot of these plugins, so I'll just follow hacky solution.
          Hoping it would lasts some time for newer C4D versions.

          1 Reply Last reply Reply Quote 0
          • ferdinandF
            ferdinand
            last edited by ferdinand

            We will very likely never abandon this technique. The issue is more that there are a lot of hacks in the Spline Mask code and almost none of them are shown in the public code example. And we cannot publish all of these hacks both for strategic (we do not want to show all of our internals) and practical reasons (we cannot explain all the nitty gritty details there).

            It was not such a good decision to publish that code example; which as far as I understood came to pass as a user asked as to how the Spline Mask object has been realized. But we probably should just have said "no" then. Just as much as I probably should not have shown you that simulation hack. Hacks lead to more hacks and more problems.

            Cheers,
            Ferdinand

            PS: And to be super verbose, you ONLY need this pattern when you "have to" implement a spline that has other (spline) objects as inputs. When you have implemented regular splines like this, you should probably revert that.

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 1
            • First post
              Last post