Make mesh looking solid while using opacityTexture

Hello guys,

I try to create a metal plate with holes. Instead of creating the holes for real I fake them with an opacityTexture. Unfortunately you can look inside of the plate with this method. Is there a way to make the plate look solid while using the opacityTexture?

Problem:

Goal:

I appreciate your help!

Best

Iā€™m not sure I understand.

If you donā€™t want to look through, set the alpha values to 1 for the holes, or donā€™t use an opacity texture and create the holes in the diffuse texture? Maybe a PG would help to understand.

I want to look through the plate but I donā€™t want to look inside of the plate. If you have a plate with 0.5cm thickness and stamp some holes in it you are not able to see the space between front and back (first image of my prev post). It should look like the second image of my prev post.

Just set backFaceCulling to false on your material.

[edit] In a more advanced way, you can try using Parallax Mapping | Babylon.js Documentation

backFaceCulling doesnā€™t help unfortunately.

I created a pg: Babylon.js Playground. I think my problem should be clearer now. All vertical spaces should look solid. Is it possible to solve it with parallax mapping? I will give it a try.

Texture tricks have their limits. If you have to zoom really near the holes, use geometry instead.

You need some kind of volumetric mesh if you donā€™t want to see the ā€œinsideā€. You can use CSG to generate the holes. See for eg (from Drawing outside edges of a Mesh created from CSG - #25 by Evgeni_Popov):

https://playground.babylonjs.com/#0HA29N

Thanks. I am familiar with CSG. It would be just nice if the is a hack to create this shape with with a texture.

Parallax occlusion mapping may be what you want:

https://playground.babylonjs.com/#10I31V#23

I will definitely try that. Thanks!

Not a texture solution but it might be an alternative Irregular Polygon Extrusion | Babylon.js Documentation.

Maybe create one box plus hole and use SPS or thin instances to produce the sheet

1 Like

Hello again,

some months past and I am still facing this problem without a solution that fits my needs. I know that there are always limitations but I want to find the best tradeoff between performance and quality.

CSG
Perfect result in terms of quality, but it takes a very long time to create the holes. Imagine a 100x100 cm plate with 1cm holes and 0.5cm offset. This leads to around 4.5k holes. CSG is slow and the plate gets a lot of faces due to the holes. A bigger plate or smaller holes make the problem even worse. This is not usable on my pc and smartphones will surely explode.

Parallax Occlusion
As far as I understand parallax occlusion places multiple layers of the texture above each other to create the illusion of depth. This wonā€™t work here because it is not just depth but a hole. So you should be able to look through the hole. Or is it still possible? Can we use parallax map with node material?

SPS or Thin Instances
I like your idea @JohnK but unfortunately there a two issues with this approach in my case. First I want to edit the mesh after creating the holes further (probably using csg) and second the plate is not just a regular box but a box with beveled corners and edges. I could imaging to create the outer part with the beveled corners and edges separately from the inner part which equals a box. But since I canā€™t csg the thin instances I canā€™t use this method.

Shader
I am very unexperienced with shaders so I wonder if it would be possible to create such an effect with it. I would love to know this.

https://playground.babylonjs.com/#03XGIN#3

You can (somewhat) do it thanks to the stencill buffer.

To create a hole in a box:

  1. Render a cylinder where you want the hole to be with colorWrite = false so that it only updates the zbuffer
  2. Draw the box. There will be a hole in the plane where the cylinder has been drawn:

    Note: to avoid z-fighting between the face of the box and the top of the cylinder, the cylinder should be a little longer so that it protrudes a bit at the top and bottom
  3. Draw the inside of the (uncapped) cylinder (cull front faces instead of back faces) with a material that disables z-testing (else the cylinder wonā€™t show up because of step 1):

    You can see itā€™s not ok, thereā€™s an artifact because the cylinder is not clipped by the plane (because of z-test = false)
  4. To overcome the problem, after step 2 draw again the cylinder from step 1 but with colorWrite = false and depthWrite = false but with z-testing = true. In effect, the hole in itself will be redrawn, which is pointless from a visual standpoint but is important for the stencil buffer: the stencil is enabled and a value (1) is written where the hole appears.
  5. Now we can do step 3 but this time by enabling the stencil buffer so that we only draw where the stencil = 1:

Artifact:

We can see the cylinder corresponding to the leftmost hole is visible through the second hole because this cylinder is drawn where stencil=1, and stencil=1 for both holes. To fix the problem, you can use a different stencil value for each hole (1 and 2 for eg) that way they wonā€™t collide. In all generality, each hole should have its own stencil value, but we are limited to 255 different valuesā€¦ In the PG below I have simply used 2 values and I have alternated between 1 and 2 between each hole. It does fix some artifacts but not everything, notably if you look at the plane at grazing anglesā€¦

Last thing, to make it fast, use thin instances for the holes!

Hereā€™s a PG with the 4500+ holes, without the fix for the artifact: https://playground.babylonjs.com/#V518NB#11

With the fix:
https://playground.babylonjs.com/#V518NB#10

At grazing angles you can see artifacts because some cylinders leak into other cylinder holes:
image

We would need a 32 bit stencil in WebGL to have a unique value for each hole, but I donā€™t think itā€™s possibleā€¦

3 Likes

Thereā€™s a way to make it work in all cases but itā€™s slowerā€¦

You can draw each hole one after the other and reset the stencil buffer to a 0 value between each draw. That way, the holes canā€™t ā€œleakā€ one inside the other.

But to do this you must issue 2 draw calls per hole and you canā€™t use thin instances anymore (except for the first step as outlines above). So, in your case you get around 9000 draw calls which is too much: on my card (GTX 1080), Iā€™m around 3-5 fpsā€¦

But by reducing the number of holes drawn it works quite well:

https://playground.babylonjs.com/#V518NB#15

No artifacts at grazing angles anymore:

2 Likes

Thank you very much. This solution is definitely the best one. I didnā€˜t use stencil buffer before but your explanation makes it pretty clear.

Resetting the stencil buffer is not an option since the draw calls will kill all devices. But good to know that is would be possible to remove the artifacts. Anyway I think the best tradeoff is to have some artifacts but good performance.

@Evgeni_Popov , your post is really great and helpful. I am trying to translate your code to ThreeJS but I fail to achieve the effect as yours. Would you mind posting the code in ThreeJS too please?

I have posted my question in SO with some screen shots and code.

really? :slight_smile: I know @Evgeni_Popov is a kind guy but you are asking him to port all the code he did using BJS API to 3js API?

2 Likes

Sorry, I donā€™t know Threejs enough to make the port. I think you should post in their forum, maybe someone will be able to help there.

1 Like

Thank you @Evgeni_Popov