Rotate a texture with an arbitrary angle.

I have a stamp texture that I am stamping onto a larger texture, and now I am trying rotate that texture before stamping it.

This is what I have tried so far.

var stamp : Texture2D;

function rotImage (rotAngle : int){
	
	
	var rotStamp = new Texture2D(stamp.width,stamp.height);
	
	var ang = rotAngle * Mathf.Deg2Rad;
	


	for (var i = 0; i < stamp.height; i++) {
		
		for (var j = 0; j < stamp.width; j++) {
			
			var x_new : int=(j) * Mathf.Cos(ang) - (i)*Mathf.Sin(ang);
			var y_new : int=(i) * Mathf.Cos(ang) + (j)*Mathf.Sin(ang);
			
	
			
			rotStamp.SetPixel ( x_new, y_new, stamp.GetPixel(x_old,y_old));
			}
			}
			rotStamp.Apply();
			}

This only works when the value is 0,90,180,270 or 360. Otherwise The result is seemingly random.

I have never done anything like this with textures before, so don’t laugh to hard if I am miles off.

1 Like

where do x_old and y_old get updated?

I don’t think this will do what you want, image rotation is slightly more complicated than what your algorithm takes into consideration.
This has some good info you might want to read:
http://www.leptonica.com/rotation.html
The source (written in C) is available, perhaps you could port it for your needs?

oops, it didn’t get copied over from my file. x_old and y_old are just i and j.

var x_old =i;
var y_old =j;

that should have been inside the stamp.width loop.

Thanks for the link. I guess i am confused because it does work for 90,180 etc. So I thought I was on the right track

Well I had to think about it awhile myself before it started to make sense.
Still not sure it does. It may help you to draw some pictures (or play with rotations in an and image editor), it helped me…

When you do a rotate by 90 degrees (or multiple of) then the rotated image bounds matches the original bounds. Thats why it looks okay for those angles. However, for any thing else, say 45 degrees then the rotated image no longer fits within the original bounds, so how those areas get resolved is where the hard part comes into play and why your results look funky.

It may just be easier to make several textures of various rotations and scales in your favorite image editor and then just randomly load those up when you need them.

As well as GetPixel, Texture2D also has a GetPixelBilinear method. Image processing transforms like this inevitably want non-integer pixel coordinates from the source image. GetPixelBilinear handles this for you by returning a weighted average of four neighbouring pixels. The rotated texture will look much better if you use this rather than rounding pixel coordinates off to the nearest integer and using GetPixel.

Try this, adapted from:
http://homepages.inf.ed.ac.uk/rbf/HIPR2/rotate.htm

Texture2D rotateTexture(Texture2D tex, float angle)
    {
        Debug.Log("rotating");
        Texture2D rotImage = new Texture2D(tex.width, tex.height);
        int  x,y;
        float x1, y1, x2,y2;

        int w = tex.width;
        int h = tex.height;
        float x0 = rot_x (angle, -w/2.0f, -h/2.0f) + w/2.0f;
        float y0 = rot_y (angle, -w/2.0f, -h/2.0f) + h/2.0f;

        float dx_x = rot_x (angle, 1.0f, 0.0f);
        float dx_y = rot_y (angle, 1.0f, 0.0f);
        float dy_x = rot_x (angle, 0.0f, 1.0f);
        float dy_y = rot_y (angle, 0.0f, 1.0f);
        
        
        x1 = x0;
        y1 = y0;

        for (x = 0; x < tex.width; x++) { 
            x2 = x1;
            y2 = y1;
            for ( y = 0; y < tex.height; y++) { 
            //rotImage.SetPixel (x1, y1, Color.clear);           

            x2 += dx_x;//rot_x(angle, x1, y1); 
            y2 += dx_y;//rot_y(angle, x1, y1); 
            rotImage.SetPixel ( (int)Mathf.Floor(x), (int)Mathf.Floor(y), getPixel(tex,x2, y2)); 
            }

            x1 += dy_x;
            y1 += dy_y;
            
        }

        rotImage.Apply();
       return rotImage; 
    }

    private Color getPixel(Texture2D tex, float x, float y)
    {
        Color pix;
        int x1 = (int) Mathf.Floor(x);
        int y1 = (int) Mathf.Floor(y);

        if(x1 > tex.width || x1 < 0 ||
           y1 > tex.height || y1 < 0) {
            pix = Color.clear;
        } else {
            pix = tex.GetPixel(x1,y1);
        }
        
        return pix;
    }

    private float rot_x (float angle, float x, float y) {
        float cos = Mathf.Cos(angle/180.0f*Mathf.PI);
        float sin = Mathf.Sin(angle/180.0f*Mathf.PI);
        return (x * cos + y * (-sin));
    }
    private float rot_y (float angle, float x, float y) {
        float cos = Mathf.Cos(angle/180.0f*Mathf.PI);
        float sin = Mathf.Sin(angle/180.0f*Mathf.PI);
        return (x * sin + y * cos);
    }

also just fyi, I did not look at any of the licensing for this; so that will need to be investigated before using for anything other than personal use.

3 Likes

You are a life saver my friend, it works perfectly.

You have earned a gold star.

You have to imagine its gold…

This thread is probably really dead, but I thought I would throw a bump at it. Any advice on rotating a Texture2D around its center axis? I need to take an actual Texture2D object and rotate it like the code above, but from a specific pivot point.

The answer above is amazing but it is too slow on mobile. Is there really no easy and fast way to do this?