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