jdavid

How big of a terrain to balance performance + appearance on low-end machines?

Recommended Posts

Hello all,

I'm working on my first Babylon.JS project, which involves a ground terrain for a small island.  I'd like to find a good balance of performance and looking good, and currently I have neither. :-/

Currently, I've got a terrain heightmap I exported from WorldCreator (2048 x 2048 PNG) that I'm using with BABYLON.MeshBuilder.CreateGroundFromHeightMap.

Here are the parameters I'm creating the GroundFromHeightMap with:

{
	width: 2048,
	height: 2048,
	subdivisions: 1024,
	minHeight: -289,
	maxHeight: 364
}

Then I'm just applying a green StandardMaterial and adding a blue Ground plane to represent water.

The result of this, using a UniversalCamera with no gravity for the moment, is already down to 12-13 frames per second, and the terrain shape still looks pretty terrible.  It's especially blocky at the waterline.  (Pictures attached.)

There are so many different places I could have gone wrong here, that I thought it might be best to ask for some guidance.  What would I have to change to get a nice, smooth shoreline at 60fps on a 2016 Macbook Pro?

Changing the number of subdivisions obviously has a huge impact on performance, but lowering it (to raise FPS) makes things look even worse.  Changing the width and height don't seem to matter much.

Is it not realistic to have a terrain this size, and I should be looking into chunking it?  If so, what sort of sizes of heightmap chunks vs # of subdivisions have people had good results with in the past on middle-of-the-road hardware?  Or is the problem somewhere else entirely?  (I'm sort of afraid the answer may involve shaders, since I really do not understand what those are or how to do anything useful with them. :) )

Thanks for any advice!

 

Terrain2.jpg

Terrain.jpg

Share this post


Link to post
Share on other sites

Just for testing purposes, I tried this with a 512x512 heightmap and these settings:

{
	width: 512,
	height: 512,
	subdivisions: 512,
	minHeight: -56,
	maxHeight: 39
}

I also turned off the minimap and (grasping at straws) set the specularColor to black on the ground and water textures.  The scene is basically as minimal as I can possibly make it.

None of that seemed to affect the frame rate.  It still sits in the low teens, though it seems to run faster if I pull the camera back away, even though that results in many more polygons in frame.  Counterintuitively, the more of my little island is in view (due to increasing altitude) the faster the framerate gets, on up to 40-60fps.

The only change I made that did help the frame rate at ground level was deleting the water ground plane, which seems like it pushes the framerate into the high teens / low 20s.  But at that point it's hard to tell if I'm looking at the same part of the map, so I can't be sure that's apples-to-apples.  Weirdly (to me), increasing the subdivisions in the water plane also helped, allowing me to leave it in but keep the upper-teens framerate.

I've also noticed that if I stop moving the camera, after a few seconds the frame rate will shoot up to 60 and I can rotate the camera at that location without loss of performance.  But as soon as I move the camera, it dives back into the teens.

This same computer runs the playground demo for height maps at 60fps without breaking a sweat, so I am pretty sure the problem here is me.  If I set my parameters to exactly the same values that demo uses (200x200, 250 subdivisions, 0-10 height, updatable false) I still get high-teens framerates.

 

Share this post


Link to post
Share on other sites

Thanks for the response and suggestion, @JohnK!

It's a very small demo/personal learning project, basically a walking simulator with a very small island and two buildings where you can walk out of one building, across part of the island, and into the other building, and that's it.  Mostly I'm hoping to use it to learn how to make an environment look good: textures, grass, trees, good-looking water, etc.  Since it's so small, I could certainly fit it within any reasonable constraints, if I just understood what the constraints were. :)

So I'd like to keep it as simple as possible, and It'd be great to understand where I've gone wrong with the basic terrain mesh.  (Since many of the things that happen are quite surprising to me, like increasing the subdivisions of the water plane causing the frame rate to go up, that suggests I've still got a lot to learn about the basics!)  But since I've more or less hit a dead end on that for now, I'll work through some of the material on dynamic terrains and see if I'm clever enough to make a go of that. :)

 

 

Share this post


Link to post
Share on other sites

OK, so I fussed with the dynamic terrain extension at some length, and I was able to get it to work.  Unfortunately, unless I turn the "terrainSub" value down so low that you can see the terrain being popped in right in front of you, it performs about the same as or worse than the basic terrain mesh; FPS in the teens.  For a larger project, the dynamic terrain extension is really slick and definitely the way to go.

I created a smaller 512x512 heightmap with significantly less altitude variation, and set that to be 256x256 with 256 subdivisions.  That helped quite a bit with the "antialiased Minecraft" look visible in my earlier screenshots, although the much smaller, much flatter island is certainly missing some of the majestic drama of the original. :)

That doesn't perform great, only around 30-40fps, but it's at least usable for now.

It would still be great to hear from anyone who has worked with terrain meshes, especially around how big of a mesh they are rendering (whether dynamic or just a basic static mesh) and what kind of performance they are getting.  That would really help me calibrate my expectations to determine how much of my performance problem is poor coding and how much is unrealistic expectations. 🙂 

 

 

Share this post


Link to post
Share on other sites

Hey @jdavid

It's all in the math. Look at the least common hardware you want to support, and do an evaluation of vertices, materials, and textures. Always use a power 2 texture until we enter full support of WebGL 2.0. I always look at my code as a water pipe and a bathtub... how much water can I push through the pipe and how much water can the bathtub hold?

DB

Share this post


Link to post
Share on other sites

I think that Babylon has in the latest version some small performance problem due to small bug in the latest version of Chrome (if you use Chrome).

I made a field editor that runs at 60 FPS: https://bitbucket.org/JSbabylon/terraineditor Try to see what this gives.

You can also use an octree in the terrain, but currently Octree is lowering the performance because of the Bug in Chrome. which I hope will soon be fixed.

There is also terrain.optimize (64); who can help.

You can also reproduce your way of doing it in the Playground.

 

Share this post


Link to post
Share on other sites

Please do a PG so we can understand where's your issue

[EDIT] please have a look at this example : http://jerome.bousquie.fr/BJS/demos/flightSim.html

The terrain is only 200x200 or 300x300 subdivisions (just can't remember) sliding on a map of 2000x2000 points and it runs quite smoothly in my Chrome here.

Share this post


Link to post
Share on other sites

Thanks for the responses, all.

My understanding is that I cannot do a PG because I am using Typescript for my project, is that correct?  (I have a background in programming, but both Javascript and 3D are fairly new to me.)

@jerome I looked at your flight simulator twice, and it consistently runs at 56-60fps on this system (almost always at 60fps).  It is very smooth and I would love to get to that point.

There are only three meshes in this scene at present: the terrain mesh, the water plane mesh, and (sometimes) a skybox.  That's it.  So based on what I read about those suggestions, I don't think I'm at a point where the octree (not enough meshes) or auto-LOD (part of ground & water meshes is always nearby, and the geometry of the skybox is already pretty simple) will bail me out.  Does that sound right?  (FWIW removing the Skybox appears to have no effect on performance.)

Likewise, the only textures are on the Skybox.  The ground and sea materials are StandardMaterial with diffuseColor set to a Color3.

So I don't think I'm flooding the bathtub, yet. :)   (My test is being done on a 2016 Macbook Pro with a Radeon 460, but I don't really have the first idea how many polygons that can actually push or how to build a scene budget based on that knowledge.  Yet. 🙂 )

I cannot find any documentation of a terrain.optimize() call, but I'll certainly try to find some more information about that.  And I'll see if I can somehow get something going on PG.  It sounds like I could maybe post the heightmap on Github and then access it from a PG.

However, I think I might have a lead.  Last night, while messing around with walking around on the terrain with gravity on, I noticed that if the player fell onto the surface of the water (which had checkCollisions set true temporarily just to keep the player from falling out of the world) the FPS dropped to 2-3 and basically stuck there.  So I just had a few minutes this afternoon, and I tried turning gravity off and removing checkCollisions from both the terrain and the water plane.  And, voila, I can fly around at 50-60fps, no problem.

This would kind of explain why my frame rate went up when not moving; much of the collision code can probably be skipped at that point.

Does this sound like a reasonable explanation?  Maybe a terrain-sized mesh is just too large and complicated to collision-check efficiently?

Gravity + collisions already had the significant drawback of not being able to move uphill at all, not even 1cm, and I've seen various other methods discussed on these forums in all the searching I've done on this issue, so I'd been planning to look into those anyway. 

 

Share this post


Link to post
Share on other sites

Octree can help with the collisions in the field. and mesh.optimise () can be found in the API.

When I create large terrain with collision, I use Octree + optimize () and it always makes me return one of the PFS to 60.

Share this post


Link to post
Share on other sites

Wow, cool!

I just have to step back for a moment and say that Babylon.JS is not only an amazing piece of high-quality open source code, it also seems to be a really well-run project.  The playground feature was impressive before. With Typescript support?  Even better!

I'm also very grateful for how welcoming and helpful the posts here have been!

Thanks to everyone!

 

Share this post


Link to post
Share on other sites
10 minutes ago, Dad72 said:

Octree can help with the collisions in the field. and mesh.optimise () can be found in the API.

When I create large terrain with collision, I use Octree + optimize () and it always makes me return one of the PFS to 60.

Aha, I was looking for something specific to terrain.  Looking at the reference page for Mesh, I see an optimizeindices method, but that takes a callback, not a number.   Is it that, or something else, hiding in a base class maybe?

I think I'm going to try to load the bigger terrain again tonight, and I will try both octree and optimize in conjunction with that.

 

Share this post


Link to post
Share on other sites
Just now, Dad72 said:

Sorry, it was for GroundMesh and not Mesh. But you create ground with GroundMesh logically with Heighmap.

http://doc.babylonjs.com/api/classes/babylon.groundmesh#optimize

Aha, got it, thanks again!

The documentation is a bit sparse on what that actually does, but I can always read the source code and hope my brain doesn't explode. :)

Or it may become apparent what it does after I spend a bit more time learning about octree generally.

 

Share this post


Link to post
Share on other sites

So, I got a bit of time to work on this tonight.

Building on the checkCollisions discovery, I went back to the original 2048x2048 terrain heightmap.  Still 50-60fps.  I added a colormap diffuseTexture on it.  (No splat map yet.)  Still 50-60fps.  I added a textured placeholder building with collisions (that's all I have so far), still 50-60fps.

It may be an effect of having even a rudimentary texture on it, or else I somehow accidentally fixed the 8-bit heightmap issue, because the "anti-aliased Minecraft" look is gone as well.  

So I turned collisions and gravity back on and I definitely took a hit, but nothing like it was before.  That brings it down to the 30's, but still very usable.

Huge progress, you should see my grin!

But at this point, I'm a little confused.  This is a far more complicated scene than before, but it's running much better.  And by and large I've been commenting things out, so it's not like I've done a big rewrite that could have fixed anything.

The two unexplained things are:

- The frame rate got a lot better.

- The terrain mesh got a lot smoother.

Odd!  Related?

On the optimize() call, here is what I found in the Octree how-to:


"By calling groundMesh.optimize(chunkSize) where chunkSize defines the number of submeshes you want, the mesh will be optimized for rendering, picking and collisions by creating an internal octree (Be sure to select a correct chunkSize)."


It does not indicate what a correct chunkSize is or how to calculate one.  In addition to @Dad72's suggestion of 64, I tried 8, 16, and 256.  In all four cases, the terrain mesh disappeared.  But I'm optimistic that if I get it working like he says, I'll have collision and an even better frame rate at the same time.

Alas, that's where I ran out of time, so no luck on figuring out how to make a PG from this, nor how to run uphill. Yet. :)
 

@Deltakosh, if I figure out what "a correct chunksize" is and get optimize() working, I'll see what I can do in the way of a PR. 

Share this post


Link to post
Share on other sites

@Deltakosh, I noticed since the version 3.3, when one moves the camera (free or rotate ...) the FTP moves enormously between 50 and 60 FPS.

It is enough that I move a small millimeter so that the FPS goes from 60 to 51, 52 FPS. IF I do not move the camera, I stay at 60 FPS.

When I move the camera for a long time, the FPS can put down <= 40 (-20 FPS just by moving the camera)

I think there must be some worries somewhere. Before 3.3 did not change anything to the FPS when moving the camera.

Share this post


Link to post
Share on other sites

I may need more info than that to help. Can you do a profile check between 3.2 and 3.3? Can you repro in the PG?

We have added some counter measures to work around the Chrome bug but maybe some bugs can remain.

We are a week away from the release so we need to fix it now or never ;)

Share this post


Link to post
Share on other sites

I think my scene has increased between 3.2 and 3.3 which makes me think that. and I did not use labels yet

Ok, but the fall of FPS is pretty huge I think, no ?

What is the way to optimize this? Arf, that's not the subject of the post, I thought it was bind, but no.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.