Spline Generator GetVirtualObjects() + GetContour()
-
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
-
Hey @baca,
thank you for reaching out to us.
Let me preface things by stating that mixing
GetVirtualObjects
andGetCountour
is generally not a great idea. And I am fully aware that we do this ourself, point and case - theoffset_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 aHierachyHelp
hh
(which is not actually wrapped as a type in Python) with which you then call methods such asBaseObject.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 inGetContour
there is nohh
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:
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 toCopyTagsTo
is very non-conformant, as in Python it is documented to take three Boolean arguments at the end, notBaseObject, bool, int, bool
. Its internal signature is actuallyBaseObject, int, int, int
but even there this is non-standard, as in C++ this is meant to takeNOTOK
(-1
),false
(0
), andtrue
(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 thisGVO
+GC
workflow.I might de-publish the code example, I have not decided yet.
Cheers,
Ferdinand -
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. -
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,
FerdinandPS: 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.