- Home /
Question by
stoneblade · Apr 07, 2015 at 01:03 AM ·
texturerotateimagemath
Rotating texture with 3 shear
I'm trying to implement this,I'm having trouble keeping the image to the center as it rotate around the center
i.e. calculating a correct offset to the shear so the image remain centered
I'm not looking for it to be perfect, but at least -45 and 45 degree having the same image when using a symmetric image, I have try using floor round ceiling to calculate the center offset, it is still off by 1-2 pixel, please help
Here's my implementation that run in the editor, place a quad and assign it to the renderer slot
using UnityEngine;
[ExecuteInEditMode]
public class Test : MonoBehaviour
{
public bool reverseSign = true;
public int size = 32;
public float degree = 45;
public float area = 0.5f;
bool lastSign;
int lastSize;
float lastDegree;
float lastArea;
public Renderer renderer;
void Update()
{
if (size != lastSize || degree != lastDegree || area != lastArea || reverseSign != lastSign)
Execute();
lastSign = reverseSign;
lastSize = size;
lastDegree = degree;
lastArea = area;
}
void Execute()
{
var tempMaterial = new Material(renderer.sharedMaterial);
var sizeX = size;
var sizeY = size;
Texture2D outputTex = new Texture2D(sizeX, sizeY, TextureFormat.ARGB32, false);
var data = new float[sizeX, sizeY];
Color32[] pixelArray = new Color32[sizeX * sizeY];
for (int i = 0; i < sizeX; i++)
for (int j = 0; j < sizeY; j++)
if (i >= sizeX * (1 - (area / 2 + 0.5))
&& i < sizeX * (area / 2 + 0.5)
&& j >= sizeY * (1 - (area / 2 + 0.5))
&& j < sizeY * (area / 2 + 0.5))
data[i, j] = 1;
data = ShearRotate(data, reverseSign ? -degree : degree);
for (int j = 0; j < sizeY; j++)
for (int i = 0; i < sizeX; i++)
pixelArray[i + j * sizeX] = new Color(data[i, j], 0, 0);
outputTex.SetPixels32(pixelArray, 0);
outputTex.Apply();
outputTex.wrapMode = TextureWrapMode.Clamp;
outputTex.filterMode = FilterMode.Point;
tempMaterial.SetTexture("_MainTex", outputTex);
renderer.sharedMaterial = tempMaterial;
}
float[,] ShearRotate(float[,] data, float degree)
{
var radian = degree * Mathf.PI / 180f;
var sizeX = data.GetLength(0);
var sizeY = data.GetLength(1);
var alpha = -Mathf.Tan(radian / 2);
var beta = Mathf.Sin(radian);
//print("alpha: " + alpha + " beta: " + beta);
var output = new float[sizeX, sizeY];
ShearX(data, output, alpha, sizeX, sizeY);
ShearY(output, data, beta, sizeX, sizeY);
ShearX(data, output, alpha, sizeX, sizeY);
return output;
}
float[,] ShearX(float[,] data, float[,] output, float shear, int sizeX, int sizeY)
{
int centerOffset = Mathf.FloorToInt((float)sizeY / 2 * shear);
for (int y = 0; y < sizeY; y++)
{
var skew = shear * y;
var skewi = Mathf.FloorToInt(skew);
var skewf = skew - skewi;
float oleft = 0;
for (int x = 0; x < sizeX; x++)
{
var pixel = data[x, y];
var left = pixel * skewf;
//var left = 0; //no anti alias
pixel = pixel - left + oleft;
var index = x + skewi - centerOffset;
if (index >= sizeX)
output[sizeX - 1, y] = pixel;
else if (index >= 0)
output[index, y] = pixel;
oleft = left;
}
var index2 = skewi + 1 - centerOffset;
if (index2 >= sizeY)
output[sizeY - 1, y] = oleft;
else if (index2 >= 0)
output[index2, y] = oleft;
}
return output;
}
float[,] ShearY(float[,] data, float[,] output, float shear, int sizeX, int sizeY)
{
int centerOffset = Mathf.FloorToInt((float)sizeX / 2 * shear);
for (int x = 0; x < sizeX; x++)
{
var skew = shear * x;
var skewi = Mathf.FloorToInt(skew);
var skewf = skew - skewi;
float oleft = 0;
for (int y = 0; y < sizeY; y++)
{
var pixel = data[x, y];
var left = pixel * skewf;
//var left = 0; //no anti alias
pixel = pixel - left + oleft;
var index = y + skewi - centerOffset;
if (index >= sizeY)
output[x, sizeY - 1] = pixel;
else if (index >= 0)
output[x, index] = pixel;
oleft = left;
}
var index2 = skewi + 1 - centerOffset;
if (index2 >= sizeX)
output[x, sizeX - 1] = oleft;
else if (index2 >= 0)
output[x, index2] = oleft;
}
return output;
}
}
Comment