首页 > 解决方案 > SDL2:如何处理透明度?

问题描述

我正在试验 SDL2,当我在中间透明纹理上绘制时遇到了无法正确管理的情况。

我试图混合的图像:

  1. img_w_A_channel
  2. 一些带有 alpha 的纯黑色:2551280
  3. 可选的窗口 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

因此,将中间纹理视为我要绘制的容器。因此,由于窗口可以具有像这里这样的背景纹理,SDL_BLENDMODE_NONE因此不能选择中间纹理。

结果是:

在此处输入图像描述

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

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

我的完整测试代码是:

#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 构建,但没关系。

任何想法来解决这个问题?

** 编辑 **

所以我renderImageInATexture()根据@aram的回答修改了我的函数:

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 的建议保存我的屏幕。但我不得不使用 aSDL_RENDERER_ACCELERATED来防止not supported operationon SDL_ComposeCustomBlendMode()call。无论如何,我收到一条Surface doesn't have a colorkey消息。这是个问题吗?

但似乎它仍然SDL_ComposeCustomBlendMode()不是解决方案。
首先,我认为背景图像并不重要,因为从我的测试来看,无论有没有它,我都得到了相同的结果。
不幸的是,如果@aram 的回答给了我与我将图像渲染为实心中间纹理时相同的结果: 在此处输入图像描述

标签: sdl-2alphablending

解决方案


推荐阅读