3

Is there a technique to visualize the non-planar faces on a mesh. Similar to how the overlays panel allows an option to see "face orientation" in red or blue?

George
  • 117
  • 1
  • 4
  • 2
    Are you worried that the non-planar faces are going to cause shading issues? If so, you could experiment with a few "unforgiving" matcaps to highlight any irregularities. – Christopher Bennett Jun 01 '20 at 20:56
  • Related: https://blender.stackexchange.com/questions/53622/is-there-a-way-to-get-a-list-of-coplanar-faces-using-python – batFINGER Jun 02 '20 at 13:59
  • 1
    Yes, there is. Mesh analysis panel in Edit mode, https://blender.stackexchange.com/questions/104353/what-does-distortion-in-the-mesh-analysis-panel-do – Mr Zak Apr 25 '21 at 13:44

3 Answers3

4

I don't think you can get that with standard tools. I would use a script to highlight (select in edit-mode) non coplanar faces:

import bpy
import bmesh

obj = bpy.context.active_object  # Get selected object

if obj:
    bpy.ops.object.mode_set(mode='EDIT')  # Go into edit mode
    bpy.ops.mesh.select_all(action='DESELECT')  # Deselect everything

    bm = bmesh.from_edit_mesh(obj.data)  # Create bmesh object for easy mesh evaluation

    for f in bm.faces:  # Check all the faces
        # 3 points will always define a unique plane. We define its coordinates.
        A = f.verts[0]
        B = f.verts[1]
        C = f.verts[2]
        a1 = B.co.x - A.co.x
        b1 = B.co.y - A.co.y 
        c1 = B.co.z - A.co.z 
        a2 = C.co.x - A.co.x
        b2 = C.co.y - A.co.y
        c2 = C.co.z - A.co.z
        a = b1 * c2 - b2 * c1 
        b = a2 * c1 - a1 * c2 
        c = a1 * b2 - b1 * a2 
        d = (- a * A.co.x - b * A.co.y - c * A.co.z)
        # Check if any point after the third one is a part of this plane (ie the distance to the plane is == 0)
        if len(f.verts) > 3:
            for v in f.verts[3::]:
                if a * v.co.x + b * v.co.y + c * v.co.z + d != 0:
                    f.select_set(True)  # If this vertex is not part of the base plane, select the face and break
                    break

    bmesh.update_edit_mesh(obj.data)

Illustration :

enter image description here

Also, if you want faces to highlight only if the vertices deviate from a certain threshold to to the base plane, you could insert it in the code :

Replace

if a * v.co.x + b * v.co.y + c * v.co.z + d != 0:

With

if abs(a * v.co.x + b * v.co.y + c * v.co.z + d) > 2 :  # Threshold

Note that this is not deterministic and could change depending on which vertices get evaluated to define the plane coordinates.

enter image description here

Further and further reading.

Gorgious
  • 30,723
  • 2
  • 44
  • 101
  • Unfortunately, when the whole mesh is rotated and the local and the global axes do not align any more then your script selects all faces, even if they are coplanar. At least in Blender 2.92. Try hitting RR on the cube above, for instance. – Cel Apr 25 '21 at 13:54
3

Similarly

https://blender.stackexchange.com/a/53976/15543

4 points are coplanar if the volume created by the points is 0. If any three points determine a plane then additional points can be checked for coplanarity by measuring the distance of the points from the plane, if the distance is 0 then the point is coplanar

Below uses 3 verts to compute the face normal.

Vert 0 (v0, the coordinate of Vert 0) is a point on plane. The cross product (v1 - v0).cross(v2 - v0) defines the normal.

Feeding the rest of verts into mathutils.geometry.distance_point_to_plane determines if a face does not have coplanar vertices if any distance is not 0. A small tolerance is used.

See other example in link re creating a convex hull from the face and testing it has zero volume.

import bpy
import bmesh

from mathutils.geometry import distance_point_to_plane as dp2p

TOL = 1e-6

context = bpy.context ob = context.edit_object # run in edit mode me = ob.data

bm = bmesh.from_edit_mesh(me)

for f in bm.faces:

if len(f.verts) == 3: #  tri
    f.select_set(False)
    continue
v1 = f.verts[1].co - f.verts[0].co
v2 = f.verts[2].co - f.verts[0].co
norm = v1.cross(v2)
f.select_set(
    any(
        abs(dp2p(
            v.co, 
            f.verts[0].co, 
            norm)
            ) > TOL for v in f.verts[3:]
        )
    )

bmesh.update_edit_mesh(me)

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • I knew there had to be a method in python utils for this but couldn't find it ! Thanks for the tips :) – Gorgious Jun 02 '20 at 20:18
  • I noticed with your method (unselecting coplanar faces) that some vertices might get deselected even if they are part of a non-coplanar face depending on the order of execution. The faces still get correctly selected or un-selected though – Gorgious Jun 02 '20 at 20:20
2

In edit mode, open the "Viewport Overlays" panel in the top right corner, check the "Mesh Analysis" box, and change the type dropdown to "Distortion":

Screenshot of Viewport Overlays panel with mesh analysis enabled

(Credit to original comment: Color Only Non-Planar Faces)

Wes Lord
  • 121
  • 3