Search Unity

Shader works in Editor but not in build

Discussion in 'Shaders' started by tteneder, Jan 20, 2020.

  1. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    Hi,

    I'd be super happy if someone can point me to where I can investigate further on this topic.

    I've created a shader(s) that are altered copies of the Unity Standard shader with this changes:
    • double-sided (every pass, like forward-base, forward-add, has a duplicate with front-face-culling and normals/tangents inverted)
    • roughness instead of smoothness
    • different channel mapping (occlusion/roughness/metallic textures, just like in glTF 2.0 standard)

    It works fine in the Editor, but in builds it looks like certain features/maps (like normal or roughness maps) are turned off.

    A demo-material on two planes works fine in the editor. Left is front-facing and right is back facing:



    Screenshot 2020-01-20 at 10.48.47.png
    In a build, only the back-facing part works. The front facing passes miss normal, occlusion, roughness, metallic maps.
    build.png
    I'm using Unity 2019.2.f18
    Behaviour is consistent throughout platforms (iOS, Android, mac) and rendering backends (Metal/OpenGL).

    Current sources are here:
    https://github.com/atteneder/glTFast/tree/normal_map_fix/Runtime/Shader

    The object is static in scene, so I think I can exclude missing shader variants. I looked up the logs and find no error whatsoever.

    My gut says, maybe I exceed some kind of instruction/parameter limit, but how can I be sure?

    Thanks in advance for giving me ideas,
    atti

    P.S.:
    I'm willing to file a report with a minimal demo project, but I'd like to see if someone can point it out faster.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    UsePass
    is ... funny. I suspect the issue is at build time Unity isn't properly marking all of the appropriate variants from the "front pass" version of the shader that you're referencing via
    UsePass
    . I would say this is a bug, but I also wouldn't expect Unity to fix it any time soon, if ever.
    UsePass
    is very rarely used these days by Unity themselves. You could fix it by making sure your Shader Variant Collection has the necessary variants for both the single sided and double sided versions of the shader.


    The other thing is it isn't really necessary to have two versions of the shader. A single shader can handle single and double sided rendering without too much work. Certainly less than you're already doing to handle the smoothness -> roughness swap already.

    The trick is using the
    VFACE
    semantic.
    VFACE
    is a fragment shader input that is a 1.0 if it's the front face, -1.0 if it's the back face.
    Code (csharp):
    1. // modify your top level fragment functions like this
    2. half4 fragBase (VertexOutputForwardBase i, half facing : VFACE) : SV_Target { // etc
    From there you can either flip the tangent space normal after it's been sampled from the texture, or you can flip the values in the tangentToWorld matrix.
    Code (csharp):
    1. i.tangentToWorldAndPackedData[2].xyz *= facing;
    Just do that all of the time. It's inexpensive enough it doesn't really matter if you're doing it on non-double sided materials. Then just use that
    _DoubleSided
    parameter you already have, though I might suggest using this instead:
    Code (csharp):
    1. // will show a dropdown with Off, Front and Back as options.
    2. [Enum(UnityEngine.Rendering.CullMode)] _CullMode ("Cull Mode", Float) = 2.0
     
    morepixels and tteneder like this.
  3. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    sounds very good. I'll try to test it asap, latest next week.
    thanks!
     
  4. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    Hi again,

    your tips turned out to be worth gold! :)

    One thing is unclear to me though. The normal map resembles an outwards/convex half-sphere, the red light (directional) points to the right side and the blue light points downwards. Looking at the highlights of the left side quad (which is the front-facing one), this makes sense to me.

    On the back-facing quad (on the right side) I'd expect the normal map to "point inwards" (resembling a concave half-sphere). Therfore the colored highlights should appear on the opposite sides (red: right; blue: bottom). My original shader did that.

    Screenshot 2020-01-29 at 22.58.57.png


    I naively tried multiplying all tangentToWorld matrix factors by -1 and got the desired effect:

    Screenshot 2020-01-29 at 23.08.26.png


    here's the code:
    Code (csharp):
    1. half4 fragAddFacing (VertexOutputForwardAdd i, half facing : VFACE) : SV_Target {
    2. #ifdef _TANGENT_TO_WORLD
    3.         i.tangentToWorldAndLightDir[0].xyz *= facing;
    4.         i.tangentToWorldAndLightDir[1].xyz *= facing;
    5.         i.tangentToWorldAndLightDir[2].xyz *= facing;
    6. #else
    7.         i.tangentToWorldAndLightDir[2].xyz *= facing;
    8. #endif
    9.         return fragAdd(i);
    10.     }
    Visually this seems good, but I'm not sure if/why the math is correct.
    Any clue before I dig into linear algebra books?

    thanks!
     
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    Nope, that's perfect.

    Usually I handle it by modifying the tangent space normal rather than the tangent to world matrix itself, but it's totally fine to do it this way too for the most part. The one danger is if you're doing anything else in tangent space, like parallax mapping techniques (like when using a height map in the Standard Shader), then modifying the matrix might not be what you want to do.
     
    tteneder likes this.
  6. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175
    Oh, great! :)

    Seems to work in builds as well now!

    I'd like to mention your contribution in the release log/changelog of that project. Let me know if that's cool and if you want more/something else than just your nick name "bgolus".

    Thank you very, very much!
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,342
    You're welcome, and you have permission to mention me in the change log. You can put my real name Ben Golus if you feel fancy, otherwise the nickname "bgolus" is fairly universally me anyway.
     
  8. tteneder

    tteneder

    Unity Technologies

    Joined:
    Feb 22, 2011
    Posts:
    175