Проблема прозрачности мобильных шейдеров Unity3d
Мой 3D-объект перекрывается с альфа-каналом при использовании пользовательского шейдера в Unity3D (версия без подсветки):
Это должно выглядеть примерно так:
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 ответ
- Шейдер не горит, потому что вместо шейдера Surface вы используете обычный CG-шейдер, целью которого является удобное обеспечение освещения за сценой. Решение: начать заново с шаблона шейдера поверхности
- Альфа-смешение не используется, так как
(col.a < _Cutoff)
всегда либо true, либо false без промежуточных значений, оно всегда полностью отображается или полностью скрыто. Кроме того, то, как вы пишете это условие, вероятно, генерирует некоторое динамическое ветвление в шейдере, вместо этого попробуйте статическое ветвлениеfloat newOpacity = (col.a < _Cutoff) ? 0.0 : 1.0;
(в этом случае исполняемый код всегда один и тот же, меняется только значение, что обычно намного лучше для перфораторов). - У шейдера есть 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);