1

I've been trying to create a tileset generator (blending two images together) but I'm stuck at what kind of method I need to be able to make one texture/image overlap onto the main one, or somehow fade out at specific points - or is this something that can't be done (or shouldn't be done) automaticaly?

Example of tile

With the green image fading out, the blue image should fade in on top of the green image to make a smooth transition. If I have two images already - how can I do this?

Right now, I can only cut out the part that's blue. So the only part left is green, when I've tried adding an overlay it's just simply ugly and I suppose the alpha levels should increase (the blue should get more blue the closer you are to the Bottom Right corner).

Any ideas what I should be looking at?

My current method: But currently, this only works with one corner but should work with "all" corners; can't figure out what's causing it.

Point in polygon method

public static Bitmap GenerateTile(Bitmap bitmap, Bitmap copyFrom, int x, int y, int width, int height, Point[] cutoff)
{
        if (bitmap.Size != copyFrom.Size)
            throw new Exception("Invalid image size. Image sizes must match");

        Bitmap bmap = new Bitmap(width, height);
        Bitmap overlay = new Bitmap(width, height);

        Point min, max;
        float alpha;

        // returns minimum x, y and maximum x, y
        GetCorners(cutoff, out min, out max);

        for (int bx = x; bx < (x + width); bx++)
        {
            for (int by = y; by < (y + height); by++)
            {
                if (!IsInPolygon2(cutoff, new Point(bx, by)))
                {
                    bmap.SetPixel(bx, by, bitmap.GetPixel(bx, by));
                }
                else
                {

                    alpha = ((float)((max.X - bx) + (max.Y - by)) / (float)((max.X - min.X) + (max.Y - min.Y)));

                    if (alpha >= 0 && alpha <= 0.5f)
                    {
                        bmap.SetPixel(bx, by, Color.FromArgb((int)((alpha / 0.5f) * 255f), bitmap.GetPixel(bx, by)));
                        overlay.SetPixel(bx, by, Color.FromArgb((int)(255f - ((alpha / 0.5f) * 255f)), copyFrom.GetPixel(bx, by)));
                    }
                }
            }
        }

        using (Graphics g = Graphics.FromImage(bmap))
        {
            g.DrawImageUnscaled(overlay, 0, 0);
        }

        return bmap;
}

My method returns the following results (not good yet): generate

// bottom right corner
points.Add(new Point(image.Width / 2, image.Height));
points.Add(new Point(image.Width, image.Height / 2));
points.Add(new Point(image.Width, image.Height));
points.Add(new Point(image.Width / 2, image.Height));

// rightside
points.Add(new Point(image.Width / 2, image.Height));
points.Add(new Point(image.Width, image.Height));
points.Add(new Point(image.Width, 0));
points.Add(new Point(image.Width / 2, 0));
points.Add(new Point(image.Width / 2, image.Height));
Community
  • 1
  • 1
Deukalion
  • 2,516
  • 9
  • 32
  • 50
  • Hopefully, this should work with more advanced images like real textures. – Deukalion Dec 26 '12 at 20:05
  • Could you please post an image of what you expect to see and what actually happens along with the code that does it? – user1306322 Dec 27 '12 at 02:57
  • The main image on the overall image, and the overlay slowly fading in towards the bottom right corner. Or something similiar to make a transition between two tiles. – Deukalion Dec 27 '12 at 09:23
  • You're doing this with `SetPixel` but that will be very slow if you have lots of calls. I think this should be done by alpha masking, though I'm not certain. – user1306322 Dec 27 '12 at 11:45
  • How do you alpha mask an image beforehand without using shaders? Just for the purpose of a Tileset generator. – Deukalion Jan 01 '13 at 00:36
  • I guess by a similar operation you do with `SetPixel` method, but also getting a corresponding mask pixel's opacity. There should be multiple ways to do that, I'm sure, I haven't really tried any yet. – user1306322 Jan 01 '13 at 02:29
  • Problem is to programatically create a corner alpha fade in / fade out effect or similar, almost like a border around the image but only at the half in from bottom left to the bottom right to the half height to top right part, etc. – Deukalion Jan 01 '13 at 16:14

1 Answers1

1

I would try blending the grass and snow textures together as 3D primitives. That way you won't need to generate a separate bitmap for each combination of textures and fade orientations. To demonstrate, here's a code snippet you can paste into the Draw method of the default XNA project in Visual Studio:

GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.BlendState = BlendState.NonPremultiplied;
effect.TextureEnabled = true;
effect.VertexColorEnabled = true;
effect.World = Matrix.CreateTranslation(new Vector3(-0.5f, -0.5f, 0))
    * Matrix.CreateScale(300)
    * Matrix.CreateTranslation(-Vector3.UnitZ);
effect.Projection = Matrix.CreateOrthographic(GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 1, 10000);
effect.View = Matrix.CreateLookAt(Vector3.UnitZ, Vector3.Zero, Vector3.UnitY);

var grassVertices = new[]
{
    new VertexPositionColorTexture(Vector3.Zero, new Color(1f, 1f, 1f, 1f), Vector2.Zero),
    new VertexPositionColorTexture(Vector3.UnitY, new Color(1f, 1f, 1f, 1f), Vector2.UnitY),
    new VertexPositionColorTexture(new Vector3(1, 1, 0), new Color(1f, 1f, 1f, 1f), Vector2.One),
    new VertexPositionColorTexture(Vector3.Zero, new Color(1f, 1f, 1f, 1f), Vector2.Zero),
    new VertexPositionColorTexture(new Vector3(1, 1, 0), new Color(1f, 1f, 1f, 1f), Vector2.One),
    new VertexPositionColorTexture(Vector3.UnitX, new Color(1f, 1f, 1f, 0f), Vector2.UnitX),
};
effect.Texture = grassTexture;
effect.Techniques[0].Passes[0].Apply();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, grassVertices, 0, 2);

var snowVertices = new[]
{
    new VertexPositionColorTexture(Vector3.Zero, new Color(1f, 1f, 1f, 0f), Vector2.Zero),
    new VertexPositionColorTexture(Vector3.UnitY, new Color(1f, 1f, 1f, 0f), Vector2.UnitY),
    new VertexPositionColorTexture(new Vector3(1, 1, 0), new Color(1f, 1f, 1f, 0f), Vector2.One),
    new VertexPositionColorTexture(Vector3.Zero, new Color(1f, 1f, 1f, 0f), Vector2.Zero),
    new VertexPositionColorTexture(new Vector3(1, 1, 0), new Color(1f, 1f, 1f, 0f), Vector2.One),
    new VertexPositionColorTexture(Vector3.UnitX, new Color(1f, 1f, 1f, 1f), Vector2.UnitX),
};
effect.Texture = snowTexture;
effect.Techniques[0].Passes[0].Apply();
GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleList, snowVertices, 0, 2);

And here's what is needed in the LoadContent method to initialize resources:

grassTexture = Content.Load<Texture2D>("grass");
snowTexture = Content.Load<Texture2D>("snow");
effect = new BasicEffect(GraphicsDevice);

To create the tile fade in other directions, you would only edit grassVertices and snowVertices. For fades that go directly right, left, up or down, you'd need to use four triangles instead of two.

vvnurmi
  • 448
  • 6
  • 10