1
$\begingroup$

Good afternoon everyone!

I've been learning hard surface modelling and after a while noticed that some polys of my mesh are darker than others. On closer inspection, it appears that each of these is somehow not a single face but 2 polys taking same exact space and sharing same exact vertices.

Initially, I thought that this happens due to duplicated verts and did merge by distance but apparently that's not the case. If I box select one of those polys in wireframe mode blender prints Verts: 4, Edges: 4, Faces: 2.

I strongly suspect that doing fill holes (Alt + F) did this to me, but I don't understand why.

Any ideas on how to fix this? I surely can pick them manually but would like to know a proper solution which can remove them automagically. Googling yielded nothing but I might've been googling wrong terms.

Blender 2.80.

Thanks in advance!

enter image description here

Blender file:

$\endgroup$
12
  • $\begingroup$ Have you tried going to edit mode, selecting all and then mesh > normals > recalculate outside? $\endgroup$ – Christopher Bennett Jun 23 '20 at 7:37
  • $\begingroup$ Does this help ? blender.stackexchange.com/a/34514/86891 $\endgroup$ – Gorgious Jun 23 '20 at 7:39
  • $\begingroup$ @ChristopherBennett those faces are still there, but now shading is all weird (and also resembles a badly drawn penises) prntscr.com/t4su94 $\endgroup$ – Max Yari Jun 23 '20 at 7:39
  • $\begingroup$ @Gorgious if you mean using F to merge faces - then no, it messes up mesh if used on the whole thing, and does nothing if used on individual pair. $\endgroup$ – Max Yari Jun 23 '20 at 7:41
  • $\begingroup$ Recalculate inside then? I'm not sure.... something else must be going on, because that shouldn't happen. When you merge by distance, did you try increasing the value above the default 0.0001m? $\endgroup$ – Christopher Bennett Jun 23 '20 at 7:50
3
$\begingroup$

Ok. I got it to work by doing this:

  • Select all > Mesh > Split > Faces by Edges
  • Merge by distance
  • Recalculate outside (just to be safe)

Though I'm still not sure exactly what was going on, there were obviously a great number of duplicate SOMETHING because the merge by distance operation after the edge-split removed 8743 vertices.

I suspect that the fill-holes operation ( on whatever you had selected when you performed it) created faces that were SOMEWHERE? (I give pause here because up until now, I believed it impossible for blender to define 2 faces with the same verts and edges in the same place - if anyone can clarify further, It would be very informative, and I would be very curious to know how this works).

The only way I can conceive of this happening is that there could be 2 faces on top of one another with their normals facing opposite ways, however this theory is negated by the normal's directions themselves as seen in the images below:

Normals1

Normals2

Regardless, the "faces-on-faces" theory still has some merit, because that's the only way I can explain an edge split followed by a merge by distance working the way it did. The only other POSSIBLE thing I can think of is that somehow, some faces got "folded back on themselves", creating the ultimate 180 degree non-manifold plane (sounds weirder the more that I think about it).

Either way, my guess is this is likely the result of a fill-holes operation on to many conjoined faces at once. That's the best I can do. Anyone who knows more about how this type of situation can come about is welcome to explain it further.

Here is an updated .blend with the result of the operations (however they worked)

$\endgroup$
13
  • 1
    $\begingroup$ While not automagical, it sure is more wholesome for a solution in case the same issue is spread over the mesh. Splitting all faces to then later merge by distance is a nice workaround. But you only need to merge and then recalculate, as faces on top of each other won't affect the merge no matter what direction they face. $\endgroup$ – Xylvier Jun 23 '20 at 8:22
  • 1
    $\begingroup$ I played with it some more, it turns out it was even simpler than that - 2 steps. But I agree, the same issue affected the whole mesh in this case. Possibly the result of that curious boolean modifier combined with a fill holes operation? Either way, the merge removed 8743 verts, so something heavy was going on. $\endgroup$ – Christopher Bennett Jun 23 '20 at 8:24
  • 1
    $\begingroup$ Simple is good, but in case of automating the solution to make it more magical, i'd include the recalculate outside. Please consider though to explain a bit why you did what you did to make it easier to understand the underlying issue. Gonna remove my answer, so i would be glad to see a bit more details in your answer ;) $\endgroup$ – Xylvier Jun 23 '20 at 8:30
  • 2
    $\begingroup$ I would definitely call this a bug. As you pointed out the mesh algorithms should not authorize two faces to have the exact same vertices, like how you can't have a face with a hole in it. $\endgroup$ – Gorgious Jun 23 '20 at 9:07
  • 2
    $\begingroup$ Agreed. It's very strange - It's something impossible, yet I'm looking right at it. It's either a bug, a miracle, or some kind of paradox that holds the secrets of the universe. $\endgroup$ – Christopher Bennett Jun 23 '20 at 9:14
2
$\begingroup$

This script is as inefficient as it gets but it did the trick for me.

We iterate over the mesh faces indices in reversed order to prevent the infamous "delete elements from a collection while iterating over it" hair-pulling situation :

Important : you need to be in object mode and have your object selected before running this script

Basically, for each face polygon we iterate over every other face polygon and check if they both share the exact same vertices. If they do, we remove one of these two faces. (Extremely inefficient in large meshes)

import bpy, bmesh

obj = bpy.context.active_object
bm = bmesh.new()
bm.from_mesh(obj.data)

bm.faces.ensure_lookup_table()
faces = bm.faces
double_faces = []

for i in range(len(faces) - 1, 0, -1):
    for j in range(i - 1, -1, -1):
        if all([vert in faces[i].verts for vert in faces[j].verts]):
            double_faces.append(i)

for f in double_faces:
    bm.faces.ensure_lookup_table()
    faces.remove(faces[f])

bm.to_mesh(obj.data)
$\endgroup$
1
  • 1
    $\begingroup$ Yes, this does sound quite inefficient if you have thousands of polys to iterate, maybe it can iterate over selected polys instead (which could be a good compromise between full automation and performance)? But anyway it's a legit approach, thanks :) $\endgroup$ – Max Yari Jun 24 '20 at 16:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.