[√]OpenGL绘制图片

150 阅读2分钟

最简单的图片绘制程序

float vertices[] = {
        //-- 位置 ----     -- 纹理坐标--
        400, 400, 0.0f,    1.0f, 1.0f,   // 右上
        400, 0,   0.0f,    1.0f, 0.0f,   // 右下
        0,   0,   0.0f,    0.0f, 0.0f,   // 左下
        0 ,  400, 0.0f,    0.0f, 1.0f    // 左上
};
// 顺时针
// 3 -- 0
// |  \ |
// 2 -- 1
unsigned int indices[] = { // 注意索引从0开始! 
        0, 1, 3, // 第一个三角形
        1, 2 ,3, // 第二个三角形
};
GLuint vbo, ebo, texture;

glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);

glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);


glEnableVertexAttribArray(_attribPosition);
glVertexAttribPointer(_attribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (GLvoid*)0);

glEnableVertexAttribArray(_aTexCoord);
glVertexAttribPointer(_aTexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (GLvoid*)(sizeof(float) * 3));

Image img;
img.initWithImageFile("./vx.png");
int width = img.getWidth();
int height = img.getHeight();

glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0); // 在绑定纹理之前先激活纹理单元
glBindTexture(GL_TEXTURE_2D, texture);// 绑定纹理到激活的纹理单元

glEnable(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// png使用GL_RGBA, jpg使用GL_RGB
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.getData());
glGenerateMipmap(GL_TEXTURE_2D);

_ourTexture=glGetUniformLocation(ourShader.ID, "texture1");
glUniform1i(_ourTexture, 0);// 设置每个采样器属于哪个纹理单元

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
CHECK_GL_ERROR_DEBUG();

动态合图原理分析

如果多个图片一个drawCall完成绘制,其原理就是将要绘制的图片,统一绘制到一张大纹理(RenderTexture),实现细节为通过glTexSubImage2D可以修改纹理的部分区域。

需要将不同格式(RGB888、RGBA8888等)的纹理数据转换为RenderTexture的纹理格式。

在提交顶点数据时,注意映射好每张图片的纹理坐标,即可。

cocos2dx生成material的规则:

void TrianglesCommand::generateMaterialID()
{
    // glProgramState is hashed because it contains:
    //  *  uniforms/values
    //  *  glProgram
    //
    // we safely can when the same glProgramState is being used then they share those states
    // if they don't have the same glProgramState, they might still have the same
    // uniforms/values and glProgram, but it would be too expensive to check the uniforms.
    struct {
        GLuint textureId;
        GLenum blendSrc;
        GLenum blendDst;
        void* glProgramState;
    } hashMe;

    hashMe.textureId = _textureID;
    hashMe.blendSrc = _blendType.src;
    hashMe.blendDst = _blendType.dst;
    hashMe.glProgramState = _glProgramState;
    _materialID = XXH32((const void*)&hashMe, sizeof(hashMe), 0);
}

TriangleCommand只使用了quadIndices前6位:

image.png