SDL2:如何处理透明度?

时间:2018-09-04 16:44:20

标签: sdl-2 alphablending

我正在尝试SDL2,遇到一种情况,当我在中间透明纹理上绘制时无法正确处理。

我要融合的图像:

  1. img_w_A_channel
  2. 某些纯黑色,其alpha值为:2551280
  3. window bg,这是可选的。

因此,如果我将其表示为图层,则如下所示

img_w_A_channel    img_w_A_channel    img_w_A_channel    img_w_A_channel
                    solid_texture    half_transparent   transparent_texture
   window               window            window            window
  • 在左侧,我直接在窗口上渲染图像。
  • solid_texture表示带有alpha=255的黑色中间纹理,在其中绘制图像,然后在窗口上绘制纹理。
  • half_transparent表示带有alpha=128的黑色中间纹理,在其中绘制图像,然后在窗口上绘制纹理。
  • transparent_texture表示带有alpha=0的黑色中间纹理,在其中绘制图像,然后在窗口上绘制纹理。

因此,请考虑将中间纹理作为我要绘制的容器。由于窗口可以具有此处的背景纹理,因此SDL_BLENDMODE_NONE不是中间纹理的选项。

结果是:

enter image description here

如您所见,第一张和第二张图像(在固体中间纹理上绘制的是相同的)。 第三和第四张图像(绘制在半透明和透明的中间纹理上)不同。

问题出在右边的图像上。我希望结果与左侧的图像匹配。即能够在透明容器中绘制并获得与直接在窗口上绘制相同的结果。

我的完整测试代码是:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *background = NULL;
SDL_Texture *image = NULL;
SDL_Surface* surface = NULL;

SDL_Rect dst = {20, 20, 100, 100};

#define SOLID 255
#define HALF_TRANSPARENT 128
#define TRANSPARENT 0

SDL_Texture * renderImageInATexture(SDL_Texture *image, Uint8 transparency) {

    // Create an intermediate texture
    SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, 200, 200);
    SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
    SDL_SetRenderTarget(renderer, texture);

    // Paint it
    SDL_SetRenderDrawColor(renderer, (Uint8) 0, (Uint8) 0, (Uint8) 0,(Uint8) transparency);
    SDL_RenderClear(renderer);

    // Render the image in intermediate texture
    SDL_SetRenderTarget(renderer, texture);
    SDL_RenderCopy( renderer, image, NULL, &dst );

    SDL_SetRenderTarget(renderer, NULL);
    return texture;
}

int main(char *argc, char **argv) {

    SDL_Init( SDL_INIT_VIDEO);

     window = SDL_CreateWindow("Win", SDL_WINDOWPOS_UNDEFINED, 
                               SDL_WINDOWPOS_UNDEFINED,
                           800, 200, SDL_WINDOW_SHOWN);

    // So we can save into pngs to check the value
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);


    SDL_SetRenderTarget(renderer, NULL);

    // Fill the window with a texture for fun (doesn't change anything on the problem) can be removed ....
    surface = IMG_Load( "./carbone.png" );
    background = SDL_CreateTextureFromSurface( renderer, surface );
    SDL_FreeSurface( surface );
    // draw background in main display
    SDL_RenderCopy( renderer, background, NULL, NULL );
    // .... until here

    surface = IMG_Load( "./image.png" );
    image = SDL_CreateTextureFromSurface( renderer, surface );
    SDL_FreeSurface( surface );
    // draw imagein main display
    SDL_RenderCopy( renderer, image, NULL, &dst );

    SDL_Texture *texture = renderImageInATexture(image, SOLID);
    // render intermediate texture in main display
    SDL_Rect dstTexture = {200, 0, 200, 200};
    SDL_RenderCopy( renderer, texture, NULL, &dstTexture );

    SDL_Texture *texture2 = renderImageInATexture(image, HALF_TRANSPARENT);
    // render intermediate texture2 in main display
    SDL_Rect dstTexture2 = {400, 0, 200, 200};
    SDL_RenderCopy( renderer, texture2, NULL, &dstTexture2 );

    SDL_Texture *texture3 = renderImageInATexture(image, TRANSPARENT);
    // render intermediate texture3 in main display
    SDL_Rect dstTexture3 = {600, 0, 200, 200};
    SDL_RenderCopy( renderer, texture3, NULL, &dstTexture3 );


    SDL_RenderPresent(renderer);

    SDL_Delay(10000);

    SDL_DestroyTexture(image);
    SDL_DestroyTexture(bakcground); // only if you use a background
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

}

并进行构建:

cc main.c -lSDL2 -lSDL2_image

内置SDL 2.0.8,但这没关系。

有解决此问题的主意吗?

**编辑**

所以我根据@aram的答案替换来修改了renderImageInATexture()函数:

SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);

作者:

    SDL_BlendMode mode = SDL_ComposeCustomBlendMode(1, 1, 
                                                    SDL_BLENDOPERATION_ADD,
                                                    1, 1, 
                                                    SDL_BLENDOPERATION_ADD);
    SDL_SetTextureBlendMode(texture, mode);

我还直接在上面的先前代码中更改了初始化,以便能够按照@aram的建议保存屏幕。但是我必须使用SDL_RENDERER_ACCELERATED来阻止not supported operation上的SDL_ComposeCustomBlendMode()通话。 无论如何,我收到一条Surface doesn't have a colorkey消息。有问题吗?

但是看来SDL_ComposeCustomBlendMode()仍然不是解决方案。
首先,尽管背景图片并不重要,因为通过我的测试,无论有没有背景图片,我都能得到相同的结果。
不幸的是,如果@aram的答案给我的结果与以实心的中间纹理渲染图像时的结果相同: enter image description here

0 个答案:

没有答案