Подтвердить что ты не робот

Почему центр внимания в моей сцене three.js остается в центре внимания камеры, но только в Chrome для Android?

В настоящее время я использую AngularJS и Three.js, чтобы попытаться разработать небольшой пример приложения VR. Я определил элементы управления на основе того, является ли пользовательский агент мобильным устройством или нет. Это изворотливый метод, но это всего лишь пример. OrbitControls используются на немобильных устройствах, а DeviceOrientationControls используются иначе.

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;

Я также создал несколько объектов для фактического отображения.

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

Это отлично работает в Chrome для OSX, Safari для OSX и Safari на iPad (включая, в случае необходимости, элементы управления ориентацией устройства).

Проблема возникает при запуске приложения в Chrome для Android. Прожектор, который был добавлен в сцену, будет постоянно направлен в том же направлении, что и камера. Вот скриншот приложения, работающего на Android:

Прожекторное изображение

В каждом другом браузере, который я пытался использовать, свет позиционируется правильно (50, 50, 50) и остается статичным. В приведенном выше примере свет отображается в середине камеры и продолжает следить за камерой при ее перемещении или повороте. Фактические элементы управления ориентацией работают очень хорошо.

Тот факт, что это происходит только в одном браузере, действительно дает мне головные боли, так как демо нужно запускать в Chrome для Android.

Спасибо.

Обновление: пытались использовать множество различных решений от различных методов управления для различных типов освещения. [/p >

4b9b3361

Ответ 1

Я вижу проблему на моем Moto G 1st gen (Qualcomm Snapdragon 400), но не на моем планшете Project Tango (nVidia Tegra K1), поэтому вполне вероятно, что это либо ошибка драйвера GPU, либо неподдерживаемая функция на некоторых аппаратных средствах.

Я смог написать простой повторяемый тестовый пример и использовать его, чтобы определить, где вычисление расходится между моими двумя платформами. Оказалось, что в этой части шейдера фрагмента Three.js GLSL (извлечен из файла Three.js script), что вызывает несоответствие (комментарии добавлены мной):

#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

Этот раздел кода определяет нормаль на фрагменте. Настройки материала приводят к включению блока FLAT_SHADED. По-видимому, вызовы производных функций dFdx() и dFdy(), которые предоставляются расширением GL_OES_standard_derivatives для WebGL, вызывают противоречивые результаты. Это говорит о том, что расширение либо реализовано неправильно, либо не поддерживается на платформах, вызывающих проблемы. Эта ошибка Mozilla поддерживает эту гипотезу, в частности, указывая на аппаратное обеспечение Qualcomm:

Несколько устройств обнаруживают OES_standard_derivatives, но сломались его реализации

Простым обходным путем является избежание прямого кода кода штриховки. Ваш floorMaterial содержит параметр:

shading: THREE.FlatShading,

Удаление этой отдельной строки будет по умолчанию равномерным затенением (или вы можете явно изменить значение на THREE.SmoothShading). Ваша сетка уже предоставляет нормали вершин, поэтому это должно просто работать.

Я пытался клонировать ваш тестовый сайт и комментируя, что одна строка выглядит намного лучше для меня на моем Moto G. Я также создал этот jsfiddle, который показывает два квадроцикла, один с гладким оттенком (слева) и один с плоским затенением (справа). Квадраты должны казаться отражениями друг друга, но не будут, если платформа имеет проблемы с плоским шейдером.

Ответ 2

Идя по вашим словам, что он отлично работает на рабочем столе Chrome, но проблема заключается только в android,  вы можете попробовать запустить chrome в настольном режиме в android. так же, как вы можете сделать "запрос на рабочий стол" для хром. Посмотрите, поможет ли это. Как работает сайт "Запрос рабочего стола Chrome" вариант работы?