Why does the spotlight in my three.js scene remain centered in the camera perspective, but only on Chrome for Android? Why does the spotlight in my three.js scene remain centered in the camera perspective, but only on Chrome for Android? google-chrome google-chrome

Why does the spotlight in my three.js scene remain centered in the camera perspective, but only on Chrome for Android?


I see the problem on my Moto G 1st gen (Qualcomm Snapdragon 400) but not on my Project Tango tablet (nVidia Tegra K1), so it is likely that this is either a GPU driver bug or an unsupported feature on certain hardware.

I was able to write a simple repeatable test case and use it to determine where the computation diverged between my two platforms. It turned out to happen in this portion of the Three.js GLSL fragment shader (extracted from the Three.js script) that causes the discrepancy (comments added by me):

#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

This section of code determines the normal at a fragment. Your material settings result in enabling the FLAT_SHADED block. Apparently the calls to the derivative functions dFdx() and dFdy(), which are provided by the GL_OES_standard_derivatives extension to WebGL, are producing inconsistent results. This suggests that the extension is either implemented incorrectly or not supported on the platforms causing problems. This Mozilla bug supports this hypothesis, specifically pointing out Qualcomm hardware:

A number of devices expose OES_standard_derivatives, but have broken implementations of it

The simple workaround is to avoid the flat shading code path. Your floorMaterial contains the parameter:

shading: THREE.FlatShading,

Removing this single line will default to smooth shading (or you can explicitly change the value to THREE.SmoothShading). Your mesh already provides vertex normals so this should just work.

I tried to clone your test site and commenting out that one line looks much better to me on my Moto G. I also created this jsfiddle that shows two quads, one with smooth shading (left) and one with flat shading (right). The quads should appear to be reflections of each other but won't if the platform has problems with the flat shader.


Going by your words that it works fine in chrome desktop, but issue is only with android, you may try running chrome in desktop mode in android. just like you can do "request desktop site" for chrome. See if this helps. How does Chrome's "Request Desktop Site" option work?