openGL在运行时创建纹理图集?

问题描述 投票:6回答:1

所以我在一个简洁的小系统中设置我的框架,将SDL,openGL和box2D一起包装成2D游戏。

现在它是如何工作的,我创建一个“GameObject”类的对象,指定一个“源PNG”,然后它自动创建一个openGL纹理和相同尺寸的box2d体。

现在我担心如果我开始需要在屏幕上渲染许多不同的纹理。

是否可以在运行时加载我的所有精灵表,然后将它们组合成一个纹理?如果是这样,怎么样?什么是实现它的好方法(这样我就不必手动指定任何参数或任何东西)。

我想在运行时而不是预先完成它的原因是我可以轻松地将所有(或大多数)瓷砖,敌人等等一定程度地加载到这一个纹理中,因为每个级别都赢了有同样的敌人。它也使整个创作艺术过程更容易。

c++ opengl
1个回答
7
投票

可能存在一些用于创建纹理图集的库(最佳打包是一个非常重要的问题)并将旧纹理坐标转换为新纹理坐标。

但是,如果你想自己做,你可能会这样做:

  • 从磁盘加载所有纹理(“源PNG”)并检索原始像素数据缓冲区,
  • 如有必要,将所有源纹理转换为相同的像素格式,
  • 创建一个足够大的新纹理来容纳所有现有纹理,以及用于保存像素数据的相应缓冲区
  • 将源图像中的像素数据“Blit”到给定偏移处的新缓冲区(见下文)
  • 使用新缓冲区的数据正常创建纹理。
  • 在执行此操作时,确定从“旧”纹理坐标到“新”纹理坐标的映射(应该是记录纹理图集的每个元素的偏移并进行快速转换的简单问题)。在像素着色器中进行它可能也很容易,但是需要一些分析来查看传递额外参数的开销是否值得。

显然你也想检查以确保你没有做一些愚蠢的事情,比如将相同的纹理加载到地图集中两次,但这是一个在此过程之外的问题。


要从源图像“复制”(复制)到目标图像,您可以执行以下操作(假设您将128x128纹理复制到512x512图集纹理,从目标上的(128,0)开始):

unsigned char* source = new unsigned char[ 128 * 128 * 4 ]; // in reality, comes from your texture loader
unsigned char* target = new unsigned char[ 512 * 512 * 4 ];

int targetX = 128;
int targetY = 0;

for(int sourceY = 0; sourceY < 128; ++sourceY) {
    for(int sourceX = 0; sourceX < 128; ++sourceX) {
        int from = (sourceY * 128 * 4) + (sourceX * 4); // 4 bytes per pixel (assuming RGBA)
        int to = ((targetY + sourceY) * 512 * 4) + ((targetX + sourceX) * 4); // same format as source

        for(int channel = 0; channel < 4; ++channel) {
            target[to + channel] = source[from + channel];
        }
    }
}

这是一个非常简单的暴力实现:有更快,更简洁和更聪明的方法来复制数组,但想法是你基本上将源纹理的内容复制到给定X和Y的目标纹理中偏移。最后,您将创建一个包含旧纹理的新纹理。

如果索引数学对你没有意义,那么考虑一下how a 2D array is actually indexed inside a 1D space(比如计算机内存)。

请原谅任何错误。这不是生产代码,而是我编写的内容,而不检查它是否编译或运行。


既然你正在使用SDL,我应该提到它有一个很好的功能,可以帮助你:SDL_BlitSurface。您可以完全在SDL中创建SDL_Surface,只需使用SDL_BlitSurface将源表面复制到其中,然后使用convert the atlas surface into a GL texture

它会处理所有数学运算,也可以为您进行格式转换。

© www.soinside.com 2019 - 2024. All rights reserved.