CSG.subtract Incorrectly Modifies SubMeshes MultiMaterial

When using CSG to create a cutout of custom Polygon Mesh with MultiMaterial, the resulting mesh created from CSG has incorrect materials for subMeshes, even with keepSubMeshes = true option:

Adding @Evgeni_Popov for the CSG part.

The bug is also present on other CSG operations, such as union.

What is the alternative way to detect pickedMesh face after CSG operation?

I can only think of using normals to find all indices on the same face in order to apply custom Material to that particular face, but it seems computationally intensive for such should-be-trivial task.

The app highlights the pickedMesh face on mouse move while being hovered over, similar to button onHover effect, so all calculations, uv mapping, updating vertexBuffer, applying Material, etc. must happen within 2ms.

This PR will fix the problem with the materials on submeshes:

Regarding face picking, it still does work with the CSG mesh, so I’m not sure I understand your question? Maybe you could be interested in some posts dealing with making picking faster, for eg:

But there are probably a lot of others.

3 Likes

Will test PR and update status.

Regarding the picking question: before CSG operation, I can compute each face of the Polygon very fast without any ray picking, by their faceId facets (example: faceId: 7 belongs to the Green side), but after CSG operation, the mesh indices change and faceId: 7 no longer belongs to Green side of the Polygon.

What is the correct and efficient way to pick and apply MultiMaterials to a specific side of the Polygon after CSG operation?

This is actually two questions in one:

  1. How to apply MultiMaterials to the picked Polygon face from scene.pick() pickInfo, after CSG?
  2. How to apply MultiMaterials to a particular face of the Polygon without Ray picking, after CSG?

The 2nd question can be solved by applying MultiMaterial to Polygon first before running CSG with above PR, but it does not cover the cutouts.

UPDATE

  1. How to apply MultiMaterials to the picked Polygon face from scene.pick() pickInfo, after CSG?
    A working solution is to find subMesh with picked faceId falling within the indexStart and indexCount range, then
    mutate .materialIndex.
    https://playground.babylonjs.com/#2NJYI5#1030 (pick the face, it will turn red)

It seems that CSG pushes the subtracted/unioned subMesh to the start of Mesh.subMeshes index.

Is this consistent and expected behavior? Could it possibly be pushed to the end of Mesh.subMeshes index, so that original subMeshes order is preserved after CSG operation?

My mistake, there was no bug in the CSG code!

The problem is in your PG: you should convert the meshes to CSG (by calling FromMesh) in the order you create the sub materials in the multi material.

As you create first the materials for the polygon then the material for the window in your multi material, you must call the FromMesh method in this order:

let wall = BABYLON.CSG.FromMesh(polygon)
const window = BABYLON.CSG.FromMesh(windows)

https://playground.babylonjs.com/#2NJYI5#1032

That’s how the code matches the sub meshes and the sub materials in the final CSG mesh:

  • the sub mesh #0 of the first mesh for which you call FromMesh will be mapped to the sub material #0 of the material you pass to toMesh
  • the sub mesh #1 of the first mesh for which you call FromMesh will be mapped to the sub material #1 of the material you pass to toMesh
  • the sub mesh #n-1 of the first mesh for which you call FromMesh will be mapped to the sub material #n-1 of the material you pass to toMesh
  • the sub mesh #0 of the second mesh for which you call FromMesh will be mapped to the sub material #n of the material you pass to toMesh
  • and so on

The sub meshes in the final mesh are also created in the same order:

  • the sub mesh #0 of the final mesh is the sub mesh #0 of the first mesh for which you called FromMesh
  • the sub mesh #n-1 of the final mesh is the sub mesh #n-1 of the first mesh for which you called FromMesh
  • the sub mesh #n of the final mesh is the sub mesh #0 of the second mesh for which you called FromMesh
  • and so on

Note however that the sub meshes won’t have the same index range than in the initial meshes as generally new faces are created.

It seems that CSG pushes the subtracted/unioned subMesh to the start of Mesh.subMeshes index.

No, as explained above the sub meshes are created in the order given, first the sub meshes of the first mesh you call FromMesh for, then the sub meshes for the second mesh you call FromMesh for.

1 Like

Awesome, that totally made sense now.

Would be great to add your explanation to the MultiMaterials docs.

1 Like

@PirateJC for the doc :slight_smile:

Hi @Evgeni_Popov,

Why does the final CSG Mesh depend on the order of CSG.FromMesh calls? Is there any flag to control the order of subMeshes in the final CSG.ToMesh call? (

Ideally, it should preserve the order of the CSG instance that initiates intersect/subtract/union. Example: A.subtract(B) will preserve the subMeshes order of A.

Because of caching and for performance reasons, I have a use case where the same CSG is reused for different intersect/union/subtract operations with different Meshes, thus cannot control the order of CSG.FromMesh creation.

That’s how it is coded in the class and I don’t think it’s something easy to change (and even if it can be changed at all)…

You can have a look in the csg class:

I looked at that but didn’t find anything that could relate to vertex/polygon ordering, because the FromMesh method seems quite functional in logic (i.e. no OOP context dependent logic, besides transforms).

It must be at the vertex buffer or inside some GPU memory caching level, because CSG.subtract() produces different CSG.polygons orders if you change FromMesh order.