How can I optimise my THREE.JS rendering?

I commented out the coords code with the Math.abs calls, put the far plane back to 1000 and it tanked still down to 1fps to 8fps then back to 35 then 60, change Far plane back to 100 and it is the same as it was before commenting the coords out.
I can move forwards and backwards and sideways without issue, it is the rotation that causes the tank, without rotation it goes to 53fps briefly then back to 60, so I don’t believe it is anything in the renderanimationframe loop as i’ve left just the renderer.render in and it still tanks with the Far plane set to 1000.
Thanks for the suggestion though.

this make good changes on my game fps

renderer = new THREE.WebGLRenderer(
                    {
                        antialias: false,
                        alpha: true,
                        precision: "lowp", //highp", "mediump" or "lowp"
                        powerPreference: "low-power", //"high-performance", "low-power" or "default"
                    });

Render on specific fps changes drasticaly too:

 var deltafps= 0;
 var timestep: 1 / 30; //change 1 to to 30 - find ur best performance
    renderSceneFps: function () {//fast render
        var delta=clock.getDelta();
        this.deltafps += delta;
        while (this.deltafps >= this.timestep) {
         //your render secene here
         this.deltafps -= this.timestep;
         }
     }

Use 2 or more renders same this, with diferent fps,
graphics render on fast fps, physics calculations, audio reposition, lights on more slow fps

see example:

https://gameengine-100722.mariox.repl.co/index.html

this is neat, did you write your own engine?! instructions on how to destroy the hostiles would be cool. you should look at the three-mesh-bvh library addon, i recon it could be of use for an environment like this.

Walkaround-2.zip (146.5 KB)
I have uploaded the code I am using but in the separate demo, this has a small hard coded “map” and runs fine with Far plane of 1000, and has no stats or renderstats.

So apart from the stats, and the movement of the key checks into a function the render loop is the same, and the code is the same apart from the map loader which populates the rooms, walls and player data which is hard coded in this.

I can possibly hard code a more complex map if needed but hopefully someone can give some pointers based on this code.
Thanks

If it got locked completely try setting the camera further. Also try resizing your browser, and make it really small. Dis you take a look at the code pens I posted? They should answer a lot of the questions here.

I tried moving the camera but it still locked, took a while before it got to the render stage too, set as low as 320 x 200.

I looked at the fiddles yes, one just goes a bit slow and the other runs normally (i7 9th gen RTX2060 6G DDR4, 64GB RAM), no FPS so not sure what it is running at.

three-mesh-bvh is very useful if my iterations were based on bvh, but bvh is inside primitive components ( cube sphere cinlinder ) so I don’t need to interact directly with bvh

I’m not sure where you get that assumption, bounding volume hierarchy is the fastest what to calculate the bounding volume of the most complex shapes,
https://gkjohnson.github.io/three-mesh-bvh/example/bundle/skinnedMesh.html

You can see this thread also… Its a library that automatically creates the bounding volume hierarchy for your meshes :slight_smile:

I understand when people use BVH and raytracing this library is amazing, I don’t need to calculate the raytracing of the BVH because I only calculate the raytracing of the primitive objects that contain the bvh inside
Sem título

Oh, of course that makes sense I was inverted aha!

Sorry for the delay, been busy with other stuff. I tested your .zip and for me it doesn’t produce any negative effects on rotations. It stays at around 5.5% to 6% CPU and 38% GPU - by the way, @dubois’s fiddles above also don’t crash my browser or render slowly, the most I get is 16% to 17% CPU immediately after refreshing (probably when creating things) and it’s roughly the same for both fiddles.

In other words, whether I use W, A, S, D to move, or ← and → to rotate, it’s the same, no bad performance at all. I even set the camera’s near and far to 0.000001 and 999999 with no visible effect. Ok, my current laptop (AMD Ryzen 5 5600H at 4.25GHz, 8 GB DDR4 RAM, NVIDIA GeForce GTX 1650 with 4 GB GDDR6, SSD) is good enough compared to my old one (Intel Core i3-2350M at 2.30GHz, 4 GB DDR3 RAM, AMD HD 7610M with 1GB DDR3, HDD), but I doubt that it’s so good to not even notice any performance drops… :thinking:

From my understanding the demo in the zip file is just a small version with only a few geometries, it’s not the actual realtime environment @mrticklespot is using.

Ah, yes, indeed - my bad. I was aware that it wasn’t the actual environment, but missed the fact that it was a small scale version.

The code, as far as I could see, seems ok. The only thing I could think of by looking at it is that for a much larger map, maybe the processes don’t finish up their work by the time the animation begins, but then, both the nature of JS and the log I set in place seem to indicate everything is fine in that regard:

22:50:07.580 main.js:173 creating dummy map 2
22:50:07.580 main.js:285 creating dummy map 2 - end
22:50:07.580 main.js:40 (3) [{…}, {…}, {…}]
22:50:07.581 main.js:41 (12) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
22:50:07.581 main.js:42 {x: 128, y: 128, z: 0, angle: 0}
22:50:07.600 main.js:48 appending renderer
22:50:07.600 main.js:50 appending renderer - end
22:50:07.601 main.js:289 drawing map
22:50:07.601 main.js:325 drawing floor ceiling
22:50:07.602 main.js:339 drawing floor ceiling - end
22:50:07.602 main.js:325 drawing floor ceiling
22:50:07.602 main.js:339 drawing floor ceiling - end
22:50:07.602 main.js:343 drawing wall
22:50:07.602 main.js:392 get room wall height
22:50:07.602 main.js:395 get room wall height - end
22:50:07.602 main.js:400 calculating wall length
22:50:07.602 main.js:409 calculating wall length - end
22:50:07.602 three.min.js:6 THREE.Color: Unknown color #55cfc
setColorName @ three.min.js:6
setStyle @ three.min.js:6
set @ three.min.js:6
setValues @ three.min.js:6
vi @ three.min.js:6
drawWall @ main.js:381
(anonymous) @ main.js:317
drawMap @ main.js:296
init @ main.js:51
load (async)
(anonymous) @ main.js:452
22:50:07.603 main.js:388 drawing wall - end
22:50:07.603 main.js:343 drawing wall
22:50:07.603 main.js:392 get room wall height
22:50:07.603 main.js:395 get room wall height - end
22:50:07.603 main.js:400 calculating wall length
22:50:07.603 main.js:409 calculating wall length - end
22:50:07.603 main.js:388 drawing wall - end
22:50:07.603 main.js:343 drawing wall
22:50:07.603 main.js:392 get room wall height
22:50:07.603 main.js:395 get room wall height - end
22:50:07.603 main.js:400 calculating wall length
22:50:07.603 main.js:409 calculating wall length - end
22:50:07.603 main.js:388 drawing wall - end
22:50:07.604 main.js:343 drawing wall
22:50:07.604 main.js:392 get room wall height
22:50:07.604 main.js:395 get room wall height - end
22:50:07.604 main.js:400 calculating wall length
22:50:07.604 main.js:409 calculating wall length - end
22:50:07.604 main.js:388 drawing wall - end
22:50:07.604 main.js:325 drawing floor ceiling
22:50:07.604 main.js:339 drawing floor ceiling - end
22:50:07.604 main.js:325 drawing floor ceiling
22:50:07.604 main.js:339 drawing floor ceiling - end
22:50:07.604 main.js:343 drawing wall
22:50:07.604 main.js:392 get room wall height
22:50:07.604 main.js:395 get room wall height - end
22:50:07.604 main.js:400 calculating wall length
22:50:07.605 main.js:409 calculating wall length - end
22:50:07.605 main.js:388 drawing wall - end
22:50:07.605 main.js:343 drawing wall
22:50:07.605 main.js:392 get room wall height
22:50:07.605 main.js:395 get room wall height - end
22:50:07.605 main.js:400 calculating wall length
22:50:07.605 main.js:409 calculating wall length - end
22:50:07.605 main.js:388 drawing wall - end
22:50:07.605 main.js:343 drawing wall
22:50:07.605 main.js:392 get room wall height
22:50:07.605 main.js:395 get room wall height - end
22:50:07.605 main.js:400 calculating wall length
22:50:07.605 main.js:409 calculating wall length - end
22:50:07.606 main.js:388 drawing wall - end
22:50:07.606 main.js:343 drawing wall
22:50:07.606 main.js:392 get room wall height
22:50:07.606 main.js:395 get room wall height - end
22:50:07.606 main.js:400 calculating wall length
22:50:07.606 main.js:409 calculating wall length - end
22:50:07.606 main.js:388 drawing wall - end
22:50:07.606 main.js:325 drawing floor ceiling
22:50:07.606 main.js:339 drawing floor ceiling - end
22:50:07.606 main.js:325 drawing floor ceiling
22:50:07.606 main.js:339 drawing floor ceiling - end
22:50:07.606 main.js:343 drawing wall
22:50:07.606 main.js:392 get room wall height
22:50:07.606 main.js:395 get room wall height - end
22:50:07.606 main.js:400 calculating wall length
22:50:07.606 main.js:409 calculating wall length - end
22:50:07.606 main.js:388 drawing wall - end
22:50:07.607 main.js:343 drawing wall
22:50:07.607 main.js:392 get room wall height
22:50:07.607 main.js:395 get room wall height - end
22:50:07.607 main.js:400 calculating wall length
22:50:07.607 main.js:409 calculating wall length - end
22:50:07.607 main.js:388 drawing wall - end
22:50:07.607 main.js:343 drawing wall
22:50:07.607 main.js:392 get room wall height
22:50:07.607 main.js:395 get room wall height - end
22:50:07.607 main.js:400 calculating wall length
22:50:07.607 main.js:409 calculating wall length - end
22:50:07.607 main.js:388 drawing wall - end
22:50:07.607 main.js:343 drawing wall
22:50:07.607 main.js:392 get room wall height
22:50:07.607 main.js:395 get room wall height - end
22:50:07.607 main.js:400 calculating wall length
22:50:07.607 main.js:409 calculating wall length - end
22:50:07.607 main.js:388 drawing wall - end
22:50:07.607 main.js:321 drawing map - end
22:50:07.607 main.js:52 animating

I was thinking, maybe there’s a way to simulate a much larger map by setting the structure via a large grid where walls are drawn only between randomly chosen points:

gameplay_maze2

That might help in reproducing the issue @mrticklespot is facing. If that even happens in such a setup, which is probably cleaner and simpler than the original, that is.

Hi,
Yes, that is a small hard coded map for the benefit of seeing the “code in action”, by the time the render has been called everything has loaded into the rooms / walls arrays.
The smaller one works fine as it isn’t really drawing that much, but the larger maps is where the slowdown initiates, is there anything I can add to my code to make sure that it isn’t drawing things the camera cannot see?

The fiddles didn’t lock up, there were hardly any noticeable differences, but the suggested merged geometries code addition did, my system is as stated above (i7 9th gen RTX2060 6G DDR4, 64GB RAM).

For the map loading version it loads the map then sets up the drawing of floors / ceilings and then walls in a promise so it has to return before it starts rendering to make sure everything is done in the right order, i’ve even set a timeout for 5 seconds after the loading to ensure that it is, and it does the exact same thing as it was one of the things i’d considered, but thought as it was in a promise it couldn’t happen, but I did run a quick test and it does do as it is supposed to.

Take a look here and here to read about some very similar situations, and possibly grab some useful ideas. Interestingly, (some) rotations affecting things are present there as well, the only difference is that the talk is about instanced geometries, but you can disregard that and just wrap you mind around the essential.

Basically, Three.js indeed has Object3D.frustumCulled to avoid drawing what’s not in camera view … but that only works effectively if the object is small enough to not cause problems on its own … and it’s not part of a merged geometry. In other words, like alluded above by me and others like @mjurczyk at his 2. point, merging geometries is fine if it’s done on a “volume” that more or less fits the camera view.

This idea is found in the links above as well, where it’s suggested to use “chunks” of merged geometries instead, with each chunk large enough to make a positive difference in the number of draw calls, but small enough to not negatively affect performance on its own. So, splitting your map into merged geometries of reasonable size (ideally, only what would fit in a standard camera view) could help. Frustum culling should work for the other merged geometries in the set which would not get rendered, while the merged geometry “in view” (or the one the player is positioned within) would not cause performance issues on its own.

It appears that you can test if objects are in the viewing frustum by using the object’s bounding sphere, but then, why do that if Three.js is doing it anyway in its frustum culling process. Another thing that should be kept in mind is that “standard” frustum culling doesn’t account for depth, that is and probably could be handled in other ways. So, don’t expect walls behind the wall that is seen by the camera to positively affect performance, because as far as I know, they are a different problem, with a different solution (and probably not entirely perfect either).

Thanks for the links i’ll take a look and see what it says.

Yes I read that THREE already does frustum culling, which is why it made no difference when I explicitly set it on.

I was hoping not to merge geometries if I can help it as it makes changing material a challenge - or so i’ve read, yeah it looks like there are tricks around that but then I will get myself into a right muddle I was sure that it shouldn’t render what it cannot see, but maybe I was wrong maybe OpenGL ES isn’t powerful enough or maybe the THREE library isn’t good enough to do what I was expecting. I’ve tried all suggestions so not really sure what to conclude.

Cheers

There are examples of occlusion culling you could reference such as this example
Without getting into this quite complex method, you could also manually add “room” sections to your scene based on a distance from the camera origin, in itself would be simpler but still you would need to work out some sort of indexing / chunk system to find out which section would be added next based on proximity, as your geometries are essentially very lightweight they shouldnt have a disastrous impact on performance while moving around, as long as you are removing the previously indexed sections from the scene also, for longer corridors where they would fall out of proximity you could use scene.fog to create a falloff where empty sections have not yet been added.

I did take a look at your zip file, everything seems like it’s pretty well programmed, I ran the function where you’re creating the geometries through a for loop of 2000 iterations to try to emulate the problem and it simply seems you are hitting a hardware limit, without a clever use of instancing for sections that will be the same I think you will always have this problem.

Hopefully these suggestions can offer some resolve, it must be frustrating to not see the performance you hoped for in a larger scale environment but this is no fault of THREE.js in itself, the creators and maintainers of the project are quite literally masters of this realm and doing all they can to provide the most up to date rapid access to webgl.

Hi, thanks for the link i’ll have a look,
I see a lot of posts and the conclusion is “THREE cannot do that”, but reading between the lines, WebGL cannot do that, not THREE as it is just a wrapper. I thought about the chunk theory which is used in most Minecraft clones, but that has a lot of the “same” blocks / chunks, i.e. with the same texture. It does seem that the only way to do it is to manually intervene and draw only those that are needed to be. No magic “don’t draw what you can’t see” function for me, looks like frustum culling isn’t what I need as it draws geometries inside the frustum even if it behind other geometries, which is probably what the issue is and why it is still drawing.

Try increasing the window size on the fiddles. One should tank, the other should work normal. I think that this is exactly what is happening in your app. If your app is this screenshot that was posted, there should be absolutely no reason why this shouldn’t be able to do like a 1000 fps or something.