Графика.Blit(), похоже, плохо сочетается с моим пользовательским шейдером в сборке Android

#unity3d #shader

#unity3d #шейдер

Вопрос:

У меня есть простой проект в 2019.4.14f1, который очень хорошо работает в редакторе, но не работает, когда я создаю и запускаю для Android.

Я пытаюсь «рисовать» на прозрачной плоскости. Для этого я использовал шейдер, который берет текстуру и печатает другую текстуру в некоторых координатах. Шейдер не применяется к плоскости, но я использую его с 2 Blit() для обновления текстуры плоскости.

Ошибка, которую я получаю, заключается в том, что в редакторе альфа кажется нормальной, но на Android плоскость черная, а текстура, которую я рисую, не имеет плавного края.

На плоскости материал, который я использую, неосвещен / прозрачен, и я меняю его на _MainTex.

Шейдер DrawPaint.shader :

 Shader "Unlit/DrawPaint"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _Coordinates("BrushCoordinates", Vector) = (0,0,0,0)
        _Color("BrushColor", Color) = (0,0,0,0)
        _SizeX("BrushSizeX", Float) = 50
        _SizeY("BrushSizeY", Float) = 50
        _BrushTex("BrushTex", 2D) = "white" {}
        _Strength("Strength", Float) = 1
    }
        SubShader
        {
            Tags {"RenderType"="Transparent" }
            LOD 100

            Pass
            {
                CGPROGRAM
                #pragma vertex vert 
                #pragma fragment frag
                #pragma target 2.0

                #include "UnityCG.cginc"

                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };

                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    float4 vertex : SV_POSITION;
                };

                sampler2D _MainTex, _BrushTex;
                float4 _MainTex_ST;
                fixed4 _Color, _Coordinates;
                float _Strength, _SizeX, _SizeY;

                v2f vert(appdata v)
                {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    return o;
                }

                fixed4 frag(v2f i) : SV_Target
                {
                    half4 col = tex2D(_MainTex, i.uv);
                    half2 diff = _Coordinates.xy - i.uv;
                    half2 scaledDiff = diff * half2(_SizeX,_SizeY);
                    if (abs(scaledDiff.x) < 0.5 amp;amp; abs(scaledDiff.y) < 0.5)
                    {
                        half4 texVal = tex2D(_BrushTex, scaledDiff   half2(0.5, 0.5));
                        return saturate(texVal.w > 0.01 ? _Color * texVal * _Strength   col : col);
                    }
                    else
                    {
                        return col;
                    }
                }
                ENDCG
            }
        }
}
 

И сценарий, который находится на плоскости :

 public class DrawableSurface : MonoBehaviour
{
    [SerializeField]
    private Shader _drawShader;

    [SerializeField]
    private Texture2D _brushTex;

    private RenderTexture _paintTex;
    private Material _mat, _drawMat;

    [SerializeField]
    private float startSize = 8f;

    private void Awake() 
    {

        _drawMat = new Material(_drawShader);
        _drawMat.SetColor("_Color", Color.red);
        _drawMat.SetFloat("_SizeX", startSize);
        _drawMat.SetFloat("_SizeY", startSize);
        _drawMat.SetFloat("_Strength", 0.1f);
        _drawMat.SetTexture("_MainTex", Texture2D.whiteTexture);
        _drawMat.SetTexture("_BrushTex", _brushTex);

        _mat = GetComponent<MeshRenderer>().material;
        _paintTex = new RenderTexture(1024, 1024, 0);
        _mat.SetTexture("_MainTex", _paintTex);
    }

    public void OnHit(Vector2 texCoord)
    {
        Debug.Log("Hit at "   texCoord);
        _drawMat.SetVector("_Coordinates", new Vector4(texCoord.x, texCoord.y, 0, 0));
        RenderTexture tmp = RenderTexture.GetTemporary(_paintTex.width, _paintTex.height, 0);
        Graphics.Blit(_paintTex, tmp);
        Graphics.Blit(tmp, _paintTex, _drawMat);
        RenderTexture.ReleaseTemporary(tmp);
    }
}
 

Затем я просто передаю raycast с Physics.Raycast помощью and screenPointToRay и передаю hit.texCoord

В редакторе :
В редакторе все выглядит идеально

На Android :
На Android фон черный, а альфа-версия, похоже, не работает

Если я добавлю текстуру с прозрачностью на плоскости и прокомментирую строку _mat.SetTexture("_MainTex", _paintTex); , прозрачность будет работать (но часть рисования, очевидно, не работает :)) Android поддерживает материал на плоскости.

Поэтому я указал на ошибку в RenderTexture, и я подозреваю, что Blit, потому что я читал, что с этим есть проблема на Android, и добавление ZTest Always в мой шейдер должно решить ее, но это ничего не меняет. Я провел свой день в поисках ответов, но не смог их найти, и мне нужно использовать 2019.4 для этого проекта.

Ответ №1:

Похоже, что добавление _paintTex.Create(); решило мою проблему. Я все еще не понимаю, почему он работал в редакторе, но не на Android. Возможно, текстура рендеринга не создается автоматически на Android.