Search Unity

Resolved Strange flicker glitch on vertex color shader

Discussion in 'General Graphics' started by KayH, Jul 9, 2021.

  1. KayH

    KayH

    Joined:
    Jan 6, 2017
    Posts:
    110
    Not sure what is causing this, could be a shader issue, lighting, something else. So I'm putting it in general.



    I thought it might be missing lightmap UVs. Manually added them, no change.

    The shader:


    Shader "Custom/VertexColorSurface"
    {
    Properties
    {
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
    _Glossiness ("Smoothness", Range(0,1)) = 0.5
    _Metallic ("Metallic", Range(0,1)) = 0.0
    [KeywordEnum(Lambert, Standard)] _Lighting("Lighting", Float) = 0.0
    }

    SubShader
    {
    Tags { "RenderType" = "Opaque" }
    LOD 200

    CGPROGRAM

    #if defined(_LIGHTING_STANDARD)
    #pragma surface surf Standard fullforwardshadows noforwardadd vertex:vert
    #elif defined(_LIGHTING_LAMBERT)
    #pragma surface surf Lambert fullforwardshadows noforwardadd vertex:vert
    #endif

    // Use shader model 3.0 target, to get nicer looking lighting
    #pragma target 3.0

    sampler2D _MainTex;

    struct Input
    {
    float2 uv_MainTex;
    fixed4 color;
    };

    half _Glossiness;
    half _Metallic;

    // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    // #pragma instancing_options assumeuniformscaling
    UNITY_INSTANCING_BUFFER_START(Props)
    // put more per-instance properties here
    UNITY_INSTANCING_BUFFER_END(Props)

    void vert(inout appdata_full v, out Input o) {
    UNITY_INITIALIZE_OUTPUT(Input, o);
    o.color = v.color;
    o.uv_MainTex = v.texcoord;
    }
    void surf (Input IN, inout SurfaceOutputStandard o)
    {
    // Albedo comes from a texture tinted by color
    fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * IN.color;
    o.Albedo = c.rgb;
    // Metallic and smoothness come from slider variables
    o.Metallic = _Metallic;
    o.Smoothness = _Glossiness;
    o.Alpha = c.a;
    }
    ENDCG
    }
    FallBack "Diffuse"
    }



    My settings in the editor:

    go.jpg
    mesh.jpg
    Problem occurs both for a large mesh combining several smaller and the individual meshes. Here's one as an example.
    mesh_single.jpg

    I tried unchecking contribute global illumination, no change. The problem doesn't always occur, seems to relate to the angle of my directional light. Almost always at evening/night, when the light shines from the side/below. Had it during the day as well.

    I use the same material, with very similar mesh renderer settings, on other game objects and I don't get the glitch there. Trying to change the few setting that are different according to the non-glitching object doesn't help.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    Yeah ... you can't do that. It's going to ignore those
    #if
    conditions and always render both the standard and lambert passes at the same time. Also
    fullforwardshadows
    only does anything if you don't also have
    noforwardadd
    as it allows the forward add pass to receive shadows.
     
  3. KayH

    KayH

    Joined:
    Jan 6, 2017
    Posts:
    110
    So basically I was (almost) doubling my shader rendering workload? The idea was to enable different lighting quality and GPU workload based on device. An alternative might be to have two different shaders and materials that need to be assigned based on hardware.

    I removed this if block and defaulted to Standard lighting and also removed the noforwardadd. But the problem persists, it seems the flicker is caused by something else.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    This is what using multiple
    SubShader
    s is for. You can either define a specific
    #pragma target
    to have it auto select based on the abilities of the GPU, or assign an explicit
    LOD
    to select from code.
    https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
    https://docs.unity3d.com/Manual/SL-ShaderLOD.html

    Unity's built in Standard shader also already does this and automatically switches to lower quality versions based on the device's abilities.

    Then my next guess is this particular mesh has doubled up vertices. My quick guesstimate for how many vertices that bottle should have came to about 140, assuming you don't have the interior of the bottle modelled.

    You might also try the Frame Debugger to see if there's something rendering that mesh more than once.
     
  5. KayH

    KayH

    Joined:
    Jan 6, 2017
    Posts:
    110
    Okay so the right way to implement such a switch is to use LOD, noted.

    Your guess that the mesh is rendered more than once was true. I've been using this picnic for a long time but the flicker bug is fairly recent. So it was caused by a recent change.

    I had been disabling whole parent transforms of non visible areas but recently changed that to just disabling the mesh renderers contained in those transforms. Problem was, on enabling them, both the renderers of the single meshes and the combined mesh became active, rendering the geometry twice. I didn't check on collecting all the contained renderers if they were enabled in the first place.

    I had kept the single meshes for their mesh colliders and because the combining didn't actually yield much of a performance gain (if at all). It seems on Quest rendering many meshes with the same material is nearly as fast as rendering a combined mesh in one draw call. So I'm still undecided which to use, combined or individual meshes. The latter has the advantage that out of view meshes don't need to be rendered at all whereas the combined mesh will have to discard each vertex of those parts in the vertex program (which still is quite quick).

    This also explains why it not always occured. The area the picnic is in had to be disabled once before both versions of the meshes would be enabled. So it only occurs when not starting the game in that area which I misassociated with different times of day/angles of the directional light. It was really just the order in which I arrived at the place the bug occurs though.