如何在SDL中创建渐变颜色

4

SDL没有这样的功能,我很好奇是否有人曾经做过这件事情并愿意指引我方向。我想在一个矩形的高度上创建两种颜色之间的渐变。


3
如果只是水平或垂直的线性渐变,很简单:在R1和R2,G1和G2,B1和B2之间进行插值。 - Michael
更多通用的渲染方式:https://dev59.com/M3rZa4cB1Zd3GeqP4Jem#36504803 - Ciro Santilli OurBigBook.com
2个回答

10

只需在所需的y位置上制作循环,在此过程中:

  1. 通过在渐变端点颜色之间插值计算所需的颜色。
  2. 调用SDL_SetRenderDrawColor()来设置颜色。
  3. 调用SDL_RenderDrawLine()来绘制当前y位置处的水平线。

不完全是我原来想做的,但肯定帮助了我度过难关。有关位置的那一部分为我澄清了事情。 - j0h
这个可以工作,但一定有硬件加速的解决方案。 - Mariusz Jaskółka

10

昨天我在思考这个问题时,想到了一个有趣的主意。如果将渲染器缩放设置为线性,您可以将仅包含几个像素的纹理缩放到任何尺寸,并获得颜色之间的平滑插值 - 实际上,硬件加速的纹理过滤器使您可以获得渐变而无需CPU计算。

我测试了一下,只使用四个像素的纹理就能够创建一个任意矩形,在每个角落都有不同的颜色,并且之间进行平滑混合。唯一需要注意的是,在我的Windows机器上,纹理插值会向灰色渐变,从边缘开始,颜色部分稍微偏移。幸运的是,将源纹理从2x2图像扩展到4x4图像,并从中心2x2正方形中复制解决了这个问题,重现了我在Devuan机器上得到的结果。

当然,这本身只会给您沿X或Y轴或目标矩形的斜边提供渐变,但这已经足够使用了。我相信巧妙地应用旋转功能可以让您以任意角度获得渐变。以下是代码:

// Set linear blending (haven't tried this with bilinear...)
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,"1");

// Create a 4x4 texture to serve as the source for our gradient.
uint32_t * bgpixels;
SDL_Texture * background = SDL_CreateTexture(renderer,SDL_PIXELFORMAT_RGBA8888,
    SDL_TEXTUREACCESS_STREAMING,4,4);

// Set up the gradient colors.
// Each 2x2 quadrant of the texture has a separate color:

// AABB
// AABB
// CCDD
// CCDD
SDL_LockTexture(background,NULL,(void**)(&bgpixels),&i);
bgpixels[0] = 0x0000ffff;
bgpixels[1] = 0x0000ffff;
bgpixels[2] = 0x00ff00ff;
bgpixels[3] = 0x00ff00ff;
bgpixels[4] = 0x0000ffff;
bgpixels[5] = 0x0000ffff;
bgpixels[6] = 0x00ff00ff;
bgpixels[7] = 0x00ff00ff;
bgpixels[8] = 0xff0000ff;
bgpixels[9] = 0xff0000ff;
bgpixels[10] = 0xffffffff;
bgpixels[11] = 0xffffffff;
bgpixels[12] = 0xff0000ff;
bgpixels[13] = 0xff0000ff;
bgpixels[14] = 0xffffffff;
bgpixels[15] = 0xffffffff;
SDL_UnlockTexture(background);

// Blit it into place with the renderer.
SDL_RenderCopy(renderer,    // The SDL 2D renderer we're using
    background,             // The background texture
    &(SDL_Rect){1,1,2,2},   // We blit from the center 2x2 square to avoid a
                            // quirk on the Windows version.
    NULL);                  // The destination rectangle - just using the full
                            // target surface here.

你能否就你的方法在性能上与已接受答案相比提供一些提示?(我知道这可能取决于许多硬件和驱动程序细节,但是将负载移动到GPU通常应该优于在CPU端执行任何渲染,特别是在任何普通的游戏PC和智能手机上(带有GLES)。) - Scheff's Cat
我从未对此进行过基准测试。正如你所说,我预计使用专为快速处理此通用情况而设计的硬件将比在通用 CPU 上执行它更快,但是当真正重要时,永远不要假设。如果您想测试,软件中的线性插值并不太难实现; 如果将昂贵的操作移出循环(提示:查找每个像素的 delta 值并重复添加,而不是为每个像素执行乘法/除法-对于二维梯度,您需要找到每侧的垂直 delta 并在每行重新计算水平 delta),则相当简单。 - commodorejohn
计算不是问题。最耗时间的是图形调用。如果渐变为512*512像素,则手动绘制需要512个fillrect调用。 - Andrei Nikolaenko
该解决方案可行,但会产生非线性梯度。 - Mariusz Jaskółka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接