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
    • Unread
    • Recent
    • Tags
    • Users
    • Login
    1. Maxon Developers Forum
    2. Manuel
    • Profile
    • Following 0
    • Followers 2
    • Topics 1
    • Posts 1,281
    • Best 287
    • Controversial 0
    • Groups 0

    Manuel

    @Manuel

    346
    Reputation
    455
    Profile views
    1.3k
    Posts
    2
    Followers
    0
    Following
    Joined Last Online
    Website developers.maxon.net/ Location France

    Manuel Unfollow Follow

    Best posts made by Manuel

    • RE: Add/Remove Groups of User Data

      Hello,

      After some research in the forum, i've found this post that show how to react to a button pressed.

      With that, it juste a matter of using AddUserData and his friend RemoveUserData

      Let me try to explain a bit more what i've done.
      In the UserData tab, i've a got a group that will be used as a container, so i can add or remove thing inside without touching other userdata. I just browse through all user data using GetUserDataContainer and check the parent of the fields with DESC_PARENTGROUP

      I'm pretty sure you will go through this code easily but if you got any questions, feel free to ask.

      i'm adding the file so you can play with the code directly
      AddRemoveGroup.c4d

      And the code. At the top, i've got the ID of both button and the group that will serve as a container.

      import c4d
      
      
      # the group id where all the fiels will be created.
      addButtonID = 1
      removeButtonID = 2
      mainGroupID  = 3
      
      
      
      def AddGroupOfUserData():
          """
          Creating the group with differents field.
          Called by button Add
          """
          obj = op.GetObject() # get the object where we want the user data
          parentGroup = obj.GetUserDataContainer()[mainGroupID][0]
          newGroup = CreateGroup(parentGroup)
      
          nameString = AddString(newGroup, "Name")
          check = AddBool (newGroup, "Use Sound")
          timeField = AddTime(newGroup, "StartTime")
          AddSoundPath(newGroup, "Sound")
          
          #as function are returning the id of the userdata we can change their value
          obj[nameString] = "Default value for the string"
          #Set the bool to tru by default
          obj[check] = True
          #set the time to 0 
          obj[timeField] = c4d.BaseTime(0)
      
      def RemoveGroupOfUserData():
          """
          this will iterate trough all group and remove the last one
          including his children
          """
          obj = op.GetObject() # get the object where we want the user data
          lastGroupID, count = GetLastGroupID()
      
      
          if lastGroupID > -1:
              # we find a group so let remove all the child of that group we found
              for descID, bc in op.GetObject().GetUserDataContainer():
      
                  if IsChildOfGroup(bc, lastGroupID):
                     obj.RemoveUserData(descID)
                     del(obj[descID]) #remove the information in the basecontainer
      
              obj.RemoveUserData(lastGroupID)
              del(obj[lastGroupID])
              obj.Message(c4d.MSG_UPDATE)
      
      
      def IsChildOfGroup(bc, groupID = mainGroupID):
          """
          Check if the parent is the same id of groupID
          """
          if bc[c4d.DESC_PARENTGROUP].GetDepth() > 1:
              if bc[c4d.DESC_PARENTGROUP][1].id == groupID:
                  return True
          return False
      
      
      def GetLastGroupID(parent = None):
          """
          get the last group in the user data
          """
          groupID = -1
          count = 0
          for descID, bc in op.GetObject().GetUserDataContainer():
              if descID[1].dtype == c4d.DTYPE_GROUP:
                  if IsChildOfGroup(bc):
                          count += 1
                          groupID = descID[1].id
      
          return groupID, count
      
      
      def CreateGroup(parent, trackNumber = -1):
          """
          this will create a group in the user data below "myGroup" with all the different data needed
          """
          if trackNumber < 0:
              # we must calculate the track number
              lastGroupID, trackNumber = GetLastGroupID()
      
          #Get the default container for the group type
          bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_GROUP)
          longName  = "Track " + str(trackNumber)
          shortName = "Track"  + str(trackNumber)
      
          bc[c4d.DESC_NAME] = longName
          bc[c4d.DESC_SHORT_NAME] = shortName
          bc[c4d.DESC_TITLEBAR] = True
          bc[c4d.DESC_GUIOPEN] = False
          bc[c4d.DESC_PARENTGROUP] = parent
          #return the group id added so we can add other element to it
          return op.GetObject().AddUserData(bc)
      
      
      
      def AddBool (group, name):
          """
          this will create a boolean gadget in the group
          """
          bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_BOOL)
          bc[c4d.DESC_NAME] = name
          bc[c4d.DESC_SHORT_NAME] = name
          bc[c4d.DESC_PARENTGROUP] = group
          return op.GetObject().AddUserData(bc)
      
      
      def AddTime(group, name):
          """
          this will add the field start time for exemple
          """
          bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_TIME)
          bc[c4d.DESC_NAME] = name
          bc[c4d.DESC_SHORT_NAME] = name
          #bc[c4d.DESC_UNIT] = c4d.DESC_UNIT_TIME
          bc[c4d.DESC_PARENTGROUP] = group
          return op.GetObject().AddUserData(bc)
      
      def AddSoundPath(group, name):
          """
          this will add the field for file
          """
          bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_FILENAME)
          bc[c4d.DESC_NAME] = name
          bc[c4d.DESC_SHORT_NAME] = name
          bc[c4d.DESC_PARENTGROUP] = group
          return op.GetObject().AddUserData(bc)
      
      
      def AddString(group, name):
          """
          this will add a static string to a group
          """
          bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_STATICTEXT)
          bc[c4d.DESC_NAME] = name
          bc[c4d.DESC_SHORT_NAME] = name
          #bc[c4d.DESC_CUSTOMGUI] = c4d.CUSTOMGUI_STATICTEXT
          bc[c4d.DESC_PARENTGROUP] = group
          return op.GetObject().AddUserData(bc)
      
      
      
      def message(msg_type, data) :
          if msg_type == c4d.MSG_NOTIFY_EVENT:
              event_data = data['event_data']
              if event_data['msg_id'] == c4d.MSG_DESCRIPTION_COMMAND:
                  desc_id = event_data['msg_data']['id']
                  if desc_id[1].id == addButtonID:
                      AddGroupOfUserData()
                  elif desc_id[1].id == removeButtonID:
                      RemoveGroupOfUserData()
                      
      
      
      def main() :
          pass
      
      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: Move just the axis of a polygonal object

      Hello @rui_mac

      you don't really need to deal with hierarchy as long as you are using global space.
      you have to come back to local space with the new matrix, by multiplying the points position with the inverse matrix.
      Be sure to also move the axis of the object as @mp5gosu stated and to ask the object to update itself.

              # Retrieves selected object
              op = doc.GetActiveObject()
              if op is None:
                  raise TypeError("There's no object selected.")
          
              # Retrieves the matrix of the object
              opmg = op.GetMg()
          
              # Retrieves the point in global space
              pointsGlob = [p * opmg for p in op.GetAllPoints()]
          
              # Starts the undo process (the initial scene to be restored after an undo action)
              doc.StartUndo()
          
              # Notifies a change on the obj
              doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
          
              # Updates the matrix
              opmg.off = c4d.Vector(0)
              # Updates the axis of the object
              op.SetMg(opmg)
          
              # Notifies the object, that internal data changed and it needs to be updated
              op.Message(c4d.MSG_UPDATE)
          
              # Inverses the matrix to come back to local space
              invopmg = ~opmg
          
              # Retrieves points from global to local space
              newPoints = [p * invopmg for p in pointsGlob]
          
              # Updates the points
              doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
              op.SetAllPoints(newPoints)
          
              # Ends the undo process (the final scene state)
              doc.EndUndo()
          
              # Updates Cinema 4D
              c4d.EventAdd()
          
      

      Cheers
      Manuel

      posted in General Talk
      ManuelM
      Manuel
    • RE: Retrieve the World Rotation of a Selected Edge?

      hello,

      To answer this question if someone want to do it by code.

      import c4d
      from c4d import gui
      
      # Welcome to the world of Python
      
      
      # Main function
      def main():
          #get the selected object
          op = doc.GetActiveObject()
          if not op:
              raise TypeError("there's no object selected")
          if not op.IsInstanceOf(c4d.Opolygon):
              raise TypeError("obj should be a polygon object")
      
          #setup neighbor
          nbr = c4d.utils.Neighbor()
          nbr.Init(op)
      
          #get the selected edge
          bs = op.GetSelectedEdges(nbr,c4d.EDGESELECTIONTYPE_SELECTION)
          
      
          #maximum number of edge should be number of polygon * 4
          sel = bs.GetAll(op.GetPolygonCount() * 4)
          
          #get all polygon
          vadr = op.GetAllPolygons()
          #init point a and b index to -1 for error check
          a = b = -1
          #initialise a counter to check in sel array.
          countEdge = 0
          
          #we can check now every edge to find the corresponding points. So for each polygon
          for i in xrange(op.GetPolygonCount()):
              #get the polygon information
              pli = nbr.GetPolyInfo(i)
      
              for side in xrange(4): # Test all 4 sides of a polygon
                  # Only proceed if edge is marked
                  # and edge really exists (for triangles side 2 from c..d does not exist as c==d)
      
                  if pli["mark"][side] or (side==2 and vadr[i].c == vadr[i].d): 
                      continue 
                  
                  #if the edge is marked as selected in our sel array
                  if sel[countEdge]:
                      if side==0:
                          a=vadr[i].a; b=vadr[i].b
                      elif side==1:
                          a=vadr[i].b; b=vadr[i].c
                      elif side==2:
                          a=vadr[i].c; b=vadr[i].d
                      elif side==3:
                          a=vadr[i].d; b=vadr[i].a
                  countEdge +=1
      
          if a == -1 or b == -1:
              raise ValueError("points index can't be negatives")
          
          #get all points array 
          points = op.GetAllPoints()
      
          
          #Get the direction of the edge in global coordinate (multiply the points'vector by the matrix of the object)
          opmg = op.GetMg()
          #i've picked a direction from point a to point b so the angle could need to be reverted.
          dirVector = points[b]*opmg - points[a]*opmg
          #normalize a vector is often a good idea.
          dirVector.Normalize()
          
          #transform the vector to hpb note the result is in radian
          hpb = c4d.utils.VectorToHPB(dirVector)
          
          #transform radian to degree
          hpb.x = c4d.utils.RadToDeg(hpb.x)    
          hpb.y = c4d.utils.RadToDeg(hpb.y)
          hpb.z = c4d.utils.RadToDeg(hpb.z)
      
          print "the edge is poiting to",dirVector,"the corresponding angle is", hpb
      
      
      # Execute main()
      if __name__=='__main__':
          main()
      

      Cheers
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: Modifying or Adding Script Directory?

      Hello,

      On windows, you can create an environment variable named C4D_SCRIPTS_DIR more informations in the doc
      The doc say : Multiple paths can be separated using a semicolon (;) but it's seem buggy at the moment, i have to investigate a bit further and i'll be back if i found something.

      On OSX you don't have environment variables but you can create a Symbolic Link (not an alias). You have to use the Terminal to do so (ln -s /<source>/myscript.py /<preferences path>/library/scripts) This will create a link in your scripts directory.
      I've tried to link from directory to directory but it doesn't work.

      Cheers
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: LoadFile(Filename file) does not work for layouts.

      Several things here,

      your path on windows should use backslash (\) and not slash (/)
      and you should have two.

      "C:\\Program Files\\MAXON\\Cinema 4D R20 Education\\library\\layout\\myLayout.l4d"
      

      A better way to do this is to use operator so your path will be compatible with all OS.

      // Create a filename to point to "Application directory/library/layout/Animate.l4d"
      const Filename file = GeGetStartupPath() + Filename("library") + Filename("layout") + Filename("Animate.l4d");
      // load the layout.
      Bool result = LoadFile(file);
      // check the result.
      if (!result)
      	DiagnosticOutput("can't load the layout");
      		
      

      I've tested this code in PluginMessage() using C4DPL_COMMANDLINEARGS and C4DPL_PROGRAM_STARTED

      Cheers
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: Set Use As Render View

      hello,

      For your next threads, please help us keeping things organised and clean.

      • Q&A New Functionality.
      • How to Post Questions especially the tagging part.

      I've added the tags and marked this thread as a question so when you considered it as solved, please change the state 🙂

      There's no function to set the viewport used for rendering.

      Why can't you use CallCommand ? (even if in this case the command is the same what ever the active viewport is)

      you can change it in the BaseContainer of the document. The symbol is not exposed so you have to use the ID itself.

          #DOCUMENT_RVIEW 10001
          bc = doc.GetDataInstance()
          print bc[10001]
          bc[10001] = 1
      

      Cheers,
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • Building R23 SDK with Visual Studio 16.9

      Hi,

      There's a know issue about compiling the R23 sdk with Visual Studio 16.9.
      Trying to compile with this version will lead you to the following error:

      Error C2079 'maxon::ResultBase<RESULT_TYPE>::_value' uses undefined class 'maxon::BlendAnimationRef' math.framework <path to the file> 571
      

      This issue will be fixed in the next update.
      To fix the issue, open the file objectbase.h of core.framework and change those lines :

      around line 1088:

      // template <typename I, typename = I*> struct VirtualCreate
      // become 
      template <typename I, typename = I*(*)()> struct VirtualCreate
      
      

      around line 1102:

      // template <typename I> struct VirtualCreate<I, decltype(I::Create())>
      // become 
      template <typename I> struct VirtualCreate<I, decltype(&I::Create)>
      

      Cheers,
      Manuel

      posted in News & Information news sdk
      ManuelM
      Manuel
    • RE: Use a list or array for data?

      Hello,

      The first thing that come to mind is a for loop. But you need to get informations in userData that are stored in your obj in a chaotic way.

      What i suggest here, is to create those userdata in a more organized way (maybe with a script) so can easily create a loop in that case.

      in pseudo code it could be something like this at the end.

      tracks = obj.GetCTracks()
      
      for index, track in enumerate(tracks):
      	obj[c4d.ID_USERDATA, index * 4  + 0] = track.GetName()
      	track[c4d.CID_SOUND_ONOFF] = obj[index*4 + 1]
              track[c4d.CID_SOUND_START] = obj[index*4 + 2]
              track[c4d.CID_SOUND_NAME]  = obj[index*4 + 3]
      
      

      Let me know what do you think about it ?

      Cheers

      posted in General Talk
      ManuelM
      Manuel
    • RE: Buttons ids

      Hello,

      there's no real list where you can find easily those IDs.

      @m_adam came with this idea :
      open the Script log (menu script > script log) and click the button you want to call.
      in the console you will see something like

       c4d.CallButton(tool(), c4d.MDATA_NEWTRANSFORM)
      

      so you know that the ID is c4d.MDATA_NEWTRANSFORM

      Another place to look for, is the folder ressource/modules where you can find the files .res that build the ui. (using your OS search function will help a lot) Openning those file you will find the information

      BUTTON MDATA_NEWTRANSFORM	{ FIT_H; }
      

      and you can maybe open the file with the same name with the extention .h where you will find the id

      MDATA_NEWTRANSFORM							= 701,   // Button
      

      Other than that, there are the enums on the documentation like this page but it's not really "user friendly"

      Let me know.

      Cheers
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: is there a market to sell my plugin?

      Hello,

      There's no official market for Cinema 4D's plugins own by Maxon.

      But, as an old plugins seller myself, i can try to give you some hints and share my experience.

      If you want to sell your plugins, you have several options and some legal part to consider.

      You must collect VAT for example. As a European, things can be different depending on witch country your client is from. I'm far to be a specialist, and there is some tools that can handle those things for you. Don't be afraid of legal part.

      1 - You can run your own shop by having your own provider, using "simple tools" like
      Wordpress + WooCommerce. If you add plugins to handle VAT and other legal stuff, this can be a breeze. You have your own Design, you can handle serial numbers the way you want, you have total control.

      2 - Using a market place ( Aescripts or Gumroad for exemple) have some advantages :

      • they will manage the legal stuff for you,
      • they help you if you got any question
      • you can focus on your development
      • they will generate a lot more traffic and your tools will be more visible (people can come for another plugins and check what they have in the catalog)

      You also have to consider the tax they will charge of course. They will varie form plateform to plateform. Don't hesitate to contact them.

      Final point, DO IT, it's fun, you will have some nice feedback, having people, sending work they have done with your tools, from all over the world is just a blast.

      Cheers
      Manuel

      posted in General Talk
      ManuelM
      Manuel

    Latest posts made by Manuel

    • RE: Metadata Supported for FBX Imports?

      you can use our contact from
      https://developers.maxon.net/forum/contact

      or send us an email at [email protected]

      posted in General Talk
      ManuelM
      Manuel
    • RE: Metadata Supported for FBX Imports?

      Hey Daniel,
      We are not allowed to talk about our roadmap.
      I still do not understand how you are using those data in your workflow. Maybe you want the Meta-Data to be accessible with python, Xpresso, something else. Or you just want to import an fbx in c4d, do something and export it again without loosing those data.

      Cinema 4D is reading everything he can handle, other information is ignored, so yes, meta-data are lost.
      If you cannot or do not want to talk about your workflow in public maybe we can use our mail box if you feel more confortable?

      Cheers,
      Manuel

      posted in General Talk
      ManuelM
      Manuel
    • RE: FindNodesByName Not Working As Expected

      Hi,
      I tested the following code and while i got some error on a Redshift material in 2023.0 and 2023.1 i have no error anymore in 2023.2.1

      Standard renderer seems to always works. So this seems to not be an issue with the function FindNodesByName itself.

      There were lots of improvement in the node API and i can just guess what have been fixed.
      Can you still reproduce the issue in 2023.2.1 ?

      import c4d
      import maxon
      import time
      
      
      def main():
          # Retrieve the selected BaseMaterial
          mat = doc.GetActiveMaterial()
          if mat is None:
              raise ValueError("There is no selected BaseMaterial")
      
          # Retrieve the reference of the material as a node material.
          nodeMaterial = mat.GetNodeMaterialReference()
          if nodeMaterial is None:
              raise ValueError("Cannot retrieve node material reference")
      
          # Retrieve the current node space Id
          nodespaceId = c4d.GetActiveNodeSpaceId()
      
          # Retrieve the Nimbus reference for a specific node space
          nimbusRef = mat.GetNimbusRef(nodespaceId)
          if nimbusRef is None:
              raise ValueError("Cannot retrieve the nimbus ref for that node space")
      
          # Retrieve the graph corresponding to that node space.
          graph = nimbusRef.GetGraph()
          if graph is None:
              raise ValueError("Cannot retrieve the graph of this nimbus ref")
      
          settings: maxon.DataDictionaryInterface = maxon.DataDictionary()
          settings.Set(maxon.nodes.UndoMode, maxon.nodes.UNDO_MODE.START)
          
          for loopId in range(0, 100):
      
              with graph.BeginTransaction(settings) as transaction:
                  input_node = []
                  scale_node = graph.AddChild("", "net.maxon.node.type", maxon.DataDictionary())
                  scale_node.SetValue(maxon.NODE.BASE.NAME, maxon.String("scale_node"))
                  maxon.GraphModelHelper.FindNodesByName(graph, "scale_node", maxon.NODE_KIND.ALL_MASK, maxon.PORT_DIR.INPUT, True, input_node)
                  print (input_node)
                  if len(input_node) < 1:
                      print("cannot find the node")
                  transaction.Commit()
                  
              with graph.BeginTransaction(settings) as transaction:
                  input_node = []
                  maxon.GraphModelHelper.FindNodesByName(graph, "scale_node", maxon.NODE_KIND.ALL_MASK, maxon.PORT_DIR.INPUT, True, input_node)
                  for graphnode in input_node:
                      graphnode.Remove()
                  transaction.Commit()
          # Pushes an update event to Cinema 4D
          c4d.EventAdd()
      
      
      if __name__ == "__main__":
          main()
      

      Cheers,
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: Problem Adding description parameter by clicking button and access this

      You can use SetParameter or change the value directly in the BaseContainer. Using SetParameter is a better option if you want to move the data anywhere else outside the BaseContainer. If you do so, you will have to override the NodeData.SetDParameter function to handle your data properly. (note the difference, there is a D in that function name)
      Calling SetParameter will work on both cases, storing your data in a BaseContainer or in your own way.
      It is always a clever idea to initialise your data.

      I would rather clean the BaseContainer when you press the "delete" button. That will avoid having a BaseContainer getting bigger and bigger, especially if you copy paste your generator from document to document.

      Cheers,
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: Problem Adding description parameter by clicking button and access this

      @ThomasB said in Problem Adding description parameter by clicking button and access this:

      You told me something about cleaning the BaseContainer?
      2023-05-11 01-11-45.mp4

      hi, that is exactly why i was talking about cleaning the BaseContainer, or to initialise correctly the values. It is even worse if you mix datatype.

      I was thinking of the morph tag and the way he does add or remove morph target using the same IDs.

      And of course, removing data that you are not using anymore is a good idea.

      Cheers,
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: FindNodesByName Not Working As Expected

      Hi,

      sorry, we have a company meeting next week, i will not be able to check again this issue until 15 of May.
      many things were fixed in 2023.2.

      Cheers,
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: Accessing Sweep's spline data from C4DImportExport.cpp

      @yesbird said in Accessing Sweep's spline data from C4DImportExport.cpp:

      Could you tell me please, if you have plans of it's implementation ?
      If not, I could implement it myself, having access to Cineware sources.

      HI,

      I'm sorry but we cannot share this kind of information or the source code. The function is implemented in the regular SDK. i am sure that there were technical difficulties to make it available in Cineware.

      Cheers,
      Manuel

      posted in Cineware SDK
      ManuelM
      Manuel
    • RE: Save Project with Assets not updating the maxon::Url of node textures in R26 and 2023

      @Aaron said in Save Project with Assets not updating the maxon::Url of node textures in R26 and 2023:

      I am Kirill from CentiLeo project. I have written a question here because it seems there is more life on the public forum and the nodes api is now public.

      By the way i hope you have access to our beta forum. There is a thread from 2021 in our gallery, a small test of Centileo. Now I remember the time you asked questions about our node API, in our old beta forum, answered by Sebastian and Ole. If you do not have access to our new forum or are not a registered developer, you can join us at sdk_support at maxon.net so we can talk about it.

      I could test the pluging and, first, amazing job, now i understand how much effort you put on that project and why it looks so great. Sorry for not remembering immediately, it is sometime hard to follow everybody's project.

      About the issue, i tested it with 2023.1.3 and could reproduce the issue but not with 2023.2. In 2023.2, it is working as expected. Our standard/physical nodespace is also working with 2023.3.1 so it is not a global bug.
      The Project Asset Inspector have been improved in 2023.2 and texture renaming should work now.

      In your implementation of maxon::nodes::NodeSystemClassInterface SupportsImpl, you can define what node are supported in your nodespace.

      const maxon::Id& id = templ.GetId();
      
      const maxon::String idString = id.ToString();
      if (idString.StartsWith("net.maxon"_s))
      	return true;
      

      After that you should be able to instantiate any of our nodes inside your graph and test if ImportData url is renamed or not. It is just to see if it is a node issue (that would be surprising now) or an issue with your nodespace.

      On my side, i will compile 2023.1.3 today and have a look, from what i see in the code there is no reason to not work. I will also have to ask our developers if they have an idea.

      Cheers,
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: Save Project with Assets not updating the maxon::Url of node textures in R26 and 2023

      hi,
      sorry for the delay.
      thanks a lot for your help here @Deyan i do not think @Aaron is implementing its own material.
      After looking in our code, i can confirm that the node system will received MSG_MULTI_CLEARSUGGESTEDFOLDER and MSG_RENAMETEXTURES and for both doing the same thing.

      It looks into all the ports inside the node system and check if the DataType of the port is Url. Whatever the node is.
      Now i am wondering if you set the datatype correctly of you texture node and did not used a string instead?

      9009f6b3-68e3-42df-8f83-53fad925a4d3-image.png

      What you can try is to include the "Import Data' node inside your material setup and see if this node url will be renamed when you save the project with assets. That way we will know if the problem is your node or not.

      you can no longer open the resource editor with a right click. g_developerNodeEditorFunctions has been removed.

      Cheers,
      Manuel

      posted in Cinema 4D SDK
      ManuelM
      Manuel
    • RE: Python Tag how to hide a mogragh object

      hi,

      well the main problem is not where but when to change that MoData. Specially in python i see no solution.
      With c++ you could find a hacky way of doing it but i did not tried.

      One way of doing it would be to create a setup inside the message function of the tag (so you are on the main thread). Creating a formula effector, hide it inside the object manager and use the formula to hide the object you want. something like id!=2&id!=3 will work. Of course, you need to include that effector to the cloner's effector list. I would not call that a "good solution", but it will work.

      Cheers,
      Manuel.

      posted in Cinema 4D SDK
      ManuelM
      Manuel