Jump to content

Babylon.js: A double array to 3d


foumfo
 Share

Recommended Posts

Hey everyone,  I've just started working with Babylon.js and I have a question.

I've got a double array filled with 1 & 0 and I want it tranformed to 3d. 1 being blocks and 0 spaces.

I did it this way:

var sizeFactor = 0.2;
for (var i = 0; i < array.length; i++) {
   for (var j = 0; j < array[0].length; j++) {
      if (array[i][j] === 1) {
         var box = BABYLON.MeshBuilder.CreateBox('box', {height: sizeFactor, width: sizeFactor, depth: sizeFactor}, scene);
         box.position.x = i * sizeFactor;
         box.position.y = 0;
         box.position.z = j * sizeFactor;
       }
    }
}

but its very taxing I believe to the system because of the many boxes.

Is there any other less taxing way to achieve this?

Link to comment
Share on other sites

9 hours ago, Raggar said:

I'm sure it's because of the draw calls.

If I import ~600 box models I hit around ~20 FPS, but if I merge those boxes I'm back at 60 FPS.

You can merge the boxes after creation, or use instances, but this depends on the use-case.

How could I merge them? after the merger will there be any hidden faces?

Link to comment
Share on other sites

32 minutes ago, foumfo said:

How could I merge them? after the merger will there be any hidden faces?

Did a little test.

Without merging I get about 30-34 FPS.

http://www.babylonjs-playground.com/#VQ84FP#1

With merging I'm at 60.

http://www.babylonjs-playground.com/#VQ84FP

If you use different materials, you'll have to merge the ones sharing the same material:

I'm not sure how you would get rid of hidden faces. Maybe use planes instead?

 

Link to comment
Share on other sites

1 minute ago, Raggar said:

Did a little test.

Without merging I get about 30-34 FPS.

http://www.babylonjs-playground.com/#VQ84FP#1

With merging I'm at 60.

http://www.babylonjs-playground.com/#VQ84FP

If you use different materials, you'll have to merge the ones sharing the same material:

I'm not sure how you would get rid of hidden faces. Maybe use planes instead?

 

Thank you for the response, is there any way to see all the face outlines? or perhaps switch to a gridview?

Link to comment
Share on other sites

Hi and welcome to the forum from me as well.

Checkout wireframe  PG  https://www.babylonjs-playground.com/#VQ84FP#2

or edge rendering PG https://www.babylonjs-playground.com/#VQ84FP#3

IMHO  SPS is still the way to go, it also creates a single mesh

SPS

Basic https://www.babylonjs-playground.com/#9PP17F

Wireframe https://www.babylonjs-playground.com/#9PP17F#1

edge rendering https://www.babylonjs-playground.com/#9PP17F#2

250000 boxes https://www.babylonjs-playground.com/#9PP17F#3

Thrown in some array methods as well.

Removing hidden faces is much more of a problem.

EDIT on further thinking the line

mapArray[0]--

should not be included

Link to comment
Share on other sites

1 hour ago, JohnK said:

Hi and welcome to the forum from me as well.

Checkout wireframe  PG  https://www.babylonjs-playground.com/#VQ84FP#2

or edge rendering PG https://www.babylonjs-playground.com/#VQ84FP#3

IMHO  SPS is still the way to go, it also creates a single mesh

SPS

Basic https://www.babylonjs-playground.com/#9PP17F

Wireframe https://www.babylonjs-playground.com/#9PP17F#1

edge rendering https://www.babylonjs-playground.com/#9PP17F#2

250000 boxes https://www.babylonjs-playground.com/#9PP17F#3

Thrown in some array methods as well.

Removing hidden faces is much more of a problem.

EDIT on further thinking the line


mapArray[0]--

should not be included

Thank you for all the help. As I gather, both merging meshes and sps are essentially the same, apart from the fact that sps is more versatile.

Let's say I create the unified mesh I want using SPS. Wont the many faces of the mess, hidden or not, create perfomance issues? I do want them to have textures in the end

Link to comment
Share on other sites

Whatever you want to do will require a minimum number of faces, its just the best way to keep the draw calls down. Both merging and sps reduce the draw calls. A merged mesh can only have one texture, there is more versatility with sps.

Link to comment
Share on other sites

2 hours ago, foumfo said:

Wont the many faces of the mess, hidden or not, create perfomance issues? I do want them to have textures in the end

I remember digging into this cool project once, if you really don't want to create the faces you don't need.  You could do a similar loop, except he does 3d, while you are only in a double array, so your loop would be easier (ie: this example uses Array<Array<Array<...>>>).
https://github.com/SvenFrankson/planet-builder-web/blob/master/scripts/PlanetChunckMeshBuilder.ts
Basically creating meshes on the fly, but not adding a face if there is an adjoining block, which sounds like what you're after.
 

Link to comment
Share on other sites

8 minutes ago, brianzinn said:

I remember digging into this cool project once, if you really don't want to create the faces you don't need.  You could do a similar loop, except he does 3d, while you are only in a double array, so your loop would be easier (ie: this example uses Array<Array<Array<...>>>).
https://github.com/SvenFrankson/planet-builder-web/blob/master/scripts/PlanetChunckMeshBuilder.ts
Basically creating meshes on the fly, but not adding a face if there is an adjoining block, which sounds like what you're after.
 

That requires a lot of thought. Do you believe that deleting the hidden faces would offer any kind of performance gain?

Link to comment
Share on other sites

My game builds blocks side-by-side in 3d as well.  I do believe that using blocks and detecting occluded faces has a performance penalty.  I'm not an expert, but imagine freezingWorldMatrix() or instances probably more performance gain (https://doc.babylonjs.com/how_to/how_to_use_instances).  You are measuring FPS, but it can be CPU or GPU constrained.  Only way that I would know how much of a gain is by building and testing, but you were focusing on unneeded faces, so I thought it would be helpful to provide a specific solution :)

Link to comment
Share on other sites

11 minutes ago, brianzinn said:

My game builds blocks side-by-side in 3d as well.  I do believe that using blocks and detecting occluded faces has a performance penalty.  I'm not an expert, but imagine freezingWorldMatrix() or instances probably more performance gain (https://doc.babylonjs.com/how_to/how_to_use_instances).  You are measuring FPS, but it can be CPU or GPU constrained.  Only way that I would know how much of a gain is by building and testing, but you were focusing on unneeded faces, so I thought it would be helpful to provide a specific solution :)

So you suggest, if using blocks, to use the freezeWorldMatrix() command and create every block as an instance ?

Link to comment
Share on other sites

31 minutes ago, foumfo said:

So you suggest, if using blocks, to use the freezeWorldMatrix() command and create every block as an instance ?

Those will help along with many other possible optimizations (https://doc.babylonjs.com/how_to/optimizing_your_scene).  JohnK's 250K box demo is pretty impressive and is running 60FPS on my laptop... :)

Link to comment
Share on other sites

14 minutes ago, JohnK said:

@foumfo at last a PG done with planes so no faces are drawn where they would be hidden, with textures too - https://www.babylonjs-playground.com/#9PP17F#9

As for performance improvements? You would need to check.

Just wow! Seriously you put a lot of effort and thinking there thank you for that. That is a bit complex and it requires a lot of reading and thinking from my part to completely understand it.

By I will definitely try to use it

Link to comment
Share on other sites

59 minutes ago, JohnK said:

@foumfo at last a PG done with planes so no faces are drawn where they would be hidden, with textures too - https://www.babylonjs-playground.com/#9PP17F#9

As for performance improvements? You would need to check.

    var mapArray = [];
    var leftArray = [];
    var rightArray = [];
    var frontArray = [];
    var backArray = [];

    var count = 0;
    for(var i = 0; i < mapData.length; i++) {
        if(mapData[i] == 1) {
            mapArray.push(count);
            if(i % width == 0) {
                leftArray.push(count);
            }
            else if(mapData[i-1] == 0) {
                leftArray.push(count);
            }
            if((i % width) + 1 == width) {
                rightArray.push(count);
            }
            if(i < width) {
                frontArray.push(count);
            }
            else if(mapData[i  - width] == 0) {
                frontArray.push(count);
            }
            if(Math.floor(i / width) + 1 == depth) {
                backArray.push(count);
            }
        }
        else {
            if(mapData[i - 1] == 1 && i % width > 0) {
                rightArray.push(count - 1);
            }
            if(mapData[i - width] == 1 && i >= width) {
                backArray.push(count - width);
            }
        }
        count++;
    }
This is the part that I don't get
Link to comment
Share on other sites

Short explanation. width 3 and depth 4  [0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1] Move along the array.

At my current position should there be a box?  Answer is yes.  Remember this position needs a top and base. Looking to my left is there a space ? If so remember this position to add a left wall to it. Look to the front, is there a space? If so remember this position to add a front wall to it. Am I at the end of a row? If so remember the position to add a right wall to it. Am I at the back? If so remember the position to add a back wall to it.

At my current position should there be a space? Answer is yes. Looking to my left is there a box? If so remember the left position to add a right wall to it. Look to the front, is there a box? If so remember the front position to add a back wall to it.

Also count is not needed the index i does just as well https://www.babylonjs-playground.com/#9PP17F#10

TL;DR

Long Explanation. I am using a single dimension array of 0s and 1s, for example on with width 3 and depth 4  [0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1] so from front to back the grid is numbered as

 Back

 9 10 11
 6  7  8
 3  4  5
 0  1  2

 Front

with the 0s and 1s positioned at

Back

0  1  1
1  0  1
1  1  0
0  1  0

Front

the 'boxes' will be in positions 1, 3, 4, 6,  8, 10 and 11 and if you set a `count` to 0 and add 1 to it each time you move along the array the count gives you the index to the array (so have now had to look at it more closely `count is not necessary the `for-next` variable `i` will do). As you move along the array each time you meet a 1 the count (or index) is pushed to the mapArray. So the mapArray gives you the indexes for the positions where there is a box. Each box needs a top and a bottom so the mapArray tells you where to place a top and bottom.

Now you need to place the left, right, front and back faces of the box in the correct positions.  The left and right is your left and right as you look from the front.

For the left faces. Any count (or index) in the leftmost column  with 1 in the array needs a left face, that is push the count into the leftArray. In the example anything in the left most column is a multiple of 3 and so i modulo 3 will be 0. In any other column a left face will only be necessary when there is a 0 at your current position i and in your previous position (i - 1) there was a 1 and so in this case push the position index to the left arrary.

For right faces. Any 1 in the rightmost column will mean a right face to be added and in the rightmost column index modulo width will be 1 less than the width. In any other column you will only need a right face in the previous box if there is a 0 at your current position i  and a 1 at your previous position (i - 1).

For front and back faces it is similar except you are considering rows and when you are at position i a previous box is at position, in this example,  i - 3 and generally i - width. You are at the front row if the position index is less than the width. For the back row note that in this example 9/3 = 3, 10/3 =3.3333, 11/3 = 3.66666 and the integer part is 3, in general Math.floor(i/width) = depth -1.

 

 

Link to comment
Share on other sites

@JohnK I won't lie to you, all this is so confusing to me, it will take time for me to understand all this.

Plus I'll have to change a few things before I implement your code into mine because I'll be using 2 big planes for the ground and roof of the entire level

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...