【问题标题】:SDL + SDL_ttf: Transparent blended text?SDL + SDL_ttf:透明混合文本?
【发布时间】:2023-12-09 21:39:01
【问题描述】:

我想在具有给定 Alpha 通道的 SDL_Surface 上呈现抗锯齿字符串。

我发现可以渲染:

  • 具有字符串渲染方法的Blended 变体的抗锯齿字符串(即:TTR_RenderText_Blended)。但是我不能让它透明。
  • 使用Shaded 方法的抗锯齿字符串。但是有一个坚实的背景。背景和绘制的字符串可以设为透明,但纯色背景仍然存在。也不可能给它传递一个透明的背景颜色。
  • 一个非抗锯齿字符串,我可以使用Solid 变体使其透明。但它没有抗锯齿。

谢谢

【问题讨论】:

  • 你有没有让这个工作?
  • @BruceConnor:不。这确实很可悲。我所做的是更改为 OpenGL 并使用位图字体。这需要做很多工作,但当我终于让它工作时,我真的很满意。希望您准备好花几个小时的编程来做同样的事情。
  • 您好,我遇到了和你一样的问题,还没有解决。也许你现在已经有了一个想法,我在那里问了一个问题:*.com/questions/12700085。就我而言,我现在不能使用位图字体。
  • @ForceMagic:不,我从来没有解决过。我转向了真正的东西,它与 GPU 一起工作,而不是 CPU。学习OpenGL,它更强大。一旦你知道如何使用它,你会很高兴你学会了。
  • @MartijnCourteaux 感谢您的建议,我目前正在使用这两种方法,我使用一些 SDL 通过鼠标输入和类似的东西让我的生活更轻松,但我确实使用 OpenGL 来绘制我的大部分内容屏幕上的纹理和瓷砖系统。但是,我认为 SDL_ttf 可以在文本绘图部分为我节省一些时间。我基本上是在尝试使用 OpenGL 从 SDL_ttf 绘制生成的纹理。不过,两者之间的混合似乎并不是很有效。

标签: c++ string rendering sdl


【解决方案1】:

我知道我在这方面有点晚了:/

根据SDL_SetAlpha 上的 SDL 文档:

请注意,每像素和每表面 alpha 不能组合;如果可用,则始终使用每像素 alpha。

所以常规的SDL_BlitSurface/SDL_SetAlpha 在这里不起作用。但可以做到:

我能想到的 alpha 混合 TTF_RenderText_Blended 输出的唯一方法是使用 OpenGL,或调整表面中每个像素的 alpha 值。

通过调整每个像素的 alpha 值

您可以通过将每个像素的 alpha 值从 [0, 255] 缩放到新范围 [0, alpha] 来做到这一点:

// Changes a surface's alpha value, by altering per-pixel alpha if necessary.
void SetSurfaceAlpha (SDL_Surface *surface, Uint8 alpha)
{
    SDL_PixelFormat* fmt = surface->format;

    // If surface has no alpha channel, just set the surface alpha.
    if( fmt->Amask == 0 ) {
        SDL_SetAlpha( surface, SDL_SRCALPHA, alpha );
    }
    // Else change the alpha of each pixel.
    else {
        unsigned bpp = fmt->BytesPerPixel;
        // Scaling factor to clamp alpha to [0, alpha].
        float scale = alpha / 255.0f;

        SDL_LockSurface(surface);

        for (int y = 0; y < surface->h; ++y) 
        for (int x = 0; x < surface->w; ++x) {
            // Get a pointer to the current pixel.
            Uint32* pixel_ptr = (Uint32 *)( 
                    (Uint8 *)surface->pixels
                    + y * surface->pitch
                    + x * bpp
                    );

            // Get the old pixel components.
            Uint8 r, g, b, a;
            SDL_GetRGBA( *pixel_ptr, fmt, &r, &g, &b, &a );

            // Set the pixel with the new alpha.
            *pixel_ptr = SDL_MapRGBA( fmt, r, g, b, scale * a );
        }   

        SDL_UnlockSurface(surface);
    }       
}           

我知道它看起来很吓人,但它很简单。重点在这里:

*pixel_ptr = SDL_MapRGBA( fmt, r, g, b, scale * a );

你可以这样使用它:

text_surface = TTF_RenderText_Blended( font, "Hello World!", color );
SetSurfaceAlpha( text_surface, 128 );

使用 OpenGL

如果使用 OpenGL,事情就容易多了。假设您将 SDL_SurfaceTTF_RenderText_Blended 转换为 GL 纹理,您可以使用:

glColor4f( 1.0, 1.0, 1.0, Alpha );

在纹理四边形上渲染之前。

但不要忘记先启用 alpha 混合!

glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

【讨论】:

  • 感谢您抽出宝贵时间提供这个迟到的答案。当更多人投票支持它时,您可能会获得死灵法师徽章。
  • 此外,如果您使用的是 OpenGL 可编程管线,您可以在片段着色器中将纹理单元乘以 alpha 值。颜色 = myColor.a * 纹理(myTexture, myCoords);
【解决方案2】:

您所要做的就是在您的SDL_Surface 上调用SDL_SetAlpha创建渲染文本的精灵之后,但在该精灵上调用SDL_DisplayFormatAlpha 之前强>。

// Make the sprite with the text on it
SDL_Surface *swSprite = TTF_RenderText_Solid( font, text, textColor ) ;

// CALL SET ALPHA NOW
SDL_SetAlpha( swSprite, SDL_SRCALPHA, 128 ) ; // 50% opacity

// OK, NOW you can convert it to display format.  I'm presuming
// you called `SDL_SetVideoMode` with the `SDL_HWSURFACE` flag set previously
SDL_Surface* hwSprite = SDL_DisplayFormatAlpha( swSprite ) ;

// If you invert the above 2 steps, it won't work.

// We don't need the software sprite anymore
SDL_FreeSurface( swSprite ) ;

// Now draw the hwSprite as normal
SDL_BlitSurface( hwSprite, NULL, screen, &spriteLocation );

【讨论】:

  • 请注意,这仅适用于 TTF_RenderText_Solid 变体,不适用于 TTF_RenderText_Blended
【解决方案3】:

使用 TTF 的方法是使用 SDL_SetTextureAlphaMod() 类似这样的东西

SDL_Surface *surface;
SDL_Texture *texture;
SDL_Color color = {255, 255, 255, 128}
surface = TTF_RenderText_Blended_Wrapped(myFont, "HI!", color, 100);
// myFont and the _renderer is pre-defined somewhere in the game
texture = SDL_CreateTextureFromSurface(_renderer, surface);
SDL_SetTextureAlphaMod(texture, color.a);
SDL_RenderCopy(_renderer, texture, NULL, &dest);
SDL_DestroyTexture(texture);
SDL_FreeSurface(surface);

/*...*/

SDL_RenderPresent(_renderer);

https://wiki.libsdl.org/SDL_SetTextureAlphaMod

【讨论】:

  • 万岁,感谢您的回答!我想知道这是否是新问题,因为问题最初是发布的?但这绝对对我有用。 +1
【解决方案4】:

为什么不使用位图字体?您可以使用 alpha 通道构建 png 图像。我认为 SDL_ttf 与相同的系统一起工作,它构建一个内部使用位图字体的图像。

【讨论】:

  • 请注意,@ForceMagic 已删除死链接。如果你能找到替代品,请将其重新添加。对于 ForceMagic,既然你问过,删除死链接很好,但请添加评论(这将通知发帖人),以便他们收到通知并找到新的(或替换)链接。