Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System.ComponentModel;
- using UnityEngine;
- public class Main : MonoBehaviour
- {
- //Based on this article: https://estebanhufstedler.com/2020/06/08/rearrange-a-picture-into-another/
- public Texture2D sourceImage;
- public Texture2D targetImage;
- public int segmentSize;
- public bool rotateTiles;
- public string executionTime;
- Texture2D[,,] sourceTiles;
- Texture2D[,] targetTiles;
- Texture2D[,] modifiedTiles;
- Texture2D finishedImage;
- Color[,,][] sourceTilePixels;
- Color[,][] targetTilePixels;
- int ySegments;
- int xSegments;
- void Start()
- {
- float startTime = Time.realtimeSinceStartup;
- if (sourceImage.width != targetImage.width || sourceImage.height != targetImage.height)
- {
- Debug.LogError("Images must have the same dimensions!");
- return;
- }
- ySegments = sourceImage.height / segmentSize;
- xSegments = sourceImage.width / segmentSize;
- sourceTiles = new Texture2D[xSegments, ySegments, 4];
- targetTiles = new Texture2D[xSegments, ySegments];
- modifiedTiles = new Texture2D[xSegments, ySegments];
- sourceTilePixels = new Color[xSegments, ySegments, 4][];
- targetTilePixels = new Color[xSegments, ySegments][];
- for (int y = 0; y < ySegments; y++)
- {
- for (int x = 0; x < xSegments; x++)
- {
- CreateTile(x, y);
- }
- }
- for (int y = 0; y < ySegments; y++)
- {
- for (int x = 0; x < xSegments; x++)
- {
- MatchTileToTarget(x, y);
- }
- }
- finishedImage = new Texture2D(sourceImage.width, sourceImage.height);
- for (int y = 0; y < ySegments; y++)
- {
- for (int x = 0; x < xSegments; x++)
- {
- Color[] tileColors = modifiedTiles[x, y].GetPixels();
- finishedImage.SetPixels(x * segmentSize, y * segmentSize, segmentSize, segmentSize, tileColors);
- }
- }
- finishedImage.Apply();
- GameObject canvas = GameObject.CreatePrimitive(PrimitiveType.Quad);
- canvas.transform.localScale = new Vector3(3, 4, 1);
- canvas.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Unlit/Texture"));
- canvas.GetComponent<MeshRenderer>().material.mainTexture = finishedImage;
- executionTime = ((Time.realtimeSinceStartup - startTime) * 1000f) + "ms";
- }
- void CreateTile(int x, int y)
- {
- Color[] sourceColors = sourceImage.GetPixels(x * segmentSize, y * segmentSize, segmentSize, segmentSize);
- sourceTiles[x, y, 0] = new Texture2D(segmentSize, segmentSize);
- sourceTiles[x, y, 0].SetPixels(sourceColors);
- sourceTiles[x, y, 0].Apply();
- sourceTilePixels[x, y, 0] = sourceTiles[x, y, 0].GetPixels();
- //Create rotated version of tiles
- for (int i = 1; i < 4; i++)
- {
- sourceTiles[x, y, i] = RotateTexture(sourceTiles[x, y, i - 1], true);
- sourceTiles[x, y, i].Apply();
- sourceTilePixels[x, y, i] = sourceTiles[x, y, i].GetPixels();
- }
- targetTiles[x, y] = new Texture2D(segmentSize, segmentSize);
- Color[] targetColors = targetImage.GetPixels(x * segmentSize, y * segmentSize, segmentSize, segmentSize);
- targetTiles[x, y].SetPixels(targetColors);
- targetTiles[x, y].Apply();
- targetTilePixels[x, y] = targetTiles[x, y].GetPixels();
- }
- void MatchTileToTarget(int xCoord, int yCoord)
- {
- int xOptimalCoord = 0;
- int yOptimalCoord = 0;
- int optimalRotation = 0;
- float minCost = float.MaxValue;
- for (int y = 0; y < ySegments; y++)
- {
- for (int x = 0; x < xSegments; x++)
- {
- if (modifiedTiles[x, y] == null)
- {
- for (int i = 0; i < 4; i++)
- {
- float cost = CalculateCost(xCoord, yCoord, i, x, y);
- if (cost < minCost)
- {
- minCost = cost;
- xOptimalCoord = x;
- yOptimalCoord = y;
- optimalRotation = i;
- }
- }
- }
- }
- }
- modifiedTiles[xOptimalCoord, yOptimalCoord] = sourceTiles[xCoord, yCoord, rotateTiles ? optimalRotation : 0];
- }
- float CalculateCost(int x1, int y1, int rot, int x2, int y2)
- {
- Color[] pixels1 = sourceTilePixels[x1, y1, rot];
- Color[] pixels2 = targetTilePixels[x2, y2];
- float totalDiff = 0;
- for (int i = 0; i < pixels1.Length; i++)
- {
- float r1 = pixels1[i].r;
- float g1 = pixels1[i].g;
- float b1 = pixels1[i].b;
- float r2 = pixels2[i].r;
- float g2 = pixels2[i].g;
- float b2 = pixels2[i].b;
- float redDiff = (r1 - r2) * (r1 - r2);
- float greenDiff = (g1 - g2) * (g1 - g2);
- float blueDiff = (b1 - b2) * (b1 - b2);
- totalDiff += redDiff + greenDiff + blueDiff;
- }
- return totalDiff;
- }
- Texture2D RotateTexture(Texture2D originalTexture, bool clockwise)
- {
- Color32[] original = originalTexture.GetPixels32();
- Color32[] rotated = new Color32[original.Length];
- int w = originalTexture.width;
- int h = originalTexture.height;
- int iRotated, iOriginal;
- for (int j = 0; j < h; ++j)
- {
- for (int i = 0; i < w; ++i)
- {
- iRotated = (i + 1) * h - j - 1;
- iOriginal = clockwise ? original.Length - 1 - (j * w + i) : j * w + i;
- rotated[iRotated] = original[iOriginal];
- }
- }
- Texture2D rotatedTexture = new Texture2D(h, w);
- rotatedTexture.SetPixels32(rotated);
- rotatedTexture.Apply();
- return rotatedTexture;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement