sdl-2 - SDL2:如何处理透明度?
问题描述
我正在试验 SDL2,当我在中间透明纹理上绘制时遇到了无法正确管理的情况。
我试图混合的图像:
- img_w_A_channel
- 一些带有 alpha 的纯黑色:
255
、128
或0
- 可选的窗口 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
因此不能选择中间纹理。
结果是:
如您所见,第一张和第二张图像(在实心中间纹理上绘制)是相同的。第三和第四张图像(在半透明和透明中间纹理上绘制)不完全相同。
问题在于右边的图像。我希望结果与左侧的图像匹配。即能够在透明容器中绘制并获得与直接在窗口上绘制相同的结果。
我的完整测试代码是:
#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 operation
on SDL_ComposeCustomBlendMode()
call。无论如何,我收到一条Surface doesn't have a colorkey
消息。这是个问题吗?
但似乎它仍然SDL_ComposeCustomBlendMode()
不是解决方案。
首先,我认为背景图像并不重要,因为从我的测试来看,无论有没有它,我都得到了相同的结果。
不幸的是,如果@aram 的回答给了我与我将图像渲染为实心中间纹理时相同的结果:
解决方案
推荐阅读
- angular - 由于使用 UUID 生成的密钥无法加密有效负载,因此面临 AES 加密问题
- rdf - 如何区分同名的本体个体
- openshift - OpenShift - pod 无法在 CodeReady 容器上重新启动
- bigcommerce - 如何使用 bigcommerce 的 checkout-sdk-js 在结帐中添加新的自定义字段?
- node.js - mongoDB聊天系统数据库结构
- java - 如何在应用栏中强制将四个以上的菜单项作为操作项
- android - 除非应用程序被杀死并重新启动,否则通知设置不会反映在我的 android 应用程序中
- .net-core - 在 adfs 2012 r2 使用 oauth2.0 协议的情况下如何获取新的访问令牌
- angular - Firebase Cloud Messaging 在 Angular 10 中无法在生产模式下工作
- eclipse - Eclipse 不尊重 Lombok AllArgsConstructor、Getter 和 Setter