Objective c 如何为openGL ES使用顶点和索引缓冲区填充结构右侧

Objective c 如何为openGL ES使用顶点和索引缓冲区填充结构右侧,objective-c,struct,opengl-es,vertices,Objective C,Struct,Opengl Es,Vertices,目前,我在使用网格顶点填充结构时遇到问题(高分辨率的屏幕填充四边形) 这是结构: typedef struct { float Position[3]; float Color[4]; float TexCoord[2]; }Vertex; 通常情况下,我只会用每只手来填充 const Vertex Vertices[]= { {{1,-1,0},{1,0,0,1},{1,1}}, {{1,1,0},{0,1,0,1},{1,0}

目前,我在使用网格顶点填充结构时遇到问题(高分辨率的屏幕填充四边形)

这是结构:

    typedef struct {
    float Position[3];
    float Color[4];
    float TexCoord[2];
    }Vertex;
通常情况下,我只会用每只手来填充

    const Vertex Vertices[]= {
    {{1,-1,0},{1,0,0,1},{1,1}},
    {{1,1,0},{0,1,0,1},{1,0}},
    {{-1,1,0},{0,0,1,1},{0,0}},
    {{-1,-1,0},{0,0,0,1},{0,1}}
    };
把它绑在我的缓冲器上

因为我需要一个分辨率更高的网格(我手工填充的11x11网格是不够的),所以我想用这种方法填充

    - (void) createMesh : (int) width withHeight: (int)height{
        int size = width * height + height +1;
        Vertex Vert[]; //since we will be adding a vertex at the end for the (1,y), (1,v) and the x u

        int sizeInd = width * height * 2 * 3;
        GLubyte Ind[sizeInd]; // width * height * 2 number triangles, 3 indices per triangle

        float x,y,u,v;
        int count = 0;

        // Fill Vertices
        for (int i = 0 ; i <= height ; i++){

            y = ((1.0 - i/height) * -1.0) + ((i/height) * 1.0);
            v = 1.0 - (float) i / (float) height;

            for (int j = 0; j <= width; j++){

                x = (float) j / (float) width;
                u = x; //(float) j/ (float) count;

                //Vert[count]= {{x,y,0},{0,0,0,1.0},{u,v}}; 
                Vert[count].Position[0] = x;
                Vert[count].Position[1] = y;
                Vert[count].Position[2] = 0;

                Vert[count].Color[0] = 0.0;
                Vert[count].Color[1] = 0.0;
                Vert[count].Color[2] = 0.0;
                Vert[count].Color[3] = 1.0;

                Vert[count].TexCoord[0] = u;
                Vert[count].TexCoord[1] = v;
                count++;
            }
        }
        //Fill indices

        count = 0;
        for (int c = 0; c < sizeInd; c++){
            Ind[c] = count;
            c++;
            Ind[c] = count + 1;
            c++;
            Ind[c] = count + width + 1 + 1;
            c++;
            Ind[c] = count + 1;
            c++;
            Ind[c] = count + width + 1 + 1 + 1;
            c++;
            Ind[c] = count + width + 1 + 1;
            count++;
        }

        //Fill buffer
        glGenBuffers(1,&_vertexMeshBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Vert), Vert, GL_STATIC_DRAW);

        glGenBuffers(1, &_indexMeshBuffer);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Ind), Ind, GL_STATIC_DRAW);

    } 
由于GLubyte Ind不存在于函数之外,因此我无法通过

    sizeof(Ind)/sizeof(Ind[0]) 
就像我通常做的那样

那么,这是填充结构的正确方法还是我必须以其他方式填充结构?这种方法对我来说似乎是正确的,但这也可能是因为我在这种情况下缺乏正确的客观c知识

现在,我的应用程序在连接所需硬件时在启动时崩溃,所以可能只是内存分配有问题

或者有人知道如何在objective c/opengl es中正确设置更高分辨率的网格吗

我已经在C++中实现了一个钻石步进算法,我知道这个方法不是完美的编码,我已经简化了我个人使用的调用。 这是关于结合匹配调用正确使用struct类型的更多内容

欢迎任何帮助

编辑:

我的自动索引有一些问题,主要是我忘了从一行的末尾跳到下一行,因为我不希望一行的最后一个元素成为下一个三角形块的起点

这应该是正确的:

    //Fill indices

    count = 0;
    int jumpBarrier = 1;
    for (int c = 0; c < sizeInd; c++){
        Ind[c] = count;
        c++;
        Ind[c] = count + 1;
        c++;
        Ind[c] = count + width + 1; //; + 1;
        c++;
        Ind[c] = count + 1;
        c++;
        Ind[c] = count + width + 1 + 1;// + 1;
        c++;
        Ind[c] = count + width + 1 ;//+ 1;

        //jump
        if (jumpBarrier == width){
            count++;
            count++;
            jumpBarrier = 1;
        }
        else{
            count++;
            jumpBarrier++;
        }
    }
//填充索引
计数=0;
int-jumpBarrier=1;
对于(int c=0;c
编辑#2

duh,内for循环增加i而不是j,修正了, 顶点和索引现在按其应有的方式创建

编辑#3

因此,我设法绕过了这个问题,通过对这个算法进行修改,将所有内容打印到文本文件中,然后将项目中的所有内容复制到需要它们的地方


如果有人还想解释我哪里做错了,以及如何正确填充此结构,欢迎您回答此问题以进一步学习。

关于创建网格:

首先,要真正地将最基本的代码复杂化。另外,一些注释将帮助您调试代码。看看这部翻拍的电影:

- (void)createMesh:(int)width height:(int)height {
    int horizontalVertexCount = width+1; // one more then the number of surfaces
    int verticalVertexCount = height+1; // one more then the number of surfaces

    int vertexCount = horizontalVertexCount * verticalVertexCount; // a number of unique vertices

    // generate a buffer
    size_t vertexBufferSize = sizeof(Vertex)*vertexCount;
    Vertex *vertexBuffer = malloc(vertexBufferSize);

    // iterate through vertices and fill them
    for(int h=0; h<verticalVertexCount; h++) {

        // generate y position coordinate

        GLfloat y = h;
        y /= verticalVertexCount; // normalzie to be in range of [0,1]
        y = 2.0f*y - 1; // converting the range [0,1] to [-1,1]

        // generate y texture coordinate

        GLfloat v = h;
        v /= verticalVertexCount; // normalzie to be in range of [0,1]
        v = 1.0f - v; // converting the range [0,1] to [1,0]

        for(int w=0; h<horizontalVertexCount; w++) {
            // generate x position coordinate

            GLfloat x = w;
            x /= horizontalVertexCount; // normalzie to be in range of [0,1]

            // generate x texture coordinate

            GLfloat u = x;

            /*
             The next segment may be replaced by using access as:

             vertexBuffer[h*horizontalVertexCount + w].Position[0] = x;
             */

            Vertex *currentVertex = vertexBuffer + h*horizontalVertexCount + w;
            currentVertex->Position[0] = x;
            currentVertex->Position[1] = y;
            currentVertex->Position[2] = .0f;

            currentVertex->Color[0] = .0f;
            currentVertex->Color[1] = .0f;
            currentVertex->Color[2] = .0f;
            currentVertex->Color[3] = 1.0f;

            currentVertex->TexCoord[0] = u;
            currentVertex->TexCoord[1] = v;
        }
    }

    // create index buffer
    int numberOfSurfaces = width*height;
    int indicesPerSurface = 2*3; // 2 triangles per surface
    size_t indexBufferSize = sizeof(GLushort)*numberOfSurfaces*indicesPerSurface;
    GLushort *indexBuffer = malloc(indexBufferSize);

    for(int h=0; h<height; h++) {
        for(int w=0; w<width; w++) {
            int surfaceIndex = h*width + w;
            int firstIndexIndex = surfaceIndex*indicesPerSurface;

            indexBuffer[firstIndexIndex] = h*horizontalVertexCount + w; // upper left
            indexBuffer[firstIndexIndex] = h*horizontalVertexCount + (w + 1); // upper right
            indexBuffer[firstIndexIndex] = (h+1)*horizontalVertexCount + w; // lower left

            indexBuffer[firstIndexIndex] = h*horizontalVertexCount + (w + 1); // upper right
            indexBuffer[firstIndexIndex] = (h+1)*horizontalVertexCount + (w+1); // lower right
            indexBuffer[firstIndexIndex] = (h+1)*horizontalVertexCount + w; // lower left
        }
    }

    //Fill buffer
    glGenBuffers(1,&_vertexMeshBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexMeshBuffer);
    glBufferData(GL_ARRAY_BUFFER, vertexBufferSize, vertexBuffer, GL_STATIC_DRAW);

    glGenBuffers(1, &_indexMeshBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexMeshBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSize, indexBuffer, GL_STATIC_DRAW);

    // release the memory
    free(vertexBuffer);
    free(indexBuffer);
}
如果你不习惯工会的概念,我建议你把它放在你的阅读清单上。在这种情况下,它允许您通过多个属性访问相同的数据:如果您有一个
Vector4f myVector
,那么
myVector.x
始终与
myVector.r
相同,这样做是为了让代码更清楚地了解您在做什么。您可以看到GLSL(着色器语言)使用相同的原则。然后,使用方法可以是:

            currentVertex->position.x = x;
            currentVertex->position.y = y;
            currentVertex->position.z = .0f;

            currentVertex->color.r = .0f; // could use .x
            currentVertex->color.g = .0f; // could use .y
            currentVertex->color.b = .0f; // could use .z
            currentVertex->color.a = 1.0f; // could use .w
在您拥有一个好的结构之后,您所需要的就是
sizeof
(您已经在使用它)和
offsetof
(我希望您在为属性分配指针时使用它)。这样,如果编辑结构,则无需更改图形代码。例如,如果在某些点上选择在
顶点
结构中添加法线,则只需在结构中添加另一个向量,并且不需要更改其他代码即可使程序正常工作

包装数据:

所以,在你有了你的结构之后,你会想把它们打包成一些对象。此时,我建议您转到完整的Objective-C并创建一个新类,该类保存绘制对象所需的所有数据。这意味着您将拥有顶点缓冲区和索引缓冲区、绘图模式、偏移、步幅和顶点计数的ID。基本实现应该是这样的:

@interface MeshVertexObject : NSObject

@property (nonatomic) GLuint vertexBufferID; // assigned when generating a mesh
@property (nonatomic) GLuint indexBufferID; // assigned when generating a mesh
@property (nonatomic) GLuint vertexCount; // assigned when generating a mesh
@property (nonatomic) GLenum drawMode; // assigned when generating a mesh. GL_TRIANGLES

@property (nonatomic, readonly) void *positionPointer; // depending on the Vertex structure
@property (nonatomic, readonly) void *colorPointer; // depending on the Vertex structure
@property (nonatomic, readonly) void *texturePointer; // depending on the Vertex structure

@property (nonatomic, readonly) GLint positionStride; // depending on the Vertex structure
@property (nonatomic, readonly) GLint colorStride; // depending on the Vertex structure
@property (nonatomic, readonly) GLint textureStride; // depending on the Vertex structure


@end

@implementation MeshVertexObject

- (void)dealloc {
    // remove all the GL data bound to this calss on destructor
    if(self.vertexBufferID > 0) {
        GLuint vBuffer = self.vertexBufferID;
        self.vertexBufferID = 0;
        glDeleteBuffers(1, &vBuffer);
    }
    if(self.indexBufferID > 0) {
        GLuint iBuffer = self.indexBufferID;
        self.indexBufferID = 0;
        glDeleteBuffers(1, &iBuffer);
    }
}

- (void *)positionPointer {
    return (void *)offsetof(Vertex, position);
}
- (void *)colorPointer {
    return (void *)offsetof(Vertex, color);
}
- (void *)texturePointer {
    return (void *)offsetof(Vertex, textureCoordinates);
}

- (GLint)positionStride {
    return sizeof(Vertex);
}
- (GLint)colorStride {
    return sizeof(Vertex);
}
- (GLint)textureStride {
    return sizeof(Vertex);
}

@end
现在,这个类将保存您的网格生成方法,并可能包含其他形状生成器,例如立方体、球体

但是兔子洞更深了。。。现在,您可以在系统上构建一个系统,您可以创建更复杂的对象,其中也包括纹理ID(或者更确切地说是包含这些ID的
纹理
对象)和网格对象。然后还将其位置和方向的数据附加到场景中,方便您生成用于绘制管道的矩阵

结论:


你做得对,或者至少走得对。但是如果你想继续构建一个系统,如果你想调试你的代码,并且大部分时间都能维护你的代码,那么就让模块尽可能简单,尽可能有注释,然后继续向上构建。

谢谢你提供了这样一个详细的答案!简言之,我们必须使用malloc手动分配内存,而不是创建一个具有特定大小的数组,然后将创建的结构/元素推送到正确的位置。分配本身没有什么区别。通常,如果数组足够小且顶点数固定,则可以使用静态数组。否则,显式内存分配会提高性能和稳定性,因为在objectiveC中使用它几乎没有坏处,所以我建议您使用它。另一种方法是使用NSData或其可变版本,它做的事情几乎相同,但已经包装在Objective中,因此不需要释放内存
            currentVertex->position.x = x;
            currentVertex->position.y = y;
            currentVertex->position.z = .0f;

            currentVertex->color.r = .0f; // could use .x
            currentVertex->color.g = .0f; // could use .y
            currentVertex->color.b = .0f; // could use .z
            currentVertex->color.a = 1.0f; // could use .w
@interface MeshVertexObject : NSObject

@property (nonatomic) GLuint vertexBufferID; // assigned when generating a mesh
@property (nonatomic) GLuint indexBufferID; // assigned when generating a mesh
@property (nonatomic) GLuint vertexCount; // assigned when generating a mesh
@property (nonatomic) GLenum drawMode; // assigned when generating a mesh. GL_TRIANGLES

@property (nonatomic, readonly) void *positionPointer; // depending on the Vertex structure
@property (nonatomic, readonly) void *colorPointer; // depending on the Vertex structure
@property (nonatomic, readonly) void *texturePointer; // depending on the Vertex structure

@property (nonatomic, readonly) GLint positionStride; // depending on the Vertex structure
@property (nonatomic, readonly) GLint colorStride; // depending on the Vertex structure
@property (nonatomic, readonly) GLint textureStride; // depending on the Vertex structure


@end

@implementation MeshVertexObject

- (void)dealloc {
    // remove all the GL data bound to this calss on destructor
    if(self.vertexBufferID > 0) {
        GLuint vBuffer = self.vertexBufferID;
        self.vertexBufferID = 0;
        glDeleteBuffers(1, &vBuffer);
    }
    if(self.indexBufferID > 0) {
        GLuint iBuffer = self.indexBufferID;
        self.indexBufferID = 0;
        glDeleteBuffers(1, &iBuffer);
    }
}

- (void *)positionPointer {
    return (void *)offsetof(Vertex, position);
}
- (void *)colorPointer {
    return (void *)offsetof(Vertex, color);
}
- (void *)texturePointer {
    return (void *)offsetof(Vertex, textureCoordinates);
}

- (GLint)positionStride {
    return sizeof(Vertex);
}
- (GLint)colorStride {
    return sizeof(Vertex);
}
- (GLint)textureStride {
    return sizeof(Vertex);
}

@end