Navigation

    • Register
    • Login
    • Search
    1. Home
    2. Peek
    3. Posts
    • Profile
    • More
      • Following
      • Followers
      • Topics
      • Posts
      • Best
      • Groups

    Posts made by Peek

    RE: Problems with Reused Asset Resources in MGS_GETALLASSETS

    Hi @ferdinand , thanks a ton for the very extensive reply. I do understand where you are coming from decision/code wise and that it might indeed be intended behavior, but I also appreciate you flagging this behavior to be looked at!

    I will look into the code you provided and see what I can make of it to work for our specific case. As with all the examples i receive on here it is also about learning itself, to become better.
    I already found out that I can run my piece of code 2 times to catch the first set of instances, perhaps it is also possible to run that on a loop until the len() doesn't increase anymore :) It's a hack-job but it might be a good last resort.

    To address the first comment about the post itself, my reasoning was that since it was about GetAllAssetsNew which we talked about last, I added it to my post to keep it all together.
    But I can see how it deviated too much from the original question that started the topic, my apologies.

    Cheers,

    posted in Cinema 4D SDK •
    Problems with Reused Asset Resources in MGS_GETALLASSETS

    @ferdinand : I've been working for a while with the solution of GetAllAssetsNew now but Today I noticed an issue:
    When a texture is used in multiple shaders, in the "Project Asset Inspector" it has a "+" before "Asset". However when I pull that texture with GetAllAssetsNew it seems that is only displaying 1 "owner" shader, even though in reality it's multiple.

    When I then loop over all texture assets to convert the paths from local to global, the extra owners keep their local paths and it's only changed for one of the owner shaders.

    In my example I have 4 images assinged to 5 shaders. When I pull a len() on the list of assets I get 4. Then when I convert the paths to global, one of the shaders get's left behind and in the Project Asset Inspector the "+" vanishes and I now see 5 textures instead of 4. Same goes if I then pull a len() on the list again, it now says 5.

    How can I make sure that it makes paths global on all owners of the texture?

    Cheers,
    Joep

    Code:

    def globalizeTextures():
        doc = c4d.documents.GetActiveDocument()
        textures = []
        c4d.documents.GetAllAssetsNew(doc, 0, "", flags=c4d.ASSETDATA_FLAG_TEXTURESONLY, 
                                      assetList=textures)
    
        print("The numder of textures is: ", len(textures))
        print("Textures are: ", textures)
    
        # Extract filename from all textures and put that name into the owner (shader) using the bitmap
        for texture in textures:
            print(texture)
            filePath = texture
            file = os.path.split(filePath["filename"])
    
            workPath = doc.GetDocumentPath()
            globalPath = str(os.path.join(workPath, "tex"))
    
             # Check whether the texture file is in the texture (sub)folder(s)
            for texture in os.walk(globalPath):
                i = 0             
                for filename in texture[2]:                
                    # print("Texture in tex folder is: ", filename)
                    # Check if the filenames match between the file in the shader and the file on the 
                    # network
                    if (file[1] == filename):
                        globalPath = str(os.path.join(str(globalPath),str(filename)))
                        owner = filePath["owner"]
                        print("Owner is: ",filePath["owner"])
                        returnShader(owner, globalPath)  
                    else:
                        i += 1
                    
                    if (i == len(texture[2])):
                        if not filePath["exists"]:
                            print("This file ", file[1], " does not exist!")
                        else:
                            print("File ", file[1], " not found in the tex folder of the project, use "
                                  "'Localize texture paths' first to copy the file to the tex folder "
                                  "of the project")
            updateScene()
        return True
    

    edit: forked form https://plugincafe.maxon.net/topic/14732/ by Ferdinand.

    To have your code not "messed up", you should markdown formating.

    ```
    def foo: return 3.14
    ```

    which would render as

    def foo: return 3.14
    
    posted in Cinema 4D SDK •
    RE: Traversing a layer shader with python

    @ferdinand : The GetAllAssetsNew is a far more elegant solution for the problem I am trying to solve and I've rewritten the code so that it works now. We use Corona render and Redshift so it's a bonus that this works with pretty much all materials.

    Thank you very much for the help, I will put your information about the layer shader in my database for future reference as I'm sure it will become helpful in another project!

    Kind regards,
    Joep

    posted in Cinema 4D SDK •
    RE: Traversing a layer shader with python

    Hi @ferdinand

    First of all thank you very much for the extensive reply, I haven't had the time yet to put the code intro practice but I wanted to answer your question on what I wanted to do with my code first.

    I haven't had much effective code since I can't get to the actual bitmap's filepath in the layer shader, but this is what I have, sorry for the ton of print statements but I need to figure out what the code was doing:

                 if (i.GetType() == 1011123):      
                    print ("Layershader found!")
                    print("i inside layershader is ", i)
                    layerShader = i
                    layer = layerShader.GetFirstLayer()
    
                    while layer.GetNext():
                        print("Layer is: ", layer)
                        print("Layer name: ", layer.GetName(doc))
                        print("Layer type is: ", layer.GetType())
                        print("Layer parameter is: ", layer.GetParameter(0))
                        print("Next layer is: ", layer.GetNext())
                        nextLayer = layer.GetNext()
                        print("Layer name: ", nextLayer.GetName(doc))
                        print("Layer type is: ", nextLayer.GetType())
                        print("Layer parameter is: ", nextLayer.GetParameter(0))
                        print("Next layer is: ", nextLayer.GetNext())
                        print("-----------------------------------------------------")
                        
    
                        if (layer.GetType() == 5833) or (layer.GetType() == 1036473):
                            print("Bitmap found in layer!")
                            file = os.path.split(shader(i))
                            print("file is: ", file[1])
                            if layer.GetNext():
                                layer = layer.GetNext()
                            else:
                                pass
                        else: 
                            print("No bitmap found in layer!")
                            if layer.GetNext():
                                layer = layer.GetNext()
                            else:
                                pass    
    

    What I want to do in code is this:

    • Go through all shaders in the scene.
    • Go into each shader and into each "slot" in each shader to see if a bitmap is present.
    • If a bitmap is present, I either want to make the texture path local, or make the texture path global to our server location.
    • If I run into a layer shader in a slot, I want to go into each layer of said layer shader to check if there is a bitmap loaded, and if so to change the texture path to local or global.

    So far I've tackled the first 3 things but I'm running into issues with the 4th as I can't read out the texture path from a layer in the layer shader it seems.

    posted in Cinema 4D SDK •
    Traversing a layer shader with python

    Hi guys,

    Got a question regarding traversing a layer shader with Python.

    For an internal plugin I need to go through shaders and localize/globalize the file paths in the bitmaps.

    When I run into a layer shader I want to get into said shader and traverse all layers, checking if it's a bitmap and if so localize/globalize the path.

    However, the SDK documentation is very sparse for the layer shader itself, specifically the "LayerShaderLayer.GetParameter(self, id)", it says to look at the C++ documentation for ID's, which I did.
    For instance "For shaders (TypeShader): LAYER_S_PARAM_SHADER"
    Neither:

    • 2
    • LAYER_S_PARAM_SHADER
    • [LAYER_S_PARAM_SHADER]
    • [c4d.LAYER_S_PARAM_SHADER]
      Give me any result.

    2 comes back as "none" and the rest gives an attribute error.
    0 also comes back as "none".

    I imagine that the GetParameter is used to get the file path of a layer if it's a bitmap, if not, what should I use?
    The LayerShaderLayer only seems to have: GetNext, GetType, GetName, GetPreview, GetParameter, SetParameter.

    When I run a GetType on the layer, it gives me back "2" which is "TypeShader" and with GetName it returns the name of the Bitmap in that layer.
    But how do I then get to the actual file path inside that layer to change it?

    Kind regards,

    Joep

    posted in Cinema 4D SDK •
    RE: Python writing to desktop

    Hi Ferdinand,

    Let me reply on the company account as I'm not at home, thank you very much for this information.

    This is a much more simplified and clean way to go about it indeed, I did spend some time on Google before composing my code and even asking here.
    Thank you for answering even though it is out of the scope of this forum technically, much appreciated.
    I have tons of C4D python code that works, so no questions about that so far :)

    I imagine this will work just fine, going to adapt it into my script.

    posted in General Talk •
    RE: Aligning object local axis to world axis via Python

    @ferdinand : Thank you for the pointers to the articles, and I fully understand that you do not have the time to explain the more complex parts of the Matrix concepts.
    I will read the material you have provided and otherwise search for info on Linear Algebra to get a better undertstanding.

    I think I understand it a bit better now, basically those 3 numbers per axis (X,Y,Z) basically tell you along which world axis they lie.
    So the main columns are X,Y,Z and then each row is technically X,Y,Z as well.

    X Y Z
    X X X
    Y Y Y
    Z Z Z

    With the help of Cairyn I've figured out that the issue is with the transforms of parents and grandparents, so I will rewrite my code to remove all of those as well and this should hopefully fix the issue.

    Thank you very much for your help and should I run into further issues on this, I will post again in this thread!

    Kind regards,

    posted in Cinema 4D SDK •
    RE: Aligning object local axis to world axis via Python

    @ferdinand Thanks again for this extensive explanation, I will be sure to keep this at hand for reference.

    I do indeed grasp the concepts of multiple layers of coordinate systems but my issue specifically with the Matrix manual is that when I look at for instance the second image, with the nice colored columns for each component (Or so it would seem to me).

    Then when I see the 3rd image I see the number "1" jump colums which is the part that makes it confusing to me. I believe in the dabble I had with matrices that default "1" is the scale but I don't grasp why it doesn't just stay in one of the colored columns.

    Another time when I read out the matrix of an object that had rotations on it, the matrix showed everything 0 apart from those 3x default 1 jumping columns.
    So it appeared the matrix did not have any rotational values stored.
    Again, this confused me.

    To be open and honest here, I'm a visual artist that has started to do coding to make internal company tools and while I have an ok understanding of math some things like this I can't yet visualise for myself so I don't fully understand it yet.

    Kind regards,
    Joep

    posted in Cinema 4D SDK •
    RE: Aligning object local axis to world axis via Python

    The parent doesn't have the transforms but the grandparent indeed does, which seems to be the issue indeed.

    I've already got my code to move the points around to the old relative transformations so I'll re-use that one for these purposes.
    https://plugincafe.maxon.net/topic/13840/object-size-not-updated-after-points-move

    The Subdivision Surface object two up has rotation on it, below that is a null with only a scale of 1.3 and inside that null is my object.
    So if I store the points in my object and then reset the rotation of the SubS and scale of the null, and then put them back, all should be good.

    I'm making an in-house turntable tool to isolate out objects in complex scenes and I get to see all kinds of weird modelling actions from team members and externals that I need to catch and correct :dog: This is one of them.

    But say I wanted to rotate the pivot point to offset parent(s) transformations, how would I go about doing that in code?

    posted in Cinema 4D SDK •
    RE: Aligning object local axis to world axis via Python

    @ferdinand : Thanks a lot for replying in such an extensive manner, that code was really helpful in it's own way but for other purposes.

    Your code actually rotates and moves my object, which I do not want. I want it to remain in exactly the same location and orientation but I want it's axis system to match up to that of the world.

    It seems I wasn't detailed enough in my initial question:
    The object has no rotational transforms (all are 0) but the Pivot ("Enable Axis" button) is incorrectly oriented. The objects' local coordinate system does not match up with the worlds' coordinate system in terms of orientation (X-axis, Y-axis, Z-axis).

    Normally, as a human, one would press the "Enable Axis" button and manually rotate the objects'' Pivot point to match the orientation of the world axis. So that Y is up, etc.

    How would one do this in Python code?

    Currently the Y axis of the object is on the worlds' X axis, so if I call the GetRad() function, the width of the object is actually put in the Y component of the c4d.Vector, not in the X where it should belong.

    Edit: I have read up on the matrix manual but it's confusing to me, but that is a different subject.

    Kind regards,

    posted in Cinema 4D SDK •
    Aligning object local axis to world axis via Python

    Hi there,

    I've got a question that I can't seem to solve myself and neither is Google being of much help.

    I've got an object of which it's local axis are not aligned with the world axis.
    In this case:
    The y of the object is on the x of the scene
    The x of the object is on the -z of the scene
    The z of the object is on the -y of the scene

    I'm trying to build a custom bounding box for an internal tool and as you can imagine, reading of GetRad along completely wrong axis will give me an incorrect bounding box.

    So I will need to align the axis of the object to the world axis first and then do my GetRad.

    Normally as human, one would rotate the pivot point of the object to align with the world, however I would like to do this in code, as this will be part of a recursive loop going through a list of objects.

    I've tried fiddling around with the matrices but this did not result in anything.

    Kind regards,

    posted in Cinema 4D SDK •
    RE: Object size not updated after points move

    Well, that indeed fixed the issue, now the size gets properly updated! :)

    Thank you very much for the help

    posted in Cinema 4D SDK •
    Object size not updated after points move

    Hi there,

    I have a technical Python question which I can't seem to solve.

    The following script is used to store the points in an object, then reset the rotation of the object and then put the points back into their old position:

    def reAlignPoints(Object):
        if (Object.GetType() == c4d.Opolygon) or (Object.GetType() == c4d.Opoint):
            oldm = Object.GetMg()
            points = Object.GetAllPoints()
            pcount = Object.GetPointCount()
            Object.SetAbsRot(c4d.Vector(0))
            Object.SetAbsScale(c4d.Vector(1))
            newm = Object.GetMg()
            
    
            for p in range(pcount):
                Object.SetPoint(p,~newm*oldm*points[p])
    

    This works very well, however I'm running into a problem if I look under the Coordinate Manager of the object and then it's size. Under size the object still appears to be in it's old orientation at first glance.
    However, if I click on any of the size values and then simply hit enter, all the values jump around to the give the object it's correct orientation again.
    For instance, the longest axis is initially the "Z" axis (old orientation) but when I click the value and hit enter, the contents of the "Z" axis jump to the "Y" axis where they should be.

    My question is two fold:

    • Why is this happening? What is going awry in my code that the object size is not properly updated?
    • What is the best way to fix this in python code and/or can I automate this clicking and hitting enter to switch the values around?

    Currently I read the bounding box of the/multiple objects and compile a custom bounding box afterwards, but this currently has the wrong orientation because the size parameters are not in the correct axis.

    Kind regards,

    posted in Cinema 4D SDK •