TextureScale

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
m (Text replace - "<javascript>" to "<syntaxhighlight lang="javascript">")
m (Text replace - "</javascript>" to "</syntaxhighlight>")
Line 23: Line 23:
 
renderer.material.mainTexture = newTex;
 
renderer.material.mainTexture = newTex;
 
TextureScale.Bilinear (newTex, tex.width*2, tex.height*2);
 
TextureScale.Bilinear (newTex, tex.width*2, tex.height*2);
}</javascript>
+
}</syntaxhighlight>
  
 
Note that you probably don't want to scale the actual textures in your project.  Instantiate a copy first, as shown in the code above.
 
Note that you probably don't want to scale the actual textures in your project.  Instantiate a copy first, as shown in the code above.
Line 140: Line 140:
 
  c1.b + (c2.b - c1.b)*value,  
 
  c1.b + (c2.b - c1.b)*value,  
 
  c1.a + (c2.a - c1.a)*value);
 
  c1.a + (c2.a - c1.a)*value);
}</javascript>
+
}</syntaxhighlight>
  
 
[[Category: Utility]]
 
[[Category: Utility]]
 
[[Category: JavaScript]]
 
[[Category: JavaScript]]

Revision as of 20:53, 10 January 2012

Author: Eric Haines (Eric5h5)

Description

If you've used Texture2D.Resize, you may have been disappointed to find that it only resizes the texture; it doesn't scale the contents. Using TextureScale, however, you can in fact do just that, using either bilinear or point (nearest neighbor) filtering. It also uses multi-threading to speed up the process on CPUs with more than one core. (Although SetPixels() and Apply() cause a pretty big hit, so the multi-threading is perhaps limited in usefulness, but it can still be nice for large textures, and in any case it's faster than not having it.)

Usage

Name this script TextureScale and have it somewhere in your project, preferably in a folder such as Standard Assets that compiles before other folders, so you can call it from C# or Boo. You can then call TextureScale.Bilinear to use bilinear scaling, and TextureScale.Point to use point scaling. The arguments are:

function Bilinear (texture : Texture2D, newWidth : int, newHeight : int) : void

texture is the texture that you want to scale using bilinear filtering. newWidth and newHeight are the desired dimensions for the texture. It will be resized using Texture2D.Resize, and the contents scaled. Texture2D.Apply is called when done so that the changes take effect immediately. The texture must be RGBA32, RGB24, or Alpha8 in order for the function to work, and also must be read/write enabled.

function Point (texture : Texture2D, newWidth : int, newHeight : int) : void

The same as above, except point filtering is used instead of bilinear.

Note that the functions resize the texture that's passed in; they don't return a new texture. An example of usage:

var tex : Texture2D;
 
function Start () {
	var newTex = Instantiate (tex);
	renderer.material.mainTexture = newTex;
	TextureScale.Bilinear (newTex, tex.width*2, tex.height*2);
}

Note that you probably don't want to scale the actual textures in your project. Instantiate a copy first, as shown in the code above.

TextureScale.js

// Only works on ARGB32, RGB24 and Alpha8 textures that are marked readable
 
import System.Threading;
 
class ThreadData {
	var start : int;
	var end : int;
	function ThreadData (s : int, e : int) {
		start = s;
		end = e;
	}
}
 
private static var texColors : Color[];
private static var newColors : Color[];
private static var w : int;
private static var ratioX : float;
private static var ratioY : float;
private static var w2 : int;
private static var finishCount : int;
 
static function Point (tex : Texture2D, newWidth : int, newHeight : int) {
	ThreadedScale (tex, newWidth, newHeight, false);
}
 
static function Bilinear (tex : Texture2D, newWidth : int, newHeight : int) {
	ThreadedScale (tex, newWidth, newHeight, true);
}
 
private static function ThreadedScale (tex : Texture2D, newWidth : int, newHeight : int, useBilinear : boolean) {
	texColors = tex.GetPixels();
	newColors = new Color[newWidth * newHeight];
	if (useBilinear) {
		ratioX = 1.0 / (parseFloat(newWidth) / (tex.width-1));
		ratioY = 1.0 / (parseFloat(newHeight) / (tex.height-1));
	}
	else {
		ratioX = parseFloat(tex.width) / newWidth;
		ratioY = parseFloat(tex.height) / newHeight;
	}
	w = tex.width;
	w2 = newWidth;
	var cores = Mathf.Min(SystemInfo.processorCount, newHeight);
	var slice = newHeight/cores;
	finishCount = 0;
 
	if (cores > 1) {
		for (i = 0; i < cores-1; i++) {
			var threadData = new ThreadData(slice*i, slice*(i+1));
			var thread = useBilinear? new Thread(BilinearScale) : new Thread(PointScale);
			thread.Start(threadData);
		}
		threadData = new ThreadData(slice*i, newHeight);
		if (useBilinear) {
			BilinearScale(threadData);
		}
		else {
			PointScale(threadData);
		}
		while (finishCount < cores);
	}
	else {
		threadData = new ThreadData(0, newHeight);
		if (useBilinear) {
			BilinearScale(threadData);
		}
		else {
			PointScale(threadData);
		}
	}
 
	tex.Resize(newWidth, newHeight);
	tex.SetPixels(newColors);
	tex.Apply();
}
 
private static function BilinearScale (threadData : ThreadData) {
	for (y = threadData.start; y < threadData.end; y++) {
		var yFloor = Mathf.Floor(y * ratioY);
		var y1 = yFloor * w;
		var y2 = (yFloor+1) * w;
		yw = y * w2;
 
		for (x = 0; x < w2; x++) {
			var xFloor = Mathf.Floor(x * ratioX);
			var xLerp = x * ratioX-xFloor;
			newColors[yw + x] = ColorLerpUnclamped(ColorLerpUnclamped(texColors[y1 + xFloor], texColors[y1 + xFloor+1], xLerp),
												   ColorLerpUnclamped(texColors[y2 + xFloor], texColors[y2 + xFloor+1], xLerp),
												   y*ratioY-yFloor);
		}
	}
 
	finishCount++;
}
 
private static function PointScale (threadData : ThreadData) {
	for (y = threadData.start; y < threadData.end; y++) {
		var thisY = parseInt(ratioY * y) * w;
		var yw = y * w2;
		for (x = 0; x < w2; x++) {
			newColors[yw + x] = texColors[thisY + ratioX*x];
		}
	}
 
	finishCount++;
}
 
private static function ColorLerpUnclamped (c1 : Color, c2 : Color, value : float) : Color {
	return new Color (c1.r + (c2.r - c1.r)*value, 
					  c1.g + (c2.g - c1.g)*value, 
					  c1.b + (c2.b - c1.b)*value, 
					  c1.a + (c2.a - c1.a)*value);
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox