Why android device is not good for webgl

Hi, I developed an application in three.js in normal HTML file. The application is running smoothly in IOS browser browser. But it is very stuckup and lagging in Android browser. What might be the reason for this. and how to overcome this?
Note :
1. I am using WebGL Renderer.
2. I am using some gltf files
3. I am using RGBELoader for loading .hdr image for setting as environmentMap

  1. Performance depends on quality of the hardware - so be sure to run the tests on comparable devices (ie. iPhone 12 & Galaxy S20 will give much closer results than iPhone 12 & Xiaomi Mi 5.)

  2. Be sure to set correct pixel ratio in the renderer. Some displays can render pixelRatio equal to 2, but for most it will be an unnecessary overhead (since you’d be rendering twice the resolution.)

  3. Try disabling the HDRI envmap and see if it is indeed it that may be causing the problem - maybe the resolution of the image is too big.


I was going to say the same thing! :smiley: However, a pixel ratio of 2 needs to render four times the number of pixels than a ratio of 1:

DPI 1: 1024 x 1024 = 1,048,576 pixels
DPI 2: 2048 x 2048 = 4,194,304 pixels


@mjurczyk @marquizzo . Thank you so much for your reply. I am giving my source code below. Please help me to debug.

New Text Document.txt (37.6 KB)

I don’t understand how we can debug, without knowing what devices you are testing on - did you try what I wrote earlier?

I tried with many android devices like Xiaomi Redmi 5, Lenovo 7inch Tab, Samsung s7 edge. All are facing the lagging issue. I tried with disabling the HDRI too. It is also not working. @mjurczyk .
https://www.toyotabharat.com/urbancruiser-360/ Please look into this link . This is perfectly working in all devices, which I have listed above. So What I am doing wrong in my project.

There’s a million reasons why it may not work well.

(1) You are starting the render loop, and at the same time execute 1200+ lines of loading assets and conditional material updates. Asset requests do affect the rendering for as long as they are active (so if you’re loading a big model, it can slow down the execution for a longer time.)

(1b) Especially considering your use case, it’s best if you pack all the models and textures into a single glTF / glb, allow it to load, adjust materials, and then start rendering. This will also allow you to optimize materials on the go (ex. using mesh names, you can decrease visual quality of items that won’t be much visible anyway, or just hide them altogether.)

(1c) It’s not possible to see how detailed your models and textures are, but be sure the model does not exceed 10k verts and (at least on mobile) textures are optimised - if that’s necessary, use 512-2K textures for albedo and normals, but any other texture can usually have a lower resolution. Use textures appropriate for the object size - metal bolts don’t need 4K albedo maps.

(2) If I remember right how texture sampling worked, setting anisotropy to 100.0 - first, is not power of 2, second, increases texture sampling 100 times. It may decrease performance. A lot.

(3) If your models are very complex, allowing every single submesh to cast and receive shadows may decrease performance.

(4) If your models are complex, setting MeshPhysicalMaterial / MeshStandardMaterial for virtually every submesh (moreover a transparent MeshPhysicalMaterial with transmission enabled) can decrease the performance significantly.

(4b) Instead, for smaller, shiny surfaces you can use MeshPhongMaterial, and MeshLambertMaterial for rough ones.

(4c) Reuse materials. It’s hard to believe none of these submeshes have a similar-looking surface.

(4d) If you absolutely must use this amount of complex materials - precompile them after loading all assets and before rendering the scene.

(5) You don’t have to call renderer.render on every requestAnimationFrame - especially on lower-end devices. Use frame throttling, or intervals to limit framerate to something lower (ex. 30fps) but stable - frame stutter is far more noticable than just a lower framerate.

(5b) There’s nothing stopping you from dynamically adjusting the framerate as well. If you detect that the device is struggling with 60FPS, lock it as 30.

(Bonus) Back in my days you go straight to jail for that:

window.color_change = function color_change(code) { ... };

See also:

1 Like

Thank you @mjurczyk. I am changing my script one by one, As you said, I changed my material from MeshPhysicalMaterial to MeshLambertMaterial and MeshPhongMaterial. If I set like that, I couldn’t able to apply the envMap. It throws following error.

 THREE.WebGLProgram: shader error:  0 35715 false gl.getProgramInfoLog No compiled fragment shader when at least one graphics shader is attached.

If I remove envMap, there is no error, but there is no lighting as earlier. So I need envMap. How to do this.

I cannot see line 276 on the screen you shared - maybe these materials do not support HDR envMaps for some reason (if you could show the line from the error I can check the shaders.)

But anyway, you’re free to skip that point and just continue to the other ones - all in all, (1) is the most important, others can just help.

1 Like

I checked your code, just to add to the tips above

  • comment this line // renderer.setPixelRatio(window.devicePixelRatio);
  • set antialias to false
  • I see you use a lot of standard and physical material, this type of materials are heavy on older devices, so I suggest you use lambert or basic material, and if you still want to maintain your shine and metallness you can use matcapmaterial
1 Like

@mjurczyk @waverider404 . Thanks for your answers. But Those materials doesn’t accept my envMap. So the reality effect is gone. Any alternate ways to overcome this?

@jaya_kannan that is kind of the point - rendering envMap on objects that do not need envMaps (ex. small bolts, car brand logo, tyres) may decrease performance. Especially in a very detailed model.

If you absolutely need envMaps on even the tiniest elements - use LOD, and render MeshStandardMaterial only when the camera is close to a specific object (on the other hand, don’t use LODs for every single mesh if you have an extremely detailed model - LOD geometry still does take up memory space.)

1 Like

Understood @mjurczyk. Thank you so much :heart_eyes: