在模仿OPENGLES教程中的代码时,首先看了一遍代码,能粗通代码的意思,但是开始自己写时碰到了不少问题,经常性的得不到正确的图形,而是一堆不知道为什么会是这样的图形,在自习研究如下代码后我知道了原因
#import "AGLKVertexAttribArrayBuffer.h"
@interface AGLKVertexAttribArrayBuffer ()
@property (nonatomic, assign) GLsizeiptr
bufferSizeBytes;
@property (nonatomic, assign) GLsizei
stride;
@end
@implementation AGLKVertexAttribArrayBuffer
@synthesize name;
@synthesize bufferSizeBytes;
@synthesize stride;
/
// This method creates a vertex attribute array buffer in
// the current OpenGL ES context for the thread upon which this
// method is called.
- (id)initWithAttribStride:(GLsizei)aStride
numberOfVertices:(GLsizei)count
bytes:(const GLvoid *)dataPtr
usage:(GLenum)usage;
{
NSParameterAssert(0 < aStride);
NSAssert((0 < count && NULL != dataPtr) ||
(0 == count && NULL == dataPtr),
@"data must not be NULL or count > 0");
if(nil != (self = [super init]))
{
stride = aStride;
bufferSizeBytes = stride * count;
glGenBuffers(1, // STEP 1
&name);
glBindBuffer(GL_ARRAY_BUFFER, // STEP 2
self.name);
glBufferData( // STEP 3
GL_ARRAY_BUFFER, // Initialize buffer contents
bufferSizeBytes, // Number of bytes to copy
dataPtr, // Address of bytes to copy
usage); // Hint: cache in GPU memory
NSAssert(0 != name, @"Failed to generate name");
}
return self;
}
/
// This method loads the data stored by the receiver.
- (void)reinitWithAttribStride:(GLsizei)aStride
numberOfVertices:(GLsizei)count
bytes:(const GLvoid *)dataPtr;
{
NSParameterAssert(0 < aStride);
NSParameterAssert(0 < count);
NSParameterAssert(NULL != dataPtr);
NSAssert(0 != name, @"Invalid name");
self.stride = aStride;
self.bufferSizeBytes = aStride * count;
glBindBuffer(GL_ARRAY_BUFFER, // STEP 2
self.name);
glBufferData( // STEP 3
GL_ARRAY_BUFFER, // Initialize buffer contents
bufferSizeBytes, // Number of bytes to copy
dataPtr, // Address of bytes to copy
GL_DYNAMIC_DRAW);
}
/
// A vertex attribute array buffer must be prepared when your
// application wants to use the buffer to render any geometry.
// When your application prepares an buffer, some OpenGL ES state
// is altered to allow bind the buffer and configure pointers.
- (void)prepareToDrawWithAttrib:(GLuint)index
numberOfCoordinates:(GLint)count
attribOffset:(GLsizeiptr)offset
shouldEnable:(BOOL)shouldEnable
{
NSParameterAssert((0 < count) && (count < 4));
NSParameterAssert(offset < self.stride);
NSAssert(0 != name, @"Invalid name");
glBindBuffer(GL_ARRAY_BUFFER, // STEP 2
self.name);
if(shouldEnable)
{
glEnableVertexAttribArray( // Step 4
index);
}
glVertexAttribPointer( // Step 5
index, // Identifies the attribute to use
count, // number of coordinates for attribute
GL_FLOAT, // data is floating point
GL_FALSE, // no fixed point scaling
(self.stride), // total num bytes stored per vertex
NULL + offset); // offset from start of each vertex to
// first coord for attribute
#ifdef DEBUG
{ // Report any errors
GLenum error = glGetError();
if(GL_NO_ERROR != error)
{
NSLog(@"GL Error: 0x%x", error);
}
}
#endif
}
/
// Submits the drawing command identified by mode and instructs
// OpenGL ES to use count vertices from the buffer starting from
// the vertex at index first. Vertex indices start at 0.
- (void)drawArrayWithMode:(GLenum)mode
startVertexIndex:(GLint)first
numberOfVertices:(GLsizei)count
{
NSAssert(self.bufferSizeBytes >=
((first + count) * self.stride),
@"Attempt to draw more vertex data than available.");
glDrawArrays(mode, first, count); // Step 6
}
/
// Submits the drawing command identified by mode and instructs
// OpenGL ES to use count vertices from previously prepared
// buffers starting from the vertex at index first in the
// prepared buffers
+ (void)drawPreparedArraysWithMode:(GLenum)mode
startVertexIndex:(GLint)first
numberOfVertices:(GLsizei)count;
{
glDrawArrays(mode, first, count); // Step 6
}
/
// This method deletes the receiver's buffer from the current
// Context when the receiver is deallocated.
- (void)dealloc
{
// Delete buffer from current context
if (0 != name)
{
glDeleteBuffers (1, &name); // Step 7
name = 0;
}
}
@end
在该类中,类维持着一个opengl缓存标志符,在刚开始学OpenGL的时候我觉得这个标识符没用,其实是大错特错,以至于后来自己写代码出现一些非预期的图形自己死活找不到原因,只能照着example重新写一遍。缓存标识符标识当前活动的GPU内存,当你想配置某一块内存或者你想绘制这一块内存的内容时,你需要调用GLBindbuffer函数,并且该函数第二个参数要设置成你想操作内存的标识,然后接下来的操作都是针对这一块内存进行的,操作完过后记得再次调用GLBindBuffer(GL_ARRAY_BUFFER,0),将当前活动内存设置为空,非必需,但是这样做会是个好习惯.下面是我写的一些代码,在ObjectMesh类中大家可以将prepareToDraw,draw函数中的glbindbuffer函数全部注释,然后看下是否能得到想要的图形。
@interface ObjectMesh()
@property(nonatomic,strong)NSData *indicesData;
@property(nonatomic,assign)GLsizei vertsNum;
@property(nonatomic,assign)GLsizei indiceCount;
@property(nonatomic,assign)GLuint name;
@property(nonatomic,assign)GLuint index;
@end
@implementation ObjectMesh
@synthesize name;
@synthesize index;
-(id)initWithVertexData:(NSData *)data Indices:(NSData *)indices{
self=[super init];
if(self){
glGenBuffers(1, &name);
glBindBuffer(GL_ARRAY_BUFFER, name);
_vertsNum=(GLsizei)data.length/sizeof(ObjectMeshVertex);
glBufferData(GL_ARRAY_BUFFER, data.length, data.bytes, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
if(indices){
glGenBuffers(GL_ELEMENT_ARRAY_BUFFER, &index);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.length, indices.bytes, GL_STATIC_DRAW);
}
}
return self;
}
-(id)initWithPositionData:(GLfloat *)data normalData:(GLfloat *)normal texCoordsData:(GLfloat *)texCoords vertexCount:(GLsizei)count indexData:(GLfloat *)indices indicesCount:(GLsizei)indiceCount{
if(nil==data || nil ==normal){
return nil;
}
NSMutableData *vert=[NSMutableData data];
NSData *indicedata;
for(int i=0;i<count;++i){
ObjectMeshVertex meshVertex;
meshVertex.position.x=data[i*3];
meshVertex.position.y=data[i*3+1];
meshVertex.position.z=data[i*3+2];
meshVertex.normal.x=normal[i*3];
meshVertex.normal.y=normal[i*3+1];
meshVertex.normal.z=normal[i*3+2];
if(texCoords){
meshVertex.texCoords0.s=texCoords[2*i];
meshVertex.texCoords0.t=texCoords[2*i+1];
}else{
meshVertex.texCoords0.s=0;
meshVertex.texCoords0.t=0;
}
[vert appendBytes:&meshVertex length:sizeof(meshVertex)];
}
indicedata=[NSData dataWithBytes:indices length:sizeof(GLfloat)*indiceCount];
return [self initWithVertexData:vert Indices:indicedata];
}
-(void)prepareToDraw{
glBindBuffer(GL_ARRAY_BUFFER, name);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(ObjectMeshVertex), NULL+offsetof(ObjectMeshVertex, position));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(ObjectMeshVertex), NULL+offsetof(ObjectMeshVertex, normal));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(ObjectMeshVertex), NULL+offsetof(ObjectMeshVertex, texCoords0));
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
-(void)draw{
if(_indicesData){
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index);
glDrawElements(GL_TRIANGLES, (GLsizei)_indicesData.length/sizeof(GLfloat), GL_UNSIGNED_SHORT, _indicesData.bytes);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}else{
glBindBuffer(GL_ARRAY_BUFFER, name);
glDrawArrays(GL_TRIANGLES, 0, _vertsNum);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
完整源代码请参照:
点击打开链接该代码没有给对象添加移动的效果,请自行添加