Проблема прозрачности мобильных шейдеров Unity3d - PullRequest
0 голосов
/ 06 июня 2018

Мой 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
     }
    }
   }

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

Редактировать 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 Ответ

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

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

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

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

...