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

    Dynamic VertexMap

    Cinema 4D SDK
    python sdk r20
    3
    6
    947
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • N
      neon
      last edited by

      Hello PluginCafe,

      I wanted to know whether it is possible to change the data count of a vertex map dynamically without always killing the tag and recreating it? I have a mesh that gets subdivided dynamically and I need the vertex map to always fit the mesh vertex count but I can't have the user to always re-link the vertex map on every change.

      Best Regards,
      Florian

      1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand
        last edited by ferdinand

        Hi,

        this should not be necessary, since vertex maps are being automatically resized to match the point count of their hosting object. Could you provide some code or an example on where you did encounter a different behavior? Below you will find a script, that shows you how to access the high level data of a vertex map.

        import c4d
        
        
        def main():
            """
            """
            # Ensure that the current selection is a polygon object.
            if not isinstance(op, c4d.PolygonObject):
                return
        
            # Get the first vertex map of the object.
            vertextmaps = [tag for tag in op.GetTags()
                           if tag.CheckType(c4d.Tvertexmap)]
            if not vertextmaps:
                return
            vmap = vertextmaps[0]
        
            # Vertex maps are instances of c4d.VariableTag. VariableTag.GetDataCount()
            # returns the number of data elements of the instance, e.g. the number of
            # weights for a vertex map.
            print "vertex map data count before subdivision:", vmap.GetDataCount()
        
            # Subdivide the object once
            bc = c4d.BaseContainer()
            bc[c4d.MDATA_SUBDIVIDE_SUB] = 1
            res = c4d.utils.SendModelingCommand(
                command=c4d.MCOMMAND_SUBDIVIDE,
                list=[op],
                mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                bc=bc,
                doc=doc)
            # The vertex map has been automatically resized.
            print "vertex map data count after subdivision:", vmap.GetDataCount()
        
            # A list of weights with the length of the size of the vertex map, where
            # even IDs (i.e. the point IDs of the polygon object) are a weight of 1
            # and odd elements are a weight of 0.
            weights = [float(n % 2 == 0) for n in range(vmap.GetDataCount())]
        
            # Write the new weight data into our vertex map.
            vmap.SetAllHighlevelData(weights)
            # Update Cinema
            c4d.EventAdd()
        
        
        # Execute main()
        if __name__ == '__main__':
            main()
        
        

        Cheers
        zipit

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • M
          m_adam
          last edited by m_adam

          Hi @neon please make use of the Q&A Functionality.

          Regarding your question I would ask you for more information regarding your context, are you in a CommandData, ObjectData?
          Normally as @zipit said the vertex map is automatically resized when obj.Message(c4d.MESSAGE_UPDATE) is called (which is normally done for each modeling operation).

          So maybe you simply need this as "subdivided dynamically" is very obscure and could mean a lot of things.

          Cheers,
          Maxime.

          MAXON SDK Specialist

          Development Blog, MAXON Registered Developer

          1 Reply Last reply Reply Quote 0
          • N
            neon
            last edited by

            Hello,
            thanks m_adam and zipit for your replies.
            I am working in an ObjectData Plugin.
            I am loading a mesh into my ObjectData (in Init) and need to add modifiers/subdivision in GetVirtualObjects.
            After Zipits answer I noticed why it didn't work properly and that is that I added the tag to my ObjectData instead of the loaded mesh, the reason for that is that I would need the user to see the vertexmap but I can't expose the mesh.

            I have now changed it so the vertexmap is created on my internal mesh, and that scales just fine when subdividing, so in that regard my problem is solved.

            But I don't know if I am now able to expose the tag, and only the tag, somehow to the user.
            My Plugin uses the vertexmap internally and I want the user to be able to use it for materials etc.

            Is there any way?
            Thanks for your help so far!
            Best Regards,
            Florian

            1 Reply Last reply Reply Quote 0
            • M
              m_adam
              last edited by

              Hi @neon sorry for the delay, unfortunately, Cinema 4D is not designed this way.
              If you think about it, there is no tag that works by hierarchy inheritance except the selection tag. Which work by naming a selection. So it's a very special case.

              The main issue is Cinema 4D will, in any case, reset the data you define in the vertex map to the number of polygons. (and in this case, 0 since it's a generator).

              So here a workaround, but it's very experimental and can be buggy. So please don't use it in production as he does some really cross-thread things that are not allowed and that could crash Cinema 4D. But at least it can give you some ideas.
              pc_11963.c4d

              And the python code of the python generator.

              import c4d
              
              
              def Bl2DIterator(obj):
                  """
                  Iterates over any BaseList2D list
                  """
                  
                  while obj:
                      yield obj
                      for opChild in Bl2DIterator(obj.GetDown()):
                          yield opChild
                      obj = obj.GetNext()
              
              def FindAllVetexShaderFromObj(obj, targetVertexMap):
                  """
                  Retrieve from each material assigned to `obj` all vertexMap shader
                  where `targetVertexMap` is used.
                  """
                  allVertexShader = []
                  
                  for tag in obj.GetTags():
                      if not tag.IsInstanceOf(c4d.Ttexture):
                          continue
                      
                      mat = tag[c4d.TEXTURETAG_MATERIAL]
                      if mat is None:
                          continue
                      
                      for shader in Bl2DIterator(mat.GetFirstShader()):
                          if shader.IsInstanceOf(c4d.Xvertexmap):
                              vMap = shader[c4d.SLA_DIRTY_VMAP_OBJECT]
                              if vMap is not None and vMap == targetVertexMap:
                                  allVertexShader.append(shader)
                  
                  return allVertexShader
              
              def main():
                  # Retrieve a copy of linked obj
                  polygonObj = op[c4d.ID_USERDATA,1]
                  if not isinstance(polygonObj, c4d.PolygonObject):
                      return
                  polygonObj = polygonObj.GetClone()
                  polygonObj.SetMl(op.GetMg())
              
                  # Retrieve vertex map from the copied object
                  vMap = polygonObj.GetTag(c4d.Tvertexmap)
                  if vMap is None:
                      return
              
                  # Subdivide the opbject
                  bc = c4d.BaseContainer()
                  bc[c4d.MDATA_SUBDIVIDE_SUB] = 1
                  res = c4d.utils.SendModelingCommand(
                      command=c4d.MCOMMAND_SUBDIVIDE,
                      list=[polygonObj],
                      mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                      bc=bc,
                      doc=polygonObj.GetDocument())
              
                  # Assign random values
                  weights = [float(n % 4 == 0) for n in range(vMap.GetDataCount())]
                  vMap.SetAllHighlevelData(weights)
              
                  # Retrieve existing vertexMap and shader from the applied material that use this vertex map
                  shaderUsingOldVertexMap = []
                  tMapOld = op.GetTag(c4d.Tvertexmap)
                  if tMapOld is not None:
                      shaderUsingOldVertexMap += FindAllVetexShaderFromObj(op, tMapOld)
                      tMapOld.Remove()
              
                  # Creates a new tag with the correct number of data and disable it so C4D don't overwrite it
                  # Cross-thread Operation, that could crash Cinema 4D
                  vMapGenerator = op.MakeVariableTag(c4d.Tvertexmap, polygonObj.GetPointCount())
                  vMapGenerator[c4d.EXPRESSION_ENABLE] = False
              
                  # Copy the data from the vertex map within the generator to the one exposed to the user
                  vMapGenerator.SetAllHighlevelData(vMap.GetAllHighlevelData())
                  
                  # Remap all the vertex shader to use the new vertex map.
                  for shader in shaderUsingOldVertexMap:
                      shader[c4d.SLA_DIRTY_VMAP_OBJECT] = vMapGenerator
                  
                  return polygonObj
              

              Cheers,
              Maxime.

              MAXON SDK Specialist

              Development Blog, MAXON Registered Developer

              1 Reply Last reply Reply Quote 0
              • N
                neon
                last edited by

                Hello Maxime,
                thanks for your answer!

                Its too bad that I can't do it without some hacky way, but thanks for your code snipped and example.

                I'll mark this thread as solved, so thanks!

                Best Regards,
                Florian

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post