Three.js Render Performance Question

I have been trying to hunt down a performance issue for some time now and I “think” I may have discovered the issue (sort of).

I have an mmo written in three.js (titansoftime.com) and just created a new ambitious forest zone. There are many trees of 2 different varieties scattered throughout the zone. Mostly the scattering is uniform, except in 2 spots on opposite ends of the map, where they are more clustered together in groups of about 30. Each type of tree shares the same geometry and material.

On one end I have roughly 30 trees which are skinny with small leaves at about 2100 polygons, and on the other send of the zone I have the same amount which are much thicker looking with larger leaves at about 1800 polygons.

I would expect the scene to run maybe a little faster with the lower poly thick trees. Nope, not completely wrong. The scene view with the skinny trees in frustum renders at about 52fps on my Android Galaxy S7 and of course at 60fps on my desktop (AMD A10 cpu (old, i know), a Geforce 1060, and 16GB RAM).

On my desktop I have all settings maxed out (nice reflective water, anisotropic filtering, particles, antialiasing etc.). On mobile I have all that turned way down or off.

The scene with the lower poly trees which are modeled to have thicker trunks and larger leaves render’s at 15fps on my Android, and a dismal 30fps on my desktop. What the heck?

Now, I have those tree meshes scaled at 20x, when I make them tiny at 5x, everything runs MUCH faster. It’s also surprising to me that even with all the smaller leaf trees within camera frustum, it still runs faster than when looking at the larger leaf trees with about roughly a third of the trees in frustum.

So it appears to me, the more screen pixels a single mesh takes up, the much more significant the performance hit, regardless of polygon count. If it’s not due to screen projection, I am at a total loss.

Is this correct, is this to be expected?

The only difference I see using Chromes Performance monitor is a significant increase in cpu usage and an increase in the time it takes to run the (recalling from memory) the project objects and render objects functions when looking at the thicker looking trees. I’m not great at interpreting this data, especially using larger libraries so I’m not super sure about this.

I find my only solution is to either make the trees smaller or take some out, which I really don’t want to do ( I mean there are only about 30 on each side).

Will Instanced Geometry help? I kind of doubt it myself as it doesn’t seem like a draw call issue.

I don’t have a fiddle ready yet (my app is pretty involved and difficult to pull components out of). But I will work on setting one up. In the meantime, any insight?

Edit* Here is the fiddle: http://jsfiddle.net/titansoftime/hxn62d6p/

I can reproduce the behavior on my Galaxy S7 in the fiddle, when looking at the big leaf trees a scene takes about 30ms to render (especially when looking up at the leaves), when looking the opposite direction at the lighter looking trees it runs in about 15ms. On my desktop, I see no difference in this particular example, as it’s pretty lightweight. However as noted, when in the actual game on my desktop with high settings, it is noticeable.

Changing the scale has a huge effect. The smaller, the faster.

Edit* It is SUPER noticeable on my old crappy work desktop. When looking at the “big” trees: 180-220ms, smaller trees: 50-60ms.

Big Trees
bigtrees

Small Trees
smalltrees

Again, I’m not sure if this is a bug. Maybe this is expected behavior. I certainly hope it’s a bug because the effect is significant and a major bummer.

Thanks in advance for any assistance.

I would say that’s not surprising. Your demo is a good example for a pixel/fragment limited WebGL application. The bottleneck is not the CPU and the vertex shader but the fragment shader. If you draw more surfaces, you have effectively more fragments to process. You can easily simulate a performance gain when you just set side to THREE.FrontSide (the default) of the respective material.

From my point of view, the amount of polygons in your scene as well as the amount of draw calls is not the problem. As you’ve already mentioned, instanced rendering won’t solve your issue. Instead, you have to decrease the amount of surfaces you are going to draw ( => simplify your trees).

BTW: I’ve seen that you’ve set transparent to true. You can achieve a similar effect if you just set alphaTest to e.g. 0.5 in order to create an alpha cutout. From my experience, this is more efficient since you don’t perform blend operations which can be very expensive.

2 Likes

Arg, this is what I feared =[

Well, back to the tree drawing board I guess.

The look I was going for was a nice canopied forest a user can walk through that simulated walking through the woods.

Removing the surface area of the leaves would of course decrease this effect. And of course frontsided textures won’t really work for the trees, which a user can see from many angles. I know you mentioned it just as a example of the issue, but it’s a bummer I can’t actually do that.

So I guess I just have to get some new models and do some peel and stick testing. Which sucks because I’m not a modeler lol. Oh well. Man, I was really hoping this was something that could be tweaked in the library. Oh well =[

Oh, and thank you for the alphaTest tip. I’m sure there are many small tweaks I can make like that throughout my, game. Wish I knew em all hehe =]

I appreciate your time and all the hard work you are putting into the library.

Thanks. The trees look actually great :wink:! Especially the “small” ones :+1:

Ha, thanks, I actually used a procedural tree generator called Tree[d] to make them. I don’t think they make that program anymore though unfortunately.

Oh and at least on my work pc (cheap intel integrated junk), alphaTest: 0.5, though it looks way better, actually runs about 2x as slow.

Um, that surprises me…

Alpha Test:
alphatest

Transparent:
transparent

cpu
gfx
ff

Same in Chrome 63.

Hey umm, one more thing.

How do you think I should go about explaining this to a modeler?

How do I request a tree with a nice canopy effect without having a large draw area?

Is there certain lingo I should use?

Maybe i would show the modeler some references…

BTW: This issue might be interesting for your use case. It links to an article that explains really well the difference between alpha blend and alpha test and why the latter one is often used for vegetation.

1 Like

Right on.

Thanks for the info.