我该如何为我的文本设置属性指针?

时间:2016-11-21 05:35:23

标签: c++ opengl

我已经定义了一个顶点数据块,如下所示:

struct vertex {
    float x, y, u, v;
};

struct vertex_group {
    vertex tl, bl, br, tr;
    glm::vec4 color;

    vertex_group(float x, float y, float width, float height, glm::vec4 c) {
        tl.x = x;           tl.y = y + height;  tl.u = 0; tl.v = 0;
        bl.x = x;           bl.y = y;           bl.u = 0; bl.v = 1;
        br.x = x + width;   br.y = y;           br.u = 1; br.v = 1;
        tr.x = x + width;   tr.y = y + height;  tr.u = 1; tr.v = 0;
        color = c;
    }

    vertex_group(positioned_letter const& l) :
    vertex_group(l.x, l.y, l.width, l.height, l.l.color) {
    }

    const float * data() const {
        return &tl.x;
    }
};

属性指针的设置如下:

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)(4 * 4 * sizeof(GLfloat)));

并且调用绘图代码如下:

vertex_group vertices(l);
glBindTexture(GL_TEXTURE_2D, g.texture);
glBindBuffer(GL_ARRAY_BUFFER, objects.rect_buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STREAM_DRAW);
glDrawArrays(GL_QUADS, 0, 4);

基本思想是四边形的所有四个顶点都应该使用相同的颜色数据,即使它们需要不同的位置和纹理数据值。但是,当我将颜色设置为红色(1,0,0,1)时,屏幕上的结果是......不太正确。

Font rendered incorrectly

仅供参考,如果 * only 所做的更改是针对前两部分代码,请执行以下操作:

struct vertex {
    float x, y, u, v;
};

struct vertex_group {
    vertex tl;
    glm::vec4 color1;
    vertex bl;
    glm::vec4 color2;
    vertex br;
    glm::vec4 color3;
    vertex tr;
    glm::vec4 color4;

    vertex_group(float x, float y, float width, float height, glm::vec4 c) {
        tl.x = x;           tl.y = y + height;  tl.u = 0; tl.v = 0;
        bl.x = x;           bl.y = y;           bl.u = 0; bl.v = 1;
        br.x = x + width;   br.y = y;           br.u = 1; br.v = 1;
        tr.x = x + width;   tr.y = y + height;  tr.u = 1; tr.v = 0;
        color1 = color2 = color3 = color4 = c;
    }

    vertex_group(positioned_letter const& l) :
    vertex_group(l.x, l.y, l.width, l.height, l.l.color) {
    }

    const float * data() const {
        return &tl.x;
    }
};

(其他部分)

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), nullptr);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(4 * sizeof(GLfloat)));

它呈现正确:

Font Renders Correctly

简而言之,我的问题是:我想构建我的数据(并使用它进行渲染),如xyuvxyuvxyuvxyuvrgba,但我能让它工作的唯一方法是xyuvrgbaxyuvrgbaxyuvrgbaxyuvrgba 。如何设置指针/调用绘图函数以便我可以使用第一种方法?

1 个答案:

答案 0 :(得分:2)

你做不到。但是您可以使用实例化渲染来实现此布局:

xyuvxyuvxyuvxyuv              // <- only once
whrgbawhrgbawhrgbawhrgba...   // <- repeated per glyph

其中w和h是要在顶点着色器中应用的每个四元组的大小

这里我将它拆分为两个缓冲区,但您可以在技术上将它们全部加载到一个缓冲区中。此外,我在这里使用OpenGL 4.5无绑定API,因为我认为它更容易使用。如果您还没有,那么您可以将其更改为相应地使用较旧的呼叫。

float quad[] = {
    0, 1, 0, 0,
    0, 0, 0, 1,
    1, 1, 1, 0,
    1, 0, 1, 1,
};

struct Instance {
    vec2 size;
    // TODO: add index of the glyph you want to render
    vec4 color;
};

Instance inst[] = { ... };
int ninst = sizeof(inst)/sizeof(inst[0]);

GLuint quad_buf = ... create buffer from quad[] ...;
GLuint inst_buf = ... create buffer from inst[] ...;

GLuint vao;
glCreateVertexArrays(1, &vao);

glEnableVertexArrayAttrib(vao, 0);
glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribBinding(vao, 0, 0); // from 0th buffer

glEnableVertexArrayAttrib(vao, 1);
glVertexArrayAttribFormat(vao, 1, 2, GL_FLOAT, GL_FALSE, offsetof(Instance, size));
glVertexArrayAttribBinding(vao, 1, 1); // from 1st buffer

glEnableVertexArrayAttrib(vao, 2);
glVertexArrayAttribFormat(vao, 2, 4, GL_FLOAT, GL_FALSE, offsetof(Instance, color));
glVertexArrayAttribBinding(vao, 2, 1); // from 1st buffer

glVertexArrayVertexBuffer(vao, 0, quad_buf, 0, sizeof(float)*4); // 0th buffer is the quad
glVertexArrayVertexBuffer(vao, 1, inst_buf, 0, sizeof(Instance)); // 1th buffer for instances
glVertexArrayBindingDivisor(vao, 1, 1); // 1st buffer advances once per instance

// to draw:
glBindTexture(...);
glBindVertexArray(vao);
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, ninst);