How can I implement an opaque glass material with a blur-like effect?

Hello, community members.

I have been making steady progress towards my desired results thanks to the invaluable assistance I’ve received here.

Current Outcome:


refraction | Babylon.js Playground (babylonjs.com)
I’m just one step away from achieving my desired outcome with this project.

Desired Material:
image

I am looking to replicate the above semi-opaque material (perhaps a semi-opaque plastic?) in code. Could anyone provide a sample code for achieving this effect?

PS.
I have previously sought advice on opaque techniques within the community. However, is there a simpler way, perhaps with some abstraction provided by BABYLON, to achieve the material I’m looking for? Is this something that becoming more familiar with NME might easily resolve?

PS2.
It seems there might be some hints here: Pure BabylonJS code to build model with accurate translucency (like the "Mosquito In Amber" demo), but I’m not quite sure how to approach this. Could anyone offer some guidance?

1 Like

This looks like something that can maybe already be achieved with PBR using diffuse transmission, roughness, and maybe some kind of refraction. @bghgary anything stand out in the screenshot above as not achievable with Babylon’s PBR implementation? Any similar example Playgrounds you can point to, even if it is loading a glTF with similar material properties?

@sebavan @Evgeni_Popov @PatrickRyan any thoughts?

why not using a reflection probe in the refraction ? Real time PBR filtering is coming to Babylon | by Babylon.js | Medium

1 Like

@bghgary While I’m still fairly new to this, my current understanding is that to represent a projected material, we need to use a renderTargetTexture that converts the entire screen into a texture. We then create a reflection texture from this and apply it to the projected material. This seems to be the standard approach I’ve observed in all the playground samples I’ve referenced. I’ve also come to understand that reflection probes are tools designed for creating mirror effects.

Here are the results after several adjustments.

While some effects were removed, the internal components have finally begun to be visible.

My target material is opaque glass. Here’s the current status:

  • Have the elements behind the glass been made opaque by applying a blur process to the reflection texture? Yes.
  • Is the curvature of the glass (internal, adjusted alpha values) visible? Yes.
  • Is the curvature of the glass within itself also blurred? No.

These are the references I’ve used.

  1. Creating realistic glass is impossible.
  2. It’s more cost-effective to create slightly non-realistic glass, which is something only developers might fully understand.
  3. Alternatively, one must resort to using tricks.

image(form blender)
To create internal refractions, I attempted to use a trick involving a dummy element.

This method involves overlapping two elements, where the dummy element is exposed only to the renderTargetTexture and not displayed on the screen. Unfortunately, this approach did not work as intended.

dummy.layerMask = 0x10000000;
camera.layerMask = 0x0FFFFFFF;

renderTargetTexture.renderList.push(dummy);



The red color showed the internal light refraction I was aiming for, but the yellow color revealed the dummy edges due to light refraction, creating an unintended effect. This issue led me to remove the blur, which made this trick unviable.

Am I challenging an impossible area, or is it just because I’m not yet familiar with these techniques? :sob:

Maybe this one could help you too:

Thank you for your response.

I appreciate the reference to the previous suggestions, however, the outcomes were not as desired. I’m facing a couple of specific issues:

  1. The surface has turned rough and uneven. Ideally, I’m aiming for a smooth surface with a material effect that resembles light scattering inside, similar to opaque glass.
  2. Because the interior is represented with an alpha value, the surface’s light scattering does not affect the interior, resulting in the internal cylinder being too pronounced and visibly hollow.

Currently, I have overlaid two identical objects (labeled 1 and 2):

  • Object 1 is layered with a reflection texture.
  • Object 2, positioned over Object 1 with an alpha value to make the interior visible, has a blurred reflection texture to mimic the appearance of frosted glass. The issue with this approach is that the texture of Object 2 is slightly visible, and the internal surface refraction is not effectively implemented.

Do you have any recommendations on how to achieve a material effect that allows the interior to be visible while still resembling opaque glass?

![Your Current Result]


I would greatly appreciate any advice or suggestions you might have. Thank you!

Can you share a PG with the mesh you are testing on?

I’m not sure how to upload font.json and model.glb to the PG, so I haven’t been able to test it there…
stair_apply.zip (2.6 MB)

Below is the code I’m using in my project, and although I don’t fully understand how the stencil works, I’ve left it as is because it produces the desired results.

I’ve organized the code to make it easier to understand and removed unnecessary properties to simplify it further.

		const engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true, antialias: true, depth: true});
		const scene = new BABYLON.Scene(engine);
		scene.clearColor = new BABYLON.Color4(1, 1, 1, 1);

		const camera = new BABYLON.ArcRotateCamera('camera', -Math.PI / 2, Math.PI / 2, 40, BABYLON.Vector3.Zero(), scene);
		camera.attachControl(canvas, true);

		const light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(1, 1, 0), scene);
		light.intensity = 2;

		// sphere
		const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', { segments: 36, diameter: 100 }, scene);
		sphere.position = new BABYLON.Vector3(0, 0, 0);

		sphere.enableEdgesRendering(0.9999);
		sphere.edgesWidth = 10;
		sphere.edgesColor = BABYLON.Color4.FromColor3(BABYLON.Color3.Black());

		// text
		const fontData = await (await fetch('/fonts/Pretendard_Variable_Regular.json')).json(); // Providing you have a font data file at that location
		const myText = BABYLON.MeshBuilder.CreateText("myText", " WE DESIGN \n AND DEVELOP \n DIGITAL SPACES", fontData, {
			size: 8,
			resolution: 64,
			depth: 0,
			faceUV: [
				new BABYLON.Vector4(0, 0, 1, 1),
				new BABYLON.Vector4(0, 0, 1, 1),
				new BABYLON.Vector4(0, 0, 1, 1),
			]
		});
		myText.position = new BABYLON.Vector3(0, -20, 150);
		myText.parent = camera;
		myText.material = new BABYLON.PBRMaterial("material", scene);
		myText.renderingGroupId = 1;

		var previousStencilMask = engine.getStencilMask();
		var previousStencilFunction = engine.getStencilFunction();

		myText.onBeforeRenderObservable.add(function(){
			engine.setStencilMask(0x00);
			engine.setStencilBuffer(true);
			engine.setStencilFunctionReference(1);
			engine.setStencilFunction(BABYLON.Engine.NOTEQUAL);
		});

		myText.onAfterRenderObservable.add(function(){
			engine.setStencilBuffer(false);
			engine.setStencilMask(previousStencilMask);
			engine.setStencilFunction(previousStencilFunction);
		});
		scene.setRenderingAutoClearDepthStencil(1, false);

		/// logo
		const logoMaterial = new BABYLON.PBRMaterial("glass", scene);

		logoMaterial.metallic = .5;
		logoMaterial.roughness = .5;
		logoMaterial.backFaceCulling = false;

		const renderTargetTexture = new BABYLON.RenderTargetTexture("opaqueRTT", 2048);
		renderTargetTexture.clearColor = BABYLON.Color4.FromHexString("#6615E9");
		logoMaterial.refractionTexture = renderTargetTexture;

		const horizontalBlur = new BABYLON.BlurPostProcess("horizontalBlur", new BABYLON.Vector2(2.0, 0), 12.0, 1.0, null, BABYLON.Texture.BILINEAR_SAMPLINGMODE, engine, false);
		const verticalBlur = new BABYLON.BlurPostProcess("verticalBlur", new BABYLON.Vector2(0, 2.0), 12.0, 1.0, null,BABYLON. Texture.BILINEAR_SAMPLINGMODE, engine, false);
		renderTargetTexture.addPostProcess(horizontalBlur);
		renderTargetTexture.addPostProcess(verticalBlur);

		logoMaterial.stencil.enabled = true;
		logoMaterial.stencil.func = BABYLON.Engine.ALWAYS;
		logoMaterial.stencil.funcRef = 1;
		logoMaterial.stencil.funcMask = 0xFF;
		logoMaterial.stencil.mask = 0xFF;
		logoMaterial.stencil.opDepthFail = BABYLON.Engine.KEEP;
		logoMaterial.stencil.opStencilDepthPass = BABYLON.Engine.REPLACE;
		logoMaterial.stencil.opStencilFail = BABYLON.Engine.KEEP;

		let logo;
		BABYLON.SceneLoader.ImportMesh("", "/stair_apply.glb", "", scene, function (newMeshes) {
			logo = newMeshes[1];

			logo.material = logoMaterial;
			logo.position = new BABYLON.Vector3(0, 0, 0);
			logo.rotation = new BABYLON.Vector3(-Math.PI / 9, -Math.PI / 9, 0);
			logo.scaling = new BABYLON.Vector3(5, 5, 5);
		});

		let backPlateLogo;
		BABYLON.SceneLoader.ImportMesh("", "/stair_apply.glb", "", scene, function (newMeshes) {
			backPlateLogo = newMeshes[1];

			const backPlateMaterial = new BABYLON.PBRMaterial("glass", scene);
			backPlateMaterial.alpha = .5;
			backPlateMaterial.metallic = .5;
			backPlateMaterial.roughness = .5;
			backPlateMaterial.backFaceCulling = false;

			backPlateLogo.material = backPlateMaterial;

			backPlateLogo.position = new BABYLON.Vector3(0, 0, 0);
			backPlateLogo.rotation = new BABYLON.Vector3(-Math.PI / 9, -Math.PI / 9, 0);
			backPlateLogo.scaling = new BABYLON.Vector3(5, 5, 5);

			backPlateLogo.layerMask = 0x10000000;
		});
		camera.layerMask = 0x0FFFFFFF;

		engine.runRenderLoop(() => {
			renderTargetTexture.renderList = [myText, backPlateLogo];
			scene.render();
		});
1 Like

No worries, I uploaded your assets to my FTP and created a PG so you can make changes here and share your progress online:

Now let’s try to mimic the material you are so eagerly after :stuck_out_tongue:

2 Likes

Getting close :stuck_out_tongue:

EDIT:
You should create your own env texture and reflect it. Now it uses a stock env texture. I didn’t play with the stencils.

Is this something close to your requirements?

1 Like

For future reference :slight_smile: Using External Assets In the Playground | Babylon.js Documentation (babylonjs.com)

2 Likes

Due to a busy schedule, my response was delayed.

[Desired Material]
image
I would like to achieve a material appearance where the interior is visible yet opaque. Similar to the red area, it would be ideal if the opposite side could be seen in an opaque manner.

[Current Status]
image
I have simplified the code using only understandable properties.

Is it possible for the interior to also be projected while appearing hazy?

[Research Done]

  1. Using alpha and backFaceCulling, it’s possible to render the inside of the object. However, this method makes the interior too distinct. Is there a material that allows for some diffusion, so the interior appears slightly hazy when projected?
  2. The reflection texture (text behind) also appears too distinct. Is there a property similar to glassMaterial.roughness = .5; that can add a slight blur more simply? (Using a process to apply blur on the render target texture seems like a heavier method. Is there a better way?)

[Reference Code and Example]
refraction test | Babylon.js Playground

I have simplified the material property code to achieve the desired translucent material, although it is not quite the desired color.

vs

?

You have to use your own environment texture to get the reflections real.

@roland

The material in the above image is my ultimate goal.

The PG (Playground) and image I uploaded use only the properties I am aware of (simply organized code).

image

Is it possible to make the interior appear semi-transparent, similar to this feeling? Adjusting the alpha value makes the interior look transparent, not semi-transparent, which is not the material I want.

Try to use the approach I used here - frosty sphere, it’s kinda similar:

Thank you always for your responses.

I remember you recommended this article to me previously.

However, it does not produce the desired result I am looking for.

image

The internal holes are too visible. If the material on the outside scatters light due to the bump, the material on the inside should also scatter light. (In the image, the use of alpha causes the inside to be too clear)

I found a sample based on a three.js project.

How to Make a 3D Glass Effect using Three.js and React (olivierlarose.com)


This effect exactly implements what I wanted (though it lacks slight blurring…)

Is there an easy way to achieve this effect in BJS?
Or is such an effect already implemented in BJS?

Look at the examples in this topic. You have a bunch of transmissive materials in the PGs.

How should I refer to this topic if the Playground is only used for loading GLB files?

image

This Playground, too, does not render its backside. Although the red sphere appears to render the backside, shouldn’t it also display the back corresponding to the red line? As for the blue sphere, it appears transparent due to missing mesh parts, but it also does not render its own backside.

I found a topic discussing this issueFrom what I understand, it seems that BabylonJS does not natively support such a feature, and one would need to use tricks or custom shaders to replicate this functionality.