Modify some texture pixels in fragment function

Greetings,

Now I have a camera moving over a mesh and what I’m trying to do is painting the area covered by this camera (between the 4 frustrum corners).

I’ve been able to create a runtime Texture2D in a projector, get that texture, get the UV coordinates corresponding to the four frustrum corners hit points and modifying all pixels of my texture with SetPixels32().
This works “fine”, I move the camera and it leaves a rectangular spot on the mesh according to the area covered which I can show/hide just by activating the projector. The problem is that this code makes graphics performance to fall every time it executes texture.Apply().

What I’m looking for is the SetPixels32() sentence needed to modify these same texture pixels inside a fragment shader. The CG code needed to take this sampler2D _ProjectedTexture and modify its pixels in the fragment function of a shader.

Thanks in advance.

I’ve taken the basic Unlit shader from this page: Vertex and fragment shader examples

and added some functionality to it. Namely, you specify min and max uv values and a color and if a pixel is inside the uv values, it is rendered in the specified color. You could possibly optimize this by combing the uv properties into float2 or float4, but I’m not sure how that would work with the PropertyBlock code below.

Disclaimer: I didn’t test this.

Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _UVMin_x("UV Min_x", float) = 0
        _UVMin_y("UV Min_y", float) = 0
        _UVMax_x("UV Max_x", float) = 0
        _UVMax_y("UV Max_y", float) = 0
        _ProjectorColor("Projector Color", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _UVMin_x;
            float _UVMin_y;
            float _UVMax_x;
            float _UVMax_y;
            fixed4 _ProjectorColor;
            
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                if(i.uv.x >= _UVMin_x && i.uv.y >= _UVMin_y && i.uv.y <= _UVMax_x && i.uv.y <= _UVMax_y) 
                {
                       col = _ProjectorColor;
                }
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

To access these added variables, you need to include a function like this in a script:

Renderer myRenderer

void UpdateOutline(Color color, Vector2 uv_min, Vector2 uv_max, ) {
        MaterialPropertyBlock mpb = new MaterialPropertyBlock();
        if (myRenderer!= null) {
            myRenderer.GetPropertyBlock(mpb);
            mpb.SetFloat("_UVMin_x", uv_min.x);
            mpb.SetFloat("_UVMin_y", uv_min.y);
            mpb.SetFloat("_UVMax_x", uv_max.x);
            mpb.SetFloat("_UVMax_y", uv_max.y);
            mpb.SetColor("_ProjectorColor", color);
            myRenderer.SetPropertyBlock(mpb);
        }
    }