Share Texture Across Multiple Meshes

I have a plane that has a normal diffuse material and a texture to go with it. I want to break the plane up into smaller planes with pieces that are random sizes but all fit within the area of the plane (like breaking up an assembled puzzle with rectangular pieces). However the pieces are not supposed to just be separated all at the same time, the plane will break up into mini-planes from a point. The mini planes should still retain the texture occupying the space that they used to be in, when the plane wasn’t broken. I’m not asking for code or even psuedo-code (although that would be nice), but what is some of the logic that would go into this as I haven’t the slightest idea about how to do this? Or even a way to somewhat fake the effect would be very helpful.

Here is a rather crude example which I have put together for you from one of my past experiments :slight_smile:

How to use it:

  1. Create an empty game object.
  2. Attach the following “Puzzle” script.
  3. Select a texture using the inspector.
  4. Hit “Play” and then hold space key to animate tiles.

How does it work:?

Initially the script generates the triangles and UV coordinates for each tile. The vertices are updated each frame using the Update message. Tiles can be moved individually by adjusting their respective tilePosition. Use SetTilePosition to adjust the position of a specific puzzle tile.

Source Code:

using UnityEngine;

public class Puzzle : MonoBehaviour {

	// Texture for puzzle
	public Texture2D puzzleTexture;
	
	// Number of rows and columns in puzzle
	public int rows = 5;
	public int columns = 5;

	// Size of a single tile
	public Vector2 tileSize = new Vector2(1, 1);

	// Speed of random movements
	private Vector3[] randomDirections;
	public float randomSpeed = 1f;

	// Tile positions in local space
	[System.NonSerialized]
	public Vector3[] tilePositions;

	// Generated objects
	private Material _mat;
	private Mesh _mesh;

	private Vector3[] _vertices;

	private void Awake() {
		_mat = new Material(Shader.Find("Unlit/Texture"));
		_mat.mainTexture = puzzleTexture;
		
		PrepareMesh();
		
		MeshFilter filter = gameObject.AddComponent<MeshFilter>();
		filter.sharedMesh = _mesh;
		
		MeshRenderer renderer = gameObject.AddComponent<MeshRenderer>();
		renderer.sharedMaterial = _mat;

		// Prepare random directions
		randomDirections = new Vector3[ tilePositions.Length ];
		for (int i = 0; i < randomDirections.Length; ++i)
			randomDirections *= new Vector3(Random.value - 0.5f, Random.value - 0.5f, 0);*
  • }*

  • private void Update() {*

  •  // Only perform animation when space key is pressed*
    
  •  if (Input.GetKey(KeyCode.Space)) {*
    

_ float deltaSpeed = randomSpeed * Time.deltaTime;_

  •  	// Do something with tiles!*
    
  •  	for (int ti = 0; ti < tilePositions.Length; ++ti) {*
    

_ tilePositions[ti] += randomDirections[ti] * deltaSpeed;_

  •  	}*
    
  •  }*
    
  •  UpdateVertices();*
    
  • }*
    public void SetTilePosition(int row, int column, Vector3 position) {
    tilePositions[ row * columns + column ] = position;
    }
    public Vector3 GetTilePosition(int row, int column) {
    return tilePositions[ row * columns + column ];
    }

  • private void PrepareMesh() {*

  •  _mesh = new Mesh();*
    

_ int tileCount = rows * columns;_
_ int vertexCount = tileCount * 4;_
_ int triangleCount = tileCount * 2;_

  •  tilePositions = new Vector3[ tileCount ];*
    
  •  Vector2[] uvs = new Vector2[ vertexCount ];*
    

_ int tris = new int[triangleCount * 3];_

  •  _vertices = new Vector3[ vertexCount ];*
    
  •  // Size of single tile in UV space*
    
  •  Vector2 uvSize = new Vector2(1f / (float)columns, 1f / (float)rows);*
    
  •  // Current position of cursor*
    

_ Vector3 cursor = new Vector3(0f, rows * tileSize.y, 0f);_

  •  Vector2 uvCursor = new Vector2(0, 1 - uvSize.y);*
    
  •  int ti = 0;*
    
  •  int vi = 0;*
    
  •  int tri = 0;*
    
  •  // Generate vertices*
    
  •  for (int row = 0; row < rows; ++row) {*
    
  •  	for (int column = 0; column < columns; ++column) {*
    
  •  		uvs[vi + 0] = uvCursor;*
    
  •  		uvs[vi + 1] = new Vector2(uvCursor.x, uvCursor.y + uvSize.y);*
    
  •  		uvs[vi + 2] = new Vector2(uvCursor.x + uvSize.x, uvCursor.y + uvSize.y);*
    
  •  		uvs[vi + 3] = new Vector2(uvCursor.x + uvSize.x, uvCursor.y);*
    
  •  		tilePositions[ti++] = cursor;*
    
  •  		tris[ tri++ ] = vi + 0;*
    
  •  		tris[ tri++ ] = vi + 1;*
    
  •  		tris[ tri++ ] = vi + 2;*
    
  •  		tris[ tri++ ] = vi + 2;*
    
  •  		tris[ tri++ ] = vi + 3;*
    
  •  		tris[ tri++ ] = vi + 0;*
    
  •  		// Proceed to next vertex!*
    
  •  		cursor.x += tileSize.x;*
    
  •  		uvCursor.x += uvSize.x;*
    
  •  		vi += 4;*
    
  •  	}*
    
  •  	// Move to start of next row*
    
  •  	cursor.x = 0;*
    
  •  	cursor.y -= tileSize.y;*
    
  •  	uvCursor.x = 0;*
    
  •  	uvCursor.y -= uvSize.y;*
    
  •  }*
    

#if UNITY_4_0

  •  _mesh.MarkDynamic(); // Unity4 Only!*
    

#endif

  •  _mesh.vertices = _vertices;*
    
  •  _mesh.uv = uvs;*
    
  •  _mesh.triangles = tris;*
    
  •  //_mesh.RecalculateNormals(); // Add if you need them*
    
  • }*

  • private void UpdateVertices() {*
    _ int tileCount = rows * columns;_

  •  int vi = 0;*
    
  •  // Update vertices for each frame!*
    
  •  for (int ti = 0; ti < tileCount; ++ti) {*
    
  •  	Vector3 position = tilePositions[ti];*
    
  •  	_vertices[vi + 0] = new Vector3(position.x, position.y - tileSize.y, position.z);*
    
  •  	_vertices[vi + 1] = position;*
    
  •  	_vertices[vi + 2] = new Vector3(position.x + tileSize.x, position.y, position.z);*
    
  •  	_vertices[vi + 3] = new Vector3(position.x + tileSize.x, position.y - tileSize.y, position.z);*
    
  •  	vi += 4;*
    
  •  }*
    
  •  _mesh.vertices = _vertices;*
    
  • }*

}