Determine if a polygon is facing the camera
-
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. -
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. -
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?
-
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 -
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)