Проблема прозрачности мобильных шейдеров Unity3d

Мой 3D-объект перекрывается с альфа-каналом при использовании пользовательского шейдера в Unity3D (версия без подсветки):

Screenshot1

Это должно выглядеть примерно так:

screenshot2

Shader "Custom/Shader1" {
    Properties {
     _Color ("Main Color", Color) = (1,1,1,1)
     _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
     _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
    }

    SubShader {
     Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
     Pass {
         ZWrite On
         ColorMask 0
     }
     Pass {
      ZWrite Off // don't write to depth buffer 
      Blend SrcAlpha OneMinusSrcAlpha // use alpha blending
      CGPROGRAM

      #pragma vertex vert
      #pragma fragment frag

      uniform float4 _Color; // define shader property for shaders
      uniform sampler2D _MainTex;
      uniform float _Cutoff;

      struct vertexInput {
       float4 vertex : POSITION;
       float2 texcoord : TEXCOORD0;
      };
      struct vertexOutput {
       float4 pos : SV_POSITION;
       float2 tex : TEXCOORD0;
      };

      vertexOutput vert(vertexInput input) {
       vertexOutput output;

       output.tex = input.texcoord;
       output.pos = UnityObjectToClipPos(input.vertex);
       return output;
      }

      float4 frag(vertexOutput input) : COLOR {
       float4 col = tex2D(_MainTex, input.tex) * _Color;    
       float newOpacity = 1.0;
       if (col.a < _Cutoff) {
         newOpacity = 0.0;
       }
       return float4(col.r, col.g, col.b, newOpacity);
      }
      ENDCG
     }
    }
   }

Я что-то пропустил? Кажется, что прозрачность альфа перекрывает себя.

Edit 1 Я удалил первый проход, затем включил Zbuffer и удалил if (col.a < _Cutoff) и пусть он будет динамичным в соответствии с его текстурой, но я все равно получаю тот же результат, что и 1-е изображение.

Shader "Custom/Shader1" {
    Properties {
     _Color ("Main Color", Color) = (1,1,1,1)
     _MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
     _Cutoff ("Alpha cutoff", Range(0,1)) = 0.5
    }

    SubShader {
     Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
     Pass {
      ZWrite On
      Blend SrcAlpha OneMinusSrcAlpha // use alpha blending
      CGPROGRAM

      #pragma vertex vert
      #pragma fragment frag

      uniform float4 _Color; // define shader property for shaders
      uniform sampler2D _MainTex;
      uniform float _Cutoff;

      struct vertexInput {
       float4 vertex : POSITION;
       float2 texcoord : TEXCOORD0;
      };
      struct vertexOutput {
       float4 pos : SV_POSITION;
       float2 tex : TEXCOORD0;
      };

      vertexOutput vert(vertexInput input) {
       vertexOutput output;

       output.tex = input.texcoord;
       output.pos = UnityObjectToClipPos(input.vertex);
       return output;
      }

      float4 frag(vertexOutput input) : COLOR {
       float4 col = tex2D(_MainTex, input.tex) * _Color;    
       return col;
      }
      ENDCG
     }
    }
   }

1 ответ

  1. Шейдер не горит, потому что вместо шейдера Surface вы используете обычный CG-шейдер, целью которого является удобное обеспечение освещения за сценой. Решение: начать заново с шаблона шейдера поверхности
  2. Альфа-смешение не используется, так как (col.a < _Cutoff) всегда либо true, либо false без промежуточных значений, оно всегда полностью отображается или полностью скрыто. Кроме того, то, как вы пишете это условие, вероятно, генерирует некоторое динамическое ветвление в шейдере, вместо этого попробуйте статическое ветвление float newOpacity = (col.a < _Cutoff) ? 0.0 : 1.0; (в этом случае исполняемый код всегда один и тот же, меняется только значение, что обычно намного лучше для перфораторов).
  3. У шейдера есть 2 прохода, что предотвратит последующее пакетирование, что очень плохо для производительности. Один заполняет Zbuffer, а другой выполняет альфа-смешивание (2 операции, которые на самом деле не совместимы). Препасс не работает должным образом, потому что он заполняет буфер необработанной сеткой, не имея информации о прозрачности, исходящей из текстуры. Конечно, вы можете изменить первый проход, чтобы сделать это, но результат, который вы ищете, по сути, является просто очень простым шейдером Surface с включенным альфа-тестированием.

Вы можете прочитать о семантике, предоставляемой Unity для управления альфа-тестированием в шейдерах Surface, здесь: https://docs.unity3d.com/Manual/SL-SurfaceShaders.html, в частности, эта часть:

alphatest: VariableName - Включить прозрачность альфа-выреза. Значение отсечения находится в переменной с плавающей точкой с VariableName. Вы, вероятно, также захотите использовать директиву addhadow для генерации правильного прохода заклинателя теней.

в качестве альтернативы вы можете использовать метод clip() в сочетании с addhadow, скорее всего, в соответствии с clip(col.a - 0.5);

Другие вопросы по тегам