- Home /
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 :)
-Travis
I am also having the same problem. $$anonymous$$y sprites update is doing:renderer.material.SetTextureOffset ("_$$anonymous$$ainTex", v); and it is having no effect.
Answer by Ben-BearFish · Jan 28, 2014 at 07:14 PM
@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.
that sounds intersting.
does somebody have an idea how to write such a shader ?
I'm having issues with this as well. I tried to use a 3D quad but then I couldn't get it to render in front of the sprites. I've tried changing sortingLayerName and sortingOrder (which works for particle systems and Text$$anonymous$$eshes) but it didn't work. I also made a brief foray into the land of UV-hacks but didn't get that far…
@ActionVillian, I added a few example scripts you can try.
Answer by Simonius Skjorn · Aug 12, 2014 at 10:35 PM
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.
Answer by inejwstine · May 24, 2016 at 07:42 PM
(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: http://docs.unity3d.com/ScriptReference/Material.SetTextureOffset.html
Answer by Matheus_Dem · Jan 19, 2017 at 10:30 PM
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.
Your answer
Follow this Question
Related Questions
Why not tiling on Shader (Sprite/Diffuse)? Unity 5.4.1 f1 1 Answer
PNG / SVG (Vector Graphics) sprites quality 1 Answer
How to generate lightmaps without tiling and offset modifications? 1 Answer
Quad Background (Scrolling) Texture = Mutated Image 1 Answer
How can I change the Unity 5 UI hitbox/collider to fit my complex image? 1 Answer