Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login
    1. Maxon Developers Forum
    2. Peek
    3. Posts
    P
    • Profile
    • Following 0
    • Followers 0
    • Topics 5
    • Posts 21
    • Best 1
    • Controversial 0
    • Groups 0

    Posts made by Peek

    • RE: Running commanline application with Python

      @ferdinand : Yeah I will because that is definitely not what I'm seeing 🙂

      Manually login in in both commandline/c4dpy works. As that is what we are doing now on all render nodes when the licenses vanish yet again.

      Thanks!

      posted in General Talk
      P
      Peek
    • RE: Running commanline application with Python

      @ferdinand When I was talking about Commandline I mean the actual Cinema4D app/.exe, not the terminal/powershell.

      I will give the command a go Today and see how it goes. Thanks for the help regardless that it was outside of scope 🙂

      Well, with your command on MacOS I basically get a wall of text but it does finish. However when I then manually run the C4D commandline again I get the standard "Enter the license method:" window

      When I run it in c4dpy it ends on "Welcome to the world of C4D and python (....)" and >>>.

      Cheers,

      posted in General Talk
      P
      Peek
    • RE: Running commanline application with Python

      @ferdinand

      Thanks for adding the SDK info and also thanks for the hints, I will investigate further. We normally log in to Maxon accounts via the commandline or via the login window in Cinema, so it should work I imagine.

      posted in General Talk
      P
      Peek
    • RE: Running commanline application with Python

      @ferdinand Due to the busy schedule at work I've only now gotten around to getting to implement this and I'm a bit stuck.

      • When I run both the commandline and c4dpy the terminal goes into some kind of endless loop on one of the MacOS rendernodes, it just keeps going endlessly with the same wall of text.
      • When I run just the commandline part it ends, but the license info doesn't seem to be inputted. As when I then manually run the commandline afterwards it asks for license info again.
      • When I run just the c4dpy part it also goes into an endless loop spouting the same wall of text over and over again.

      You mentioned in your reply "and we will also expose it in the technical and user documentation (in fact a few things should be updated there)." but I can't find anything in the SDK documentation about "g_license", just one quick mention in c4dpy about passing username and password as arguments.

      posted in General Talk
      P
      Peek
    • RE: Running commanline application with Python

      Hi @ferdinand : Thanks a ton for helping out even though technically this kind of support is outside the scope.

      I will read up on the material you provided and implement the code example into our own code.

      As always you've been very helpful 🙂

      Cheers,

      Joep

      posted in General Talk
      P
      Peek
    • RE: Running commanline application with Python

      @ferdinand : I will, thanks again for investigating 🙂

      Cheers,
      Joep

      posted in General Talk
      P
      Peek
    • RE: Running commanline application with Python

      @ferdinand : Hi Ferdinand, thanks for getting back to me on this.

      As for the legal aspects (the following is my personal opinion), what do you mean exactly?
      We pay for licenses and we don't want the inconvenience of having to manually go through all render clients when the licensing system fails us yet again.
      These actions (inputting license information on all commandline clients in our farm) cost man hours which can be more effectively spent working for clients rather than working around a needlessly cumbersome system.
      There is no effective difference between me manually inputting the information on a client and doing it in an automated fashion with a piece of code.

      That being said, if I'm missing something else here please feel free to correct my thinking.

      Cheers,
      Joep

      posted in General Talk
      P
      Peek
    • Running commanline application with Python

      Hi guys,

      Running into a bit of an issue with the commandline application on Windows/MacOS when running and "driving" it via Python (standalone, outside Cinema4D).

      We're writing an application that automatically handles the license logins on the machines in our renderfarms. Every time there is a minor update to Cinema or the Maxon App, all our machines seem to lose their license which is a lot of manual labor to get working again.

      We have the following code:

      import subprocess
      import os
      from os.path import expanduser
      import time
      
      # Petermine the platform (Windows or MacOS)
      is_windows = os.name == 'nt'
      
      # Path to your C4D executable
      if is_windows:
          try:
              c4d_executable = r'C:\Program Files\Maxon Cinema 4D 2023\Commandline.exe'
          except:
              print("Commandline executablecould not be found!")
              subprocess.wait(5)
      else:
          try:
              c4d_executable = '/Applications/Maxon Cinema 4D 2023/Commandline.app/Contents/MacOS/Commandline'
          except:
              print("Commandline executablecould not be found!")
              subprocess.wait(5)
      
      
      # Define the license information to provide
      license_method = "2"
      license_username = "XXXXXXXX"
      license_password = "XXXXXXXX"
      license_floating_commandline = '1'
      
      # Define license files
      
      
      # Get user home directory
      home = expanduser("~")
      print(home)
      
      
      # Create a subprocess to run C4D
      c4d_process = subprocess.Popen(
          [c4d_executable],
          stdin=subprocess.PIPE,
          stdout=subprocess.PIPE,
          stderr=subprocess.PIPE,
          shell=True,
          text=True
      )
      
      # Use a loop to read and print the output in real-time
      def capture_and_print_output(process):
          while True:
              output_line = process.stdout.readline()
              if not output_line:
                  break  # No more output, exit the loop
              print(output_line, end='')  # Print the line without adding extra newline
      
              # Check for error messages in the output
              if "Error:" in output_line:
                  print("Error message detected:", output_line)
      
          while True:
              error_line = process.stderr.readline()
              if not error_line:
                  break  # No more error output, exit the loop
              print("Error:", error_line, end='')
      
      # Capture and print outputs before providing license information
      capture_and_print_output(c4d_process)  # Output before license input
      
      # Wait for Commandline to prompt for input
      output, _ = c4d_process.communicate(timeout=10)
      
      print("Output:", output)
      
      if "Please select:" in output:
          print("Inside the license method loop")
          # Provide the license information
          time.sleep(5)
          c4d_process.stdin.write(license_method + '\n')
          c4d_process.stdin.flush()
      
          print("sleeping")
          time.sleep(2)
      
          # Capture and print outputs after providing license method
          capture_and_print_output(c4d_process)
      
          # Send the Enter key
          c4d_process.stdin.write('\n')
          c4d_process.stdin.flush()
      
          print("sleeping after Enter")
          time.sleep(2)
      
          # Capture and print outputs after providing license method
          capture_and_print_output(c4d_process)
          
          time.sleep(2)
          
      
          # Capture and print outputs after providing license method
          capture_and_print_output(c4d_process)
      
      if "Account email address []: " in output:
          print("Inside the email address loop")
          # Provide the license information
          c4d_process.stdin.write(license_username)
          c4d_process.stdin.flush()
      
          # Send the Enter key
          c4d_process.stdin.write('\n')
          c4d_process.stdin.flush()
      
          # Capture and print outputs after providing email address
          capture_and_print_output(c4d_process)
      
      if "Password: " in output:
          print("Inside the password loop")
          # Provide the license information
          c4d_process.stdin.write(license_password)
          c4d_process.stdin.flush()
      
          # Send the Enter key
          c4d_process.stdin.write('\n')
          c4d_process.stdin.flush()
      
          # Capture and print outputs after providing password
          capture_and_print_output(c4d_process)
      
      if "Please choose one of the following options: " in output:
          print("Inside the license type loop")
          # Provide type of license
          c4d_process.stdin.write(license_floating_commandline)
          c4d_process.stdin.flush()
      
          # Send the Enter key
          c4d_process.stdin.write('\n')
          c4d_process.stdin.flush()
      
          # Capture and print outputs after providing license type
          capture_and_print_output(c4d_process)
      
      else:
          print("No input detected!")
          c4d_process.wait(5)
          c4d_process.stdin.close()
          c4d_process.stdout.close()
          c4d_process.stderr.close()
          c4d_process.terminate()
      
      # You can now continue working with the C4D process or wait for it to finish
      print("Licensing process ran succesfully")
      c4d_process.wait(5)
      
      # Close the subprocess and clean up
      c4d_process.stdin.close()
      c4d_process.stdout.close()
      c4d_process.stderr.close()
      c4d_process.terminate()
      

      Basically what happens is that the commandline application doesn't seem to register the "replies" that Python gives it when it asks for specific license information inputs. I've tried a ton of different ways to go about it but none seem to work.
      Tried with sleep, without sleep, "Please select: ", "Please select:", "Enter the license method:", "Enter the license method: ", with \n, without \n etc.

      Is there some specific timing I need to adhere to or something else behind the scenes that I'm not aware of?

      Kind regards

      posted in General Talk 2023 python macos windows
      P
      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 Bugs
      P
      Peek
    • 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://developers.maxon.net/forum/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 Bugs python
      P
      Peek
    • 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
      P
      Peek
    • 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
      P
      Peek
    • 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 python 2023
      P
      Peek
    • 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
      P
      Peek
    • 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
      P
      Peek
    • 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
      P
      Peek
    • 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://developers.maxon.net/forum/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 🐶 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
      P
      Peek
    • 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
      P
      Peek
    • 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 python r25
      P
      Peek
    • 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
      P
      Peek