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

    how to get object's position and material color on all time line?

    Cinema 4D SDK
    python windows r21
    3
    3
    910
    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.
    • J
      jhpark
      last edited by m_adam

      Dear. MAXON's SDK Team

      I use R21 on microsoft windows with python.

      I have threads that how to get object's position and material color on all time line.
      below my simple source code.

      import c4d							# import Cinema 4D module
      doc = c4d.documents.GetActiveDocument()	# Cinema 4D active document
      
      number_of_sphere = 10		# [Set] sphere number
      frames_count = 2600		# [Set] frames counter
      
      for i in range(0, number_of_sphere):
      	for f in range(0, frames_count):
      		doc.SetTime(c4d.BaseTime(f, doc[c4d.DOCUMENT_FPS]))
      		c4d.EventAdd()
      		obj = doc.SearchObject('Sphere_' + str(i))
      		# get object position
      		x = int(obj.GetMg().off.x)
      		y = int(obj.GetMg().off.y)
      		z = int(obj.GetMg().off.z)
      		# get object color
      		r = int(obj[c4d.ID_BASEOBJECT_COLOR].x * 255)
      		g = int(obj[c4d.ID_BASEOBJECT_COLOR].y * 255)
      		b = int(obj[c4d.ID_BASEOBJECT_COLOR].z * 255)
      		print(obj.GetName() + ", Frame = " + str(f) + ", (X,Y,Z) = " + str(x) + "," + str(y) + "," + str(z) + ", RGB = " + str(r) + "," + str(g) + "," + str(b))
      

      Please, guide to me for method of this.

      Cheers,
      MAXON's SDK Team

      1 Reply Last reply Reply Quote 0
      • ?
        A Former User
        last edited by A Former User

        Hi @jhpark!
        I don't work for the SDK team, but I believe the script below will do what you want.

        Some quick notes about posting:

        1. When entering your code into a post on this forum, make sure you hit this button first
          code.png
          It creates code tags in your post. Put your code in between those and then it will format your code automatically.

        2. Also, after submitting, hit the button Topic Tools at the bottom right of your post to Ask as Question.
          code3.png

        3. When someone has answered your question correctly, click this button at the bottom of their post.
          code2.png
          This makes it clear to the moderators when the question has been correctly answered.

        Here's the code. Because you were using ID_BASEOBJECT_COLOR, I was unsure if you wanted the object's display color or the material color (they are two different things), but I wrote this for the sphere's texture tags' material's color. Also, the code is for the spheres' relative position. More work would need to be done to get the animating position track values into global space.

        import c4d
        from c4d import gui
        
        def GetNextObject(op):
            #function for navigating the hierarchy
            if op==None: return None
            if op.GetDown(): return op.GetDown()
            while not op.GetNext() and op.GetUp():
                op = op.GetUp()
            return op.GetNext()
            c4d.EventAdd()
        
        def getPreviewRange(doc,fps):
            #returns the active preview range
            fps = doc.GetFps()
            fromTime = doc.GetLoopMinTime().GetFrame(fps)
            toTime = doc.GetLoopMaxTime().GetFrame(fps)+1
            return [fromTime,toTime]
        
        def convertVecToRgb(vector):
            #converts vector to rgb list
            return [vector[0]*255,vector[1]*255,vector[2]*255]
        
        def main(doc):
            fps = doc.GetFps()
            previewRange = getPreviewRange(doc,fps) #rather than needing to set frames manually, you can simply resize your preview range.
            frame_count = previewRange[1]-previewRange[0]
        
            # this section navigates the hierarchy and saves all of the spheres to a list called 'output'
            # it's better to do this than to use doc.SearchObject in the case you have multiple spheres with the same name
            obj = doc.GetFirstObject()
            if obj==None:
                gui.MessageDialog('There are no objects in the scene.')
                return
        
            output = []
            while obj and obj!=None:
                if obj.GetType() == c4d.Osphere:
                    output.append(obj)
                obj = GetNextObject(obj)
        
            if len(output) == 0:
                gui.MessageDialog('There are no spheres in the scene.')
        
            # loops through spheres in the scene
            for sphere in output:
                #prints a separating line to the console
                print '#' * 80
                for f in range(previewRange[0], previewRange[1]):
                    doc.SetTime(c4d.BaseTime(0, doc[c4d.DOCUMENT_FPS]))
                    keyTime = c4d.BaseTime(f,fps) #get the current frame
        
                    # POSITION
                    pTracks = sphere.GetCTracks() #get the sphere's animating tracks
                    
                    pos = [sphere.GetMl().off.x,sphere.GetMl().off.y,sphere.GetMl().off.z] #get the sphere's default relative position
        
                    #replace those values with the animating ones.
                    for t in pTracks:
                        descid = t.GetDescriptionID() #get the track's id
                        if descid[0].id == c4d.ID_BASEOBJECT_REL_POSITION: #see if it matches the object's position track
                            curve = t.GetCurve() #get the track's animation curve
                            keyvalue = curve.GetValue(keyTime, fps) #get the animation curve's value at the current frame
                            if descid[1].id == c4d.VECTOR_X:
                                pos[0] = keyvalue #add to x
                            elif descid[1].id == c4d.VECTOR_Y:
                                pos[1] = keyvalue #add to x
                            elif descid[1].id == c4d.VECTOR_Z:
                                pos[2] = keyvalue #add to z
        
                    # MATERIAL COLOR
                    tags = sphere.GetTags() #get sphere's tags
        
                    matColor = [] #create material color list
        
                    for tag in tags: #loop through sphere's tags
                        if tag.GetType() == c4d.Ttexture: #check if tag is a texture tag
                            mat = tag.GetMaterial() #if yes, get the tag's material
        
                            tracks = mat.GetCTracks() #get the material's animating tracks
                            
                            for t in tracks:
                                descid = t.GetDescriptionID() #get the track's id
                                if descid[0].id == c4d.MATERIAL_COLOR_COLOR: #see if it matches the material color track
                                    curve = t.GetCurve() #get the track's animation curve
                                    keyvalue = curve.GetValue(keyTime, fps) #get the animation curve's value at the current frame
                                    matColor.append(keyvalue*255) #add r,g,b to matColor
                            
                            if len(tracks) == 0: #in case it's not animating, use general Color
                                matColor = convertVecToRgb(mat[c4d.MATERIAL_COLOR_COLOR])
        
                    # I prefer using string formatting with the placeholder %s for strings, %d for numbers,
                    # and the % as the replacement operator
                    print("Name: %s, Frame: %d, Position (x,y,z): %d,%d,%d, Material Color (r,g,b): %d,%d,%d"%(
                                                                                    sphere.GetName(),f,pos[0],pos[1],pos[2],
                                                                                    matColor[0],matColor[1],matColor[2]))
        
        if __name__=='__main__':
            # rather than using documents.GetActiveDocument, I found that you can pass a reference to the document using this method
            main(doc)
        

        Here's a scene file where the object's display colors and material colors are different. The display colors are visible in the viewport, but you will see the material color if you render.
        Spheres.c4d

        1 Reply Last reply Reply Quote 1
        • r_giganteR
          r_gigante
          last edited by

          Hi jhpark, thanks for reaching out us.

          Aside from the notes left by @blastframe - thanks dude for the remarks - I think it's worthy, thinking of a more generic scene, to mention the need BaseDocument::ExecutePasses() to be sure that everything is actually evaluated before querying the scene rather than the EventAdd() which serves a different scope.
          This function is responsible to execute the scene evaluation and, consequently to be sure that, moving from a frame to another, all the items in the scene reflect the changes imposed by the frame switch.

          The approach used by @blastframe actually operates on CTracks and key but, although this approach works fine for your specific case, when more evaluation dependencies are created in the scene you could easily end up in unexpected results.

          The code could then look like

              frames_count = 10 # [Set] frames counter
          
              for f in range(0, frames_count):
                  doc.SetTime(c4d.BaseTime(f, doc.GetFps()))
                  
                  # evaluate the scene
                  doc.ExecutePasses(None, True, True, True, c4d.BUILDFLAGS_NONE)
          
                  obj = doc.SearchObject('Cube')
          
                  # get object position
                  x = int(obj.GetMg().off.x)
                  y = int(obj.GetMg().off.y)
                  z = int(obj.GetMg().off.z)
          
                  # get object color
                  r = int(obj[c4d.ID_BASEOBJECT_COLOR].x * 255)
                  g = int(obj[c4d.ID_BASEOBJECT_COLOR].y * 255)
                  b = int(obj[c4d.ID_BASEOBJECT_COLOR].z * 255)
                  print("Frame = " + str(f) + ", (X,Y,Z) = " + str(x) + "," + str(y) + "," + str(z) + ", RGB = " + str(r) + "," + str(g) + "," + str(b))
          
          
          1 Reply Last reply Reply Quote 0
          • First post
            Last post