Rendering issue with normals and DoubleSided materials on some Adreno GPU series

Description of the problem

Hi, I’m working with a small team on implementing a THREE scene with glTF and PBR/IBL.
It all works great except when testing on specific mobile devices we’ve come across a weird rendering issue.

It is easily reproducable (though only on some hardware!) by opening the MeshStandardMaterial example and setting the material.side to THREE.DoubleSide.

Steps to reproduce:

  • Connect Android device using USB debugging and set up Chrome Remote Device Debugging
  • Navigate to the MeshStandardMaterial example
  • Switch to the viewer iframe in the console.
  • Setting the material to doublesided using scene.children[1].children[0].material.side = THREE.DoubleSide , scene.children[1].children[0].material.needsUpdate = true

The models will appear as follows:

Demo gun
The gun model from the examples

Our model
The model that caused the initial problem

Is there anything we can do to provide more info? Anything blatantly obvious we’ve overlooked? Thank you in advance.

Some things of note

  • Lighting the material using an envMap is required. Both LDR and HDR envMaps are affected.
  • The affected devices (as far as we were able to test!) have a Qualcomm Adreno 500 series GPU
  • When removing the normalMap, the material renders correctly (roughness, metallic) albeit without the normal map affecting the lighting 😉
Three.js version
  • Dev
  • r101
Browser
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • Windows
  • macOS
  • Linux
  • Android
  • iOS
Hardware Requirements (graphics card, VR Device, …)

Android Device with Qualcomm Snapdragon SOC with an Adreno 500 series GPU: We’ve tested on 505, 506 and 530

Author: Fantashit

3 thoughts on “Rendering issue with normals and DoubleSided materials on some Adreno GPU series

  1. @Mugen87 The OP is demonstrating DoubleSide is an issue here. We need to understand why DoubleSide causes a problem.

    @donmccurdy I wonder if the reintroduction of tangent support can be used to solve problems with low-precision mobile by avoiding the use of screen-space derivatives.

  2. Update here @WestLangley & @Mugen87

    Same issue here on r114Oneplus 7GPU Adreno 640Chrome 80.0.39MeshStandardMaterial

    Info:

    • I’m exporting from blender and I’m experiencing the same issue, when I disabled the normalMap everything starts working again.

    • I confirm that the bug comes from the doubleSide, if I set frontSide only everything works.

    • I tried to export with tangents enabled

    • I tried fixing with material.normalMapType = ObjectSpaceNormalMap, I get better result but far away from how it should be

    Temporary solution:

    BufferGeometryUtils.computeTangents(el.geometry)
    el.material.vertexTangents = true
    

    Hope this can help.

    Here a screenshot with on the left – FrontFace, and on the right a DoubleSide
    image

  3. @dghez We’re currently using that solution as well in production specifically targeting Adreno GPUs.

    var gpuHasFrontFacingDoubleSidedBug = false;
    var debugInfo = renderer.getContext().getExtension('WEBGL_debug_renderer_info');
    if (debugInfo !== null)
    {
        var gpu = renderer.getContext().getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
        gpuHasFrontFacingDoubleSidedBug = gpu.match(/adreno.+(5|6)[0-9][0-9]/gi) !== null;
    }
    
    scene.traverse(function(node)
    {
        if (node.material.side === THREE.DoubleSide && gpuHasFrontFacingDoubleSidedBug)
        {
            THREE.BufferGeometryUtils.computeTangents(node.geometry);
            node.material.vertexTangents = true;
            node.material.needsUpdate = true;
        }
    }
    

    Hope this helps!

Comments are closed.