Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adreno 300 series GPU black texture flickering #9988

Closed
3 of 10 tasks
gauravrane opened this issue Nov 2, 2016 · 34 comments
Closed
3 of 10 tasks

Adreno 300 series GPU black texture flickering #9988

gauravrane opened this issue Nov 2, 2016 · 34 comments

Comments

@gauravrane
Copy link

gauravrane commented Nov 2, 2016

When loading the website on an Android phone with a Adreno 300 series, get a weird black glitch in diffuse textures causing black flickering. I am using MeshPhongMaterial for the meshes with point lights.

The same is reproduced in the threejs examples from the website, which i am giving links for instead of a jsfiddle.
https://threejs.org/examples/?q=texture#webgl_materials_texture_filters
https://threejs.org/examples/?q=texture#webgl_materials_texture_manualmipmap

Screenshots -
motog3
oneplusx_2

From my application -
car_1
car_2

In my project, the floor outside which is a Plane Geometry does not have this issue. Only the mesh I have loaded using the SEA3d loader.
car_3

Strangely there was no issue when viewing the anisotropy example too.

It is a major issue because a lot of phones use Adreno 300 series GPU's.

Three.js version
  • Dev
  • r81
  • ...
Browser
  • [] All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • [] All of them
  • Windows
  • Linux
  • Android
  • IOS
Hardware Requirements (graphics card, VR Device, ...)

Tested with the following android devices. Work fine on other GPU series.
Oneplus X - Adreno 330
Moto G3 - Adreno 306
Moto G2 - Adreno 305

@mrdoob
Copy link
Owner

mrdoob commented Nov 2, 2016

Do you get the same results with Android's Chrome Dev, Chrome Canary and Firefox?

@gauravrane
Copy link
Author

Same results with Chrome Dev, Canary and Firefox as well.

@mrdoob
Copy link
Owner

mrdoob commented Nov 5, 2016

@kenrussell is this a known issue?

@kenrussell
Copy link

@mrdoob it's hard to know. As you remember we filed ~4 driver bugs with Qualcomm against the Adreno 330 last year - the GPU in the Nexus 5. We were told that that device was not going to receive the Android N update, so no graphics driver updates, and the bugs were closed as "won't fix".

I don't remember exactly which of the WebGL conformance tests in https://github.com/KhronosGroup/WebGL/tree/master/sdk/tests/conformance/glsl/bugs were created for these cases.

If this is a serious issue then I recommend iteratively simplifying the shader and figuring out what part of it is executing incorrectly on the Adreno 300 series GPUs. This would only be in order to figure out a workaround -- there is no point in filing a driver bug about it since the driver will never be updated. We will gladly add a reduced test case to the WebGL conformance suite if you can come up with one and if it doesn't already exist.

@gauravrane
Copy link
Author

gauravrane commented Nov 5, 2016

@mrdoob it seems that adding a normal map to the phong material is causing the issue in my project on some meshes. The flicker still exists on the other materials, Basic and Lambert as well unlike my initial observations. I have tested with a lot of devices with the 300 series GPU just to be sure.

Here is a screen without the normal map on the door.
car4

There are a couple of more issues with these devices though, even with the Fog shader which causes issues with the fog distance set as well as the device crashing when the screen locks with the browser on and you try to unlock it.

@mrdoob
Copy link
Owner

mrdoob commented Nov 5, 2016

Does this example render correctly on those devices?
https://threejs.org/examples/#webgl_materials_normalmap

@gauravrane
Copy link
Author

Yes so far it is rendering fine without any flicker for this link.

@gauravrane
Copy link
Author

gauravrane commented Nov 7, 2016

@mrdoob Any chance there's a workaround for this ?

@mrdoob
Copy link
Owner

mrdoob commented Nov 7, 2016

The example I mentioned uses MeshPhongMaterial and normalMap. If that one renders fine then we need to find what's the actual reason the glitches appear.

@gauravrane
Copy link
Author

I am using MeshPhongMaterial with a normalMap for the render. How do we go about identifying the reason for the glitch ?

@mrdoob
Copy link
Owner

mrdoob commented Nov 7, 2016

Basically enabling/disabling things. Compare how is your code different from the one in the example

@gauravrane
Copy link
Author

At the moment, short of using a different format for loading my meshes, i cannot think of anything. Will still test and keep you updated. Currently I am using the Open3DGC for SEA3D loader for the extra compression.

@mrdoob
Copy link
Owner

mrdoob commented Nov 8, 2016

@sunag any ideas?

@sunag
Copy link
Collaborator

sunag commented Nov 8, 2016

@gauravrane You can send me the door in .sea with Normal Map for me to do some tests?

@gauravrane
Copy link
Author

Hi @sunag , here is the file with the normal map included. In the project i am not adding the map directly onto the object and exporting, instead applying a custom material at runtime. I tried using this object on the Adreno 330 with only the normal map exported from the SEA3d exporter but was getting the same results. One observation though, at a certain angle of the camera the flicker seems to disappear (ideally when the object and camera are almost in a straight line) but all other angles its still present. I am using Orbitcontrols for the camera controller.

L_Door_inside.zip

@sunag
Copy link
Collaborator

sunag commented Nov 9, 2016

Hi @gauravrane

I fix the problem in webgl_materials_texture_filters disabling antialiasing.
Another thing I noticed is some GPU not initializes webgl context with antialiasing enabled.

Fixed with antialiasing disabled

@gauravrane
Copy link
Author

@sunag @mrdoob disabling antialias also solves the issue with the fog distance. But it is a feature that will be required for the project. I have also tried the FXAA shader from the normalMap material example with the same results.
No luck with the texture filter example for me, though on an Adreno 330 it flickers and settles because the movement of the camera stops. On an Adreno 305/306 the flicker continues for a while.

@gauravrane
Copy link
Author

Hi guys, there has been no solution to this yet. Is there an alternate shader you could point me to, for use instead of phong, i'm very bad with shader programming. I am assuming that the main fix here will be changing the normal part of the shader.

@mrdoob
Copy link
Owner

mrdoob commented Nov 13, 2016

Sounds like for those GPUs Chrome will have to force-disable antialias...

@gauravrane
Copy link
Author

gauravrane commented Nov 13, 2016

But the normal map flicker still persists.
The only workaround at the moment is using a custom shader. Working toward that.

@bhouston
Copy link
Contributor

This is a duplicate of this bug: #9515 There is basically an issue with the physical shader somewhere.

@mrdoob
Copy link
Owner

mrdoob commented Jan 19, 2017

Seems to be kind of resolution dependent...
Setting renderer.setPixelRatio( 1 ) reduces the glitch (Nexus 5 devicePixelRatio is 3).

@gauravrane
Copy link
Author

gauravrane commented May 22, 2017

Hey guys, as an update for a quick workaround i implemented normal calculation from the ShaderSkin file. It does not give accurate per pixel mapping, but it gets the job done for me.
If anyone is interested then here is the perturbNormal2Arb function
normal = perturbNormal2Arb( -vViewPosition );

	vec3 perturbNormal2Arb( vec3 eye_pos ) 
	{

		vec4 posAndU = vec4( -eye_pos, vUv.x );
		vec4 posAndU_dx = dFdx( posAndU ),  posAndU_dy = dFdy( posAndU );
		vec3 tangent = posAndU_dx.w * posAndU_dx.xyz + posAndU_dy.w * posAndU_dy.xyz;
		tangent += 0.00000001;
		vec3 thenormal = normalize( vNormal );
		vec3 binormal = normalize( cross( tangent, thenormal ) );
		tangent = cross( thenormal, binormal );
		mat3 tsb = mat3( tangent, binormal, thenormal );

		vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
		mapN.xy = normalScale * mapN.xy;
		mapN = normalize(mapN);

		return normalize( tsb * mapN );
	}

@gauravrane
Copy link
Author

@mrdoob should we say that the per pixel tangent space calculation is causing the flicker and close this with the alternate solution ? Or is there another workaround expected based on observations.

@mrdoob
Copy link
Owner

mrdoob commented May 22, 2017

@gauravrane do you have a test link with and without your code that we can test?

@gauravrane
Copy link
Author

gauravrane commented May 24, 2017

@mrdoob here are the links

http://carconfigurator.in/test/brezza/r84.html - With the original r84
http://carconfigurator.in/test/brezza/r84_edited.html - With the above edited normal code.

Also attaching some screenshots, tested on a Nexus 5 (Adreno 330, android 7.1.1) One Plus X (Adreno 330, android 6.0.1) and Moto G3 (Adreno 306, android 6.0.1)

1
2

Strangely though where i am using a repeatable texture the issue does not come up with the unedited version.

3

@mrdoob
Copy link
Owner

mrdoob commented May 25, 2017

As a recap...

You've replaced normalmap_pars_fragment.glsl perturbNormal2Arb():

vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {

	vec3 q0 = dFdx( eye_pos.xyz );
	vec3 q1 = dFdy( eye_pos.xyz );
	vec2 st0 = dFdx( vUv.st );
	vec2 st1 = dFdy( vUv.st );

	vec3 S = normalize( q0 * st1.t - q1 * st0.t );
	vec3 T = normalize( -q0 * st1.s + q1 * st0.s );
	vec3 N = normalize( surf_norm );

	vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
	mapN.xy = normalScale * mapN.xy;
	mat3 tsn = mat3( S, T, N );
	return normalize( tsn * mapN );

}

With this code from ShaderSkin.js:

// normal mapping

"vec4 posAndU = vec4( -vViewPosition, vUv.x );",
"vec4 posAndU_dx = dFdx( posAndU ),  posAndU_dy = dFdy( posAndU );",
"vec3 tangent = posAndU_dx.w * posAndU_dx.xyz + posAndU_dy.w * posAndU_dy.xyz;",
"vec3 normal = normalize( vNormal );",
"vec3 binormal = normalize( cross( tangent, normal ) );",
"tangent = cross( normal, binormal );",	// no normalization required
"mat3 tsb = mat3( tangent, binormal, normal );",

"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
"normalTex.xy *= uNormalScale;",
"normalTex = normalize( normalTex );",

"vec3 finalNormal = tsb * normalTex;",
"normal = normalize( finalNormal );",

With some modifications though:

vec3 perturbNormal2Arb( vec3 eye_pos ) 
{

	vec4 posAndU = vec4( -eye_pos, vUv.x );
	vec4 posAndU_dx = dFdx( posAndU ),  posAndU_dy = dFdy( posAndU );
	vec3 tangent = posAndU_dx.w * posAndU_dx.xyz + posAndU_dy.w * posAndU_dy.xyz;
	tangent += 0.00000001;
	vec3 thenormal = normalize( vNormal );
	vec3 binormal = normalize( cross( tangent, thenormal ) );
	tangent = cross( thenormal, binormal );
	mat3 tsb = mat3( tangent, binormal, thenormal );

	vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
	mapN.xy = normalScale * mapN.xy;
	mapN = normalize(mapN);

	return normalize( tsb * mapN );
}

However, if texture.wrapS and(?) texture.wrapT are set to THREE.RepeatWrapping the existing code doesn't produce artifacts on these devices.

Correct?

@mrdoob
Copy link
Owner

mrdoob commented May 25, 2017

Reminds me that we have this work-around in normal_fragment.glsl

	// Workaround for Adreno/Nexus5 not able able to do dFdx( vViewPosition ) ...

	vec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );
	vec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );
	vec3 normal = normalize( cross( fdx, fdy ) );

Could you try this code on those devices?

vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {

	vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );
	vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );
	vec2 st0 = vec2( dFdx( vUv.s ), dFdx( vUv.t ) );
	vec2 st1 = vec2( dFdy( vUv.s ), dFdy( vUv.t ) );

	vec3 S = normalize( q0 * st1.t - q1 * st0.t );
	vec3 T = normalize( -q0 * st1.s + q1 * st0.s );
	vec3 N = normalize( surf_norm );

	vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
	mapN.xy = normalScale * mapN.xy;
	mat3 tsn = mat3( S, T, N );
	return normalize( tsn * mapN );

}

@mrdoob
Copy link
Owner

mrdoob commented May 25, 2017

My suspicion is that Adreno has issues with dFdx and dFdy used on vec3, but the problem doesn't apply with float, vec2 and vec4.

So maybe we can avoid the st0 and st1 changes:

vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {

	vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );
	vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );
	vec2 st0 = dFdx( vUv.st );
	vec2 st1 = dFdy( vUv.st );

	vec3 S = normalize( q0 * st1.t - q1 * st0.t );
	vec3 T = normalize( -q0 * st1.s + q1 * st0.s );
	vec3 N = normalize( surf_norm );

	vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
	mapN.xy = normalScale * mapN.xy;
	mat3 tsn = mat3( S, T, N );
	return normalize( tsn * mapN );

}

@gauravrane
Copy link
Author

gauravrane commented May 25, 2017

@mrdoob Yes, you're right. That was the issue, the above code works perfectly, just one thing needs to get added to it is the line
st0 += 0.0000001;
which is a quick fix for a UV problem, solution from #8901

The artifacts are obvious and worse on mobile devices.
accuracy

@mrdoob
Copy link
Owner

mrdoob commented May 25, 2017

@mrdoob Yes, you're right. That was the issue, the above code works perfectly, just one thing needs to get added to it is the line
st0 += 0.0000001;

Does that only happen when texture.wrapS and/or texture.wrapT are set to THREE.RepeatWrapping?

@mrdoob
Copy link
Owner

mrdoob commented May 25, 2017

@gauravrane I think you should be able to achieve the same doing something like this:

texture.offset.set( 0.001, 0.001 );
texture.repeat.set( 0.998, 0.998 );

@mrdoob
Copy link
Owner

mrdoob commented May 25, 2017

Done! I've also added it to bumpmap_pars_fragment.glsl

screenshot_20170525-232627 screenshot_20170525-232620

@mrdoob mrdoob closed this as completed May 25, 2017
@mrdoob
Copy link
Owner

mrdoob commented May 25, 2017

By the way, I've looked into these artifacts too...

screenshot_20170525-232627

They have nothing to do with the Adreno bug, it's just an issue with 2 planes being too close to each other and the mobile not having enough precision on the z buffer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants