0

我试图让 iOS 上的 OpenGL ES 在超过 2 个属性下正常工作,但由于某种原因,它似乎是在绘制法线而不是实际对象。

我的顶点着色器:

attribute vec4 position;
attribute vec3 tc;
attribute vec3 normal;

uniform vec3 color;
uniform mat4 modelViewProjectionMatrix;
uniform mat3 normalMatrix;

varying lowp vec3 Color;

void main()
{

    vec3 eyeNormal = normalize(normalMatrix * normal);
    vec3 lightDirection = vec3(0.0, 0.0, 1.0);

    float nDot = max(0.0, dot(eyeNormal, normalize(lightDirection)));

    Color = tc * nDot;
    gl_Position = modelViewProjectionMatrix * position;
}

我像您期望的那样获取对属性的引用:

glBindAttribLocation(_program, GLKVertexAttribPosition, "position");
glBindAttribLocation(_program, GLKVertexAttribTexCoord0, "tc");
glBindAttribLocation(_program, GLKVertexAttribNormal, "normal");

我使用一个 NSMutableArray 容器来存储 Vector 对象,第一个 Vector 对象代表位置,后面的代表纹理数据,后面的代表法线。这样重复,数组中通常有大约 5000 个 Vector 对象。使用以下代码将该数组的内容读入缓冲区:

float *buffer = (float*) calloc(vBuffer.count * 3, sizeof(float));
int bufferIndex = 0;

for(int i =0; i < [vBuffer count]; i++) {

    vector3 *vec = (vector3*) vBuffer[i];

    buffer[bufferIndex] = vec.x;
    buffer[bufferIndex+1] = vec.y;
    buffer[bufferIndex+2] = vec.z;

    bufferIndex += 3;

}

然后我像你期望的那样设置 glVertexAttribPointer 的东西:

glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(12));

glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(24));

我编译并绘制了这个:http: //i.imgur.com/Q0QLsHd.png。如果我没有将表示法线的 Vector 对象包含到我的 NSMutableArray 中,我会得到预期的结果(虽然颜色很奇怪,但那是因为我正在读取纹理坐标作为颜色,忽略它):http://i. imgur.com/DOFZxaq.png

为什么当我将第三个属性添加到缓冲区时一切都搞砸了?

以下是基于解析 .obj 文件中的面部语句向数组添加位置、纹理和法线的代码:

    if(v < INT32_MAX && v != 0) {

     vector3 *position = (vector3*) _vertices[v-1];
    [vBuffer addObject:position];

    }

   if(vt < INT32_MAX && vt != 0) {

    vector3 *texture = (vector3*) _textures[vt-1];
    [vBuffer addObject:texture];

    }


    if(vn < INT32_MAX && vn != 0) {

    vector3 *normal = (vector3*) _normals[vn-1];
    [vBuffer addObject:normal];

    }

我基于 XCode 的 OpenGL 模板创建了一个新的测试项目,并添加了第三个属性,它工作正常,所以不确定是什么导致了这个特定项目的问题。是缓冲区的大小吗?里面存储了大约 15,000 个花车。

4

1 回答 1

1

诚然,手册页对其第五个参数 ( )glVertexAttribPointer的含义不是很清楚。stride他们说它“指定连续通用顶点属性之间的字节偏移量”,它的意思更像是同类属性之间的东西,即连续顶点中相同属性之间的偏移量。您看到奇怪的渲染很可能是因为您已经传递0了该参数,导致 GL 将第一个顶点的法线数据解释为第二个顶点的位置数据(依此类推)。

因为您在缓冲区中交错了多个顶点属性(按照Apple 编程指南中的建议),所以stride参数的值应该是 a) 非零,并且 b) 所有属性都相同。像这样(假设是 32 位GLfloat组件):

glVertexAttribPointer 步幅

幻数被认为是有害的,所以我喜欢为我的顶点数据声明结构sizeofoffsetof在 GL API 调用宽度和偏移量时使用:

typedef struct {
    GLKVector3 position;
    GLKVector3 normal;
    GLKVector3 texCoord0;
} Vertex;

glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 
    sizeof(Vertex), (const GLvoid *)offsetof(Vertex, position));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 
    sizeof(Vertex), (const GLvoid *)offsetof(Vertex, normal));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 3, GL_FLOAT, GL_FALSE, 
    sizeof(Vertex), (const GLvoid *)offsetof(Vertex, texCoord0));

无论包含我的顶点数据的缓冲区是否实际上是一个数组,这个技巧都有效Vertex(尽管这肯定很方便)。

于 2013-09-05T20:58:45.243 回答