2015-12-15 4 views
39

Obecnie używam AngularJS i Three.js, aby spróbować stworzyć mały przykład aplikacji VR. Zdefiniowałem formanty na podstawie tego, czy klient użytkownika jest urządzeniem mobilnym, czy nie. To podejrzana metoda, ale to tylko przykład. OrbitControls są używane na urządzeniach innych niż mobilne, a DeviceOrientationControls są używane w inny sposób.Dlaczego reflektor w mojej scenie three.js pozostaje wyśrodkowany w perspektywie aparatu, ale tylko w Chrome na Androida?

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; 

Stworzyłem również kilka obiektów do wyświetlenia.

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

Działa to dobrze na Chrome dla OSX, Safari na OSX & Safari na iPadzie (w tym kontroli orientacji urządzenia, gdzie właściwe).

Problem występuje podczas uruchamiania aplikacji w przeglądarce Chrome na Androida. Reflektor, który został dodany do sceny, będzie stale wskazywany w tym samym kierunku co kamera. Oto zrzut ekranu z uruchomionej aplikacji na Androida:

Spotlight image

Na każdej innej przeglądarce próbowałem użyć, światło jest umieszczone na (50, 50, 50) prawidłowo i pozostaje statyczne. W powyższym przykładzie światło jest renderowane pośrodku aparatu i kontynuuje podążanie za kamerą podczas jej przesuwania lub obracania. Faktyczne sterowanie orientacją działa dobrze.

Fakt, że dzieje się to tylko w jednej przeglądarce, naprawdę sprawia mi ból głowy, ponieważ demo musi działać w przeglądarce Chrome na Androida.

Dzięki.

Aktualizacja: Próbowano wielu różnych rozwiązań, od różnych metod sterowania po różne rodzaje oświetlenia, bez skutku.

+0

Czy możesz opublikować pełny kod, także dla renderera? łatwiej nam wtedy powielić i przetestować – cviejo

+0

Tak powinno się stać, gdy światło jest dzieckiem aparatu. W twoim przypadku tak nie jest, więc nie musisz dodawać kamery do sceny. – gaitat

+0

Położyłem mały przykład w Internecie, aby sprawdzić to na moich urządzeniach mobilnych ... ale nie jestem całkowicie przekonany, że mam reprodukcję. Ograniczona swoboda działania aparatu w połączeniu z dużym odbiciem światła sprawia, że ​​trudno go dostrzec. Jeśli ktokolwiek chce spojrzeć, próbka jest tutaj: http://eponalabs.com/experiments/so19086690/. –

Odpowiedz

10

widzę problemu na moim Moto G 1st gen (Qualcomm Snapdragon 400), ale nie na moim tablecie Projekt Tango (nVidia Tegra K1), więc jest prawdopodobne, że jest to albo błąd sterownika GPU lub nieobsługiwana funkcja na niektórych urządzeniach.

Udało mi się napisać prosty, powtarzalny przypadek testowy i użyć go do określenia, gdzie obliczenia różniły się pomiędzy dwiema platformami. Okazało się to zdarzyć w tej części fragmentu cieniującego Three.js GLSL (wyodrębniony ze skryptu Three.js), który powoduje różnicę (komentarze dodane przeze mnie):

#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 

Ta część kodu określa normalny w fragmencie. Twoje ustawienia materiału powodują odblokowanie bloku FLAT_SHADED. Wygląda na to, że wywołania funkcji pochodnych dFdx() i dFdy(), które są dostarczane przez rozszerzenie GL_OES_standard_derivatives do WebGL, powodują niespójne wyniki. Sugeruje to, że rozszerzenie jest implementowane niepoprawnie lub nie jest obsługiwane na platformach powodujących problemy.This Mozilla bug popiera tę hipotezę, w szczególności wskazując, Qualcomm sprzęt:

Szereg urządzeń wystawiać OES_standard_derivatives, ale złamali implementacje nim

Prostym rozwiązaniem jest unikanie płaską ścieżkę kodu cieniowania. Twój floorMaterial zawiera parametr:

shading: THREE.FlatShading, 

usunięcie tego pojedynczą linię będzie domyślnie wygładzić cieniowania (lub można wyraźnie zmienić wartość THREE.SmoothShading). Twoja siatka już dostarcza wierzchołków normalnych, więc to powinno działać.

Próbowałem sklonować twoją witrynę testową i skomentowałem, że jedna linia wygląda znacznie lepiej na moim Moto G. Stworzyłem także this jsfiddle, który pokazuje dwa quady, jeden z gładkim cieniowaniem (po lewej) i jeden z płaskim cieniowaniem (po prawej)). Czworaki powinny wydawać się odbiciami siebie nawzajem, ale nie, jeśli platforma ma problemy z płaskim modułem cieniującym.

3

Przechodząc przez słowa, które działa dobrze na pulpicie chrome, ale problem jest tylko z Androidem, możesz spróbować uruchomić chrome w trybie pulpitu w Androidzie. tak jak możesz zrobić "poproś o stronę na komputery" dla chrome. Sprawdź, czy to pomaga. How does Chrome's "Request Desktop Site" option work?

+0

Żądanie wersji stacjonarnej strony nadal utrzymuje te same problemy, co wersja mobilna. – neilthom

Powiązane problemy