¿Por qué el foco en mi escena de tres.js sigue centrado en la perspectiva de la cámara, pero sólo en Chrome para Android?

Actualmente utilizo AngularJS y Three.js para tratar de desarrollar un pequeño ejemplo de una aplicación VR. He definido controles basados ​​en si el agente de usuario es un dispositivo móvil o no. Es un método desagradable, pero es sólo un ejemplo. OrbitControls se utilizan en dispositivos no móviles y DeviceOrientationControls se utilizan de otra manera.

var controls = new THREE.OrbitControls(camera, game.renderer.domElement); controls.noPan = true; controls.noZoom = true; controls.target.set( camera.position.x, camera.position.y, camera.position.z ); // Really dodgy method of checking if we're on mobile or not if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { controls = new THREE.DeviceOrientationControls(camera, true); controls.connect(); controls.update(); } return controls; 

También he creado algunos objetos para mostrar realmente.

 this.camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.001, 1000); this.camera.position.set(0, 15, 0); this.textGeometry = new THREE.TextGeometry("Hello World", { size: 5, height: 1 }); this.textMesh = new THREE.Mesh(this.textGeometry, new THREE.MeshBasicMaterial({ color: 0xFF0000, opacity: 1 })); this.textMesh.position.set(-20, 0, -20); this.light = new THREE.SpotLight(0x999999, 3, 300); this.light.position.set(50, 50, 50); this.floorGeometry = new THREE.PlaneBufferGeometry(1000, 1000); this.floorTexture = THREE.ImageUtils.loadTexture('img/textures/wood.jpg'); this.floorTexture.wrapS = THREE.RepeatWrapping; this.floorTexture.wrapT = THREE.RepeatWrapping; this.floorTexture.repeat = new THREE.Vector2(50, 50); this.floorTexture.anisotropy = this.game.renderer.getMaxAnisotropy(); this.floorMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff, specular: 0xffffff, shininess: 20, shading: THREE.FlatShading, map: this.floorTexture }); this.floor = new THREE.Mesh(this.floorGeometry, this.floorMaterial); this.floor.rotation.x = -Math.PI / 2; this.scene.add(this.textMesh); this.scene.add(this.light); this.scene.add(this.floor); this.scene.add(this.camera); 

Esto funciona bien en Chrome para OSX, Safari para OSX y Safari en iPad (incluidos los controles de orientación del dispositivo, según corresponda).

El problema se produce al ejecutar la aplicación en Chrome para Android. El proyector que se ha añadido a la escena será constantemente apuntado en la misma dirección que la cámara. Aquí hay una captura de pantalla de la aplicación que se ejecuta en Android:

Imagen de Spotlight

En todos los demás navegadores que he intentado utilizar, la luz se posiciona correctamente (50, 50, 50) y permanece estática. En el ejemplo anterior, la luz se está representando en el centro de la cámara y continúa siguiendo la cámara cuando se mueve o gira. Los controles de orientación reales funcionan bien.

El hecho de que esto sólo suceda en un navegador realmente me da dolores de cabeza, ya que la demo necesita ejecutarse en Chrome para Android.

Gracias.

Actualización: Han estado intentando muchas soluciones diferentes de diferentes métodos de control a diferentes tipos de iluminación en vano.

Veo el problema en mi primera generación de Moto G (Qualcomm Snapdragon 400), pero no en mi tablet Project Tango (nVidia Tegra K1), por lo que es probable que se trate de un error de controlador de GPU o de una característica no admitida en cierto hardware.

Fui capaz de escribir un caso de prueba repetible simple y utilizarlo para determinar dónde el cálculo divergió entre mis dos plataformas. Resultó que sucedió en esta porción del shader de fragmentos GLSL de Three.js (extraído del script Three.js) que causa la discrepancia (comentarios añadidos por mí):

 #ifndef FLAT_SHADED // Smooth shaded - use the interpolated normal. vec3 normal = normalize( vNormal ); #ifdef DOUBLE_SIDED normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) ); #endif #else // Flat shaded - generate the normal by taking the cross // product of derivatives that lie tangent to the surface. // This is the code that produces inconsistent results on // some mobile GPUs. vec3 fdx = dFdx( vViewPosition ); vec3 fdy = dFdy( vViewPosition ); vec3 normal = normalize( cross( fdx, fdy ) ); #endif 

Esta sección de código determina lo normal en un fragmento. Su configuración de material resulta en habilitar el bloque FLAT_SHADED . Aparentemente las llamadas a las funciones derivadas dFdx() y dFdy() , que son proporcionadas por la extensión GL_OES_standard_derivatives a WebGL, están produciendo resultados inconsistentes. Esto sugiere que la extensión se implementa incorrectamente o no se admite en las plataformas que causan problemas. Este error de Mozilla apoya esta hipótesis, señalando específicamente hardware Qualcomm:

Una serie de dispositivos exponen OES_standard_derivatives, pero han roto implementaciones de la misma

La solución sencilla es evitar la ruta de código de sombreado plano. Su floorMaterial contiene el parámetro:

 shading: THREE.FlatShading, 

La eliminación de esta línea única predeterminará el sombreado suave (o puede cambiar explícitamente el valor a THREE.SmoothShading ). Su malla ya proporciona vértices normales, por lo que esto debería funcionar.

He intentado clonar tu sitio de prueba y comentar que una línea me parece mucho mejor en mi Moto G. También he creado este jsfiddle que muestra dos quads, uno con sombreado suave (izquierda) y otro con sombreado plano (derecha). Los quads deben aparecer como reflejos entre sí, pero no si la plataforma tiene problemas con el sombreado plano.

Pasando por tus palabras que funciona bien en el escritorio de cromo, pero el problema es sólo con Android, puede intentar ejecutar cromado en el modo de escritorio en android. Al igual que usted puede hacer "solicitud de sitio de escritorio" para el cromo. Ver si esto ayuda. ¿Cómo funciona la opción "Solicitar sitio de escritorio" de Chrome?

  • cómo paginar un libro electrónico html para mostrar en la aplicación basada en web android android
  • Detectar clic en el botón HTML a través de javascript en Android WebView
  • Cómo llamar a la función javascript de la actividad de Android
  • Android: fija la orientación de la pantalla sólo para una página (diferencia telefónica)
  • Imagen alfa en el navegador predeterminado de Android
  • Trabajadores web en navegadores móviles
  • ¿Por qué es el evento touchstart después de hacer clic?
  • ¿Cómo usar Phonegap SoftKeyboard Plugin para Android?
  • Cordova / phonegap bloquear y dejar atrás el botón
  • Se rehusó a mostrar un marco porque establecía X-Frame-Options en 'DENY en android webview
  • Evitar que el cuerpo se desplace (navegadores móviles y nativos)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.