Dynamic combined textures

Hello

To make it simple, I have 5 textures 128x128 that I plan to use use as Lightmaps of a single object. I have the script to change the image already.

What I want is to have all possible combinations (25) of these 5 textures, and instead of creating 25 files I want to do it via javascript.

Therefore I need a sort of image manipulation script that gets two images and returns the combination of them (by pixel multiplication or any Boolean operation).

Is this possible?

Thanks
Andres

Yes, you can use ReadPixels() and WritePixels(). Note that textures can’t be compressed when doing this, but with 128x128, that’s probably not a big deal.

–Eric

Thanks Eric

I found the Texture2D.ReadPixels on the scripting reference but it reads the screen pixels, not a file.

And I did not find the “WritePixels”.

Sorry but I am new to this. Could it be that these two functions are plain javascript and that is why they are not on the reference?

Could you give me a code example please?

I would not know what to do after the readpixels. What code should I use to multiply each pixel?

Regards,
Andres

You want to use:

and:

I am not sure what exactly you mean by combining. If you mean texture atlassing, as in combining multiple textures into one optimally you can use this function instead:

Oops, sorry for messing up the names like that! I usually check to make sure I’m not writing nonsense…shows what happens when I skip that step…

Anyway, you can simply loop through the arrays returned by GetPixels() and multiply the values. Assuming that tex1 and tex2 are arrays returned by GetPixels(), you could do this:

for (i = 0; i < tex1.Length; i++) {
	tex1[i] *= tex2[i];
}

Then use SetPixels() to assign the array in tex1 to a texture.

–Eric

Not a problem Eric, and thanks Joachim,

I am not familiar with “atlassing”, Does it mean that I can have multiple Lightmaps? or can I place multiple images into the same Lightmap?

Thanks
Andres

It’s a utility function that is useful for combining objects. Basically you combine multiple textures into one texture, this way they can share the same material, and when they share the same material you can also combine the mesh from a script, which gives you a lot better performance, because it reduces draw calls.

maybe i’m wrong but it sounds to me like he wants an overlay combine (not atlas) for a kind of ‘dynamic’ lightmap - like for example you have say 5 streetlights if 2 get shot out you want the lightmap to update correctly.

Hello drJones

That is exactly what I want.

What is an overlay combine and how can I use it?

Andres

My (edited) post above has code that basically does that. It’s actually code from a game I wrote that combines textures on the fly, so I know it works…

–Eric

hi bakno ; )

there isn’t any ‘overlay combine’ specifically - sounds like the setpixel-getpixel method or something similar is what you’re looking for - it just seemed there was some confusion as to what result you were after.

Hello Eric

Could you please share the full code?

I need to know how to declare variables and how to call the getpixels().

Sorry but I am really new to this environment.

Thanks
Andres

Here is a script I wrote a long time ago as an experiment, that does just what you want:

var textures : Texture2D[];

var combineSrc = 0;
var combineMod = 1;

enum CombineMode {Multiply = 0, Add = 1, AlphaBlend = 2}
var combineMode = CombineMode.Multiply;

var outputToRenderer : Renderer;

function Start ()
{
	var srcTexture : Texture2D = textures[combineSrc];
	var modTexture : Texture2D = textures[combineMod];
	var newTexture : Texture2D;
	newTexture = CombineTextures(srcTexture, modTexture, combineMode);
	if(outputToRenderer.material.mainTexture) Destroy(outputToRenderer.material.mainTexture);
	outputToRenderer.material.mainTexture = newTexture;
}

function CombineTextures(srcTexture : Texture2D, modTexture : Texture2D, mode : CombineMode) : Texture2D
{
	var newTexture : Texture2D = new Texture2D(srcTexture.width, srcTexture.height, TextureFormat.ARGB32, true);

	if(mode == CombineMode.Multiply)
		DoMultiply(srcTexture, modTexture, newTexture);
	else if(mode == CombineMode.Add)
		DoAdd(srcTexture, modTexture, newTexture);
	else if(mode == CombineMode.AlphaBlend)
		DoAlphaBlend(srcTexture, modTexture, newTexture);

	newTexture.Apply();

	return newTexture;
}

function DoMultiply (srcTexture : Texture2D, modTexture : Texture2D, newTexture : Texture2D)
{
	var x = 0;
	while(x < srcTexture.width)
	{
		var y = 0;
		while(y < srcTexture.height)
		{
			var basePixel : Color = srcTexture.GetPixel(x, y);
			var modPixel : Color = modTexture.GetPixel(x, y);
	
			var newPixel : Color = Color(basePixel.r * modPixel.r, basePixel.g * modPixel.g, basePixel.b * modPixel.b, basePixel.a * modPixel.a);
			newTexture.SetPixel(x, y, newPixel);
	
			y++;
		}
		x++;
	}	
}

function DoAdd (srcTexture : Texture2D, modTexture : Texture2D, newTexture : Texture2D)
{
	var x = 0;
	while(x < srcTexture.width)
	{
		var y = 0;
		while(y < srcTexture.height)
		{
			var basePixel : Color = srcTexture.GetPixel(x, y);
			var modPixel : Color = modTexture.GetPixel(x, y);
	
			var newPixel : Color = Color(basePixel.r + modPixel.r, basePixel.g + modPixel.g, basePixel.b + modPixel.b, basePixel.a + modPixel.a);
			newTexture.SetPixel(x, y, newPixel);
	
			y++;
		}
		x++;
	}	
}

function DoAlphaBlend (srcTexture : Texture2D, modTexture : Texture2D, newTexture : Texture2D)
{
	var x = 0;
	while(x < srcTexture.width)
	{
		var y = 0;
		while(y < srcTexture.height)
		{
			var basePixel : Color = srcTexture.GetPixel(x, y);
			var modPixel : Color = modTexture.GetPixel(x, y);
	
			var newPixel : Color = Color.Lerp(basePixel, modPixel, modPixel.a);
			newTexture.SetPixel(x, y, newPixel);
	
			y++;
		}
		x++;
	}	
}

Nope (it wouldn’t make much sense out of context), but here’s a simple example:

var texture1 : Texture2D;
var texture2 : Texture2D;

function Start () {
	// Textures must be the same size and uncompressed
	if (texture1.height != texture2.height || texture1.width != texture2.width) {return;}
	if (IsCompressed(texture1)) {return;}
	if (IsCompressed(texture2)) {return;}
	
	// Combine textures
	var pixels1 = texture1.GetPixels();
	var pixels2 = texture2.GetPixels();
	for (i = 0; i < pixels1.Length; i++) { 
		pixels1[i] *= pixels2[i]; 
	}
	
	// Apply combined texture
	var tex = new Texture2D(texture1.width, texture1.height);
	renderer.material.mainTexture = tex;
	tex.SetPixels(pixels1);
	tex.Apply();
}

function IsCompressed(tex : Texture2D) {
	if (tex.format != TextureFormat.ARGB32  tex.format != TextureFormat.RGB24  tex.format != TextureFormat.Alpha8) {
		return true;
	}
	else {return false;}
}

If you put that script on an object, and then drag different textures (of the same size) onto the texture1 and texture2 slots in the inspector, the object will then have a combined texture made out of the two. Presumably you’d want to make something like that into an actual function instead of just having it in Start(), but hopefully that gets you started. It’s also possible you might want to use a different method of combining textures depending on the effect you want…this method will darken any overlapping colors, for example.

–Eric