【问题标题】:Creating and loading .pngs in RGBA4444 RGBA5551 for openGL在 RGBA4444 RGBA5551 中为 openGL 创建和加载 .png
【发布时间】:2010-01-05 20:27:31
【问题描述】:

我正在创建一个 openGL 游戏,到目前为止,我一直在使用 RGBA8888 格式的 .png 作为纹理表,但是这些太占用内存,而且我的应用程序经常崩溃。我在 Apple 的网站上读到,这种格式仅在需要太多质量时才使用,并建议改用 RGBA4444 和 RGBA5551(我已经将纹理转换为 PVR,但在大多数精灵表中质量损失太大)。

我只需要在纹理加载器类中的 glTexImage2D 调用中使用 GL_UNSIGNED_SHORT_5_5_5_1 或 GL_UNSIGNED_SHORT_4_4_4_4 即可加载纹理,但我需要将纹理表转换为 RGBA4444 和 RGBA5551,我不知道如何实现这个。

【问题讨论】:

  • 有工具可以做到这一点。我不喜欢 iphone 开发,但 Nintendo DS 自制社区有一些工具可以将图像转换为这些格式。
  • 你能给我这些工具的名字吗?!谢谢。
  • 几乎有无数种工具可以将图像转换为不同的格式。有些可能是 Windows 特定的,但有些是 iOS 特定的。一个简单的 google 会产生大量可以将 png 转换为 RGBA4444 的程序。

标签: iphone opengl-es textures


【解决方案1】:

真的吗?有库可以进行这种转换。但坦率地说,这有点胡扯。有一些库使用 asm 或专门的 SSE 命令来加速这将很快,但在 C/C++ 中滚动您自己的格式转换器非常容易。 您的基本流程是:

  • 给定一个 RGBA8888 编码值的缓冲区
  • 创建一个足够大的缓冲区来保存 RGBA4444 或 RGBA5551 值。在这种情况下,它很简单 - 大小只有一半。
  • 循环遍历源缓冲区,解包每个组件,并重新打包成目标格式,并将其写入目标缓冲区。

    void* rgba8888_to_rgba4444(
      void* src, // IN, pointer to source buffer
      int cb)    // IN size of source buffer, in bytes
    {
      // this code assumes that a long is 4 bytes and short is 2.
      //on some compilers this isnt true
      int i;
      // compute the actual number of pixel elements in the buffer.
      int cpel = cb/4;
      unsigned long* psrc = (unsigned long*)src;
      // create the RGBA4444 buffer
      unsigned short* pdst = (unsigned short*)malloc(cpel*2);
      // convert every pixel
      for(i=0;i<cpel; i++)
      {
        // read a source pixel
        unsigned pel = psrc[i];
        // unpack the source data as 8 bit values
        unsigned r = p & 0xff;
        unsigned g = (pel >> 8) & 0xff;
        unsigned b = (pel >> 16) & 0xff; 
        unsigned a = (pel >> 24) & 0xff;
        //convert to 4 bit vales
        r >>= 4;
        g >>= 4;
        b >>= 4;
        a >>= 4;
        // and store
        pdst[i] = r | g << 4  | b << 8 | a << 12;
      }
      return pdst;
    } 
    

我做的实际转换循环非常浪费,可以一次提取、转换和重新打包组件,从而使代码更快。我这样做是为了使转换明确且易于更改。另外,我不确定我是否以正确的方式获得了组件订单。所以它可能是 b、r、g、a,但它不应该影响函数的结果,因为它会以相同的顺序重新打包到 dest 缓冲区中。

【讨论】:

  • 很棒的代码示例。顺便说一句,我认为您的 pdst 值应该是.... pdst[i] = r
  • 哎哟。换档方向错了!那太骇人听闻了。我在 Opengl.org 上的任何地方都找不到实际上指定所有不同格式的布局的文档:/
【解决方案2】:

使用ImageMagick,您可以通过运行创建 RGBA4444 PNG 文件:

convert source.png -depth 4 destination.png

你可以从MacPorts获取ImageMagick。

【讨论】:

  • 这将截断像素值的底部位,但 libpng(或任何正在使用的加载器)的输出仍将是 8 位组件。问题是关于如何将像素分量值打包成 OpenGL 格式。网上有很多示例代码可以做到这一点,只是一堆小玩意儿。
【解决方案3】:

您可以考虑在 Windows 上使用 Imagination 的 PVRTexTool。它专门用于以每种支持的颜色格式创建 PVR 纹理。它可以创建 PVRTC 压缩纹理(您称之为“PVR”)以及 8888、5551、4444 等中的未压缩纹理。

但是,它不输出 PNG(仅 PVR),因此您的加载代码会发生变化。此外,有时 PVR 比 PNG 大得多,因为 PNG 中的像素是使用 deflate 压缩进行压缩的。

由于您很可能在运行 OS X,因此您可以使用 Darwine (now WineBottler) 在 OS X 上运行它(和其他 Windows 程序)。

您需要先register as an Imagination developer,然后才能下载 PVRTexTool。注册和工具都是免费的。

设置完成后,它会非常轻松,并且它为您提供了一个不错的 GUI 来使用 PVR。

【讨论】:

    【解决方案4】:

    您可能还想了解如何使用 GIMP 中的 floyd-steinberg 抖动优化 RGBA8888 以转换为 RGBA4444:http://www.youtube.com/watch?v=v1xGYecsnX0

    【讨论】:

      【解决方案5】:

      您也可以使用http://www.texturepacker.com 进行转换。

      【讨论】:

        【解决方案6】:

        这是 Chris 代码的优化就地转换,它的运行速度应该是原来的 2 倍,但没有那么严格。就地转换有助于通过降低内存峰值来避免崩溃。只是想我会分享以防有人计划使用此代码。我已经测试过了,效果很好:

        void* rgba8888_to_rgba4444( void* src, // IN, pointer to source buffer
                                   int cb)    // IN size of source buffer, in bytes
        {
            int i;
            // compute the actual number of pixel elements in the buffer.
            int cpel = cb/4;
            unsigned long* psrc = (unsigned long*)src;
            unsigned short* pdst = (unsigned short*)src;
        
            // convert every pixel
        
            for(i=0;i<cpel; i++)
            {
                // read a source pixel
                unsigned pel = psrc[i];
                // unpack the source data as 8 bit values
                unsigned r = (pel << 8)  & 0xf000;
                unsigned g = (pel >> 4) & 0x0f00;
                unsigned b = (pel >> 16) & 0x00f0;
                unsigned a = (pel >> 28) & 0x000f;
        
                // and store
                pdst[i] = r | g | b | a;
            }
            return pdst;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-02-09
          • 2012-08-06
          • 2014-01-28
          • 2014-02-19
          • 2014-02-28
          • 2014-01-03
          • 2021-12-22
          • 2020-04-14
          相关资源
          最近更新 更多