What could be causing the spotlight in my three.js scene to stay centered in the camera perspective, but only when using Chrome on an Android device?

Currently, I am experimenting with AngularJS and Three.js to create a small example of a VR application. To define controls based on whether the user is using a mobile device or not, I have implemented OrbitControls for non-mobile devices and DeviceOrientationControls otherwise.

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

//My method of checking if the device is mobile may be unreliable
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;

I have also created several objects for display:

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

Everything works smoothly on Chrome for OSX, Safari for OSX & Safari on iPad (device orientation controls included when needed).

The issue arises when running the application on Chrome for Android. The spotlight added to the scene constantly follows the camera direction instead of staying static at (50, 50, 50). Here's a screenshot of the problem on Android:

https://i.sstatic.net/4jdEl.jpg

In all other browsers tested, the light remains correctly positioned at (50, 50, 50) without following the camera movement. However, in Chrome for Android, the light moves with the camera, causing the unwanted effect shown in the screenshot. The device orientation controls function properly though.

This browser-specific issue is causing frustration as the demo must run seamlessly on Chrome for Android.

Thank you.

Update: Despite trying various solutions like different control methods and lighting techniques, the issue persists.

Answer №1

Upon testing, I noticed an issue on my Moto G 1st gen (Qualcomm Snapdragon 400) but not on my Project Tango tablet (nVidia Tegra K1). Therefore, it seems probable that this could be attributed to either a GPU driver glitch or an unsupported feature on specific hardware.

To pinpoint the source of differentiation between my two platforms, I designed and executed a straightforward reproducible test case. My investigation revealed that the divergence occurred in a segment of the Three.js GLSL fragment shader (extracted from the Three.js script), which led to the discrepancy (annotated by me):

#ifndef FLAT_SHADED
  // Smooth shading - utilizes the interpolated normal.
  vec3 normal = normalize( vNormal );

#ifdef DOUBLE_SIDED
  normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );
#endif

#else
  // Flat shading - computes the surface normal using cross product 
  // of tangent derivatives.
  // This part of the code is responsible for generating inconsistent results on certain mobile GPUs.
  vec3 fdx = dFdx( vViewPosition );
  vec3 fdy = dFdy( vViewPosition );
  vec3 normal = normalize( cross( fdx, fdy ) );

#endif

This snippet determines the normal at a fragment. Your current material settings activate the FLAT_SHADED block. It appears that the functions dFdx() and dFdy(), provided by the GL_OES_standard_derivatives extension to WebGL, are yielding unreliable outcomes. This indicates potential issues with the extension's implementation or support on problematic platforms. A Mozilla bug report (source) reinforces this theory, particularly highlighting Qualcomm hardware:

Several devices expose OES_standard_derivatives but have malfunctioning implementations

A quick resolution involves avoiding the flat shading aspect. In your floorMaterial, there exists the parameter:

shading: THREE.FlatShading,

Eliminating this line will default to smooth shading (or explicitly changing to THREE.SmoothShading). Since your mesh already includes vertex normals, this adjustment should suffice.

I altered your test site by removing the specified line, resulting in improved visualization on my Moto G. Moreover, I crafted this jsfiddle demonstrating two quads – one with smooth shading (left) and another with flat shading (right). Both quads should reflect each other, unless the platform encounters problems with the flat shader.

Answer №2

If you're experiencing no issues with Chrome on your desktop but are facing problems on your Android device, you might want to consider running Chrome in desktop mode on your mobile. Just like how you can request the desktop site on Chrome. Check out this link for more information: How does enabling Chrome's "Request Desktop Site" option work?

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using Bootstrap, jQuery, and PHP to dynamically load input fields in a modal window

I am looking to dynamically load input fields in a modal window using PHP. While researching, I came across suggestions to utilize AJAX for this purpose. However, I have limited knowledge about AJAX. The plan is as follows: 1) When the user clicks on the ...

Executing Javascript code that has been retrieved using the XMLHttpRequest method in a

Would it be feasible to modify this code to function recursively if the redirects to the js file that needs to be executed? function loadScript(scriptUrl) { var xhr = new XMLHttpRequest(); xhr.open("GET", scriptUrl); xhr.onready ...

Unusual actions observed in ajax rails form calculator with pre-filled values

I have a form calculator in Rails that utilizes AJAX without a database. While it functions properly, I have noticed some peculiar behavior which I would like to address. Firstly, I navigate to the /interest_calculator page Then, I input 10 into @first_0 ...

Passing a selected option in a select box to another website is achievable using JavaScript

I'm still learning JavaScript and I would like to have a user be directed to another page when they select an option from a dropdown menu. Any suggestions on how to accomplish this? ...

Easiest way to retrieve data with Backbone.js collections

I am currently attempting to download, parse, and display a list from the XML data received from my server using Backbone.js. Below is the code snippet: var Item = Backbone.collection.extend({ url: "http://myurl.com/file.xml", parse: function() { ...

What is the process for transforming a promise outcome into JSON format?

My current challenge involves using axios to retrieve JSON data from an external API in my backend and then passing it to the frontend. The issue arises when I attempt to log the result in the frontend, as all I see is a promise object instead of the actua ...

JSON arrays that are nested within one another

I am currently working on parsing some JSON data that contains nested arrays, and I'm facing difficulties extracting the data from the inner arrays within the main array. This is a snippet of how my JSON data is structured: {"TrackingInformationResp ...

The displayed value in the text field remains constant even when the object's attribute is modified

My issue involves the Date Text Field component of Material UI. Whenever I pass an attribute from an object, the displayed value in the Text Field does not update even when the object attribute changes. const [data, setData] = useState({ title: new Da ...

Implementing the sorting feature in Angular JS to properly align sub sections with their correct parent sections

I'm facing an issue with the functionality of my sample code. Users can add sections and subsections within those sections, which are sortable using ui-sortable. However, after sorting the items, if I try to add a new sub-section to Section 2, it wron ...

Simulating Cordova plugin functionality during unit testing

I have a code snippet that I need to test in my controller: $scope.fbLogin = function() { console.log('Start FB login'); facebookConnectPlugin.login(["public_profile", "email", "user_friends"], FacebookServices.fbLoginSuccess, FacebookServic ...

Is there a way to obtain a similar perspective in List View?

Hey everyone, I'm curious about how to achieve a view like this. My initial thought is using a ListView inside a ScrollView, but I'm not sure if it will work the same way as shown in the picture. Additionally, I know that having a ListView inside ...

Using a texture the same size as the original image in three.js / react-three-fiber: A step-by-step guide

I am facing a challenge in a project where I need to create a box to improve processing efficiency. The desired texture size is 16 px by 16 px. However, when I apply the texture to the box, it appears blurry regardless of the box size, as shown in the imag ...

What is the best method for passing a JavaScript object to PHP using Ajax?

I have looked into similar questions like this and this, but none of them have helped me solve my issue. When I check the console log for my data, it displays the following: Object["row_LM#00000010", "row_LM#00000002", "row_LM#00000009", "row_LM#00000008" ...

Utilizing data attributes and JavaScript to dynamically assign a class to carousel navigation items

Hello there! I recently created a carousel and carousel navigation system using Bootstrap. I am now trying to figure out how to detect the value of 'data-slide-to' and then apply a specific style to the corresponding navigation item based on that ...

Consistent design across all API platforms with AppCompat styling

When using com.android.support:appcompat-v7:22.2.0 to implement Lolipop material design on devices running pre-Lolipop versions, I've encountered a problem. The widgets, such as EditText, are displaying different views with different parameters depend ...

Using jQuery, is it possible to retrieve the product name and image dynamically?

I'm currently working on implementing an add to cart functionality using jQuery. When the add to cart button is clicked, the product name and image should be displayed. I can achieve this statically but I need help figuring out how to dynamically retr ...

Develop a new entity utilizing Array in Javascript

let DaysArray: any = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"] I am looking to transform the above array into an Object structure as shown below: let DaysObject: any = { time: { headerName: "" }, m ...

Modify the content of a separate division by selecting a different item in a list with the help of Vue.js and TypeScript

I am still learning Vue and may not have all the answers. Currently, I am working on a feature that changes the text of another div based on the item I select from a list. You can find the code sandbox link below along with my current implementation. Code ...

Unusual conduct when employing basic directive for validation messages

Within my code, I have implemented the following directive: App.directive("validateMsgFor", function(){ return{ templateUrl : "view/templates/validateMsgFor.html", restrict: "E", scope: { field : "=" } ...

Display Image based on AngularJS value

Within my data, there exists a value {{catadata2.EndorsementList['0'].Rating}}. This value can be either 3, 4, or 5. Based on this value, I am looking to display the image <img src="/assets/img/rating.png" /> a certain number of times. For ...