【问题标题】:SDL_RenderCopy-ing to another texture results in subtly darker imageSDL_RenderCopy 到另一个纹理会导致图像稍微变暗
【发布时间】:2022-02-06 14:06:43
【问题描述】:

我一直在追逐这个视觉错误,我得出的结论是,从一个纹理到另一个纹理的 renderCopying 过程会导致图像稍微变暗。

#include "basics.h"

#include <SDL.h>
#include <SDL_ttf.h>

#ifdef WIN32
#define _WIN32_WINNT 0x0500
#include <windows.h>
#endif



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~O~~~~~~~~~~| M A I N |~~~~~~~~~~~O~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main(int argc, char *argv[]){

    SDL_Window *window;
    SDL_Renderer *renderer;
    int width = 640;
    int height = 480;
    int loop = 1;
    int mouseX, mouseY, pmouseX, pmouseY;


    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
        return 3;
    }
    if (SDL_CreateWindowAndRenderer(width, height, SDL_WINDOW_RESIZABLE | SDL_WINDOW_MAXIMIZED, &window, &renderer)) {
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window and renderer: %s", SDL_GetError());
        return 3;
    }

    SDL_GetWindowSize( window, &width, &height );


    const SDL_Color black = {0, 0, 0, 255};
    const SDL_Color white = {255, 255, 255, 255};

    char font_filename [] = "fonts/FreeSerif.ttf";//AveriaLibre-Regular
    int size = 20;

    if(TTF_Init() == -1){
        printf("TTF_Init: %s\n", TTF_GetError());
    }
    TTF_Font *font = TTF_OpenFont( font_filename, size );
    
    char str [] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
    
    SDL_Rect dst1 = (SDL_Rect){ 100, 100, 400, 200 };
    SDL_Rect dst2 = (SDL_Rect){ 515, 100, 400, 200 };

    
    SDL_Texture *buffer = SDL_CreateTexture( renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height );
    SDL_SetTextureBlendMode( buffer, SDL_BLENDMODE_BLEND );

    SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255);
    SDL_RenderClear( renderer );

    SDL_Surface *surf = TTF_RenderText_Blended_Wrapped( font, str, white, dst1.w );
    dst1.w = surf->w; dst1.h = surf->h;
    SDL_Texture *texture = SDL_CreateTextureFromSurface( renderer, surf );
    SDL_RenderCopy( renderer, texture, NULL, &dst1 );


    SDL_SetRenderTarget( renderer, buffer );
    dst2.w = surf->w; dst2.h = surf->h;
    SDL_RenderCopy( renderer, texture, NULL, &dst2 );
    SDL_SetRenderTarget( renderer, NULL );
    SDL_RenderCopy( renderer, buffer, NULL, &(SDL_Rect){0, 0, width, height} );
    

    SDL_FreeSurface( surf );
    SDL_DestroyTexture( texture );

    char ascii [] = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
    
    surf = TTF_RenderText_Blended( font, ascii, white );
    texture = SDL_CreateTextureFromSurface( renderer, surf );
    SDL_RenderCopy( renderer, texture, NULL, &(SDL_Rect){100, 500, surf->w, surf->h} );

    
    SDL_SetRenderTarget( renderer, buffer );
    SDL_RenderCopy( renderer, texture, NULL, &(SDL_Rect){100, 530, surf->w, surf->h} );
    SDL_SetRenderTarget( renderer, NULL );
    SDL_RenderCopy( renderer, buffer, NULL, &(SDL_Rect){0, 0, width, height} );


    SDL_RenderPresent(renderer);

    while( 1 ) {
        SDL_Event event;
        while( SDL_PollEvent(&event) ){
            if(event.type == SDL_QUIT) {
                goto exit;
            }
        }
    }
    exit:

    SDL_DestroyTexture( buffer );
    SDL_DestroyTexture( texture );
    SDL_FreeSurface( surf );
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    SDL_Quit();

    return 0;
}

这个程序的结果是: text rendering output

就像我说的,这是一种微妙的效果,您可能需要放大,但就我的目的而言,它真的很糟糕。任何人都知道可能是什么原因,或者一些解决方法?谢谢。

【问题讨论】:

    标签: c rendering sdl text-rendering


    【解决方案1】:

    您对同一数据递归地多次应用混合操作。

    您的渲染纹理与您的窗口大小相同。您没有清除它,所以我们假设它默认为零,包括 alpha(它可能取决于实现,我没有看到文档说明无论如何;使用所需颜色明确清除可能是个好主意)。

    SDL_ttf 为您提供带有 Alpha 通道的表面。然后,您使用 blendmode=blend 将您的第一个文本片段渲染到该纹理,将其混合在零之上。如果您查看formulas for blend operations - 渲染目标的 alpha 值会被您的文本纹理覆盖(dstA = srcA + (dstA * (1-srcA)),而dstA 为 0,所以它只是 srcA),但颜色值会乘以您的源阿尔法,所以srcRGB = srcRGB * srcA

    然后你在屏幕顶部混合这个目标纹理,它被清除为 (0, 0, 0, 255),再次应用相同的混合操作,导致由相同的 srcA 进行另一次混合,所以你的颜色现在是srcRGB = srcRGB * srcA * srcA。这显然是不正确的。

    第二个文本片段会变得更糟,因为您再次执行所有操作,但从未清除渲染目标。因此,当您再次使用渲染目标时,您会再次渲染整个纹理,包括在第一个文本片段处渲染的内容,并在此之上应用另一个混合。

    您只需要进行一次混合。有多种方法可以做到这一点,您必须决定哪种方法最适合您的情况。我不知道你想如何使用你的渲染纹理,所以假设你想保持 alpha 值,你需要在最后阶段进行混合。这可以通过使用 blendmode=none 绘制到渲染目标中来实现,然后将渲染纹理 blitting 到屏幕上,但只有一次。例如:

    SDL_Texture *buffer = SDL_CreateTexture( renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height );
    SDL_SetTextureBlendMode( buffer, SDL_BLENDMODE_BLEND );
    
    SDL_SetRenderDrawColor( renderer, 0, 0, 0, 255);
    SDL_RenderClear( renderer );
    
    // first text fragment, rendering directly to screen
    SDL_Surface *surf = TTF_RenderText_Blended_Wrapped( font, str, white, dst1.w );
    dst1.w = surf->w; dst1.h = surf->h;
    SDL_Texture *texture = SDL_CreateTextureFromSurface( renderer, surf );
    SDL_RenderCopy( renderer, texture, NULL, &dst1 );
    
    // first text fragment, rendering to render texture. blendmode=none to avoid
    // pre-blending
    SDL_SetRenderTarget( renderer, buffer );
    dst2.w = surf->w; dst2.h = surf->h;
    SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE);
    SDL_RenderCopy( renderer, texture, NULL, &dst2 );
    SDL_SetRenderTarget( renderer, NULL );
    // NOT copying render target to screen. It is not finished yet, need to do
    // that only once
    
    SDL_FreeSurface( surf );
    SDL_DestroyTexture( texture );
    
    char ascii [] = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
    
    // second text fragment, rendering directly to screen
    surf = TTF_RenderText_Blended( font, ascii, white );
    texture = SDL_CreateTextureFromSurface( renderer, surf );
    SDL_RenderCopy( renderer, texture, NULL, &(SDL_Rect){100, 500, surf->w, surf->h} );
    
    // second text fragment, rendering to render texture, blendmode=none
    SDL_SetRenderTarget( renderer, buffer );
    SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE);
    SDL_RenderCopy( renderer, texture, NULL, &(SDL_Rect){100, 530, surf->w, surf->h} );
    SDL_SetRenderTarget( renderer, NULL );
    
    // render texture finished, now it is time to blend it with screen contents
    SDL_RenderCopy( renderer, buffer, NULL, &(SDL_Rect){0, 0, width, height} );
    
    SDL_RenderPresent(renderer);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-21
      • 2021-12-09
      • 1970-01-01
      • 2017-06-25
      • 1970-01-01
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多