Projector + custom fragment shader = endless texture draw

Hi there,

What I want to do is, using a Projector, draw a texture several times within a unit, creating a grid / matrix view (i.e. draw a grid of tiles below my player). My shader defines three properties: color, texture and grid size.

Here’re the results I’m getting (using grid size = 1 and grid size = 2 respectively):

14563-gridsize1.png
14564-gridsize2.png

They repeat properly within a unit (you see the capsule covering a 2x2 grid), but it keeps painting them forever in the direction you see in the screenshots.

Here’s the shader I’ve implemented.

Shader "Projector/Custom Grid" {

	Properties {
		_Color ("Color", Color) = (1,1,1,0)
		_ShadowTex ("Cookie", 2D) = "black" { TexGen ObjectLinear }
		_Size ("Grid Size", Float) = 1
	}
	
	Subshader {
		Tags { "RenderType"="Transparent" "Queue"="Transparent+100" }
		Pass {
			ZWrite Off
			Offset -1, -1
			Fog { Mode Off }
			ColorMask RGBA
			Blend SrcAlpha OneMinusSrcAlpha
			
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma fragmentoption ARB_fog_exp2
			#pragma fragmentoption ARB_precision_hint_fastest
			#include "UnityCG.cginc"
			 
			struct v2f {
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};
			 
			sampler2D _ShadowTex;
			float4 _ShadowTex_ST;
			float4 _Color;
			float4x4 _Projector;
			fixed _Size;
			 
			v2f vert (appdata_tan v) {
				v2f o;
				o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
				o.uv = TRANSFORM_TEX (mul (_Projector, v.vertex).xy, _ShadowTex);
				return o;
			}
			 
			half4 frag (v2f i) : COLOR {
				return tex2D (_ShadowTex, fmod (i.uv, 1 / _Size) * _Size) * _Color;
			}
			
			ENDCG
		}
	}
}

The issue seems to be generated at this line:

return tex2D (_ShadowTex, fmod (i.uv, 1 / _Size) * _Size) * _Color;

And specifically when applying fmod operation. If I don’t use fmod I don’t see the texture repeating over and over.

The texture is set to clamp, I’ve been reading a while about projectors and couldn’t find a solution to this. Any ideas?
Thanks.

Found a way to fix this. Basically I had not to write if I get outside UV (1,1)

Shader "Projector/Grid Test" {

	Properties {
		_Color ("Color", Color) = (1,1,1,0)
		_ShadowTex ("Cookie", 2D) = "black" { TexGen ObjectLinear }
		_Size ("Grid Size", Float) = 1
	}
	
	Subshader {
		Tags { "RenderType"="Transparent" "Queue"="Transparent+100" }
		Pass {
			ZWrite Off
			Offset -1, -1
			Fog { Mode Off }
			ColorMask RGB
			Blend SrcAlpha OneMinusSrcAlpha
			
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma fragmentoption ARB_fog_exp2
			#pragma fragmentoption ARB_precision_hint_fastest
			#include "UnityCG.cginc"
			 
			struct v2f {
				float4 pos : SV_POSITION;
				float2 uv : TEXCOORD0;
			};
			 
			uniform sampler2D _ShadowTex;
			float4 _ShadowTex_ST;
			float4 _Color;
			float4x4 _Projector;
			fixed _Size;
			 
			v2f vert (appdata_tan v) {
				v2f o;
				o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
				o.uv = TRANSFORM_TEX (mul (_Projector, v.vertex).xy, _ShadowTex);
				return o;
			}
			 
			fixed4 frag (v2f i) : COLOR {
				if (i.uv.x < 1 && i.uv.y < 1)
					return tex2D (_ShadowTex, fmod (i.uv, 1 / _Size) * _Size) * _Color;
				else
					return fixed4 (0,0,0,0);
			}
			
			ENDCG
		}
	}
}

Probably not the most optimized and clean way to do this (how could I optimize it?), but it’s working now.

Not sure I understood the problem correctly. You do want the texture to repeat forever, or not? If you do, then just remove the fmod() call and set the texture wrap mode to Repeat?