Problem with clipping caps with IFC models

Hi all,

We want to see if we can fill the clipped elements of the buildings loaded with the IFCLoader. We are using this example as a first reference.

The end goal is to also display edges using this.

We have set up a basic example loading two different IFC files: a simple one and a more complex one. Although the code seems to work in the simple one, the more complex one seem to fail.

The example is here (all the code is here) and you can try it live here.

Simple model:

Complex model:

Thank you very much in advance!

1 Like

The stencil approach used for rendering the clip caps like this requires geometry with special properties. Specifically the geometry must be “solid” or water tight and not contain any overlapping triangles. A good rule of thumb is that every edge in the model must be shared by exactly two triangles. And the faces must be oriented in a coherent direction (though you likely want this anyway).

The stencil operations can be difficult to understand at first without digging in. But at a high level the way this effect works is the stencil buffer counts up for every front face rendered and counts down for every back face rendered. This means that when rendering a well-formed model normally (described above) the stencil value for every pixel will end with a total count of 0. If part of the model is clipped then there will be some pixels where there will be more backfaces than front faces leading to non zero stencil values. These pixels with non zero values are the ones that the caps will render to.

So basically what you’re seeing is that your complex model is not formed correctly to support this effect. I think generally a solid clip cap isn’t something you could generate for a model like this even if trying to generate one geometrically.

I theory you should be able to programmatically determine whether a mesh meets the above requirements but keep in mind that models that may look well formed and work correctly for the stencil caps effect may not look mathematically like a well formed model due to floating point and export errors (edges / vertices between triangles don’t line up exactly, etc). So making that work consistently may prove difficult.


Thanks for the super detailed response! Geometry is one of the biggest challenges of IFC. Until we figure that out, we have started trying this approach, which would allow us to achieve a similar effect for now. Once we have that, we will add the edges using BHV.

This new strategy simply consists of rendering backfaces with another color:

model.material.forEach(mat => {
    mat.side = DoubleSide;
    mat.onBeforeCompile = function( shader ) {

      shader.fragmentShader = shader.fragmentShader.replace(

        `vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;`,

        `vec3 outgoingLight = ( gl_FrontFacing ) ? reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance : vec3(0.,0.,0.);`


Although this strategy does the trick when looking at the model from above, the backfaces overlap with frontfaces of another objects (e.g. see windows). If we could solve that z-fighting always rendering the backfaces on top on the frontfaces, the capping problem would be solved.

Do you know if there’s a way to achieve this, or any reference pointing into that direction?

Thanks again!

In the end the solution was as simple as creating a copy of the mesh with side: BackSide and applying a simple material to it :slightly_smiling_face: It’s not perfect, but will do the trick for now. Thanks!

1 Like

In the end the solution was as simple as creating a copy of the mesh with side: BackSide

I wouldn’t expect this to work on it’s own – creating a new material and rendering it shouldn’t be a lot different from rendering the back faces as black in a single pass. Did you change anything else on the material?

If you’re still seeing objects poking through due to z-fighting (which is what it looked like the problem was in your second post) you can use the “Material.polygonOffset” feature to pull just the back faces toward the camera by some epsilon to try to overcome that z fighting.

1 Like

Indeed, you are right! Sorry, should have posted the whole solution. This is the material used to overcome that z-fight:

const material = new MeshBasicMaterial({
      color: 0x000000,
      side: BackSide,
      clippingPlanes: planes,
      polygonOffset: true,
      polygonOffsetFactor: -1, 
      polygonOffsetUnits: 1})

  • What’s wrong with the fill that you did with this example? * Why do you say complex models fail

The geometry that we get from IFC is not perfect yet (we have implemented the geometry engine ourselves), and that example doesn’t seem to work well on some items.