在opengl中将颜色应用于四边形中的单个顶点

时间:2013-02-20 02:25:08

标签: opengl colors cocos2d-iphone vertex-array-object

我正在尝试为通过glDrawElements绘制的四边形的单个顶点着色,我正在使用 cocos2d libray,所以我已经能够清除源代码到准确理解发生了什么,代码如下:

glBindVertexArray( VAOname_ );
glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, (GLvoid*) (start*6*sizeof(indices_[0])) );
glBindVertexArray(0);

因此使用顶点数组对象。我正在尝试修改传递的对象的单个顶点颜色,它似乎工作但是有一个毛刺,如下图所示:

enter image description here

这里我试图改变左下和右下顶点的颜色。结果是不同的,我想这是因为四边形被渲染为一对三角形,共享斜边位于从左下顶点到右上顶点的对角线上。所以这可能导致不同的结果。

现在我想对第一个案例也有第二个结果。有没有办法获得它?

1 个答案:

答案 0 :(得分:8)

你的猜测是正确的。 OpenGL驱动程序将您的四边形细分为两个三角形,其中顶点颜色以重心方式进行插值,从而产生您所看到的结果。

解决此问题的常用方法是在片段着色器中“手动”执行插值,其中考虑目标拓扑,在您的情况下为四边形。或者简而言之,您必须执行不是基于三角形而是基于四边形的重心插值。您可能还想应用透视校正。

我现在还没有准备好阅读手头的资源,但我会尽快更新这个答案(可能实际上是指我自己必须写的)。

更新

首先我们必须理解这个问题:大多数OpenGL实现将较高的基元分解成三角形并将它们局部化,即无需进一步了解基元的其余部分,例如:四边形。所以我们必须自己做这件事。

我就是这样做的。

#version 330 // vertex shader

当然我们也需要通常的制服

uniform mat4x4 MV;
uniform mat4x4 P;

首先,我们需要此着色器执行实例

处理的顶点的位置
layout (location=0) in vec3 pos;

接下来,我们需要一些顶点属性来描述四边形本身。这意味着它的角落位置

layout (location=1) in vec3 qp0;
layout (location=2) in vec3 qp1;
layout (location=3) in vec3 qp2;
layout (location=4) in vec3 qp3;

和颜色

layout (location=5) in vec3 qc0;
layout (location=6) in vec3 qc1;
layout (location=7) in vec3 qc2;
layout (location=8) in vec3 qc3;

我们将这些变换为片段着色器进行处理。

out vec3 position;
out vec3 qpos[4];
out vec3 qcolor[4];

void main()
{
    qpos[0] = qp0;
    qpos[1] = qp1;
    qpos[2] = qp2;
    qpos[3] = qp3;

    qcolor[0] = qc0;
    qcolor[1] = qc1;
    qcolor[2] = qc2;
    qcolor[3] = qc3;

    gl_Position = P * MV * position;
}

在片段着色器中,我们使用它来实现颜色分量的距离权重:

#version 330 // fragment shader

in vec3 position;
in vec3 qpos[4];
in vec3 qcolor[4];

void main()
{
    vec3 color = vec3(0);

以下内容可以简化为组合,但为了清楚起见,我将其写出来: 对于顶点的每个角点与所有角点的颜色混合,并将它们之间边缘上的位置投影为混合因子。

    for(int i=0; i < 4; i++) {
        vec3 p = position - qpos[i];
        for(int j=0; j < 4; j++) {
            vec3 edge = qpos[i] - qpos[j];
            float edge_length = length(edge);
            edge = normalize(edge);
            float tau = dot(edge_length, p) / edge_length;

            color += mix(qcolor[i], qcolor[j], tau);
        }
    }

因为我们查看每个角点4次,缩小1/4

    color *= 0.25;

    gl_FragColor = color; // and maybe other things.
}

我们差不多完成了。在客户端,我们需要传递其他信息。当然我们不想复制数据。为此,我们使用glVertexBindingDivisor,以便顶点属性仅在qp…qc…位置上每4个顶点(即四边形)前进,即位置1到8

typedef float vec3[3];
extern vec3 *quad_position;
extern vec3 *quad_color;

glVertexAttribute(0, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[0]);

glVertexBindingDivisor(1, 4);
glVertexAttribute     (1, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[0]);

glVertexBindingDivisor(2, 4);
glVertexAttribute     (2, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[1]);

glVertexBindingDivisor(3, 4);
glVertexAttribute     (3, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[2]);

glVertexBindingDivisor(4, 4);
glVertexAttribute     (4, 3, GL_FLOAT, GL_FALSE, 0, &quad_position[3]);

glVertexBindingDivisor(5, 4);
glVertexAttribute     (5, 3, GL_FLOAT, GL_FALSE, 0, &quad_color[0]);

glVertexBindingDivisor(6, 4);
glVertexAttribute     (6, 3, GL_FLOAT, GL_FALSE, 0, &quad_color[1]);

glVertexBindingDivisor(7, 4);
glVertexAttribute     (7, 3, GL_FLOAT, GL_FALSE, 0, &quad_color[2]);

glVertexBindingDivisor(8, 4);
glVertexAttribute     (8, 3, GL_FLOAT, GL_FALSE, 0, &quad_color[3]);

将上述内容放入顶点数组对象中是有意义的。使用VBO也是有意义的,但是你必须手动计算偏移量;由于typedef float vec3编译器为我们ATM做了数学运算。

通过设置所有这些,您最终可以独立绘制四边形。