【问题标题】:OpenGL ES glTexImage2D optimizationOpenGL ES glTexImage2D 优化
【发布时间】:2018-07-12 11:54:04
【问题描述】:

我的任务是展示几张图片。我将它实现为一个类来创建几个实例。每个实例代表一张图片。它编译着色器,设置两个三角形并在构造函数中加载图片数据。主程序创建实例,然后循环切换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() 函数尽可能轻,但我不能让它像现在这样轻。

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

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

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

【问题讨论】:

  • glTexImage2D 覆盖当前绑定的纹理。您应该尝试制作不同的纹理来保存每个图像,然后您可以依次绑定每个图像并进行渲染。查找 glGenTextures 和 glBindTexture。

标签: c++ optimization opengl-es textures


【解决方案1】:

你说:

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

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

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

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 的类型。

【讨论】:

  • “然后在渲染循环之外的基本代码中,您将希望从文件中加载纹理,然后可以在需要时使用此纹理对象。” - 这正是我正在做的。我在构造函数中加载一次实际纹理并在渲染()中使用它。您能否获得有关“将此纹理设置为活动并将其绑定到渲染目标并将其传递给您的着色器”的更多详细信息?我正在这样做,但它看起来不是最有效的方法。我正在传递所有纹理内容。如果我可以在构造函数中传递一次并在渲染中“切换”或“设置为活动状态”——那就太好了!
  • @CreativeMaker 尽量不要使用构造函数来完成大量工作或繁重的工作。如果您可以在大多数情况下尝试使用默认构造函数保留类,那将是很好或理想的,但如果您确实需要用户定义的,那么构造函数中最少的代码量可能会更好。如果在将对象视为可构造对象之前需要设置很多东西,那么我建议创建一个私有 init 函数并在构造函数中调用它。这些只是提示 - 建议。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2011-02-16
    • 2013-07-11
    • 1970-01-01
    • 1970-01-01
    • 2016-11-02
    • 1970-01-01
    • 2011-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多