Vertex shader breaks render to texture - camera preview and render texture not the same

Hi all,

This is my first question here so apologies if the formatting is a bit off. I’m using Unity 5.0.1 Personal.

Issue:

I’ve written a shader (see below) that should take all fragments within view of the camera and using the associated UV coordinates set the relevant pixels in a render texture to red. When my camera is selected in scene view, the camera preview shows exactly what I would expect - a red patch corresponding to the UV coordinates of fragments within view of the camera. However, the render texture attached to this camera does not contain this red patch, i.e. the camera preview and render texture do not match.

Here is a screenshot from my scene, the camera is rendering into a texture which is applied to the plane, the camera preview is correct however the render texture is not.

I have attached a [45584-shadererrorminproject.zip|45584] and my shader is below. Does anyone have any ideas why this might be happening?

Shader:

Shader "Custom/PaintShader" {
    SubShader {
        Pass {
        	Lighting Off
        	Blend SrcAlpha OneMinusSrcAlpha
                        
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

            struct vertOut {
                float4 pos:SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 norm : TEXCOORD1;
                float4 scrPos : TEXCOORD2; 
            };

            vertOut vert(appdata_base v) {
                vertOut o;
                o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
                o.norm = mul (UNITY_MATRIX_MVP, v.normal);
                o.scrPos = ComputeScreenPos(o.pos);
                o.uv = v.texcoord.xy;
                // Map UV coordinate to clip space and move vertex to this position
                o.pos.xy = v.texcoord.xy*2.0-1.0;
                return o;
            }
            
            fixed4 frag(vertOut i) : SV_Target {
            	float2 wcoord = (i.scrPos.xy/i.scrPos.w);
            	// Need to manually do frustum and back face culling
            	if( any(wcoord.xy<0) || any(wcoord.xy>1) || i.norm.z>=-0.01 ){
            		discard; // TODO: Use lerp instead of discard due to expense on mobile
            	}
                return fixed4(1.0,0.0,0.0,1.0);
            }
            
            ENDCG
        }
    }
}

Extra info:

I’m trying to create a toolset that will allow the user to interactively paint a mesh. The shader above is the starting point of being able to apply textures and colours to a model in real time. I’m using custom shaders and render textures instead of SetPixels() for speed. Hopefully someone can point me in the right direction.

All the best,
Rich

It turns out that I just needed to disable face culling, thinking about it this makes a lot of sense seeing as I’m messing with vertex coordinates! I’m still a bit puzzled as to why the camera preview should ever be different from the render texture though, are there any render texture gurus with thoughts on this?

Here’s the working shader, I’ve also added the ability to specify a brush texture and colour through the shader properties:

Shader "Custom/PaintShader" {

	Properties {
		_BrushTexture ("Brush Texture", 2D) = "white" {} 
		_BrushColor ("Brush Color", Color) = (1,1,1,1) 
	}

    SubShader {
        Pass {
        	Lighting Off
        	Cull Off
        	Blend SrcAlpha OneMinusSrcAlpha
                        
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"
            
			sampler2D _BrushTexture;
			fixed4 _BrushColor;
			
            struct vertOut {
                float4 pos : POSITION;
                float3 norm : TEXCOORD1;
                float4 scrPos : TEXCOORD2; 
            };

            vertOut vert(appdata_base v) {
                vertOut o;
                o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
                o.norm = mul (UNITY_MATRIX_MVP, v.normal);
                o.scrPos = ComputeScreenPos(o.pos);            
                o.pos.xy = (v.texcoord.xy*2-1)*o.pos.w;
                return o;
            }
            
            fixed4 frag(vertOut i) : SV_Target {
            	float2 wcoord = (i.scrPos.xy/i.scrPos.w);
            	fixed4 brushTexture = tex2D (_BrushTexture, wcoord.xy);
            	// Need to manually do frustum and back face culling
            	if( any(wcoord.xy<0) || any(wcoord.xy>1) || i.norm.z>=-0.01){
            		discard; // TODO: Use lerp instead of discard due to expense on mobile
            	}
                return fixed4(_BrushColor.rgb,brushTexture.a);
            }
            
            ENDCG
        }
    }
}

And here’s a screenshot of me using the shader to interactively paint onto a plane: