I tried to experiment with refraction planes and it didn’t go well. First, refraction planes don’t love boxes (especially those that have alpha). I also tried to attach the refraction plane to the regular plane, but the refraction plane appeared only from one side, from other side it was a solid white wall. Also, I don’t think that refraction planes work correctly with rectangular shapes. Probably it was designed for circle shape lenses. And the worst thing is that you have to pass an array of meshes that you want to be affected by refraction. It’s all doesn’t seem like a computation and complexity cheap procedure.
So, I continued with my initial approach. I found out that using planes instead of boxes can improve visuals a bit and reduce the computation load, because of a smaller number of facets.
Here is a playground: https://playground.babylonjs.com/#GV25YZ
The idea is similar to my previous example. But I significantly improved the class.
- Now, because we are using planes, we will always need to create a bounding box. It made class a bit simpler. Also, I exposed position, rotation, and rotationQuaternion as setters/getters. That made the solution more robust. Now there is significantly less chance that SPS mesh and bounding box will go out of sync. You can even move them dynamically now.
- I also added color property to constructor (in Color4 format aka RGBA). My getter and setter will handle its components properly. So, now you can create glass with different colors and transparency.
- You don’t need
{ isPickable: true }
for your SPS for body-to-body collisions. I added it only to support pointerDown
events in this demo. But it turned out that even this demo works without that setting.
- Depth argument has been removed. Width and height are own properties of the class now which makes it more serialisation friendly. Speaking of serialization, the basic idea of saves and loads for glass will be something like that:
// save
if (levelDependencies.glass) {
serializationObject.glass = [];
for (let g = 0; g < levelDependencies.glass.length; g++) {
const glass = levelDependencies.glass[g];
if (!glass.isDestroyed) {
serializationObject.glass.push({
name: glass.name,
w: glass.w,
h: glass.h,
floorPositionY: glass.floorPositionY,
color: glass.color.asArray(),
position: glass.position.asArray(),
rotation: glass.rotation ? glass.rotation.asArray() : null,
rotationQuaternion: glass.rotationQuaternion ? glass.rotationQuaternion.asArray() : null,
});
}
}
}
// load
for (let g = 0; g < saveFile.glass.length; g++) {
const savedGlass = saveFile.glass[g];
const position = BABYLON.Vector3.FromArray(savedGlass.position);
const rotation = savedGlass.rotation ? BABYLON.Vector3.FromArray(savedGlass.rotation) : null;
const rotationQuaternion = savedGlass.rotationQuaternion ? BABYLON.Quaternion.FromArray(savedGlass.rotationQuaternion) : null;
this.dependencies.glass.push(
new Glass(
savedGlass.name,
savedGlass.w,
savedGlass.h,
savedGlass.floorPositionY,
BABYLON.Color4.FromArray(savedGlass.color),
position,
rotation,
rotationQuaternion,
scene
)
);
}
As of now, I think this solution fits my needs, but I still will be glad to see any other finished solutions.
Homework:
You can add a new mesh
argument that will accept any mesh. In this case you can skip the plane creation and use a given mesh instead. This is how you can create glass sculptures of any shape and color, that you can also break/shatter. You still may need w
and h
parameters for bounding box creation though, if your sculpture is too thin.