Poor performance and different rendering on mobile

Hello three.js community.
I recently started my dive into three.js with a simple GLTFLoader viewer. Similar to the Google model-viewer.

My problem right now is that I have extremely poor performance on low end hardware compared to the actual google model-viewer and I simply don’t know why. I already tried different things like disabling AA on mobile, no hope either.

My current three.js code:

<script type="module">
	
		import * as THREE from './build/three.module.js';
		import { OrbitControls } from './jsm/controls/OrbitControls.js';
		import { WEBGL } from './jsm/WebGL.js';
		import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
		import { RGBELoader } from './jsm/loaders/RGBELoader.js';

		if ( WEBGL.isWebGL2Available() === false ) 
		{

			document.body.appendChild( WEBGL.getWebGL2ErrorMessage() );

		}
		
		var container, controls;
		var camera, scene, renderer;
		var antialias;
		var isMobile;

		if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) 
		{
			isMobile = true;
		}
		else
		{
			isMobile = false;
		}

		if(isMobile)
		{
			antialias = false;
		}
		else
		{
			antialias = true;
		}

		init();
		render();

		function init() {

			container = document.createElement( 'div' );
			document.body.appendChild( container );

			camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );
			camera.position.set( -4.8, 1.6, 5.7 );

			scene = new THREE.Scene();

			new RGBELoader()
				.setDataType( THREE.UnsignedByteType )
				.setPath( 'textures/equirectangular/' )
				.load( 'venice_sunset_1k.hdr', function ( texture ) {

					var envMap = pmremGenerator.fromEquirectangular( texture ).texture;

					// scene.background = envMap;
					scene.environment = envMap;

					texture.dispose();
					pmremGenerator.dispose();

					render();

					var loader = new GLTFLoader().setPath( 'models/' );
					loader.load( 'Sunglasses_raw.glb', function ( gltf ) {

						gltf.scene.traverse( function ( child ) {

							if ( child.isMesh ) {

								child.material.map.anisotropy = 0;
							}

						} );

						scene.add( gltf.scene );

						render();

					} );

				} );

			var canvas = document.createElement( 'canvas' );
			var context = canvas.getContext( 'webgl2', { alpha: false } );

			renderer = new THREE.WebGLRenderer( { canvas: canvas, context: context, antialias: antialias } );
			renderer.setPixelRatio( window.devicePixelRatio );
			renderer.setSize( window.innerWidth, window.innerHeight );
			renderer.toneMapping = THREE.ACESFilmicToneMapping;
			renderer.toneMappingExposure = 0.8;
			renderer.outputEncoding = THREE.sRGBEncoding;
			renderer.setClearColor( 0xffffff, 1);
			const maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
			container.appendChild( renderer.domElement );

			var pmremGenerator = new THREE.PMREMGenerator( renderer );
			pmremGenerator.compileEquirectangularShader();

			controls = new OrbitControls( camera, renderer.domElement );
			controls.addEventListener( 'change', render );
			controls.minDistance = 3;
			controls.maxDistance = 10;
			controls.enableDamping = true;
			controls.target.set( 0, 0, 0 );
			controls.maxPolarAngle = Math.PI / 2.05;   
			controls.screenSpacePanning = true;
			controls.update();

			window.addEventListener( 'resize', onWindowResize, false );	

		}

		function onWindowResize() {

			camera.aspect = window.innerWidth / window.innerHeight;
			camera.updateProjectionMatrix();

			renderer.setSize( window.innerWidth, window.innerHeight );

			render();

		}

		function render() 
		{	
			renderer.render( scene, camera );
		}

		var azimuthAngle, polarAngle;
		function animate()
		{
			controls.update();
			requestAnimationFrame(animate);
		}

		requestAnimationFrame(animate);


</script>

And also, the rendering on mobile, in this case Android Chrome 80 and Android Mozilla 74 is just wrong

How it looks on Desktop:

How it looks on Mobile:

The color of the glasses texture is completely ignored but the alpha works.

I hope someone can help me here, I’m new to three.js and completely stuck right now.

The 3D Model is btw. this one https://sketchfab.com/3d-models/mustang-mu-1683-b50360c38ecc4276bb2e7e77e69b5844
I baked the shadow in blender and exported it in .glb.

1 Like

I’m not sure but it seems you are mixing an animation loop with on-demand rendering.

For viewer software, it’s usually best to render only when the scene has changed (except for the case the model has animations). Hence, I suggest you remove the animation loop.

If you want to keep it because of the control’s damping, I recommend you remove the call of:

controls.addEventListener( 'change', render );

Since you already have an animation loop, rendering on demand is not necessary. Otherwise you have duplicated render calls which explains the poor performance.

2 Likes

I would say it’s PMREM’s fault. In my experience it’s very expensive on smartphones, especially noticeable on those with weaker hardware.