Sora
Sora

Reputation: 2551

Merging two different texture into one in unity3d

i am trying to merge two textures into one in unity the first texture is from a webcamTexture the second is from a sprite using : gameobject.getComponent<SpriteRenderer>().sprite.texture as Texture2D

I'm having problem in writing the function this is what i did so far :

public static Texture2D CombineTextures(GameObject obj, Texture2D background, Texture2D TodrawLogo)
{
    Vector3 v = obj.transform.position;// obj is TodrawLogo gameobject
    int width = TodrawLogo.width;
    int height = TodrawLogo.height;
    for (int x =(int)v.x; x < width; x++){
        background.SetPixel(x,(int)v.y,TodrawLogo.GetPixel(x,(int)v.y));
    }
    background.Apply();
    return background;
}

this what i am trying to do :

WebcamTexture enter image description here

the result Texture should be like this enter image description here

the webcamTexture is a 3dplane and the logo is a single sprite but sadly my function doesn't work does anyone know how to fix this I know that i should find the exact coordinate of the todraw image and set the pixels but i can't figure out how

Much appreciation

EDIT:

i tried to use @nexx code :

public static Texture2D CombineTexture(Texture2D background, Texture2D TodrawLogo)
{

  int width = TodrawLogo.width;
  int height = TodrawLogo.height;

  int backWidth = background.width;
  int backHeight = background.height;
// bottom right corner
int startX = backWidth - width;
int startY = backHeight - height;

// loop through texture
int y = 0;
while (y < backHeight) {
    int x = 0;
    while (x < backWidth) {
        // set normal pixels
        background.SetPixel(x,y,background.GetPixel(x,y));
        // if we are at bottom right apply logo 
        //TODO also check alpha, if there is no alpha apply it!
        if(x >= startX && y < backHeight- startY)
            background.SetPixel(x,y,TodrawLogo.GetPixel(x-startX,y-startY));
        ++x;
    }
    ++y;
}
background.Apply();
return background;
 }

but this is the resulting image i get : enter image description here

i am stuck at this can someone please tell me what am i doing wrong ?

Upvotes: 4

Views: 28216

Answers (6)

Huff
Huff

Reputation: 11

A slightly more optimized solution. Reading and writing only the area required for the watermark.

    public static Texture2D AddWatermark(Texture2D background, Texture2D watermark, int startPositionX, int startPositionY)
    {
        //only read and rewrite the area of the watermark
        for (int x = startPositionX; x < background.width; x++)
        {
            for (int y = startPositionY; y < background.height; y++)
            {
                if (x - startPositionX < watermark.width && y - startPositionY < watermark.height)
                {
                    var bgColor = background.GetPixel(x, y);
                    var wmColor = watermark.GetPixel(x - startPositionX, y - startPositionY);

                    var finalColor = Color.Lerp(bgColor, wmColor, wmColor.a / 1.0f);

                    background.SetPixel(x, y, finalColor);
                }
            }
        }

        background.Apply();
        return background;
    }

Upvotes: 1

Fritz Catz
Fritz Catz

Reputation: 11

This code works perfectly with two images that are not the same size

public static Texture2D AddWatermark(Texture2D background, Texture2D watermark, int startX, int startY)
{
    Texture2D newTex = new Texture2D(background.width, background.height, background.format, false);
    for (int x = 0; x < background.width; x++)
    {
        for (int y = 0; y < background.height; y++)
        {
            if (x >= startX && y >= startY && x < watermark.width && y < watermark.height)
            {
                Color bgColor = background.GetPixel(x, y);
                Color wmColor = watermark.GetPixel(x - startX, y - startY);

                Color final_color = Color.Lerp(bgColor, wmColor, wmColor.a / 1.0f);

                newTex.SetPixel(x, y, final_color);
            }
            else
                newTex.SetPixel(x, y, background.GetPixel(x, y));
        }
    }

    newTex.Apply();
    return newTex;
}

Upvotes: 1

Nolex
Nolex

Reputation: 136

Here's a working example. I tested!

public Texture2D AddWatermark(Texture2D background, Texture2D watermark)
{

    int startX = 0;
    int startY = background.height - watermark.height;

    for (int x = startX; x < background.width; x++)
    {

        for (int y = startY; y < background.height; y++)
        {
            Color bgColor = background.GetPixel(x, y);
            Color wmColor = watermark.GetPixel(x - startX, y - startY);

            Color final_color = Color.Lerp(bgColor, wmColor, wmColor.a / 1.0f);

            background.SetPixel(x, y, final_color);
        }
    }

    background.Apply();
    return background;
}

Upvotes: 12

wronex
wronex

Reputation: 1035

Try this (its a modification of nexx's code.) It combines two textures into a new texture. The new texture is guarenteed to be writable (otherwise SetPixel/GetPixel won't work.)

Also, it assumes that the watermark texture is smaller than the background texture.

Please note: I've not tested this.

public static Texture2D AddWatermark(Texture2D background, Texture2D watermark)
{
    // Create a new writable texture.
    Texture2D result = new Texture2D(background.width, background.height);

    // Draw watermark at bottom right corner.
    int startX = background.width - watermark.width;
    int startY = background.height - watermark.height;

    for (int x = 0; x < background.width; x++) {
        for (int y = 0; y < background.height; y++) {
            Color bgColor = background.GetPixel(x, y);
            Color wmColor = new Color(0, 0, 0, 0);

            // Change this test if no longer drawing at the bottom right corner.
            if (x >= startX && y >= startY) {
                wmColor = watermark.GetPixel(x, y);
            }

            // Alpha-blend background and watermark color.
            Color bended = bgColor * (1.0f - wmColor.a) + wmColor;
            blended.a = 1.0f;

            result.SetPixel(x, y, blended);
        }
    }

    result.Apply();
    return result;
}

Upvotes: 0

Hambalk&#243; Bence
Hambalk&#243; Bence

Reputation: 125

I don't know how you would like to do it but you can use unity's OnGUI method to draw the logo where needed.

http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnGUI.html

Its as simple as something like this:

var aTexture : Texture;

function OnGUI() {
    if(!aTexture){
        Debug.LogError("Assign a Texture in the inspector.");
        return;
    }
    GUI.DrawTexture(Rect(10,10,60,60), aTexture, ScaleMode.ScaleToFit, true, 10.0f);
}

I hope i was helpful.

Upvotes: 0

nexx
nexx

Reputation: 579

I made some changes for your CombineTextures method,

public static Texture2D CombineTexture(GameObject obj, Texture2D background, Texture2D TodrawLogo)
{
    int width = TodrawLogo.width;
    int height = TodrawLogo.height;

    int backWidth = background.width;
    int backHeight = background.height;
    // bottom right corner
    int startX = backWidth - width;
    int startY = backHeight - height;

    // loop through texture
    int y = 0;
    while (y < backHeight) {
        int x = 0;
        while (x < backWidth) {
            // set normal pixels
            background.SetPixel(x,y,background.GetPixel(x,y));
            // if we are at bottom right apply logo 
            //TODO also check alpha, if there is no alpha apply it!
            if(x >= startX && y < backHeight- startY)
                background.SetPixel(x,y,TodrawLogo.GetPixel(x-startX,y-startY));
            ++x;
        }
        ++y;
    }
    background.Apply();
    return background;
}

You can change the values inside while loop to place your texture where you want.

Upvotes: 0

Related Questions