Decal Creation RightHandedCoordinateSystem

Hey everyone,

I came across the following issue:
Whenever I try to apply a decal to certain meshes while the rightHandedCoordinate system is enabled, the decals get placed on the inside of the mesh, I’ve tried inversing the normals but I couldn’t get the decals to unflip, I’m not sure if this is a bug or not. When you turn on right hand with the default decal scene’s cat model, this issue isn’t there…

I have the following scene as an example, for some reason my playground won’t save so you’ll have to paste it in the playground manually:

var createScene = function () {
	var scene = new BABYLON.Scene(engine);

	//Adding a light
	var light = new BABYLON.HemisphericLight("Hemi", new BABYLON.Vector3(0, 1, 0), scene);

	//Adding an Arc Rotate Camera
	var camera = new BABYLON.ArcRotateCamera("Camera", -1.85, 1.2, 200, BABYLON.Vector3.Zero(), scene);
    scene.useRightHandedSystem = true
	camera.attachControl(canvas, true);

	// The first parameter can be used to specify which mesh to import. Here we import all meshes
	BABYLON.SceneLoader.ImportMesh("", Assets.meshes.flightHelmet.rootUrl, Assets.meshes.flightHelmet.filename, scene, function (newMeshes) {  	
        var cat = newMeshes[0];

		// Set the target of the camera to the first imported mesh
		camera.setTarget(cat);

		var decalMaterial = new BABYLON.StandardMaterial("decalMat", scene);
		decalMaterial.diffuseTexture = new BABYLON.Texture("/textures/impact.png", scene);
		decalMaterial.diffuseTexture.hasAlpha = true;
		decalMaterial.zOffset = -2;

    var onPointerDown = function (evt) {
        if (evt.button !== 0) {
            return;
        }

        var pickInfo = scene.pick(scene.pointerX, scene.pointerY, function (mesh) { return newMeshes.findIndex(m => m.uid == mesh.uid) > -1 });
        if (pickInfo.hit) {
            var decalSize = new BABYLON.Vector3(10, 10, 10);

            console.log(pickInfo.pickedMesh)
            var decal = BABYLON.MeshBuilder.CreateDecal("decal", pickInfo.pickedMesh, {
                position: pickInfo.pickedPoint,
                normal: pickInfo.getNormal(true),
                size: decalSize,
            });
            decal.material = decalMaterial;
            decal.setParent(pickInfo.pickedMesh);
        }
    }
		var canvas = engine.getRenderingCanvas();
		canvas.addEventListener("pointerdown", onPointerDown, false);

		scene.onDispose = function () {
			canvas.removeEventListener("pointerdown", onPointerDown);
		}
	});

	return scene;
};

Like this? Babylon.js Playground There is some distortion though around the wooden base thingy.

Yes, thank you. I coincidentally also just ran into this solution myself. I’m a bit confused why this is required for some models and not for others though. As long as it works it’s fine for the most part however.

As a further example, it actually even breaks it here (the documentation provided example scene):

var createScene = function () {
	var scene = new BABYLON.Scene(engine);

	//Adding a light
	var light = new BABYLON.HemisphericLight("Hemi", new BABYLON.Vector3(0, 1, 0), scene);

    scene.useRightHandedSystem = true
	//Adding an Arc Rotate Camera
	var camera = new BABYLON.ArcRotateCamera("Camera", -1.85, 1.2, 200, BABYLON.Vector3.Zero(), scene);

	camera.attachControl(canvas, true);

	// The first parameter can be used to specify which mesh to import. Here we import all meshes
	BABYLON.SceneLoader.ImportMesh("Shcroendiger'scat", "/scenes/", "SSAOcat.babylon", scene, function (newMeshes) {
		var cat = newMeshes[0];

		// Set the target of the camera to the first imported mesh
		camera.target = cat;

        setInterval(()=>{
            cat.rotation.y += 0.1
        }, 100);

		var decalMaterial = new BABYLON.StandardMaterial("decalMat", scene);
        decalMaterial.sideOrientation = BABYLON.StandardMaterial.CounterClockWiseSideOrientation;
		decalMaterial.diffuseTexture = new BABYLON.Texture("/textures/impact.png", scene);
		decalMaterial.diffuseTexture.hasAlpha = true;
		decalMaterial.zOffset = -2;

		var onPointerDown = function (evt) {
			if (evt.button !== 0) {
				return;
			}

			// check if we are under a mesh
			var pickInfo = scene.pick(scene.pointerX, scene.pointerY, function (mesh) { return mesh === cat; });
			if (pickInfo.hit) {
				var decalSize = new BABYLON.Vector3(10, 10, 10);

			/**************************CREATE DECAL*************************************************/
				var decal = BABYLON.MeshBuilder.CreateDecal("decal", cat, {position: pickInfo.pickedPoint, normal: pickInfo.getNormal(true), size: decalSize});
				decal.material = decalMaterial;
                decal.setParent(cat); // this won't work too
			/***************************************************************************************/	
			
			}
		}
		var canvas = engine.getRenderingCanvas();
		canvas.addEventListener("pointerdown", onPointerDown, false);

		scene.onDispose = function () {
			canvas.removeEventListener("pointerdown", onPointerDown);
		}
	});

	return scene;
};

I will have a look as soon as possible.

1 Like

Hi, not trying to be pushy. But did you have time yet to look into this? :eyes:

It’s not really a bug, the problem is that meshes loaded from a .glb file have a right-handed geometry, so the decal mesh is also created as a right-handed geometry mesh.

To fix the problem, you either have to change the orientation of the material to BABYLON.Material.CounterClockWiseSideOrientation, or set the decal mesh overrideMaterialSideOrientation property to BABYLON.Material.CounterClockWiseSideOrientation.

There’s no problem with Schrodinger’s cat, because it comes from a .babylon file, which is left-handed.

2 Likes