Is there an easy way to ensure a model's size and position is displayed consistently across several device form-factors?

Hi. I am just throwing one solution that I usually use. I had several project where I had to deal with huge amount of different object fetched from storage, where I don’t know what’s the model, which format is model etc.

This solution doesn’t require updating the position of the camera, as I usually find that not consistent for each possible model.

Basically, what I do is I create one box using Babylon, and I set the size of that box to be whichever is the biggest dimension of the mesh inside the scene. So, let’s say that your model in the scene is 2x3x4. The size of the box will be 4.

I position this box on top of the model, set this box to be parent for each mesh in the scene, then position box in (0, 0, 0) and call this

parent.normalizeToUnitCube(true);

Which sets the size of the cube to 1x1x1 (so basically, whole scene becomes 1x1x1 world where the parent box acts as world).

So when you do this, you have a parent box in 0,0,0, you can set the target at 0,0,0 (or alternatively parent box bounding box center). This way, as the world is always 1x1x1 and target is looking at the center of this parent box (which is isVisible = false, by the way :D), so no matter which size of the model comes in, it will always look the same, and no need to do anything with camera.

Few notes though. I would advise that you follow the rule that size of the box should be the biggest dimension value from W x H x D values of the mesh loaded. So basically you need to calculate the bounding box of the mesh to get these W H D values, and then use a biggest value as cube size. This is really simple if you have ONE mesh, meaning, if the whole model is containing only one mesh/part.

The problem comes if the model is assembled from multiple meshes/parts. In this case, you cannot simply take one of them and work with the size. You need to calculate combined bounding box values for those parts.

Then you can select any mesh from the mesh array, let’s say mesh[0]. And set this newly calculated bounding box to it.

To do that I use this method stated in this playground called totalBoundingInfo() (lines 30-47)

https://www.babylonjs-playground.com/#Y3RK7Z#1 (note that this playground is only to show you a method, it’s not working example of implementation I am talking about).

After you calculate totalBoundingInfo you can set that bounding info the any mesh from the meshes array (like scene.meshes). For example:

mesh[0].setBoundingInfo(totalBoundingInfo(meshes)) (where meshes is array of meshes, like scene.meshes for example).

In this moment you can easily read the bounding box values from the model, get biggest dimension, set it as a parent box size, parent everything, normalize the cube, and probably call

parent.computeWorldMatrix(true);

to be sure that future calculations will work with the new values.

One more thing though. I am not sure what’s the nature of your project. But all of this affects the scale of the mesh or meshes in the scene. So if you are using scaling values for something, you need to make sure that you are offsetting everything properly. For example:

for 2x3x4 model in the scene, if you scale it to 1x1x1 cube where 4 is the size of that cube, you will get 0.5 x 0.75 x 1 (as everything scaled down 4x, that’s why it is important to match cube size with the biggest dimension). So if you need to use the scaling values, or initial “real world dimension values” of the model, you need to use that scaling offset factor to multiply with the values to get initial values.

I wrote a lot of stuff here, maybe it sounds complicated, but if you decide to give it a go, it’s quite simple to implement, and I can create a simple playground where you could see this in practice if you want.

Thanks.

3 Likes