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

    Determine if a polygon is facing the camera

    General Talk
    python r20
    2
    5
    926
    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.
    • R
      rui_mac
      last edited by

      How can I determine if a polygon on a polygonal object is facing the current (user or editor) camera?
      I know there is a BackfaceCulling function but it always returns me with True.

      1 Reply Last reply Reply Quote 0
      • ManuelM
        Manuel
        last edited by

        hello,

        I've marked this thread as a question so when you considered it as solved, please change the state 🙂
        again, use our forum functionalities

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

        The python documentation is not the best for this function. The passed data must be in the same space. Internally it just do a Dot product and check if it's positive or negative.

           #inside a python tag  
        
            #retrieves the object where this tag is attached    
            obj = op.GetObject()
            # gets the Matrix of this object
            objMg = obj.GetMg()
            
            # retrieves the BaseDraw of view 0 (uselly the perspective)
            bd = doc.GetBaseDraw(0)
            
            # retrieves the scene camera
            cam = bd.GetSceneCamera(doc)
            
            #get the camera matrix
            camMg = cam.GetMg()
            
            # the Z axis of the object will be the normal of the plane XY
            normal = objMg.v3
                
            # Get the vector that is pointing toward the camera from object.
            objPos = camMg.off - objMg.off 
            
            #Normalize the vector isn't necessary but it's alway a good idea to debug/understand what's going on
            normal.Normalize()
            objPos.Normalize()
        
            
            print  bd.BackfaceCulling(normal, objPos), normal.Dot(objPos)
        
        

        Cheers,
        Manuel.

        MAXON SDK Specialist

        MAXON Registered Developer

        1 Reply Last reply Reply Quote 1
        • R
          rui_mac
          last edited by

          Thank you Manuel.
          Your code is for an object, not a face.
          So, I tried to adapt it and this is what I got (and it doesn't really work):

          def main():
              selected=doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_0)
          
              if selected==[]: return
              
              bd = doc.GetActiveBaseDraw()
              cam = bd.GetSceneCamera(doc)
              if cam == None: cam = bd.GetEditorCamera()
              cam_mg = cam.GetMg() # in case I need it
              cam_off = cam_mg.off # in case I need it
          
              for op in selected:
                  if op.GetType() != 5100: continue
                  mg = op.GetMg()
                  faces = op.GetAllPolygons()
                  points = op.GetAllPoints()
                  
                  selection = op.GetPolygonS()
                  selection.DeselectAll()
                  
                  for i,poly in enumerate(faces):
                      a,b,c,d = poly.a,poly.b,poly.c,poly.d
                      pta = points[a]
                      ptb = points[b]
                      ptc = points[c]
                      ptd = points[d]
                      
                      v1 = pta-ptb
                      v2 = ptb-ptc
                      
                      normal = v1.Cross(v2)
                      normal.Normalize()
                      normal = normal * mg
                      
                      if c != d:
                          center = c4d.Vector((pta.x+ptb.x+ptc.x+ptd.x)/4.0,(pta.y+ptb.y+ptc.y+ptd.y)/4.0,(pta.z+ptb.z+ptc.z+ptd.z)/4.0)
                      else:
                          center = c4d.Vector((pta.x+ptb.x+ptc.x)/3.0,(pta.y+ptb.y+ptc.y)/3.0,(pta.z+ptb.z+ptc.z)/3.0)
              
                      center = center * mg
                      
                      is_vis = bd.BackfaceCulling(normal, center)
                      
                      if (is_vis == True):
                          selection.Select(i)
                          
              c4d.EventAdd()
          

          What could be wrong?

          1 Reply Last reply Reply Quote 0
          • ManuelM
            Manuel
            last edited by Manuel

            That wasn't clear, sorry. Pick the center of the polygon and get the vector pointing towards the camera. You have to pass that vector.

             # Get the vector that is pointing toward the camera from object.
                objPos = camMg.off - objMg.off 
            

            The function do a Dot product between those vectors (the dot product return an angle).
            So the normal of the polygon and the vector from that polygon to the camera.

            Now you should be able to change your code.
            let me know.

            import c4d
            
            def main():
            
                #Cheks the document and an object is selected
                if doc is None:
                    raise ValueError("there no document")
            
                if op is None:
                    raise ValueError("there no object selected")    
            
                #Checks if it's a polygon object
                if not op.IsInstanceOf(c4d.Opolygon):
                    raise ValueError("object must be a polygonObject")
            
                #Retrieves the camera     
                bd = doc.GetActiveBaseDraw()
                if bd is None:
                    raise ValueError("error while retrieving the active BaseDraw of the document")
            
            
                cam = bd.GetSceneCamera(doc)
                if cam == None: 
                    cam = bd.GetEditorCamera()
            
                #Gets the camera position.
                cam_mg = cam.GetMg() 
                cam_off = cam_mg.off 
            
                
                
                opMg = op.GetMg()
                
                faces = op.GetAllPolygons()
                points = op.GetAllPoints()
                
                selection = op.GetPolygonS()
                selection.DeselectAll()
                
                #Checks for each polygon if they face the camera or not.
                for i, poly in enumerate(faces):
            
                    #calculate the normal of the polygon.
                    a, b, c, d = poly.a, poly.b, poly.c, poly.d
                    pta = points[a]
                    ptb = points[b]
                    ptc = points[c]
                    ptd = points[d]
                    
                    v1 = pta-ptb
                    v2 = ptb-ptc
                    
                    normal = v1.Cross(v2)
                    normal.Normalize()
            
                    #Gets the normal in the world coordinates.
                    normal = normal * opMg
                    
                    #Calculates the center of the polygon.
                    if c != d:
                        center = c4d.Vector( pta.x + ptb.x + ptc.x + ptd.x , pta.y + ptb.y + ptc.y + ptd.y, pta.z + ptb.z + ptc.z + ptd.z) / 4.0
                    else:
                        center = c4d.Vector(pta.x + ptb.x + ptc.x, pta.y+ptb.y+ptc.y, pta.z + ptb.z + ptc.z) / 3.0
            
                    #Gets the center coordinates in the globalspace.
                    center = center * opMg
                    #Gets the vector pointing towards the camera.
                    direction = cam_off - center
                    
                    #Checks if the polygon is visible.
                    isVisible = bd.BackfaceCulling(normal, direction)
                    
                    if isVisible:
                        selection.Select(i)
                        
                c4d.EventAdd()
            
            if __name__ == '__main__':
                main()
            

            The c++ is a bit more clear, both the normal and the center need to be in camera space. And the center in camera space is the vector from the camera pointing to the center.

            Cheers,
            Manuel

            MAXON SDK Specialist

            MAXON Registered Developer

            1 Reply Last reply Reply Quote 1
            • R
              rui_mac
              last edited by

              Once again, thank you, Manuel.
              I had to do a few changes and it is working now.
              I even made it select the faces that are within a certain angle from the camera.
              Here is my code:

                          for i,poly in enumerate(faces):
                              a,b,c,d = poly.a,poly.b,poly.c,poly.d
                              pta = points[a]*mg
                              ptb = points[b]*mg
                              ptc = points[c]*mg
                              ptd = points[d]*mg
                  
                              v1 = pta-ptb
                              v2 = ptb-ptc
                  
                              normal = v1.Cross(v2)
                              normal.Normalize()
                  
                              if c != d:
                                  center = c4d.Vector((pta.x+ptb.x+ptc.x+ptd.x)/4.0,(pta.y+ptb.y+ptc.y+ptd.y)/4.0,(pta.z+ptb.z+ptc.z+ptd.z)/4.0)
                              else:
                                  center = c4d.Vector((pta.x+ptb.x+ptc.x)/3.0,(pta.y+ptb.y+ptc.y)/3.0,(pta.z+ptb.z+ptc.z)/3.0)
                  
                              direction = cam_off - center
                              norm_dir = direction.GetNormalized()
                              angle = NINETY - normal.Dot(norm_dir)
                  
                              if (angle > 0.0 and angle < max_ang):
                                  selection.Select(i)
              
              1 Reply Last reply Reply Quote 0
              • First post
                Last post