Pourquoi est-ce que le projecteur dans mes trois.js scene reste centré dans la perspective de la caméra, mais seulement sur Chrome pour Android?

J'utilise AngularJS et trois.js pour essayer de développer un petit exemple d'application VR. J'ai défini des contrôles basés sur le fait que l'agent utilisateur est un appareil mobile ou non. C'est une méthode douteuse, mais c'est juste un exemple. Les contrôles orbitaux sont utilisés sur les appareils non mobiles, et les contrôles Deviceorientationont été utilisés autrement.

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;

j'ai également créé quelques objets à afficher.

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);

cela fonctionne très bien sur Chrome pour OSX, Safari pour OSX et Safari sur iPad (y compris les contrôles d'orientation de l'appareil le cas échéant).

le problème se produit lors de l'exécution de l'application sur Chrome pour Android. Le " coup de projecteur a été ajouté à la scène sera constamment pointé dans la même direction que la caméra. Voici une capture d'écran de l'application fonctionnant sur Android:

Spotlight image

sur tous les autres navigateur, j'ai essayé de l'utiliser, la lumière est placée à (50, 50, 50) correctement et reste statique. Dans l'exemple ci-dessus, la lumière est rendue au milieu de la caméra et continue de suivre la caméra lorsqu'elle est déplacée ou tournée. Les contrôles d'orientation fonctionnent très bien.

le fait que cela n'arrive que dans un seul navigateur me donne vraiment des maux de tête, car la démo doit tourner sur Chrome pour Android.

Merci.

mise à jour: ont essayé de nombreuses solutions différentes, allant de différentes méthodes de contrôle à différents types d'éclairage, sans succès.

39
demandé sur rottenoats 2015-12-15 15:39:11

2 réponses

je vois le problème sur ma Moto G 1st gen (Qualcomm Snapdragon 400) mais pas sur ma tablette Tango Project (nVidia Tegra K1), il est donc probable qu'il s'agisse d'un bug de pilote GPU ou d'une fonctionnalité non supportée sur certains matériels.

j'ai pu écrire un simple cas de test reproductible et l'utiliser pour déterminer où le calcul divergeait entre mes deux plates-formes. Cela s'est produit dans cette partie des trois cas.js GLSL fragment shader (extrait des trois.js script) qui provoque la divergence (commentaires ajoutés par moi):

#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

cette section de code détermine la normale à un fragment. Vos paramètres matériels permettent d'activer le bloc FLAT_SHADED . Apparemment , les appels aux fonctions dérivées dFdx() et dFdy() , qui sont fournis par L'extension GL_OES_standard_derivatives à WebGL, produisent des résultats incohérents. Cela donne à penser que l'extension n'est pas mise en œuvre correctement ou pas correctement. pris en charge sur les plates-formes causant des problèmes. ce bug de Mozilla supporte cette hypothèse, soulignant spécifiquement Qualcomm hardware:

un certain nombre de dispositifs exposent OES_standard_derivatives, mais ont cassé mise en œuvre des TI

la solution simple est d'éviter le chemin de code à ombrage plat. Votre floorMaterial contient le paramètre:

shading: THREE.FlatShading,

suppression cette ligne simple sera par défaut à l'ombrage lisse (ou vous pouvez modifier explicitement la valeur en THREE.SmoothShading ). Votre mesh fournit déjà des normales de vertex, donc cela devrait fonctionner.

j'ai essayé de cloner votre site d'essai et en commentant qu'une ligne me semble beaucoup mieux sur ma Moto G. j'ai aussi créé ce jsfiddle qui montre deux quads, l'un avec un ombrage lisse (à gauche) et l'autre avec un ombrage plat (à droite). Les quads devraient apparaître comme des reflets de l'un l'autre mais ne le fera pas si la plate-forme a des problèmes avec le Flat shader.

10
répondu rhashimoto 2015-12-23 23:42:26

aller par vos mots qu'il fonctionne bien dans chrome bureau, mais le problème est seulement avec android, vous pouvez essayer d'exécuter chrome en mode Bureau sous android. comme vous pouvez le faire "voir version ordinateur" pour chrome. Voir si cela aide. comment fonctionne L'option" Request Desktop Site " de Chrome?

3
répondu Ashish Rawat 2017-05-23 11:45:03