Im working on a custom item system for a project and i was wondering if there’s a way to take several base PNG files, (or any alpha containing picture file) and stack them on eachother one at a time, to create a custom new image for use in the game at runtime
basically the idea is, the user selects various parts for their item (maybe a gem, a tool head and a tool handle or something like that) then the a new item image is created based on the stacked base images.
Well, alpha blending in the sense of (srcA, oneMinusSrcA) is pretty easy. Just grab the pixel data using GetPixels() of both images (I assume they have the same resolution?). All you have to do is multiply the color of your top image by it’s own alpha value. Same for the bottom image. To combine the two colors, just multiply the bottom color by (1.0 - alpha value of top color) and add the colors together. Next we have to calculate the alpha value of the resulting color. It’s simply (T.a + (1.0-T.a)*B.a). Finally we divide the color itself by the new alpha value
It’s well described [over here][1].
Something like that:
// C#
using UnityEngine;
public static class ImageHelpers
{
public static Texture2D AlphaBlend(this Texture2D aBottom, Texture2D aTop)
{
if (aBottom.width != aTop.width || aBottom.height != aTop.height)
throw new System.InvalidOperationException("AlphaBlend only works with two equal sized images");
var bData = aBottom.GetPixels();
var tData = aTop.GetPixels();
int count = bData.Length;
var rData = new Color[count];
for(int i = 0; i < count; i++)
{
Color B = bData*;*
Color T = tData*;* float srcF = T.a; float destF = 1f - T.a; float alpha = srcF + destF * B.a; Color R = (T * srcF + B * B.a * destF)/alpha; R.a = alpha; rData = R; } var res = new Texture2D(aTop.width, aTop.height); res.SetPixels(rData); res.Apply(); return res; } } If you add this class to your project you can simply create a new texture out of two like this: // C# Texture2D bottom; Texture2D top;
Texture2D combined = bottom.AlphaBlend(top); // UnityScript var bottom : Texture2D; var top : Texture2D;
var combined = bottom.AlphaBlend(top); Keep in mind that you have to make the textures readable in the texture importer by switching to the texture type “advanced”. If you don’t do that, GetPixels will fail. Since GetPixels also allows you to specify a region of the image you could combine only parts of the image, but it makes the for loop quite a bit more complicated. You also have to pass more parameters to the method to specify the source / target rectangle. [1]: Alpha compositing - Wikipedia
You can do this on the GPU using a shader to composite multiple images. Supply each one as a texture and and use a render target to run the shader and combine them into a new texture. You can look at the source code for Unity’s Image Effects to get ideas for how to do this. Even though those are operating on full screen images the same basic principals apply.
Another way is to do this on the CPU. If the images are small enough and you don’t have huge numbers of them this would be viable as well. Load the images as textures, use GetPixels to get the pixel data, run through image A, get the corresponding pixel from Image B, combine them how you want using alpha, output to Image C. Next use Image C as input to the next round, repeat. If you have a limited number of input images you could combine them all at once rather than two at a time.
Image composition is a complicated subject. Yes, you can write shaders or Get/SetPixels. But if you’re asking how to do it either of those ways, then it’s probably too advanced for you, atm.
I’m assuming this is a 2D game. The easiest approach would be to simply have multiple GameObjects that represent the different images and place them in the correct locations. When Unity renders the objects they will get composited for you into what looks like a single image.
If you really really want to go the DIY image composition route, I would still recommend starting off with the multiple GameObject route, while you learn and build your shaders or scripts that will composite stuff the way you want.