#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
Если я добавлю текстуру с прозрачностью на плоскости и прокомментирую строку _mat.SetTexture("_MainTex", _paintTex);
, прозрачность будет работать (но часть рисования, очевидно, не работает :)) Android поддерживает материал на плоскости.
Поэтому я указал на ошибку в RenderTexture, и я подозреваю, что Blit, потому что я читал, что с этим есть проблема на Android, и добавление ZTest Always
в мой шейдер должно решить ее, но это ничего не меняет. Я провел свой день в поисках ответов, но не смог их найти, и мне нужно использовать 2019.4 для этого проекта.
Ответ №1:
Похоже, что добавление _paintTex.Create();
решило мою проблему. Я все еще не понимаю, почему он работал в редакторе, но не на Android. Возможно, текстура рендеринга не создается автоматически на Android.