I have two versions of the open world map that I’m working on
with trees and rocks:
without trees and rocks:
As you’ll see, there’s a serious frame rate drop when many environmental objects (meshes), rocks and trees in this case, are added to the scene.
This poses a bit of a problem when trying to build an open world adventure game where part of the goal is to create a large and expansive interactable world/environment. I want to be able to add seemingly many rocks and many trees into the scene for the player to interact with, but in a way that does not decrease framerate substantially.
I’m looking for feedback regarding techniques and strategies towards achieving this.
My first naïve approach would be to somehow keep track of which objects/meshes should even be considered, say those within a 2000 radius limit of the player (camera.maxZ property), and only have those meshes added to the scene instead of having all 20k trees and all 20k rocks be added to the scene from the start. As the player moves I would dispose trees and rocks that become too far from the player, and also add in the new ones that come within range.
In the question I also mentioned grass, but I actually haven’t gotten this far yet. I was thinking a cheap way to show grass would be to use some sort of shader effect like this one:
but there I wouldn’t know how to apply this on a per “patch” basis as the player navigates the world.
Here is a video from my game and this cinematic scene has generated landscape and 5-10k decor objects (grass, trees, etc).
What I have done is:
- Using instances
- Optimize scene by freezing meshes, materials and etc.
- I use offscreen canvas.
- I do compute work with web workers (vertices, indices, animations and more)
- I do compute work for landscape
- I send only chunks of data depending on player location.
- I dispose/reuse objects not visible for the player.
- I have a FPS controller maxing at 60fps
I target players with 3d card equal at GTX 1030, and I found all of these points above to be useful for me, especially using web workers for compute work and offload the engine to a separate thread.
@webgrid Thank you! This is exactly the type of advice I was hoping to receive.
Do you have code snippets that I might be able to take a look at? Each of the bulleted points you mention make sense, but I want to be sure I have the right idea about each one before beginning to implement it
@mawa I’ve been working on this on and off for 6 months (starting from knowing nothing about babylon js or colyseus.js) and I find this to be quite enjoyable.
When you say it seems like the physics and meshes take the most, what do you mean by that?
I’m using ammo.js for the physics and I don’t think the physics engine is contributing at all to the frame rate drop.
I like this idea of content “zones” which sounds like a version of the naïve approach I mentioned.
And what are you suggesting an octree for?
BabylonJS has excellent documentation on how to optimize a scene here:
Good luck with your project and keep working! I started 2 years ago, and submitted my game to Steam couple of days ago
@webgrid that’s so awesome!
Congrats man! That’s the dream!
It’s a good start. But a project like this will likely require a couple of years until distributable.
It’s good you find it enjoyable (and it is
I was just looking at the performance in ms (on an old rig actually). Meshes and most importantly physics are those taking the most time (and resources) on render
I believe you are wrong here. Physics is a part that takes the most of resources and ammo.js (unconfigured) is probably the one with the greatest impact on performance.
It wasn’t naïve at all. Downloading chunks of data as @webgrid suggested and using web workers to compute outside the engine and render loop certainly makes a huge difference.
It will help with the handling of a large number of meshes and for the above. Some doc can be found here but you will first have to determine if this can apply to your project and provide enough benefits.
So regarding content zones, would you suggest actually dividing a given map up into areas, or does caring only about the objects within a certain sphere of the player work just as well?
@mawa also, reading about this octree class that babylon provides, how would you go about measuring performance gains while using it? I’m thinking just measuring fps might be a start
I have this natural instinct to wanna build just for the sake of building, but I’m trying to keep it objective and want a way to prove to myself that what I’m doing is improving things
I have divided into zones and use object hashing to track objects sent to the client and I use a sphere of the player as you mention.
Any chance we get to see the result? I’m pretty sure it should already make a huge difference in performance. I would luv to be able to compare. Thx and have (both) a great day
I was also wondering about this aspect…
Could you use something similar to Valheim, where one players “world state” is the basis for the world, and I’m imagining like a sperate colysesus lobby room maintains that state and synchronizes with the rest of the clients. For example, say I destroy a tree, everyone should see that.
I do not understand, result as in code ? The performance is good as I do a lookup check to compare the hash on player and the object.
OOps, Apologies. There must have been a misunderstanding of mine with your latest post here. I thought you had done this change for @arcman7 project. I know it is implemented in your project and I also know the result is great . I wanted to see what it would do here.
Lol. I wish I had a someone else to work with.
I also create an openWorld. The first thing is I don’t use physics. I use instead: moveWithCollisions
Then an octree improves collisions.
The use of LOD, occlusion requests also improves things.
If the world is much too big and highpoly modeling will have a heavy impact (medium poly remains acceptable.)
The goal is to find compromises between quality and performance. Too much quality will kill performance.
Afterwards I also remain convinced that physics is very expensive for large scenes, and even counterproductive. Higtpoly modeling is to be avoided or use LOD to greatly improve things. And a land with less ambition will also help.
Also think about scale. a land may be small, but if the characters are small, then the land becomes large.
I also disable that in the motor.
this.engine.enableOfflineSupport = false;
this.engine.disableManifestCheck = true;
this.engine.disablePerformanceMonitorInBackground = true;
this.engine.renderEvenInBackground = false;
Real quick, what is the “easier path”?
You have a great weekend too!
@Dad72 I hear you. I really do.
It took me many months to get the physics engine working at a very large scale. But I believe I have that part figured out now. I’m also going to be making a modification or two soon with the ammo.js idl. I’m not convinced largeness really has that much of an impact, but rather how many render targets there are in the current screen, and to that end how large the camera.maxZ value is. I’ve tried scaling my map and characters to be really small vs what they are now and it didn’t seem to affect anything.
As for those engine properties that you toggled off, how much performance impact would you say that had?