Navigation

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

    Posts made by .del

    RE: Get all textures for a material

    Thanks Ferdinand. I'll take a stab at it again. I have to start by learning more about your Python syntax.

    Did I mention I'm a 3D/mograph guy that pretends to understand python and the c4d sdk? 🙂

    Thanks for taking the time to help people like me out. I try to do what I can with the documentation, forums and search but sometimes it's the syntax in the documentation that I don't quite understand. That's the downside for me. I learn a little more each time though and that helps.

    Thanks again for the example. I'll see if I can get GetAllTextures() to work for me.

    posted in Cinema 4D SDK •
    RE: Get all textures for a material

    That makes total sense @ferdinand.

    Kind of have to start at the beginning to understand where I'm coming from. I found myself exporting individual .fbx files on a more regular basis but only a couple at a time so it was not a problem to do it in the interface. I added the Export Selected Objects As to my toolbar for ease of use as it fills in the fbx file name with the selected objects name by default. I have my fbx export preferences preset to Selection Only. This work flow has gotten me into a habit of clicking a button to open the export panel and then clicking ok. Easy.

    That brings us to this week where I have to export 160 objects. Writing a script to do exactly what I was doing was easy enough. But then I got greedy and wanted to collect the textures as well. We don't use embedded textures in our fbx so collecting them for transfer has been a manual process. That's when I was faced with two options.

    1. Get a cake 🙂 (I love that analogy by the way) I do this for many of my other exports like .c4d, .obj and .gltf
    2. Leverage the built in Selection Only aspect of the fbx exporter and then simply use Python to copy some texture files from my tex folder to my delivery folder. It felt like it would be a simpler, lower overhead solution versus creating a 'donor' doc. Or at least it feels like it should be simple. There's even a function called GetAllTextures and an option to have it restricted to a single model rather than from the entire doc.

    I'm ok with how I had to make it in the end but now I'm really curious how the GetAllTextures() works in case I can leverage it for this or something else down the road.

    The FBX exporter is unique in Cinema since Maxon added the Selection Only option to it. If it weren't for that thing I'd be at the bakery....all.....day.....long 🙂

    import c4d
    import os
    from c4d import gui
    from c4d import documents
    from c4d import plugins
    
    
    def listModels():
        selected = []
        rawSelection = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE)
        for item in rawSelection:
            if item.CheckType(5100) or item.CheckType(5140): # PolygonalObject or Null
                selected.append(item)
        rawSelection = []
        return selected
    
    
    models = listModels()
    if models == []:
        message = "You must select at least one object"
        c4d.gui.MessageDialog(message, c4d.GEMB_OK)
    else:
        gui.SetMousePointer(c4d.MOUSE_BUSY)
        c4d.StatusSetSpin()
    
        # Get fbx export plugin,
        plug = plugins.FindPlugin(c4d.FORMAT_FBX_EXPORT, c4d.PLUGINTYPE_SCENESAVER)
        if plug is None:
            print("noPlug")
    
        op = {}
        # Send MSG_RETRIEVEPRIVATEDATA to fbx export plugin
        if plug.Message(c4d.MSG_RETRIEVEPRIVATEDATA, op):
    
            # BaseList2D object stored in "imexporter" key holds the settings
            fbxExport = op["imexporter"]
    
            # Define the settings
            fbxExport[c4d.FBXEXPORT_FBX_VERSION] = c4d.FBX_EXPORTVERSION_NATIVE
            fbxExport[c4d.FBXEXPORT_SELECTION_ONLY] = True
            fbxExport[c4d.FBXEXPORT_TRIANGULATE] = True
            fbxExport[c4d.FBXEXPORT_SAVE_NORMALS] = True
            fbxExport[c4d.FBXEXPORT_UP_AXIS] = c4d.FBXEXPORT_UP_AXIS_Y
            fbxExport[c4d.FBXEXPORT_FLIP_Z_AXIS] = False
            fbxExport[c4d.FBXEXPORT_MATERIALS] = True
            fbxExport[c4d.FBXEXPORT_EMBED_TEXTURES] = False
            fbxExport[c4d.FBXEXPORT_BAKE_MATERIALS] = False
    
    
    
        #check for target directory
        targetPath = os.path.join(doc.GetDocumentPath(), "FBX_Exports")
        if os.path.exists(targetPath) == False: #makes a new directory to store the converted files in
            os.mkdir(targetPath)
    
        for obj in (models):
            fbxName = c4d.BaseList2D.GetName(obj) + ".fbx" #get the name of the model
            fbxPath = os.path.join(targetPath,fbxName)
    
            # Get the texture files and a save a c4d file for rendering
            theTextures = doc.GetAllTextures(False, [obj])
            print(theTextures)
            # if I can get the textures I will write some shutil.copyFile type of stuff here
    
    
    
            #export the fbx
            if c4d.documents.SaveDocument(newDoc, fbxPath, c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, c4d.FORMAT_FBX_EXPORT) == False:
                if gui.MessageDialog("Export failed!" + " - " + fbxName, c4d.GEMB_OKCANCEL) == c4d.GEMB_R_CANCEL:
                    break
    
    
    
    
        c4d.gui.SetMousePointer(c4d.MOUSE_NORMAL)
        gui.MessageDialog("Export Complete", c4d.GEMB_OK)
        c4d.StatusClear()
    
    posted in Cinema 4D SDK •
    RE: Get all textures for a material

    Thanks @ferdinand for the reply and the example.

    You are correct that my current solution uses IsolateObjects and creates a new doc. Since that doc only has the single mesh and materials in it I can use SaveProject to collect the textures.

    In reference to GetAllAssets vs GetAllAssetsNew - I had originally written an exporter in R19 and pulled some of my script forward to begin this new version. I saw the new version for this but I kept getting an error and the old command still worked. I didn't understand what the last parameter was supposed to be. The documentation shows this - assetList (List[Dict]). After awhile I gave up because the old command still worked. I know that isn't the right thing to do but when the clock is ticking I have to go with what I can get working. Your example sheds more light on how I have to format that last parameter. I'm going to give it a try.

    Ultimately I was trying to create a different solution that didn't require creating an isolation doc. I feel like I should be able to iterate through a list of selected objects and export them as fbx files without creating temporary documents. I have that working. The next step is to collect the textures for those objects. I can get the material for each object and crawl through the shader tree looking for bitmaps but I was hoping for something that was going to be quicker to set up. GetAllTextures() looked promising but I struggled to get it to work and I haven't been able to find any threads or examples that.

    thanks,
    .del

    posted in Cinema 4D SDK •
    RE: Get all textures for a material

    I found a way around what I want to do by using this -
    c4d.documents.SaveProject(newDoc, c4d.SAVEPROJECT_NONE|c4d.SAVEPROJECT_ASSETS|c4d.SAVEPROJECT_DIALOGSALLOWED, targetPath, theAssets)

    I didn't realize that I could skip saving the actual project file but instead use the call just to gather textures. It's probably not very clean creating a new document and isolating my selected models to it just for the purpose of texture collection but it gets me through this jam while I learn more about how to do it the right way.

    posted in Cinema 4D SDK •
    Get all textures for a material

    Hi- I'm a bit stumped and looking for some direction. I have a file with multiple objects in it. I'd like to select 10 of those objects and export each one as an individual fbx file that has only a single object in it. 10 selected objects equates to 10 fbx files. That part I have working.

    I'd also like to collect the textures associated with the single material that has been applied to the single object in the fbx.

    I tried using doc.GetAllAssets() and set the flag to textures only but I could not find a way to link the single models to the correct texture files in the list. Maybe there is an identifier in that list that I'm not seeing that will allow me to find only the texture files I want versus the list of all textures used?

    Since I couldn't figure that out I moved on to doc.GetAllTextures() . I feel like the optional [List[c4d.C4DAtom]] is the thing I need to use in order to get the texture file list for the single, selected model instead of the all of the textures for the entire document.

    models = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_NONE)
    for obj in (models):
            #theAssets = c4d.documents.GetAllAssets(doc, False, lastPath, c4d.ASSETDATA_FLAG_TEXTURESONLY)
            theTextures = doc.GetAllTextures(False, [obj])
            print(theTextures)
    

    The script returns a c4d.BaseContainer. I'm scratching my head on what to do with that. Am I on the right path or am I missing something?

    Any tips on where to look next or reference material on how to get my texture file names out of that BaseContainer will be greatly appreciated.

    thanks,
    .del

    posted in Cinema 4D SDK •
    RE: Possible typo in documentation

    Thanks for the info and adding the tag. I totally forgot that the Cafe' merged. I'm so used to approaching from my view. I actually answered somebodies question yesterday and at the very end saw the C++ tag and hit delete 🙂

    Thanks for tips on the GUI. I was able to implement what I needed.

    posted in Cinema 4D SDK •
    Possible typo in documentation

    Hi - I'm currently making an attempt to better understand the gui.GeDialog stuff and ran across this in the sdk.

    GeDialog.GroupBorder(self, borderstyle)
    Sets the border type of the current group, and displays the title in the border if possible.

    GeDialog.GroupBorderNoTitle(self, borderstyle)
    Sets the border type of the current group, and displays the title in the border if possible.

    Am I reading these wrong and haven't learned anything yet or should GroupBorderNoTitle have a different explanation and not have border title parameters listed below it?

    Thanks for looking,
    .del

    posted in Cinema 4D SDK •
    RE: UV Peeler - accessible?

    HI -

    Thanks for the response!

    I'm going to go with the sendModelingCommand method. I never would have thought to put the CallCommand value in there.

    This is really going to help me finish this script. I appreciate your help.

    thank you,
    .del

    posted in Cinema 4D SDK •
    UV Peeler - accessible?

    Hi - I'm wondering if the UV Peeler is accessible via python. I see it listed in the SDK but I'm not familiar with how to use it.

    Can it be used with SendModelingCommand or bodypaint.CallUVCommand?

    The documentation references C4DAtom.SetParameter() but I've never used this.

    Any info that can push me in the right direction is appreciated.

    thanks,
    .del

    posted in Cinema 4D SDK •
    RE: Python uvTag.GetSlow(poly) data not matching what's in Structure Manager

    @ferdinand Thank you so much for digging into this. I'll look at your example more and try quantitizing the numbers. In the meantime I had written a catch for the -1.1102230246251565e-16 to treat it as zero but it's probably not a very robust solution. I like your idea of rounding them off instead. I didn't fully understand what that number represented. I tried searching it but didn't get any useful results. I tried again today and now I see what it is. I must have had something else in my search field when I originally tried.

    We have a script for creating atlases of textures and if the UV is outside of the bounds it gets placed incorrectly on the atlased texture. This new script is intended to catch those so they can be corrected before hand. I think rounding anything within two decimal places of zero will work for our needs.

    Is there a way to change the tags for this this thread as it's not a bug report. I thought it was but it turns out it's not.

    Thanks you for the help. It's greatly appreciated.

    posted in Cinema 4D SDK •
    RE: Python uvTag.GetSlow(poly) data not matching what's in Structure Manager

    I've been able to confirm that if I take the suspect vertexes and change them from a value 1 to .99 and then change them back to 1 they no longer cause the problem.

    posted in Cinema 4D SDK •
    RE: Python uvTag.GetSlow(poly) data not matching what's in Structure Manager

    Hi -

    Thank you both for responding.

    I searched my model group and found other models with vertexes at the bounding box corners and those did not get flagged by my script so your suggestion of a malformed UV or some sort of overflow might be what my issue is. The script also worked as expected on your plane.c4d file as well as a cube.

    If the overflow value is consistent perhaps I can test for that and allow it to pass rather than flagging the model?

    I'm attaching a scene file with two models made from the same template. Ones fails to pass the test while the other works. They are labeled accordingly.

    I've also trimmed the script to focus on the bounding box part. It's not as elegant as yours by any means but I'm a self admitted butcher of code. Just trying to make tools to streamline our workflow. They aren't pretty but they help us get home at the end of the day and I'm appreciative that the sdk is available. Please keep that in mind as you stumble through my vomit pile of a script. My code is not Pythonic.

    Thanks for looking at my stuff.

    .del

    
    
    import c4d
    import os
    import math
    
    
    from c4d import gui
    from c4d import Vector
    from c4d import bitmaps
    from copy import copy
    from c4d.modules import bodypaint
    
    
    
    #####
    
    
    
    
    
    #Start the clean up tasks to prepare for exporting to the library.
    
    
    doc.SetMode(c4d.Mmodel)
    
    dObjects = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER)
    if dObjects == []:
        message = "You must select at least one object"
        c4d.gui.MessageDialog(message, c4d.GEMB_OK)
    else:
        c4d.StatusSetSpin()
        c4d.StatusSetText("Running Python Script")
    
        isolate = False
        for obj in dObjects:
            if obj.CheckType(c4d.Opoint):
    
                ############################
                # check that UV is within bounds
                #
                uvTag = obj.GetTag(c4d.Tuvw)
                polyCount = obj.GetPolygonCount()
                polygons = obj.GetAllPolygons()
    
                for poly in range(polyCount):
                    polygon = polygons[poly]
                    data = uvTag.GetSlow(poly)
                    print("poly" + str(poly) + str(data))
                    if polygon.IsTriangle(): #if the poygon is a triangle instead of a quad we need to delete the 4th key as that position data is skewed and throwing a false positive.
                        del data['d']
                    for vertex in data:
                        if data[vertex].x < 0 or data[vertex].x > 1:
                            print(data[vertex].x)
    
                        if data[vertex].y < 0 or data[vertex].y > 1:
                            print(str(poly) +" " +vertex)
                            print(data[vertex][1])
                            print(data)
    
    
    
    
    c4d.StatusClear()
    

    uv boundary testing.c4d

    posted in Cinema 4D SDK •
    Python uvTag.GetSlow(poly) data not matching what's in Structure Manager

    Hi -

    I made a script that gets the vertex points of a UV and checks to see if they or within the 0,0 1,1 coordinate system. The script flags any vertex position less than 0 or greater than 1.

    I print the output to the script manager identifying which polygon number it is as well as if it's the a, b, c, or d UV vertex. I also print out the full data dictionary for that polygon.

    I have one model that is getting flagged by my script for having a vertex less than zero. As I was digging through my script and looking at the model with the Structure Manager pulled up I found an interesting thing. Any vertex that has a V value of 1 in the structure manager is coming through uvTag.GetSlow(poly) as a scientific notation value of -1.1102230246251565e-16. I am not seeing the same issue if the U value is equal to 1.

    I took a screen shot of the Structure manager laid next to the python console so you can see what I mean.

    Any ideas on how I can program around this?

    Thanks,
    .del

     ############################
                # check that UV is within bounds
                #
                uvTag = obj.GetTag(c4d.Tuvw)
                polyCount = obj.GetPolygonCount()
                polygons = obj.GetAllPolygons()
    
                for poly in range(polyCount):
                    polygon = polygons[poly]
                    data = uvTag.GetSlow(poly)#returns a dictionary {a: Vector( u, v, w), b: Vector( u, v, w), c: Vector( u, v, w), d: Vector( u, v, w)}
                    #print("poly" + str(poly) + str(data))
                    for vertex in data:
                        if data[vertex][0] < 0 or data[vertex][0] > 1:
                            print(data[vertex][0])
    
                        if data[vertex][1] < 0 or data[vertex][1] > 1:
                            print(str(poly) +" " +vertex)
                            print(data[vertex][1])
                            print(data)
    
    
    

    uvVertex.PNG

    posted in Cinema 4D SDK •
    RE: Enabling Team Render in Render Queue

    Thanks Manuel. I was able to work that concept into the overall script.

    posted in Cinema 4D SDK •
    Enabling Team Render in Render Queue

    Hi- I have a python script that adds projects to the render queue successfully but now I'd like to be able to enable the Team Render option for them. After reviewing the documentation I felt like BatchRender.SetUseNet(self, n, on) was going to be the answer but I havn't been able to get it to work.

    In the main body of the script I set dBatch = c4d.documents.GetBatchRender().
    Later in the script I call batchRender definition.

    def batchRender(dFilePath, objName):
        dBatchCount = dBatch.GetElementCount() #number of items already in the batch render
        dBatchCount += 1
        dBatch.AddFile(dFilePath +"/" + objName + ".c4d", dBatchCount)
        ####enable Team Render for item
        dBatch.SetUseNet(dBatchCount,True)
    
    

    The script doesn't return any errors but the Team Render box is never activated.

    c73ee49b-3898-4e8e-9d52-88713b6560af-image.png

    Any insight is appreciated.

    Thanks,
    .del

    posted in Cinema 4D SDK •
    RE: OBJ Export Options

    Thanks for looking at it Manuel. Sounds like your getting the same behavior I'm seeing.

    I'll add something to my script to parse it out.

    Thanks Manuel and Cairyn for taking time to help.

    .del

    posted in Cinema 4D SDK •
    RE: OBJ Export Options

    I was able to get it working once I knew that I was supposed to be passing text and you were right that once I re-laucnhed R23 it cleared up the problem with the export working from the main menu. I wish I knew about the GitHub file sooner as it would have saved me some time. My script is an adaptation of an fbx exporter I had been using. At the time I created I couldn't find much on .obj exporting. These things are two years old and I'm just circling back to them as I start using R23.

    Unfortunately I've come to find that the new exporter uses a file path in the .mtl file for the image whereas the previous versions did not. I'm not sure why the change was made but having a file path in there is throwing off the software that imports the .obj files. I don't see a way for me to set set a preference for it. I find myself falling back to R21 again until I can dig into the possibility of writing something to alter the .mtl file.

    posted in Cinema 4D SDK •
    RE: OBJ Export Options

    Well it looks like exporting an .obj isn't working for me at the moment anyway. The full scripts exports everything except the obj and when I try to use C4D's menu to export an .obj nothing happens either. No error message....nothing....no file...no lockup......nothing. I've submitted a support ticket. I'm not sure if it's script related or just a bug in R23. I'll have to fall back to R21 again so I can keep working.

    posted in Cinema 4D SDK •
    RE: OBJ Export Options

    Thanks for your help, that worked. I swear that the documentation and what the SDK expects changes every couple of years. Several years ago I'd try words and I'd be told to use numbers and now it seams as if numbers work for some things but words are required for others. It can be a bit confusing for me at times but at least I have a working script again.

    Just to clarify, I always thought when the documentation showed 'Parameter Type: int' that it meant a number and the number was representative of the numerical position in the list. You mentioned "numeric value of the five options shows that they are between 4092 and 4096". Where did you find those numbers? I don't see that in the Python documentation.

    thanks,
    .del

    posted in Cinema 4D SDK •
    RE: OBJ Export Options

    I'm using a 1 because it's the second value in the list much like I'm using for for Scale and Material where the numbers represent their positions in the list.

    I'll give it a try with the value instead.

    posted in Cinema 4D SDK •