# How to do "Screen Space Texture" mapping on a Unity UI Image?

So I'm fairly new to the shader and I've been trying to achieve this kind of effect from Ronja Tutorials, but instead of using it for normal mesh object, I'm trying to use it for Screen Space UI Image instead, this is what I've done so far

Shader "UI/CustomScreenSpaceTexture"
{
Properties
{
[PerRendererData] _MainTex ("Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,1,1)

_StencilComp ("Stencil Comparison", Float) = 8
_Stencil ("Stencil ID", Float) = 0
_StencilOp ("Stencil Operation", Float) = 0
_StencilWriteMask ("Stencil Write Mask", Float) = 255
_StencilReadMask ("Stencil Read Mask", Float) = 255

_ColorMask ("Color Mask", Float) = 15

[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
}

SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
"PreviewType"="Plane"
"CanUseSpriteAtlas"="True"
}

Stencil
{
Ref [_Stencil]
Comp [_StencilComp]
Pass [_StencilOp]
ReadMask [_StencilReadMask]
WriteMask [_StencilWriteMask]
}

Cull Off
Lighting Off
ZWrite Off
ZTest [unity_GUIZTestMode]
Blend SrcAlpha OneMinusSrcAlpha
ColorMask [_ColorMask]

Pass
{
Name "Default"
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0

#include "UnityCG.cginc"
#include "UnityUI.cginc"

#pragma multi_compile_local _ UNITY_UI_CLIP_RECT
#pragma multi_compile_local _ UNITY_UI_ALPHACLIP

struct appdata_t
{
float4 vertex   : POSITION;
float4 color    : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct v2f
{
float4 vertex   : SV_POSITION;
fixed4 color    : COLOR;
float2 texcoord  : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
float4 screenPosition : TEXCOORD2;
UNITY_VERTEX_OUTPUT_STEREO
};

sampler2D _MainTex;
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
float4 _MainTex_ST;

v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = v.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.screenPosition = ComputeScreenPos(OUT.vertex);

OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);

OUT.color = v.color * _Color;
return OUT;
}

fixed4 frag(v2f IN) : SV_Target
{
float screenAspect = _ScreenParams.x / _ScreenParams.y;
float2 coord = IN.screenPosition.xy / IN.screenPosition.w;

coord.x = coord.x * screenAspect;
coord = TRANSFORM_TEX(coord, _MainTex);

half4 color = tex2D(_MainTex, coord);
color *= _Color;

return color;
}
ENDCG
}
}
}


This is my texture atlas

I was going to use the leftmost image that looks like a grid, the problem is if I use the shader this happened

1. The Image uses whole texture instead of the specified one (Yes, I use the texture as atlas so I could use specific child texture)
2. Because of the image uses whole texture, I have no control over options like Tiling, like what from Ronja Tutorials has (The option is still there on Image component, but it has no effect)

For comparison, this is what the Image look like if it uses default material/shader

So I'm trying to achieve Screen Space Texture style of mapping so the background will fits nicely if I have more than 1 Image with the different position but using the same texture without worrying the "Visible Seam" but still be able to do something like "Tiling" so I can control how big/small the grid tile is for the whole screen like default example as seen above.

This is what I was trying to solve with the shader

• So how would I achieve that? What part from my shader is wrong? (Again, I'm fairly new, so maybe the whole shader is wrong)
• This is possible, but probably more work than it's worth. Objects using different textures in your atlas with this effect will still need to be drawn in separate batches anyway (since you'll have to use uniforms to tell them which section of the atlas to read from), so you don't gain any benefit at all from using the atlas anyway. You might want to consider skipping the atlas for this particular effect to keep the shader simple and easy to work with. Jul 16 '20 at 10:53
• @DMGregory I see, I've tried to use single texture, and it covers the whole screen but it still ignores the Tiled options from the Image and it scales too big and yes, I have it set as Wrap Mode Repeat on the Import option. I guess I have to figure something about the Tiling first and then the texture scaling later. Jul 16 '20 at 18:14

## 1 Answer

A couple of alternative ways to approach your problem:

1. Write a shader that draws a grid based on the world-space coordinates of each pixel (the appearance is calculated entirely in-shader, with no source texture at all). I've done this before and it works nicely.

2. Make the grid a full-screen background image, and make the movable rectangle a mask using the mask feature already built into Unity.

• The first approach seems more feasible, and I'll try that. 2nd approach could also work... if the Mask component is masking the Parent Image instead of Child Image, which will follow parent position and can't be applied as full-screen size. Jul 17 '20 at 3:10