Very low FPS when generated random ground

Hello,
I’m beginner in threejs and I try to generate a random ground, for that I use this code => https://codepen.io/Ygles/pen/mZVRmg

Sorry code is not proper but after many many try it becomes very dirty.

Each second I generate a new vertices line and create new faces(setInterval function is line 101) . The FPS is very low after 2 or 3 lines of vertices, I don’t have many vertices at the beginning and I don’t understand why the FPS is very low. I think I do something wrong in the render function.

In JS part line 185 you can find the render function.

Can you help me please ?

Thanks

Ygles

You shouldn’t generate an entirely new BufferGeometry, re-calculate all the vertex positions, then send the new data to the GPU every second. This is a very time-consuming process, and as you can see, the more vertices you have to calculate, the slower your performance.

What you should do is generate all your geometry once on init(), and then change the amount of vertices that are drawn. For example, let’s say you want to grow the number from 100 to 1,000 vertices, so you declare all 1,000 vertices once, then set how many of them are drawn with Buffergeometry.setDrawRange().

// Second 0
geom.setDrawRange(0, 100);
// Second 1
geom.setDrawRange(0, 200);
// Second 2
geom.setDrawRange(0, 300);
// Second 3
geom.setDrawRange(0, 400);

You can see this method in action in this example by dragging the “Particle Count” slider.

Thanks for your answer but in the real use case I cannot generate all the geometry in the init function because I receive the ground line x,y,z values from sensors.
It is possible to add vertices and faces without redraw all the mesh ?

Then you may want to create the full position array once with the expected total number of vertices, and only update the values of its content when necessary. Once updated, simply set its value to BufferAttribute.needsUpdate = true so the engine knows to read the new data.

This example updates the .size attribute array of 100,000 in the render() function, and it’s pretty efficient because it doesn’t re-generate a new BufferGeometry on each frame. Instead, it re-uses the same array with updated values.

2 Likes

Ok thanks, i’ll try it tomorrow

@Ygles Do you have an update on this? I too would like to see a 60 FPS, splat mapped chunked Terrain! <3 GREAT idea & GREAT project! Keep up the excellent work!

@Aerion Not yet, not enought time today, perhaps I will try this evening (french time) but not sure priority to the children

I will send a feedback here after my test

Thank you @Ygles! I much appreciate it! I look forward to your future post! :slight_smile:

I do something similar in my game, in the sense that I generate the terrain in real time. The data for that generation is pre-defined, so that’s a big difference. But the principle is the same, since terrain engine doesn’t know that the data is pre-defined, it just builds terrain based on the data it is given.

I use 2D height maps as an input, and my terrain engine slices the world into tiles, each tile is a separate mesh and is built in a worker thread.

On an OK desktop PC it takes about 1ms to build a tile 28x28 vertices (1,568 polygons). The advantage of this approach for me - is that I only built tiles that the user is going to see, and I skip the rest. This way my “map” loads very quickly, in a matter of a couple a few miliseconds, usually less than 1 frame.

The tile size I mentioned is arbitrary, I chose that size because it produced best performance for lower-end devices for my game, but there is no hard rule there.

Here are a couple of screenshots to demonstrate

5 Likes

It’s works :champagne: I turn around 40 FPS during all the ground generation and it stay stable.

https://codepen.io/Ygles/pen/BgKpRe

It’s not the best mesh ratio but you can compare with the previous codepen (https://codepen.io/Ygles/pen/mZVRmg), it’s exactly the same ground generation, I just prepare a wonderfull array of 448220 items :stuck_out_tongue:

I think with many meshes of 28x28 like @Usnul says it’s could be better and lighter.

Thanks all for your help

4 Likes

@Ygles Were you able to complete the splat mapped infinite terrain demo?

I’ll try an infinite map on only 1 direction during this week

@Ygles Wonderful! I look forward to testing this! If it works, can we make it multi-directional? I will check back in a week! Thank you! :slight_smile:

If you have worked all the technical issues of your code, you can then do something like this to control the frame-rate of your program:

To make this work make sure you are referencing Procesing5 libraries (p5js):

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.js"></script>

Then add the setup function:

//Runs once when .js executes
function setup() {
    frameRate(60); //Select a positive number
}
//Runs every frame (in this case - 60 fps)
//An idea on how to work with loop function
function draw() {
      if(treeFinished){
            nextTreePlantation();
      }else{
            growTreeUntilFinish();
      }

}

Thanks for your tips but I prefer limited the number of used libraries, if I was enought skill I did the 3D part in native WebGl but it’s not my case :sweat_smile:

Processing 5 is 2.95MB in file size. There’s no reason to bloat an app with an entire extraneous library for something that the browser can natively do with about 4 lines of code by using requestAnimationFrame().

2 Likes

Another question : what is the best ratio between number of mesh and mesh size please ? For example if a have a scene of 5000x5000 dot it is better to have meshes of 10x10 dot or have meshes of 500x500 dot ?
Is there something like a “formula” to find the best ratio please ? And what about memory use please if I have 500 meshes of 10 dot is the same has 50 meshes of 100 dot ? For my final use case I’ll need to display a very big ground size but not necessary on a gamer PC so I need to optimize the base scene before simplify it to have the best performances
Thanks

Ygles

There is no such formula. It depends on many factors. If you are going to be displaying the entire thing - I suggest not breaking it up at all. If you will be viewing only a portion of the mesh at the time - then make sure that there aren’t too many pieces in the view, so say you will be viewing 1000 pieces at a time - that’s probably too many, cut it down to <100, that’s my advice. Another thing is vertex count, if it is for PC - i recommend having at least 1k vertices per mesh, less is a waste of a draw call, preferably more, around 10k might be a good low number.

Some systems are faster at submitting draw calls, so there’s less overhead per drawcall, some GPUs systems have more RAM and shader cores and care less about how large a mesh is - it’s all relative. Profile and tweak your parameters until the results are “good enough”, there’s no fixed general answer here.

4 Likes

Thanks for your answer I’ll doing performance test on final hardware when I finish the multi-directional development (@Aerion it’s in progress but take more time than expected)

That is quite alright, @Ygles! I look forward to beta testing it!

Thank you!