Unusual "NoneType" Error for GetDeformCache()



  • Hi,

    I'm having an unusual "NoneType" Error for GetDeformCache().
    For the most part, it works. But there are times where it throws an error.
    I can't replicate the other methods but it always happens when I hit undo.

    You can see the problem here:
    https://www.dropbox.com/s/ybwoy0p403qxprr/c4d306_python_getdeformcache_nonetype_error.mp4?dl=0

    You can check the file here:
    https://www.dropbox.com/s/obngch2rx6dseqn/c4d306_python_getdeformcache_nonetype_error.c4d?dl=0

    Regards,
    Ben



  • hi,

    sounds pretty logical to me.
    Your deformer is below the object where your tag is. Your tag is at priority expression +0. So it is executed before the deformer.
    If you retrieve the cache you should retrieve the cache build on the previous execute pass.

    That's why you got the message when you load the document and when you press the a key to force the recalculation of the scene.
    If you set the tag's priority to generator +1 you will not have the message anymore.

    the a key is your best friend when you want to deal with priorities.

    Cheers,
    Manuel



  • Hi,

    I do not want to be rude, but please put up your code next time and a console dump. You always making these little videos is very nice of you and helps, but cannot replace the mentioned. In this case I could take a glimpse at the code in the video.

    To your problem is is actually not GetDeformCache which is None, but the module attribute op. Invoking an undo seems to clear the selection as you can see in your video. Which in turn means that op, the current primary object selection, is going to be None.

    However, GetDeformCache can be None, as there is no guarantee that the deformation cache is populated at any time (assuming there is some kind of deformer). Invoking undo might produce such scenario (haven't tested it, I am on my iPad). When retrieving caches, it is good practice to so something like this.

    cache = node.GetDeformCache() or node.GetCache()
    node = cache or node
    

    This will replace the reference of the symbol node with the a reference to the deformed cache, the cache or the node itself in decreasing order. After that you can evaluate the type of node to determine how to proceed.

    if not isinstance(node, c4d.PointObject):
        msg = "Could not access point data in {}."
        raise TypeError(msg.format(node))
    

    Edit: It is also worth mentioning that caches can contain caches. So you are not guaranteed to have directly some point data at the top level of the cache. My mentioned snippet therefore only "works" in cases of such "flat" caches.

    Cheers,
    zipit



  • Thanks for the response:

    @m_magalhaes

    RE: Your tag is at priority expression +0. So it is executed before the deformer.
    It seems like you're talking as if the Shrink Wrap Deformer has a "priority", but its basic tab doesn't show anything.
    Interestingly, when I set the tag to generator +1 as suggested, it seems to fix the problem.

    So, indeed, there is an inherent priority for the deformers.
    How do I change them?

    I tried the following deformer[c4d.EXPRESSION_PRIORITY] or even the deformer[c4d.ID_CA_SKIN_OBJECT_PRIORITY] but it gives me None type.

    @zipit

    RE: but please put up your code next time and a console dump
    Gotcha. Noted.

    RE: Code
    The code works as expected.

    RE: caches can contain caches.
    Just want to clarify.
    Cache (GetCache()) can contain Caches and Deform Caches (GetDeformCache)
    But Deform Cache can't contain Caches or othe Deform Caches.

    Is this assessment correct? I'm basing this on a sample image in this documentation.

    RE: "flat" caches.
    Just to clarify, by flat caches, I guess you meant objects with no stacking parent/child hierarchies?



  • @bentraje said in [Unusual "NoneType" Error for GetDeformCache()]

    RE: caches can contain caches.
    Just want to clarify.
    Cache (GetCache()) can contain Caches and Deform Caches (GetDeformCache)
    But Deform Cache can't contain Caches or othe Deform Caches.

    Is this assessment correct? I'm basing this on a sample image in this documentation.

    Yeah, deform caches are sort of flat. But they are often (when the deformer does not directly act on a PointObject) imbedded within a cache. It will look something like the tree below which represents the example of the docs, but with only one cloned cube. The problem is that this is not a monohierarchical structure which cannot be described very well with a (monohierarchical) taxonomy (i.e. the image in the docs or what I have done below). You can test this yourself with [1].

    # The actual array node.
    Array/Array
        Array/Array returns for GetCache:
            # The null object holding all parametric cubes in the cache
            Null/Array
                # A null object has no cache
                Null/Array returns 'None' for GetCache.
                # And also no deform cache
                Null/Array returns 'None' for GetDeformCache.
                # But some children
                children of Null/Array:
                    # A parametric cube as child of the cache.
                    Cube/Cube.1
                        # The cache of that part of the cache of the node :o
                        Cube/Cube.1 returns for GetCache:
                            # The actual polygonal data created by the GVO of the
                            # parametric cube object.
                            Polygon/Cube.1
                                Polygon/Cube.1 returns 'None' for GetCache.
                                Polygon/Cube.1 returns for GetDeformCache:
                                    # The deformed polygonal data generated by
                                    # the deformer reaching deep into the cache
                                    # of the array object.
                                    Polygon/Cube.1
                                        Polygon/Cube.1 returns 'None' for GetCache.
                                        Polygon/Cube.1 returns 'None' for GetDeformCache.
                                        Polygon/Cube.1 has no children.
                                Polygon/Cube.1 has no children.
                        # No deform cache here, since this is the paramteric cube
                        # not its polygonal cache.
                        Cube/Cube.1 returns 'None' for GetDeformCache.
                        Cube/Cube.1 has no children.
        # Has no deformed cache since its cache is a null object (which has
        # stuff attached to it.)
        Array/Array returns 'None' for GetDeformCache.
    
        # The actual children of the actual array object.
        children of Array/Array:
            Cube/Cube
                # This one is quite surprising I didn't know either, it seems
                # like that at least the array object *mutes* its input objects
                # to avoid overhead. 
                Cube/Cube returns 'None' for GetCache.
                Cube/Cube returns 'None' for GetDeformCache.
                Cube/Cube has no children.
            Bend/Bend
                Bend/Bend returns 'None' for GetCache.
                Bend/Bend returns 'None' for GetDeformCache.
                Bend/Bend has no children.
    

    RE: "flat" caches.
    Just to clarify, by flat caches, I guess you meant objects with no stacking parent/child hierarchies?

    I meant caches that do not contain caches. A cache that is a null to which multiple other nulls are parented would be flat in this sense, as the nulls will have no further caches. If it were parametric cubes parented instead, it would not be no longer flat, since each cube had its own cache.

    Cheers,
    zipit

    [1]

    """
    """
    import c4d
    
    
    def walk_cache(node, indent=0):
        """
        """
        if node is None:
            return
    
        node_name = node.GetTypeName() + "/" + node.GetName()
        print("{}{}".format("\t" * indent, node_name))
        f, g = node.GetCache, node.GetDeformCache()
    
        for f in [node.GetCache, node.GetDeformCache]:
            cache = f()
            msg = ("{}{} returns for {}:" if cache else
                   "{}{} returns 'None' for {}.")
            print (msg.format("\t" * (indent + 1), node_name, f.__name__))
            if cache:
                walk_cache(cache, indent + 2)
    
        children = node.GetChildren()
        msg = "{}{} has no children." if len(children) == 0 else "{}children of {}:"
        print (msg.format("\t" * (indent + 1), node_name))
        for child in children:
            walk_cache(child, indent + 2)
    
    def main():
        """
        """
        if op is None:
            raise ValueError("Please select an object.")
        walk_cache(op)
    
    
    if __name__ == "__main__":
        main()
    


  • @zipit

    Thanks for the detailed answer! The walk_cache code really clarifies a lot of what I've been having trouble understanding. Although, I still have to remain the thread open as I'm waiting for @m_magalhaes on my priorities on deformers.

    Thanks again! Have a great day ahead! :)



  • hi,

    A deformer is a generator. So it's priority is Generator.

    You can see in our documentation the sequence of calculation
    Of course there are some exceptions
    alt text

    Cheers,
    Manuel



  • @m_magalhaes

    Ah gotcha. I totally missed this one out:
    A deformer is a generator. So it's priority is Generator.

    That said, since it has a priority, can I change it's order. I believe its in Generator -1.
    I want to change it say to Generator -100 or Generator +100
    This is so I can stack them properly.

    As mentioned, I tried the following deformer[c4d.EXPRESSION_PRIORITY] or even the deformer[c4d.ID_CA_SKIN_OBJECT_PRIORITY] but it gives me None type.



  • hi,

    the skin deformer is a really particular case. The priority only change the moment where Execute will be called. (like any other Generator where you can use AddToExecution and Execute).
    But in all case it will still use ModifyObject (the GVO for deformer). The priority of this call can't be changed.

    Cheers,
    Manuel



  • @m_magalhaes
    Ah gotcha. Thanks for the clarification.
    But I'm asking for "Deformer" in general in changing their priority since it's not available in the interface.



  • Not all modifier use the Execution function.
    Even on those that use it, not all allow to change the priority.

    Cheers,
    Manuel



  • Hi @m_magalhaes

    Ah gotcha. I guess I can't change the deformer's priority.
    Anyhow. Thanks for the confirmation.


Log in to reply