Force polygon object to generate it's cache
-
Hi,
I'm going to generate some polygon geometry and modify it's cache object in the same time.
Then output bunch of these objects under single null in themain()
of Python Generator, if it matters.Since there's no method like
.SetCache()
— I need somehow to enforce object to generate it's own cache or even deformCache.
That's not a generator, just simple c4d.PolygonObject, so callingMCOMMAND_CURRENTSTATETOOBJECT
withMDATA_CURRENTSTATETOOBJECT_NOGENERATE
flag wouldn't build cache for me.Is there any solution for that?
-
Hello @baca,
Thank you for your question. Yes, that is possible, the relevant method is
BaseDocument.ExecutePasses
. We talked about it multiple times on the forum, for example here. In the geometry model section of our Python examples, I also went over caches and cache building in geometry_caches_s26.py.Note that you are not able to, but not allowed to, modify the caches of objects on your own; e. g., get the cache of an object and delete a point. Technically you can do it, but you need intimate knowledge of Cinema 4D to do it without causing crashes. If you want to modify the caches of things, you must write an
ObjectData
plugin and there overwriteModifyObject
. This will ensure that your cache modifications of another entity do not happen while something is still relying on that cache.Cheers,
Ferdinand -
Hi @ferdinand,
Unluckily
ExecutePasses
doesn't build cache for basicc4d.PolygonObject
s
To have an effect, there should be either a modifier under geometry, either it needs to be wrapped into generator, likeConnect
object.The purpose would be to use Python Generator to generate null with bunch of geometry objects,
and I'm going to modify those geometry cache object by changing their point positions.If it matters — I need both non-deformed base mesh, and deformed cache — for soft-body-dynamics, where I can set "Mix Animation" -> "Follow Shape".
So internally constraints would be aligned with rest state, rather then derived from deformed state. -
Hey @baca,
without wanting to be snarky, I would recommend you read
geometry_caches_s26.py
I have linked to above.A
PolygonObject
has no generator cache because it is not a generator. So,BaseObject.GetCache
will always returnNone
. But it can have a deform cache, in fact only discrete geometry representations such asPolygonObject
,PointObject
, andLineObject
can have a deform cache. And deform caches will be built by the cache pass just as the generator caches. If you want to modify discrete geometry, you can just do it. There is no cache. There is a lower level with the raw point and polygon data stored inPointTag
andPolygonTag
instances, but you usually do not have to mess with these (and can also break quite few things there).The purpose would be to use Python Generator to generate null with bunch of geometry objects, and I'm going to modify those geometry cache object by changing their point positions.
I do not quite follow here, but as said above and as explained in
geometry_caches_s26.py
, you cannot modify the cache of objects. Technically you can, but you will crash Cinema 4D sooner than later. When you want to modify the cache of an object, you must implement a deformer.Cheers,
Ferdinand -
Ah @ferdinand ,
With all the respect to you — I'm following your advices, before replying
Your reference is straight, but didn't help with my requirements.However your last statement made it clear for me — there's no way to build cache (retrieved with
GetCache()
) object forPolygonObject
. Cool.So only deform cache might be available — which is not possible without applying deformers, or some other affection, like dynamics.
I'll explore that way further.Just one more question — I'd like to keep context within the subject — is it possible to clone object with it's built cache?
I found that oncePolygonObject
has built deformCache and I'm getting clone withGetClone()
— clone's cache disappears. -
Hey @baca,
it is great if you have read it already. But a good portion of the things you are asking here still contradict what I (tried to) explain in the geometry model documentation. It is fine that there are sometimes misunderstandings and misconceptions, but that it makes it difficult to answer questions. So, let us from a simple scenario:
Generator Caches
You have a Cube Generator Object O with a Bend B deformer attached to it. O will return a
PolygonObject
PC forGetCache
which is the discrete polygonal form of O and its settings. PC returns None forGetCache
and aPolygonObject
PDC forGetDeformCache
. PDC is the deform cache of PC because deform caches can only be applied to discrete geometry, you can only deform points which exist.When we run the function
GetCacheTree
from the geometry model documentation on this setup, it will spit out the text below.Cache Tree of 'Cube': Cube(Cube) [cache] Cube(Polygon) [deform cache] Cube(Polygon) [child] Bend(Bend)
You can technically reach into a cache, to get for example here the deform cache, and then just modify its points. But first, all this work will be gone the next time Cinema 4D builds the caches, it might also not be directly reflected in the viewport because Cinema 4D considers caches to be static, i.e., it does not expect you to poke around there. But most importantly, there is a good chance you will crash Cinema 4D. Because when you reallocate things or delete things, stuff in C++ which relies on a certain state of that cache then will induce an access violation.
When you want to modify caches, you must write a deformer, which allows you to generate deform caches. As their name implies, they are primarily intended for deformation. You can bend the rules as for example the Bevel Deformer proves as it adds geometry, but that is a bit tricky to do.
Non-Generator Caches
Non-generators, like for example a
PolygonObject
can only have deform caches. Their discrete geometry data, the points and polygons, can be read and written at any time; at least in theory, threading restrictions also prevent you from modifying things here when you are off main-thread. If you want to know how to update aPolygonObject
, you should have a look at geometry_polygonobject_s26.py.When you have modified a polygon object, you should send
.Message(c4d.MSG_UPDATE)
to it to inform it that its data has changed. But there is no cache, as discrete data does not have to be cached. Under the hood there is another level withVariableTag
instances holding the raw data, but that is not meant to be used by frontend users and does also not yield any benefits to frontend users.What to do?
So, from what I gather here by reading between the lines, you want to deform discrete geometry. I.e., do your soft body stuff, but want it to be non-destructive. You cannot do that directly, as this contradicts the discrete nature of discrete geometry. Once you have changed one of a point it remains changed.
Generators or deformers are one way to solve this. They take an input and manipulate it and returns a result (be it a cache or a deform cache).
But both do not work too well with simulations such as soft bodies where you always must feed your last output into yourself. The solution to that are than tags. You implement a tag which does all the deformation and cache the initial state yourself.
Fig. 1: The Soft Body tag is one of the examples where a tag in Cinema 4D establishes its own caching layer.In the end you just store some point data somewhere which you restore whenever the document is on its first frame. But that all is non-trivial and Python is also not a good language to implement anything soft body related.
Cheers,
Ferdinand -
Thanks @ferdinand,
Thats gone too far, we can close this subj now.
I think I have a solution already.
I just wasn't clear enough in the beginning, I just wanted to know if
PolygonObject
can be forced to produce it's cache object by a command.I made an experiment where I spawn flat geometries between other flat geometries. Like planes in-between of deformed soft body planes. Here's working example:
Setup:
And simulation:
Once you clone original geometry — it's flat, and there would be intersections and simulation will be broken.
So you need to blend newborn geo point positions in-between of existing geometry points.
Once you blend it — there are no intersections, it nicely continue with soft body simulation.
But softbody dynamics build constraints for every new object. And if geometry first appears as deformed — wrong constraints are initialized, and each new object becomes crumpled real quick.
Also there's "Mix Animation" -> "Follow Shape" checkbox, which rebuild constraints (or adjusts them - who knows?) — and it reads original point positions, as I understood.So I had to have both — original geo, and cache.
Where cache used to simulate geometry in 3D, and original object (CacheParent?) will be used for constraints.