OpenGL ES glTexImage2D optimization

OpenGL ES glTexImage2D optimization

本文关键字:optimization glTexImage2D ES OpenGL      更新时间:2023-10-16

我的任务是展示几张图片。我将其实现为一个类来制作多个实例。每个实例代表一张图片。它编译着色器,设置两个三角形并在构造函数中加载图片数据。主程序创建实例,然后转到循环以切换prigramid并为每个实例调用render()方法。

while(true)
for (uint g = 0; g < pictures.size(); g++){
glUseProgram(pictures[g]->ProgramId);
pictures[g]->render();
}

它运行良好并显示图片,但我不喜欢它。它可以做得更好。

这是类的部分代码

Picture::Picture(picPosition* pPosition, const char * fileName)
:BasePicture(pPosition)
{
pos = glGetAttribLocation(ProgramId, "position");
uv = glGetAttribLocation(ProgramId, "texture_vert");
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
int n;
textureData = stbi_load(fileName, &picWidth, &picHeight, &n, STBI_rgb_alpha);
TextureID  = glGetUniformLocation(ProgramId, "myTextureSampler");
glBindTexture(GL_TEXTURE_2D, TextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE0);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
//calculating the vertex matrix using MVP calculated in parent class
for (int i = 0; i < 6; i++)
ModeledVerts.push_back(MVP * verts[i]);
v = glm::value_ptr(ModeledVerts[0]);
}
Picture::~Picture()
{
stbi_image_free(textureData);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &uvbuffer);
}
void Picture::render()
{
glBufferData(GL_ARRAY_BUFFER, 96, v, GL_STATIC_DRAW);
glVertexAttribPointer(pos, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid*) 0);
glEnableVertexAttribArray(pos);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesUV), verticesUV, GL_STATIC_DRAW);
glVertexAttribPointer(uv, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*) 0);
glEnableVertexAttribArray(uv);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, picWidth, picHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
glDrawArrays(GL_TRIANGLES, 0, 6);
}

我用代码玩了很多,使 render() 函数尽可能轻,但我不能让它比现在更轻。

最大的问题是每次都发送纹理数据(glTexImage2D)。数据永远不会更改。我试图将其移动到构造函数,但在这种情况下,所有图片对象都显示最新加载的相同图片。看起来一个实例覆盖了之前上传的纹理数据。我正在寻找一种在构造函数中加载一次图片数据而不是每次渲染的方法。看起来OpenGL API中有一些东西,但我还不知道。

另一个改进可能是从 render() 中获取顶点数据设置。这些数据永远不会改变。但它并不像render()中的glTexImage2D调用那么重要。

你能指出我使用OpenGL API来分离着色器的数据吗?或者告诉我我做错了什么...

你说:

运行良好并显示图片,但我不喜欢它。它可以做得更好。

从设计方法来看,我认为这可能会对您有所帮助。

将打开、读取和解析纹理数据的图像文件的功能与实际的纹理结构或类分开。这将是一个示例伪代码:

struct Texture {
unsigned int width;
unsigned int height;
bool         hasTransparency; 
GLint id; // ID that is used by OpenGL to setActive, bind, and pass to shaders as either a uniform or sampler2D.
std::string filenameAndPath; // Keep this filename associated with texture so you can prevent trying to reload the same file over and over.
GLuchar*  data; // the actual color - pixel texture data. 
}
// This function will handle the opening and reading in of the texture data
// it would return back the ID value generated by OpenGL which will also be
// stored into the texture struct. The texture struct is returned by reference so that it can be populated with data.
GLuint loadTexture( const char* filenameAndPath, Texture& texture, /*loading parameters & flags*/ ) {
// Check to see if file exists or is already loaded
if ( fileanameAndPath already exists ) {
// get the existing ID from the already loaded texture
// and just return that. 
} else {
// Try to open the new file for reading.
// parse the data for general purposes that will support
// your application. You can simply use `stbi_load` as it is a fairly
// decent third party library.
// Check the internal formatting of how the data is stored
// Compression, pixel orientation etc.
// configure the data to your needs (color format),
// (flipping the pixels either horizontally, vertically or both),
// now copy the actual pixel data into your buffer.
// close the file handle
// save all the information into your struct
// return the ID value that was generated by OpenGL
}
}

render loop之前的主机代码中,您需要从文件加载纹理,然后您可以在需要时使用此纹理对象。最后,在渲染循环中,您希望将纹理设置为活动状态,并将它们绑定到渲染目标并将它们传递给着色器。在某些情况下,您可能希望在render loop之前将它们设置为活动状态并绑定它们,具体取决于要实现的shader-technique类型。

回答我自己的问题。 解决方案是使用地图集地图。软件生成包含所有图片的图集,上传一次(glTexImage2D)并使用每张图片的坐标。这大大提高了性能,因为glTexImage2D只被调用了一次。