3
votes

I'm trying to blend several textures together with anti-aliasing enabled, it works fine if textures are not rotated, but when i rotate a texture, anti-aliasing produces a "border" at the edge of texture. Below is example.

Original texture, 100x100px image with 50x50px blue square in the middle.

original texture

I'm rendering this texture twice: as-is and rotated 45 degrees. It produces the following result:

result picture

Note gray-ish border of rotated texture. In my opinion, texture on top should seamlessly blend with texture at bottom because they both contain pixels of the same color. If anti-aliasing is disabled, then textures do blend without any border as expected, but obviously i would like to have anti-aliasing for rotated textures.

Is there a way to achieve both: anti-aliased textures and seamless blending?

I'm rendering with SDL2 and OpenGL. Below is example program demonstrating this effect.

#include <assert.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

void render(SDL_Renderer *renderer, SDL_Texture *tex) {
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF);
    SDL_RenderClear(renderer);

    SDL_Rect dst_rect = { 0, 0, 100, 100 };

    SDL_RenderCopyEx(renderer, tex, 0, &dst_rect,
        0, 0, SDL_FLIP_NONE);
    SDL_RenderCopyEx(renderer, tex, 0, &dst_rect,
        45, 0, SDL_FLIP_NONE);

    SDL_RenderPresent(renderer);
}

int main() {
    SDL_Window *window;
    SDL_Renderer *renderer;

    SDL_Init(SDL_INIT_VIDEO);
    SDL_CreateWindowAndRenderer(100, 100, SDL_WINDOW_OPENGL, &window, &renderer);

    /* comment the following line for blended images */
    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");

    SDL_Texture *tex = IMG_LoadTexture(renderer, "./sample.png" );
    assert(tex != 0);

    SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);

    render(renderer, tex);

    SDL_Event event = { 0 };
    while (1) {
        if (SDL_PollEvent(&event) == 0) {
            SDL_Delay(100);
            continue;
        }

        if (event.type == SDL_QUIT) {
            SDL_Quit();
            break;
        }
    }

    return 0;
}

Edit: I've found out that if i rotate texture by 45 degrees inside of SDL_RenderCopyEx, it adds semi-transparent border of a different color, please see picture below.

enter image description here

Note how color changes around the edges of rotated image.

1
The first example doesn't have grey colors, but different shades of blue. The seconds example produces a border with three different shades of blue going from brighter( cube ) to darker( black background ).this
You are absolutely right, it looks gray-ish, but in fact it's a different shades of blue. It's a different blue though, original blue is #87ceeb, but it transforms into #6aa2b9 - darker blue instead of semi-transparent #87ceeb which should blend with underlying pixels of the same color.plasmatron
Try with a different background.this
With #00000000 background (ARGB, transparent black) border color shifts to black (as in examples), with #00ffffff background (transparent white) color also shifts to black, with #01ffffff (almost transparent white) color shifts to white, with #0187ceeb (almost transparent blue) texture blends seamlessly. I'm confident that i'm missing something important, anti-aliasing shouldn't work like that, right?plasmatron
Maybe it has to do with transparency, try completely transparent background.this

1 Answers

0
votes

Working solution i've found is to fill transparent part of the image with almost transparent pixels of the same color. Reference picture:

enter image description here

"Transparent" color in that picture is 0x0187ceeb (ARGB). It then produces blended image as expected:

enter image description here

Some details of this workaround are described here: http://www.saschahlusiak.de/2012/10/opengl-antialiasing-in-android-with-transparent-textures/