Search Unity

Question Drawing to a RenderTexture using a shader

Discussion in 'Shaders' started by eofirdavid, Sep 18, 2022.

  1. eofirdavid

    eofirdavid

    Joined:
    Jan 3, 2020
    Posts:
    4
    I am trying to draw simple shapes (lines, circles, rectangle etc) directly into an image and display it on screen. I don't want to use stuff like LineRenderer\circle\square sprites, since I am going to draw a lot of shapes, and I don't want a whole object with all of its overhead for each such line. Instead, I am trying to write shaders and apply them to a RenderTexture and view it instead.

    While I think that I understand what needs to happen, I am not familiar enough with how unity deals with textures and shaders to know what exactly I need to do. I have been searching for how to do it, and saw many similar such questions and answers, but it still doesn't fully work for me.

    What I currently have is:
    1. Showing the RenderTexture: I have a simple square sprite with a custom shader. This shader gets a second texture and displays it instead of the standard _MainTex. Is there a better way to do this?
    I also tried using RawImage, but while I can see the image in the inspector, it doesn't show in the scene or game tabs.

    2. Applying a shader to RenderTexture:
    Here I wrote a simple shader that, for example, adds a circle to the texture
    Code (CSharp):
    1. fixed4 frag (v2f i) : SV_Target
    2. {
    3.   float2 center = float2(_centerX, _centerY);
    4.   if (distance(i.uv, center)<_radius)
    5.     return _circleColor;
    6.   return tex2D(_MainTex, i.uv);
    7. }
    In the c# code I have

    Code (CSharp):
    1. public RenderTexture texture;
    2.  
    3. public void Initialize()
    4.     {
    5.         paintMaterial = new Material(Shader.Find("Drawing/CircleDrawing"));
    6.     }
    7.  
    8. public void Render()
    9.     {
    10.         paintMaterial.SetFloat("_radius", radius);
    11.         paintMaterial.SetFloat("_centerX", center.x);
    12.         paintMaterial.SetFloat("_centerY", center.y);
    13.         paintMaterial.SetColor("_circleColor", color);
    14.         Graphics.Blit(texture, texture, paintMaterial);
    15.     }
    This more of less works - everytime I call Render(), it fills up a circle where it should. The problem is that if I try to fill a second circle, it overrides the first. I think that it first paint all the texture in black and then calls the shader. I also saw that if I change the shader to only call
    return tex2D(_MainTex, i.uv);
    in the frag() function, I also get a black texture, even when the input texture was not black.

    I also read somewhere that I should not Blit a texture to itself, so I tried changing the Blit call to
    Code (CSharp):
    1. rt = new RenderTexture(texture);
    2. Graphics.Blit(rt, texture, paintMaterial);
    but it doesn't seem to help.

    Anyway, I would appreciate any help with solving this. Also in general, if there is a better method for doing something like that, namely drawing a lot of simple shapes directly to a texture, I would be happy to hear how to do it.