GetCache Does Not Work Inside the Python Generator
-
Hi,
I have a
Text
object inside the Python Generator. I want to "bake" down (or equivalent to current state object commant) the text object so I can access it further but theGetCache
seems to return none.# inside the python generator def main() -> c4d.BaseObject: text = c4d.BaseObject(1019268) text[c4d.PRIM_TEXT_TEXT] = "Generator" print (text.GetCache()) # returns None clone = text.GetClone() print (clone.GetCache()) # returns None # I also tried the `SendModellingCommand` but it gives me `False` instead of `True` base = c4d.utils.SendModelingCommand(c4d.MCOMMAND_CURRENTSTATETOOBJECT,[clone],c4d.MODELINGCOMMANDMODE_ALL,c4d.BaseContainer(),clone.GetDocument()) print (clone) # returns False instead of True
I'm guessting there is a prerequisite on the operation.
What am I missing? -
Hey @bentraje,
Thank you for reaching out to us. There are two different mistakes in your code:
- Caches do not exist for freshly allocated objects. They must be built in a document, see geometry_caches_s26.py for an overview of the subject.
- Objects must be part of a document to be the subject of a modeling operation. While you did technically the right thing here, called
GeListNode.GetDocument
instead of blindly passing a documentclone
might or might not be a member of, the fact remains thatclone
is not yet a member of a document. See smc_extrude_s26.py for a principal overview of SMC operations.
Cheers,
Ferdinand -
Hi @ferdinand
Thanks for the respond.
RE: Caches do not exist for freshly allocated objects
Ah gotcha. Thanks for the confirmation.
Based on your reply, I can do it through a python script (i.e. insert the object temporarily and just destroy it or something like that).But how do I go about it on Python Generator object? Is it possible?
Ultimately, what I want is to have a procedural text object that allows me to modify the extrude parameter of each letter. Currently, the extrude parameter of a default text object applies to all letters. -
Hey @bentraje,
look at the examples I have posted, it is all exactly layed out there
Cheers,
Ferdinand -
Hi @ferdinand
I'm not sure I get it. The examples are for Python Script/Manager and not for Python Generator (which is what I am after).
Anyhow, I'm guessing you are referring to
GetCaches(node: c4d.BaseObject)
fromgeometry_caches_s26.py
If so I did try it in the Python Generator (not in the Python Script):
def PrintCacheTree(): ... def GetCaches(): ... def main(): text = c4d.BaseObject(1019268) GetCaches(text) return text
The result still gives me none, of which I am unable to access the individual extrude parameters of each letters.
Retrieving Caches: Text.GetCache() = None Text.GetDeformCache() = None Cache Tree of 'Text': Text(Text) Building Caches: Cache for newly allocated object: None Cache after executing the cache pass: <c4d.PolygonObject object called Cube/Polygon with ID 5100 at 2640357790656>
-
Hey @bentraje,
I understand that one has not always the time to get into the details of things, and that this file might look a bit much, but you will have to read it in order to understand caches. You must build the cache of your
Text
object, the script unpacks this bit by bit.Concretely you will have to call
BaseDocument.ExecutePasses
for a document holding your object, but I cannot help you when you just blindly copy and paste the script without trying to understand what it does.Cheers,
Ferdinand -
Hi @ferdinand
I admit I'm on the slow side. It's a bit hard to comprehend on my level.
Can I get a baseline answer (yes or no) on:
The examples are for Python Script/Manager and not for Python Generator (which is what I am after). Is it doable in Python Generator?
I can execute your script just find. It gives me caches etc. But when it comes to generator it does not.
For example, as soon as I addBaseDocument.ExecutePasses
the document freezesdef PrintCacheTree(): ... def GetCaches(): ... def main(): text = c4d.BaseObject(1019268) doc.InsertObject(text) doc.ExecutePasses(None, False, False, True, c4d.BUILDFLAGS_NONE) GetCaches(text) return text
-
Hey @bentraje,
you are bound by the threading restrictions in the
main
function of a Python Generator object, you are despite its name off-main-thread there and cannot modify the active scene. Both example scripts expand on this and that you have to use dummy documents in these cases to execute SMC or built the caches of an object.Inserting your
text
intodoc
(a.k.a. the active document) will result in infinite recursion on top of that (your freeze). Becausedoc
contains your Python Generator objectpygen
. When you now inserttext
intodoc
frompygen.main()
(i.e., the cache building function ofpygen
), and then execute the passes ondoc
, it will try to build the cache forpygen
. Which will then runpygen.main()
again, which will inserttext
intodoc
, and then try to build the caches ondoc
, which will then ...You must allocate a dummy document in your
main
function. Then insert all the newly allocated objects you want to build the caches for into this dummy document and execute the passes on it. Then you can clone the caches of these objects to return the clones as the output of your generator.Again, both script files which I have posted highlight this exact workflow.
I wrote this blindly as I am currently sitting in a train with no Cinema 4D or code editor:
import c4d import mxutils from mxutils import CheckType def main(): # Allocate the text object and a document. Use CheckType to make sure to fail gracefully when # allocation goes wrong. Insert #text into #temp. text = CheckType(c4d.BaseObject(1019268)) temp = CheckType(c4d.documents.BaseDocument()) temp.InsertObject(text) # Execute the passes on temp. temp.ExecutePasses(c4d.threading.GeGetCurrentThread(), True, True, True, c4d.BUILDFLAGS_NONE) # Clone the cache, making sure with CheckType that the cache exists and then that the # cloning did not fail. data: c4d.BaseObject = CheckType(CheckType(text.GetCache()).GetClone(c4d.COPYFLAGS_NONE)) # text and temp are destroyed automatically after the function scope has been left. # Since Python's GC can be a bit derpy you can also call BaseDocument.Flush to streamline # things. temp.Flush() return data
Cheers,
Ferdinand -
Thanks for the response. Your code works without the program freezing up (although I think it's GeGetCurrentThread instead of GetCurrentThread()). Other than that, it works as expected.
Ah. I didn't think to just pass objects from different documents.
I was thinking of something like this:
- All in the same document. Create a dummy object in the same document. In this way, the cache is already created because it now exist.
- Clone it. Store the data.
- Delete the dummy object in the same document.
The problem was that in #3, the generator no longer has access to that object for some reason. So it keeps creating a dummy object lol
Anyway, enough for my excuses. Sorry for the trouble and thanks again for your patience.
-
Hey @bentraje,
I am glad that you found your solution, and yes, you are absolutely right, it should be
GeGetCurrentThread
. I fixed that in my pseudo-code.Cheers,
Ferdiand