【问题标题】:Get pixel info from SDL2 texture从 SDL2 纹理中获取像素信息
【发布时间】:2013-10-01 03:32:03
【问题描述】:

我目前正在使用 SDL2 编写一个简单的程序,您可以在其中将一些形状(正方形、圆形、三角形等)拖到画布中并旋转它们并四处移动。每个形状都由从 PNG 文件创建的 SDL 纹理直观地表示(使用 SDL_image 库中的 IMG_LoadTexture 函数)。

问题是我想知道纹理中的某个像素是否透明,这样当有人点击图像时,我可以确定我是否需要做一些动作(因为点击是在非透明区域) 或不。 因为这是一些学校作业,所以我面临一些限制,即只能使用 SDL2 库,如果相关像素是透明的,我无法找到可以查找的地图,因为图像是动态选择的。此外,我考虑使用 SDL 表面来完成这项任务,从原始图像创建它们,但由于形状正在通过纹理旋转,这是行不通的。

【问题讨论】:

  • 我建议在这篇文章中添加 C 或 C++ 标签,以便在答案中启用语法突出显示。

标签: sdl-2


【解决方案1】:

您可以使用Render Targets 来完成此操作。

SDL_SetRenderTarget(renderer, target);
... render your textures rotated, flipped, translated using SDL_RenderCopyEx
SDL_RenderReadPixels(renderer, rect, format, pixels, pitch);

在最后一步中,您使用SDL_RenderReadPixels 从渲染目标读取像素,然后您必须确定所需像素的 Alpha 通道是否为零(透明)。您可以从渲染目标中仅读取您想要的一个像素,或整个纹理,您选择哪个选项取决于您必须执行的命中测试数量、纹理旋转/移动的频率等。

【讨论】:

  • 文档说“警告:这是一个非常慢的操作,不应该经常使用。”,我不确定这个功能是否适合这个目的。
  • 做了一些测试,它确实“非常慢”,传输一个 32 x 32 正方形的 RGBA 像素大约需要 15 毫秒(我有一台相当现代、快速的 PC)。仅此一项就会在 60 FPS 上占用您的大部分帧。如果您需要每帧都这样做,我建议您做其他事情。
【解决方案2】:

您需要使用 SDL_TEXTUREACCESS_STREAMING 标志创建纹理并锁定纹理,然后才能操作像素数据。要判断某个像素在纹理中是否透明,请确保调用

SDL_SetTextureBlendMode(t, SDL_BLENDMODE_BLEND);

这允许纹理识别 Alpha 通道。

试试这样的:

SDL_Texture *t;

int main()
{
    // initialize SDL, window, renderer, texture
    int pitch, w, h;
    void *pixels;

    SDL_SetTextureBlendMode(t, SDL_BLENDMODE_BLEND);

    SDL_QueryTexture(t, NULL, &aw, &h);
    SDL_LockTexture(t, NULL, &pixels, &pitch);
    Uint32 *upixels = (Uint32*) pixels;

    // you will need to know the color of the pixel even if it's transparent
    Uint32 transparent = SDL_MapRGBA(SDL_GetWindowSurface(window)->format, r, g, b, 0x00);

    // manipulate pixels
    for (int i = 0; i < w * h; i++)
    {
        if (upixels[i] == transparent)
            // do stuff
    }

    // replace the old pixels with the new ones
    memcpy(pixels, upixels, (pitch / 4) * h);

    SDL_UnlockTexture(t);

    return 0;
}

如果您有任何问题,请随时提出。虽然我不是这方面的专家。

如需进一步阅读和教程,请查看http://lazyfoo.net/tutorials/SDL/index.php。教程 40 专门处理像素操作。

如果方法名称有任何错误,我深表歉意(我在脑海中写下了这个)。

希望这会有所帮助。

【讨论】:

  • 查看 SDL_LockTexture 的文档,似乎这使得像素数据仅可用于写入访问。是否有其他方式可以访问像素数据以进行读取访问?
  • @Julian 锁定纹理会将像素保存到传递给它的空指针中。因此,如果您只想阅读,只需锁定和解锁纹理一次,像素就会被保存。
  • @user2437378 不是官方的 - wiki.libsdl.org/SDL_LockTexture - As an optimization, the pixels made available for editing don't necessarily contain the old texture data. This is a write-only operation, and if you need to keep a copy of the texture data you should do that at the application level. 很难想出一种可以实现的方法,但是依靠他们明确表示不要的东西似乎很狡猾。依赖此建议的读者有一天可能会面临代码被破解的风险,到那时为时已晚。
  • 感谢您的分享,但发布半成品答案的人实际上只是在浪费发布者的时间和可能依赖它的其他人的时间,或者至少花 20 分钟试图让它运行。在这种情况下,最好用粗体大写字母“此代码不完整 - 不起作用”,这样就不会有人浪费时间试图让它运行,至少他们会被警告...谢谢..
  • 不幸的是,这个答案还有另一个问题,假设即使流式纹理确实允许像这样的读取访问,也没有简单的方法可以将像素数据从渲染目标纹理传输到流式纹理。从我所见,似乎最好让纹理只写入显示器像素的接口,并且永远不要尝试读回该数据。 SDL 提供的从 GPU 读回数据的方法非常慢或根本不存在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-04
  • 2012-11-17
  • 1970-01-01
  • 1970-01-01
  • 2017-02-05
  • 1970-01-01
  • 2016-12-05
相关资源
最近更新 更多