Shader that tiles different textures from an atlas

Apologies in advance - I’m not a shader wiz at all. I’m hoping to get some guidance or pointers to some examples. I haven’t been able to find anything like I’m trying to do.

I’m working on a game with some long tubes that I’d like to have alternating textures on. I’d like to be able to put the tube’s 4 texutres in a texture atlas and have the shader automatically cycle through the 4 textures in order along the length of the tube (Unity’s Y tiling axis). Ideally, I’m looking for a version of Unity’s Mobile/Bumped Specular (1 Directional Light) shader that does this, but any example or hints would be great.

Because of some other constraints (i.e. I’m using MegaShapes to generate the tubes), I can’t just make the tubes with 4 different meshes or change the UVs on the tubes.

Here’s an example render of what I’m looking for:
1472621--81076--$tube tile texture example.png

Here’s what the texture atlas for the above tube would look like:

Thanks a ton for the help!

Grab the Mobile Bumped Specular source here: http://unity3d.com/unity/download/archive

For the 4.3 version (it’s in DefaultResourcesExtra/Mobile) you’ll be looking at line 44:

void surf (Input IN, inout SurfaceOutput o) {
	fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
	o.Albedo = tex.rgb;
	o.Gloss = tex.a;
	o.Alpha = tex.a;
	o.Specular = _Shininess;
	o.Normal = UnpackNormal (tex2D(_BumpMap, IN.uv_MainTex));
}

The tex2D call is where the shader takes the UV and samples the texture for the texel/color in _MainTex. You’ll see just above that function that uv_MainTex is just a float2. You can offset the u and v to your heart’s content. Since it sounds like you’re animating, you’ll probably want to use the built-in _Time variable.

And Here’s a simple example for animating UV’s within a shader.

Shader work can be super rewarding and fun! :smile:

Thanks a ton for the info, Paul.

It’s actually not animated - the tubes are static. However, they’re quite long and the 4 textures need to repeat many times along the length of the tube. It doesn’t look like _Time is quite what I want. I really just want to change the texture offset each time the texture is repeated in Y.

I’ll dig into it!

I just remembered on an older project I fiddled with the UV’s on the script side this way:

using UnityEngine;
using System.Collections;

[AddComponentMenu("Generator3/UVRotoscope")]

public class UVRotoscope : MonoBehaviour {
	
	public int numberOfFrames = 10;
	public float fps = 30.0f;
	
	private float timeLeft = 0.0f;
	private int currFrame = 0;
	
	// Use this for initialization
	void Start () 
	{
		NextFrame();
	}

	private void NextFrame()
	{
		currFrame++; 
		//Debug.Log("Frame: " + currFrame);
		timeLeft = 1.0f/fps;
		
		if (currFrame >= numberOfFrames)
			currFrame = 0;
		
		float offset = (1.0f/(float)numberOfFrames) * (float)currFrame;
		renderer.material.SetTextureOffset("_MainTex", new Vector2(offset, 0.0f));
	}

	// Update is called once per frame
	void Update () {
		
		timeLeft -= Time.deltaTime;

		if (timeLeft <= 0)
			NextFrame();
		
		
	}
}

Yeah, but that would change the texture offset for my entire tube…so whenever an update hit, it’d look like the the texture on the tube jumped. Right?

I did this before but there is one problem that the edges of the textures will look like crap to describe it gently. The problem is this: http://aras-p.info/blog/2010/01/07/screenspace-vs-mip-mapping/

You can easily do this with fmod(). For instance you could use fmod(UV, 0.5) + float2(X,Y); While X and Y is eighter 0 or 0.5 for a 4-Textures atlas. Didn’t test it.

Yeah, I was just talking about that with @prime31 the other day.

For those who dig up this thread later, my solution was to just hit this with a hammer instead of doing something elegant like UV or shader work. I took my 1024x1024 texture with the 4 tiles and laid them out in a 512x2048 instead. My iOS game is very light on textures, so even though this isn’t square won’t get PVR’d, it still works out for my game. I still want to implement a better solution. However, since I have a workable way forward now, I’m guessing at least version 1.0 of my game will just use the non-square texture.

Thanks a ton everyone. I’ll post back here if I come up with a better solution.