How to GPU Instance the scale tiling & offset properties of a _MainTex

I’ve been able to GPU instance shader properties like Color or Saturation using the Unity docs on GPU Instancing: Unity - Manual: GPU instancing

However I am looking for help on how to GPU Instance the _MainTex’s Tiling & Offset parameters, in a material I see them as serialized as:

m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}```

Can anyone advise on how I can setup a super simple shader where I am able to GPU Instance these properties or add new ones to replicate them so when I apply a MaterialPropertyBlock to override tiling or offset I do not break batching?

The m_Scale and m_Offset serialized properties are converted at runtime into the float4 _TexName_ST; and applied with a TRANSFORM_TEX(uv, _TexName) macro in the shader. That macro looks like this:
#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)

If you want to include the same functionality, you need to not use the built in tiling / offset options the material exposes (I’d recommend putting a [NoScaleOffset] in front of the texture property in your shader to hide those options) and use your own Vector/float4 value to do the same thing.

[NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
_MainTex_ScaleOffset ("Scale (XY) Offset (ZW)", Vector) = (1,1,0,0)

// .. .

UNITY_INSTANCING_BUFFER_START(Props)
  UNITY_DEFINE_INSTANCED_PROP(float4, _MainTex_ScaleOffset)
UNITY_INSTANCING_BUFFER_END(Props)

// ...

float4 scaleOffset = UNITY_ACCESS_INSTANCED_PROP(Props, _MainTex_ScaleOffset);
uv.xy = uv.xy * scaleOffset.xy + scaleOffset.zw;
3 Likes

Awesome, thanks so much! This is exactly what I needed.

Hey. Could you provide a full shade code, please? I’ll very appreciate this

Here is a barebones shader that accomplishes GPU instancing for scale / offset (note: untested):

Shader "Test/TestShader"
{
    Properties
    {
        _MainTex ("MainTexture", 2D) = "white" {}
        _MainScaleOffset ("Main Scale (XY) Offset (ZW)", Vector) = (1,1,0,0)
    }
    SubShader
    {
        Tags
        {
            "RenderType"="Opaque"
        }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert
        sampler2D _MainTex;

        UNITY_INSTANCING_BUFFER_START(Props)
        UNITY_DEFINE_INSTANCED_PROP(float4, _MainScaleOffset)
        UNITY_INSTANCING_BUFFER_END(Props)

        struct Input
        {
            float2 uv_MainTex;
        };

        void surf(Input IN, inout SurfaceOutput o)
        {
            float4 scaleOffset = UNITY_ACCESS_INSTANCED_PROP(Props, _MainScaleOffset);
            float2 uv = IN.uv_MainTex * scaleOffset.xy + scaleOffset.zw;
            o.Albedo = tex2D(_MainTex, uv).rgb;
        }
        ENDCG
    }
    FallBack "Mobile/Diffuse"
}
3 Likes

Thanks a lot! It’s working perfect