Remove double faces from mesh?

Hi there,

i am trying to find an idea:
i have for example two cubes, both share some triangles wich are on the same positions (i dont know which,and i dont know how many) but both share a bit of surface
like these ones highlighted here:

is there any way to find these doubled faces when they share some area? and then any way to delete them?

any idea would be great!

EDIT:

i realized, that i can also happen, that there is one fine mesh, and one rough. in this scenario i would find the faces wich are fully included by the rough one like these here:

You could try CSG but I am not entirely sure it would work here. Maybe @JohnK would have a trick ?

You could try forceSharedVertices but not sure it would work in your case. If it does work you might want to do convertToFlatShadedMesh afterwards.

Hi, thank you both!

what does CSG mean?

I will definitely try that! Thank you!

Cheers

1 Like

CSG = Constructive Solid Geometry (Merging Meshes | Babylon.js Documentation). But I would first try @JohnK’s suggestion, he knows what he is talking about :slight_smile:

1 Like

Hi,

yes i tried it, and it does something :wink: but not what i need (i think :wink: ). i am not quite sure what “adjacent” means. (from the Documentation: Force adjacent facets to share vertices and remove any facets that have all vertices in a line)

to be honest, i have no idea what really happens here: this is the original test mesh:

and this is with forceShared Vertices:

where the weird looking mesh normals are is the part of the mesh i want to be deleted…

Cheers and thanks!!!

Sorry it didn’t work out.

Perhaps this PG will help explain

Each face of the box is made up of two adjacent facet triangles each facet has 3 vertices.
Facets are adjacent if they share an edge.

In each box there are 12 facets.

Let facet 0 and facet 1 be the adjacent facets on the front face

In the bottom box we label the vertices of facet 0, - 0, 1, 2, for facet 1, - 3, 4, 5 and so on, each facet having uniquely vertex indices.

In the top box we label the corners of the box from 0 to 7 and use this numbering to label the vertices of each facet. So that the vertices of facet 0, - 0, 1, 2, for facet 2 - 0, 2 , 3.

‘forceSharedVertices’ converts the bottom box vertexData to that of the top box.
‘convertToFlatShadedMesh’ converts the top box vertexData to that of the bottom box

If facets are not truely adjacent these will not work. Looking at your image the facet triangles of your boxes are not truely adjacent, ie they do not fully share edges.

IMHO I wonder if the work involved in removing double faces in your case (it would be quite complicated) is worth the small gain your might make.

1 Like

Hi, thank you so much for your explanation! i think i understand now what it does. Yes - these faces were created by “extruding” the mesh from a polyline - and each mesh has its own polyline. probably the start/ endpoints are not 100% the same because of rounding issues.
The goal is actually not optimizing the mesh in terms of reducing faces - the goal is to have one “hull” mesh (they represent building hulls and are supposed to be used for some simulations). So i really cannot have these “inside” mesh faces.

I will now try to somehow filter the points out programmatically.

If you have any other idea - just let me know.
Thank you so much for your help!

1 Like

Will the extruded meshes you are fitting together always be box shaped? If so you might be better off constructing the boxes from planes with smaller planes on the side where it fits with another.

Sadly not. it can more or les be any shape.

i just had an idea…
even it would be very expensive - but wouldnt it be possible to somehow shoot a ray from each triangle in both normal and negative normal direction and then check if the ray hits something in a very short distance (so i could also take unprecise meshes into account) - and then if so delete the triangle where the ray was comming from.
the mesh i want to delete the faces from is now a custom mesh.
is that possible? Does that makes sense?

maybe that makes it a little bit more understandable:

Cheers and Thanks!!

Hi,
i am working on this problem again - i have made a filter function wich works like the idea i had above.
(i have a contextmesh, and my own mesh. from my own mesh i shoot a ray from each face to check if it hits something. and then if so i remove it form the array of faces…)

it works as expected, but is too slow for my liking. do you have any idea how to speed that up? especially this consumes a lot of time:

const rayIn = Ray.Transform(
          new Ray(position, normal, distance),
          matrix
        );
const rayOut = Ray.Transform(
          new Ray(position, normal.negate(), distance),
          matrix
        );

let collision = rayIn.intersectsMesh(contextMesh[0]).hit;
if (!collision) {
          rayOut.intersectsMesh(contextMesh[0]).hit
            ? (collision = true)
            : (collision = false);
        }

if (!collision) {
for (let index = 0; index < 4; index++) {
            filteredMeshPoints.push(meshPoints[meshPointsindex + index]);
          }
for (let index = 0; index < 18; index++) {
            filteredMeshPositions.push(
              meshPositions[(meshPointsindex / 4) * 6 * 3 + index]
            );
          }
}

that takes around 0.5ms wich is quite some time when doing this for around 30.000 faces.
What can i do here?

Thank you so much!

pcace

Raycasting is an expensive operation, but you can try speeding it up with octrees: Raycasting with camera - Questions - Babylon.js (babylonjs.com)

Hi, i did look into it, but did not get the results i was looking for.
i am now using https://rapier.rs/ just for the rays and it is blazingly fast! (somewhere between 10-100 times faster).

Cheers

Oh, that’s a cool solution! Was it easy to integrate the engine with Babylon? :open_mouth:

not really! this is how i did it:

import * as RAPIER from "@dimforge/rapier3d-compat";

export const rapierRays = async (
  contextMesh: AbstractMesh | undefined,
  rays: { origin: Vector3; distance: number; direction: Vector3 }[]
) => {
  if (contextMesh) {
    let indices = contextMesh.getIndices();
    let positions = contextMesh.getVerticesData(VertexBuffer.PositionKind);

    const collisions = await RAPIER.init().then(() => {
      const world = new RAPIER.World({ x: 0, y: 0, z: 0 });

      const trimesh = RAPIER.ColliderDesc.trimesh(
        new Float32Array(Object.values(positions!)),
        new Uint32Array(Object.values(indices!))
      );
      world.createCollider(trimesh);

      const rapierRays = rays.map((x) => {
        const ray = new RAPIER.Ray(
          { x: x.origin.x, y: x.origin.y, z: x.origin.z },
          { x: x.direction.x, y: x.direction.y, z: x.direction.z }
        );
        return ray;
      });

      /** necessary for world to process ray intersection */
      world.step();

      rapierRays.map((r, i) => {
        const hit = world.castRay(r, rays[0].distance, false);
        if (hit) {
          //do magic
        } else {
          //bla
        }
      });
    });
  }
};
4 Likes

Thanks for sharing! :hugs:

1 Like