Fracture - GetChildren() = None ?

On 20/05/2013 at 09:53, xxxxxxxx wrote:

When I want to read out the position data for my clones, this works with a Cloner just fine :

cache = gen.GetCache()  
clones = cache.GetChildren()  
for clone in clones:  
 pos = clone.GetAbsPos()

When I'm using a Fracture Object instead though, the cache.GetChildren() gives None.
So, how do I GetAbsPos() of the elements within a  Fracture Object ?

Anybody willing to shed a little light  ? Appreciated.


EDIT : Just to make sure I make myself clear !!
I'm not after just the MoData. I DO need the cache.

On 20/05/2013 at 11:01, xxxxxxxx wrote:

a fracture object is a baseobject like any other. it does return its cache in the same way other baseobject do. try it yourself in the console:

[OK] cache = Fracture.GetCache()
[OK] cache.GetChildren()
[<c4d.PolygonObject object called 'Sphere/Polygon' with ID 5100 at 0x000000000FAB5CB0>]

your input data seems to be not correct. you should also check if the cache is not none before
invoking any methods on it.

On 20/05/2013 at 11:38, xxxxxxxx wrote:

I see. That's what I would expect indeed.

Apparently ...

cache = gen.GetCache()  
print cache  
clones = cache.GetChildren()  
print clones

... if I put this in a Tag, it works :

<c4d.BaseObject object called 'Null/Null' with ID 5140 at 0x00000000147CAB10>  
[<c4d.PolygonObject object called 'Piece 0/Polygon' with ID 5100 at 0x0000000014A5E3F0>]

If I use it in a PyEffector though, it doesn't :

<c4d.BaseObject object called 'Null/Null' with ID 5140 at 0x00000000147CA790>  

Any idea why that is the case ?
Any workaround ?

Thanks for taking a look.


On 20/05/2013 at 11:45, xxxxxxxx wrote:

Is the effector used in the fracture object? Then it might be a priority issue. I guess the cache is
not yet generated at the point you want to access it.


On 21/05/2013 at 06:28, xxxxxxxx wrote:

Originally posted by xxxxxxxx

Is the effector used in the fracture object?

Originally posted by xxxxxxxx

I guess the cache isnot yet generated at the point you want to access it.

Yes, it is.

As I show in the above post, cache = gen.GetCache() does return the same Object in both the Fracture and the Cloner. It goes wrong with cache.GetChildren()

Simplified this as much I can. Here's the file :

So I use a Cloner and a Fracture and I do this :

cache = gen.GetCache()  
clones = cache.GetChildren()  
print clones

1. Works with the Cloner.
2. Doesn't work with the Fracture Object : gen.GetCache does, cache.GetChildren does not.

3. I also added a Horrible Xpresso workaround :
When I "refresh" the Fracture Object with a bit of Xpresso , all of a sudden it works (!!), and cache.GetChildren() returns the list I expect.
Problem is that "refresh" consists of modulating between "Explode Segments" and "Explode Segments & Connect". That's ugly and horrible, and will probably do more harm than good.

So, I guess need a way to "refresh" the Fracture Object somehow from inside the Effector's Python.
Any takers ?

I'm either too stupid or not creative enough, but hours of browsing and testing didn't get me any closer.

Thanks for enlightening me,

On 22/05/2013 at 08:45, xxxxxxxx wrote:

It looks to me like the Fracture Object is managing the caches of it's children. And this is what's preventing access to their cache.
In Object Generator plugins. We can turn off this automatic cache handling using: SetOptimizeCache(False)

I can use this line of code on the fracture's children if I put it in a python tag.
This will let me bypass the Fracture Object's cache management and lets me get at the cache for the children:

import c4d  
def main() :      
  cache = op.GetObject().GetCache()   #The pytag is on a child object of the Fracture Object  
  print cache                         #No longer prints None

I can't seem to get the pyEffector to allow me to use SetOptimizeCache() in it:

import c4d  
from c4d.modules import mograph as mo  
def main() :      
  md = mo.GeGetMoData(op)  
  if md==None: return False  
  cnt = md.GetCount()  
  marr = md.GetArray(c4d.MODATA_MATRIX)  
  fall = md.GetFalloffs()  
  for i in reversed(xrange(0, cnt)) :  
      marr[i].off = marr[i].off+fall[i]*100.0  
  md.SetArray(c4d.MODATA_MATRIX, marr, True)  
  #Now lets try to get the cache from fracture object's children  
  #We will need to first get the fracture object and it's children  
  #Then we need to somehow turn off the managed caching in the fracture object  
  fracObject = op.GetNext()     #Get the fracture Object      
  c4d.plugins.ObjectData.SetOptimizeCache(False) #<---- Wrong!!  
  child = fracObject.GetChildren()  
  cache = child[0].GetCache()  
  print cache  
  return True

If you can figure out a way to make the pyEffector accept: SetOptimizeCache(False)
You might be able to get at the children's caches.


On 22/05/2013 at 09:26, xxxxxxxx wrote:

Scott, you need to call the method on an object. You would usually do this using
self.SetOptimizeCache(False). In your example, you went the "functional" (ie. not OOP) style to
call the method, but you did it wrong:

> c4d.plugins.ObjectData.SetOptimizeCache(op, False)

which is equal to

> op.SetOptimizeCache(False)

though, both of these are wrong in this context! You can't get the ObjectData of the FractureObject
nor of the PythonEffector (at least from Python). Also, SetOptimizeCache() is a Python specific method
in the ObjectData class and does not apply to C++ plugins.

I can use this line of code on the fracture's children if I put it in a python tag.
This will let me bypass the Fracture Object's cache management and lets me get at the cache for the children:

I doubt it. SetOptmizeCache() is not defined in a PythonGenerators scope, nor in a Tags scope.
Also, one usually doesn't call this method from GetVirtualObjects() (which is equal to the main()
function in a PythonGenerator).

Douwe, I unfortunately can't think of a solution to this one.


On 22/05/2013 at 10:45, xxxxxxxx wrote:

That's truly bizzare.
SetOptimizeCache(False) was working just fine in my pytag. And now I can't do it again.
I have no idea why it worked for me the first time I used it. And now it doesn't. :dizzy_face:

I could have sworn that I read somewhere a long time ago that it was possible to manually turn the caching off for things like the FractureObject in pytags and scripts (and possibly the FO itself).


On 23/05/2013 at 07:50, xxxxxxxx wrote:

Thanks a lot for trying to help me out, guys.

I was hoping to get something useful out of the SendModelingCommand (CSTO) somehow,
but I'm getting all kinds of stuck.

I'm trying out some ideas from this topic.

I can manage to return "undead virtual children" that I can read the GetAbsPos from,
but one problem is that CSTO returns the children in their initial positions, not in the actual positions after motion/dynamics that you would expect to get from a CSTO.

Here's the .c4d
Here's the code:

import c4d  
from c4d.modules import mograph as mo  
from c4d import utils as u  
#Welcome to the world of Python  
def CSTO(obj,clonedoc) :  
  genobj = u.SendModelingCommand(  
                          command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,  
                          list    = [obj.GetClone()],  
                          mode    = c4d.MODELINGCOMMANDMODE_ALL,  
                          doc     = clonedoc)  
  return clonedoc      
def main() :  
  md = mo.GeGetMoData(op)  
  if md==None: return False  
  cnt = md.GetCount()  
  marr = md.GetArray(c4d.MODATA_MATRIX)  
  fall = md.GetFalloffs()  
  clonedoc= doc.GetClone()  
  go = CSTO(gen,clonedoc)  
  print go.GetFirstObject().GetChildren()[0].GetAbsPos()  
  print go.GetFirstObject().GetChildren()[1].GetAbsPos()  
  for i in reversed(xrange(0, cnt)) :  
  md.SetArray(c4d.MODATA_MATRIX, marr, True)  
  return True

I'm probably doing a bunch of things completely wrong,
but maybe I'm closing in on something that one of you guys knows how to deal with.

No can do ?

On 23/05/2013 at 08:26, xxxxxxxx wrote:

the children do not exist anymore, as the fracture object has already freed them, as it is
currently calling the python effector method to rebuild its cache. read more about dead
objects under c4dAtom.IsAlive().

doing the whole thing in a python effector seems rather mad to me. but the only way i could
think of is manual caching solution build outside of the effector, a globally stored class
constantly polling the cache or some xpresso mess.

go for a plugin where the whole manual caching will be much easier or simply use the matrices
and try to extrapolate missing data like particle shape and so on.