OpenGL 平铺/位图/剪切

发布于 2024-11-30 00:51:33 字数 1206 浏览 1 评论 0原文

在 OpenGL 中,如何从使用 IMG_Load() 加载的图像文件中选择一个区域? (我正在为简单 2D 游戏制作图块地图)

我使用以下原则将图像文件加载到纹理中:

GLuint loadTexture( const std::string &fileName ) {

    SDL_Surface *image = IMG_Load(fileName.c_str());

    unsigned object(0);                        
    glGenTextures(1, &object);                 
    glBindTexture(GL_TEXTURE_2D, object);   

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);

    SDL_FreeSurface(image);
    return object;
}

然后我使用以下内容在渲染中实际绘制纹理-part:

glColor4ub(255,255,255,255);                
glBindTexture(GL_TEXTURE_2D, texture);      
glBegin(GL_QUADS);                          
glTexCoord2d(0,0);  glVertex2f(x,y);
glTexCoord2d(1,0);  glVertex2f(x+w,y);
glTexCoord2d(1,1);  glVertex2f(x+w,y+h);
glTexCoord2d(0,1);  glVertex2f(x,y+h);
glEnd(); 

现在我需要一个函数,允许我从调用 loadTexture( const std::string &fileName ) 获得的 GLuint 中选择某些矩形部分,这样我然后可以使用上面的代码将这些部分绑定到矩形,然后将它们绘制到屏幕上。像这样的东西:

GLuint getTileTexture( GLuint spritesheet, int x, int y, int w, int h )

In OpenGL, how can I select an area from an image-file that was loaded using IMG_Load()?
(I am working on a tilemap for a simple 2D game)

I'm using the following principle to load an image-file into a texture:

GLuint loadTexture( const std::string &fileName ) {

    SDL_Surface *image = IMG_Load(fileName.c_str());

    unsigned object(0);                        
    glGenTextures(1, &object);                 
    glBindTexture(GL_TEXTURE_2D, object);   

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image->w, image->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);

    SDL_FreeSurface(image);
    return object;
}

I then use the following to actually draw the texture in my rendering-part:

glColor4ub(255,255,255,255);                
glBindTexture(GL_TEXTURE_2D, texture);      
glBegin(GL_QUADS);                          
glTexCoord2d(0,0);  glVertex2f(x,y);
glTexCoord2d(1,0);  glVertex2f(x+w,y);
glTexCoord2d(1,1);  glVertex2f(x+w,y+h);
glTexCoord2d(0,1);  glVertex2f(x,y+h);
glEnd(); 

Now what I need is a function that allows me to select certain rectangular parts from the GLuint that I get from calling loadTexture( const std::string &fileName ), such that I can then use the above code to bind these parts to rectangles and then draw them to the screen. Something like:

GLuint getTileTexture( GLuint spritesheet, int x, int y, int w, int h )

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

内心荒芜 2024-12-07 00:51:33

继续将整个拼贴加载到纹理中。然后在渲染几何体时使用 glTexCoord 选择它的子集。

glTexSubImage2D 不会有任何帮助。它允许您将多个文件添加到单个纹理,而不是从单个文件创建多个纹理。

示例代码:

void RenderSprite( GLuint spritesheet, unsigned spritex, unsigned spritey, unsigned texturew, unsigned textureh, int x, int y, int w, int h )
{
    glColor4ub(255,255,255,255);                
    glBindTexture(GL_TEXTURE_2D, spritesheet);
    glBegin(GL_QUADS);                          
    glTexCoord2d(spritex/(double)texturew,spritey/(double)textureh);
    glVertex2f(x,y);
    glTexCoord2d((spritex+w)/(double)texturew,spritey/(double)textureh);
    glVertex2f(x+w,y);
    glTexCoord2d((spritex+w)/(double)texturew,(spritey+h)/(double)textureh);
    glVertex2f(x+w,y+h);
    glTexCoord2d(spritex/(double)texturew,(spritey+h)/(double)textureh);
    glVertex2f(x,y+h);
    glEnd(); 
}

Go ahead and load the entire collage into a texture. Then select a subset of it using glTexCoord when you render your geometry.

glTexSubImage2D will not help in any way. It allows you to add more than one file to a single texture, not create multiple textures from a single file.

Example code:

void RenderSprite( GLuint spritesheet, unsigned spritex, unsigned spritey, unsigned texturew, unsigned textureh, int x, int y, int w, int h )
{
    glColor4ub(255,255,255,255);                
    glBindTexture(GL_TEXTURE_2D, spritesheet);
    glBegin(GL_QUADS);                          
    glTexCoord2d(spritex/(double)texturew,spritey/(double)textureh);
    glVertex2f(x,y);
    glTexCoord2d((spritex+w)/(double)texturew,spritey/(double)textureh);
    glVertex2f(x+w,y);
    glTexCoord2d((spritex+w)/(double)texturew,(spritey+h)/(double)textureh);
    glVertex2f(x+w,y+h);
    glTexCoord2d(spritex/(double)texturew,(spritey+h)/(double)textureh);
    glVertex2f(x,y+h);
    glEnd(); 
}
梦途 2024-12-07 00:51:33

尽管 Ben Voigt 的答案是通常的方法,但如果您确实想要为图块提供额外的纹理(这可能有助于边缘过滤),您可以使用 glGetTexImage 并使用 glPixelStore 参数:

GLuint getTileTexture(GLuint spritesheet, int x, int y, int w, int h)
{
    glBindTexture(GL_TEXTURE_2D, spritesheet);

    // first we fetch the complete texture
    GLint width, height;
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
    GLubyte *data = new GLubyte[width*height*4];
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

    // now we take only a sub-rectangle from this data
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, /*filter+wrapping*/, /*whatever*/);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
    glTexImage2D(GL_TEXTURE_2D, 0, RGBA, w, h, 0, 
        GL_RGBA, GL_UNSIGNED_BYTE, data+4*(y*width+x));

    // clean up
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    delete[] data;
    return texture;
}

但请记住,此函数始终将整个纹理图集读取到 CPU 内存中,然后将子部分复制到新的较小纹理中。因此,一次性创建所有需要的精灵纹理并且只读取一次数据将是一个好主意。在这种情况下,您也可以完全删除图集纹理,只使用 IMG_Load 将图像读入系统内存,以将其分配到各个精灵纹理中。或者,如果您确实需要大纹理,那么至少使用 PBO 将其数据复制到(使用 GL_DYNAMIC_COPY 用法或类似的东西),这样它就不需要离开 GPU 内存。

Although Ben Voigt's answer is the usual way to go, if you really want an extra texture for the tiles (which may help with filtering at the edges) you can use glGetTexImage and play a bit with the glPixelStore parameters:

GLuint getTileTexture(GLuint spritesheet, int x, int y, int w, int h)
{
    glBindTexture(GL_TEXTURE_2D, spritesheet);

    // first we fetch the complete texture
    GLint width, height;
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
    GLubyte *data = new GLubyte[width*height*4];
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

    // now we take only a sub-rectangle from this data
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexParameteri(GL_TEXTURE_2D, /*filter+wrapping*/, /*whatever*/);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
    glTexImage2D(GL_TEXTURE_2D, 0, RGBA, w, h, 0, 
        GL_RGBA, GL_UNSIGNED_BYTE, data+4*(y*width+x));

    // clean up
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    delete[] data;
    return texture;
}

But keep in mind, that this function always reads the whole texture atlas into CPU memory and then copies a sub-part into the new smaller texture. So it would be a good idea to create all needed sprite textures in one go and only read the data in once. In this case you can also just drop the atlas texture completely and only read the image into system memory with IMG_Load to distribute it into the individual sprite textures. Or, if you really need the large texture, then at least use a PBO to copy its data into (with GL_DYNAMIC_COPY usage or something the like), so it need not leave the GPU memory.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文