Javascript 为什么我的three.js场景中的聚光灯仍以摄影机透视图为中心,而仅在Android的Chrome上?

Javascript 为什么我的three.js场景中的聚光灯仍以摄影机透视图为中心,而仅在Android的Chrome上?,javascript,android,google-chrome,three.js,Javascript,Android,Google Chrome,Three.js,我目前正在使用AngularJS和Three.js尝试开发一个VR应用程序的小示例。我已经根据用户代理是否是移动设备定义了控件。这是一个狡猾的方法,但它只是一个例子。OrbitControl用于非移动设备,DeviceOrientationControl用于其他设备 var controls = new THREE.OrbitControls(camera, game.renderer.domElement); controls.noPan = true; controls.noZoom =

我目前正在使用AngularJS和Three.js尝试开发一个VR应用程序的小示例。我已经根据用户代理是否是移动设备定义了控件。这是一个狡猾的方法,但它只是一个例子。OrbitControl用于非移动设备,DeviceOrientationControl用于其他设备

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 for OSX、Safari for OSX和Safari on iPad(包括适当的设备方向控制)上运行良好

在Chrome for Android上运行应用程序时会出现问题。添加到场景中的聚光灯将始终指向与摄影机相同的方向。以下是在Android上运行的应用程序的屏幕截图:

在我尝试使用的所有其他浏览器上,灯光都正确定位在(50,50,50),并保持静止。在上面的示例中,光被呈现在相机的中间,并且在移动或旋转时继续跟随相机。实际的方向控制工作得很好

事实上,这只发生在一个浏览器中,这真的让我头疼,因为演示需要在Chrome for Android上运行

谢谢


更新:已经尝试了许多不同的解决方案,从不同的控制方法到不同类型的照明,但都没有效果。

照你的话说,它在chrome桌面上运行良好,但问题只在于android, 您可以尝试在android中以桌面模式运行chrome。就像你可以为chrome做“请求桌面站点”一样。 看看这是否有帮助。

我在我的Moto G第1代(高通Snapdragon 400)上看到了问题,但在我的Project Tango平板电脑(nVidia Tegra K1)上没有看到,因此这可能是GPU驱动程序错误或某些硬件上不支持的功能

我能够编写一个简单的可重复测试用例,并使用它来确定计算在我的两个平台之间的分歧。事实证明,它发生在Three.js GLSL片段着色器(从Three.js脚本中提取)的这一部分中,导致了差异(我添加的注释):

这段代码确定了片段的法线。您的材质设置导致启用“平面着色”块。显然,对衍生函数
dFdx()
dFdy()
的调用(由GL_OES_标准_衍生函数扩展提供给WebGL)产生了不一致的结果。这表明扩展的实现不正确,或者平台不支持扩展,从而导致问题。支持这一假设,特别指出高通公司的硬件:

许多设备公开了OES_标准_的衍生产品,但已经损坏 it的实现

简单的解决方法是避免平面着色代码路径。您的
floorMaterial
包含以下参数:

shading: THREE.FlatShading,
删除这一行将默认为平滑着色(或者您可以显式地将该值更改为
THREE.SmoothShading
)。您的网格已经提供了顶点法线,因此这应该可以正常工作


我试图克隆你的测试站点,并评论说,在我的Moto G上,有一行看起来更好。我还创建了两个四边形,一个带有平滑着色(左),一个带有平面着色(右)。四边形应该看起来是彼此的反射,但如果平台的平面着色器存在问题,则不会出现这种情况。

能否发布渲染器的完整代码?我们更容易复制和测试当光线是相机的子对象时应该发生的情况。在你的情况下,它不是,所以你也不必将相机添加到场景中。我在网上放了一个小例子,在我的移动设备上检查这一点。。。但我并不完全相信我有生殖能力。有限的相机自由度加上大的镜面反射高光,使它很难看到。如果其他人想查看,示例如下:。很抱歉更新太晚。下面可以找到导致问题的代码版本。当在我的Android设备上打开时,灯光将跟随相机并指向它的方向。无法在我的任何设备上复制,因此它似乎非常具体。也许下面的新答案有帮助..请求网站的桌面版本仍然与移动版本存在相同的问题。
shading: THREE.FlatShading,