Dynamic offset & tiling for SpriteRenderer

Hi,
I’m making a 2d game using Unity 4.3, and with the new sprite renderer I’m unable to dynamically set the offset and tiling. When I attempt to, I get an warning message in the editor that says “Material texture property _MainTex has offset/scale set. It is incompatible with SpriteRenderer.”

on start:

renderer.material.mainTextureScale = new Vector2( transform.localScale.x, transform.localScale.y);

on update:

renderer.material.mainTextureOffset = new Vector2(0, Time.frameCount * -0.01f);

I can do this with a 3d plane and it works, but that seems nasty to mix in with all my 2d sprites. I’m trying to create the image below, where a custom-sized polygon gets dynamically tiled with the up arrow sprite, and then those up arrows endlessly scroll (meaning your character will float in that area).

Any thoughts? Perhaps I’m just misunderstanding how Unity’s 2d sprites work and it doesn’t make any sense to do this.

Thanks for any illumination :slight_smile:

-Travis

19983-updraft_example.png

@greyhoundgames: If you have a comment, you should leave it as a comment if you can, not as an answer as it makes it more difficult for other users to find what they are looking for.

As far as the problem that we’re trying to solve, this is what the response was from Unity:

Sprites are designed with the assumption that you define a fixed texture area for the Sprite - so the texture offset feature is removed from SpriteRenderer. However UV hacks can still be done in a vertex shader.

So, you probably need to write a custom shader where you can modify the UV’s and put it on your Sprite or stick with your 3D quad/plane approach, which I ended up doing due to simplicity sake.

EDIT:
Here are a few scripts I have that help solve the problem.

As I mentioned earlier you need a shader that can move the UV’s on the 3D quad. This is a shader that Blends Color, Transparency, and can move UV’s on a mesh.

SHADER

// unlit, vertex color, alpha blended, offset uv's
// cull off

Shader "BlendVertexColorWithUV" 
{
	Properties 
	{
		_MainTex ("Base (RGB) Trans (A)", 2D) = "white" {}
	}
	
	SubShader
	{
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
		ZWrite Off Lighting Off Cull Off Fog { Mode Off } Blend SrcAlpha OneMinusSrcAlpha
		LOD 110
		
		Pass 
		{
			CGPROGRAM
			#pragma vertex vert_vct
			#pragma fragment frag_mult 
			#pragma fragmentoption ARB_precision_hint_fastest
			#include "UnityCG.cginc"

			sampler2D _MainTex;
			float4 _MainTex_ST;

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

			struct v2f_vct
			{
				float4 vertex : POSITION;
				fixed4 color : COLOR;
				float2 texcoord : TEXCOORD0;
			};

			v2f_vct vert_vct(vin_vct v)
			{
				v2f_vct o;
				o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
				o.color = v.color;
				o.texcoord = TRANSFORM_TEX (v.texcoord, _MainTex);;
				return o;
			}

			fixed4 frag_mult(v2f_vct i) : COLOR
			{
				fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
				return col;
			}
			
			ENDCG
		} 
	}
 
	SubShader
	{
		Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
		ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Cull Off Fog { Mode Off }
		LOD 100

		BindChannels 
		{
			Bind "Vertex", vertex
			Bind "TexCoord", texcoord
			Bind "Color", color
		}

		Pass 
		{
			Lighting Off
			SetTexture [_MainTex] { combine texture * primary } 
		}
	}
}

Here’s a script that accesses the mesh texture UV’s and automatically scrolls the texture’s UV’s, but you can move the UV’s however you like:

Access Texture UV’s Example Script

using UnityEngine;
using System.Collections;
public class UIAnimatingBackground : MonoBehaviour
{
	protected Material textureToAnimate;

	protected Vector2 uvOffset = Vector2.zero;
	public Vector2 uvAnimationRate = new Vector2( 0.3f, 0.3f );
	public string textureName = "_MainTex";

	protected MeshRenderer backgroundMeshRenderer;

	[SerializeField]
	protected bool resetPositionToZero = true;

	protected void Start()
	{
		backgroundMeshRenderer = GetComponent<MeshRenderer>();

		if(backgroundMeshRenderer != null)
		{
			if(resetPositionToZero)
				  backgroundMeshRenderer.transform.position = Vector3.zero;

			textureToAnimate = backgroundMeshRenderer.material;
		}
	}

	protected void Update() 
	{
		if(textureToAnimate != null)
		{
			if(uvOffset.x >= 1.0f)
			{
				uvOffset.x = 0.0f;
			}

			if(uvOffset.y >= 1.0f)
			{
				uvOffset.y = 0.0f;
			}

			uvOffset += uvAnimationRate * Time.deltaTime;
			textureToAnimate.mainTextureOffset = uvOffset;
		}
	}
}

Once these are set up, you create a Quad Mesh in the Unity scene. Attach the UV script component to the Quad Mesh, and set the shader material to the BlendVertexColorWithUV shader. To place the mesh quad in front of or behind the sprites you can change it’s z position in the inspector, or change the layer it is on to draw before the Sprites.

(I know it’s an old question, but I just ran in to this problem, so I thought I’d post how I solved it.)

@Simonius Skjorn’s solution is what worked for me, but if you need more details, here’s a good forum post for how to accomplish it:
http://forum.unity3d.com/threads/spriterenderer-changing-texture-uv-offset.366688/
Then you can just rotate the plane so it faces your camera, move it back far enough to be behind all of your other sprites, and attach a script to it to update the offset, like the one here: Unity - Scripting API: Material.SetTextureOffset

I know this post is pretty old, but i think i found a simple solution. Go to the texture and change the texture type to “advanced” and set the wrap mode to “repeat”. I dont know if that is the right solution for question but it worked for me.

Actually, using a 3D plane and a custom material with animated tiling offset is exactly what you want in this case. Other methods just add more work and are not that efficient.