Reputation: 3891
I am following along with an exercise in O'Reilly's iOS Game Development Cookbook to draw a square with OpenGL using textures. This follows a previous recipe for creating a square without texture, and that worked fine. However, when I run the code with texture, as below, I see a triangle rather than a square. Also the triangle is not the shape I would expect if only one of the two triangles I am using to draw the square were drawn. Those are right triangles, whereas the triangle that is actually appearing is isosceles.
//Modified with addition of textureCoordinates
typedef struct {
GLKVector3 position;
GLKVector2 textureCoordinates;
} Vertex;
//Modified with addition of second set of braces{} per line
const Vertex SquareVertices[] = {
{{-1, -1, 0}, {0,0}},
{{1, -1, 0}, {1,0}},
{{1, 1, 0}, {1, 1}},
{{-1, 1, 0}, {0, 1}},
};
const GLubyte SquareTriangles[] = {
0, 1, 2,
2, 3, 0
};
@interface ViewController ()
{
GLuint _vertexBuffer;
GLuint _indexBuffer;
GLKBaseEffect *_squareEffect;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
GLKView *view = (GLKView *)self.view;
view.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:view.context];
//Create the vertex array buffer in which opengl will store vertices
//tell opengl to give us a buffer
glGenBuffers(1, &_vertexBuffer);
//make this buffer be the active array buffer
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
//put this data into acive array buffer
//it's as big as square vertices array so we can use the data from that array
//also this data isn't going to change
glBufferData(GL_ARRAY_BUFFER, sizeof(SquareVertices), SquareVertices, GL_STATIC_DRAW);
//now do same for index buffer, which shows which vertices to use to draw triangle
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(SquareTriangles), SquareTriangles, GL_STATIC_DRAW);
//prepare gl effect
_squareEffect = [[GLKBaseEffect alloc] init];
_squareEffect.texture2d0.name = texture.name;
//first set up projection matrix
float aspectRatio = self.view.bounds.size.width/self.view.bounds.size.height;
float fieldOfViewDegrees = 60.0;
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(fieldOfViewDegrees), aspectRatio, 0.1, 10.0);
_squareEffect.transform.projectionMatrix = projectionMatrix;
//next we describe how the square should be positions (6 units from camera)
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -6.0f);
_squareEffect.transform.modelviewMatrix = modelViewMatrix;
//CODE ADDED TO ADD TEXTURE
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"3px-tile" ofType:@"png"];
GLKTextureInfo *texture = [GLKTextureLoader textureWithContentsOfFile:imagePath options:nil error:&error];
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
//tell the effect it should prepare opengl to draw using configured settings
[_squareEffect prepareToDraw];
//opengl alreayd knows the vertex array contains vertex data. we now tell how to use
//tell opengl how the data is laid out for position of each vertex in vertex array
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
//how that open gl knows where to find vertex positions, can draw them
int numberOfVertices = sizeof(SquareTriangles)/sizeof(SquareTriangles[0]);
glDrawElements(GL_TRIANGLES, numberOfVertices, GL_UNSIGNED_BYTE, 0);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void *)offsetof(Vertex, textureCoordinates));
}
@end
Here's what I see:
Here's what I've tried:
Why do I have a triangle and how can I get the square back?
Upvotes: 0
Views: 154
Reputation: 373
Your first call of glVertexAttribPointer
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
Has a stride of 0. This is may be incorrect, be safe and change it to sizeof(Vertex)
(as it is in the second call).
If stride is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0.
Your second call of glVertexAttribPointer
should be moved in front of your glDrawElements
, although this is most likely not a problem right now.
I'm not sure if this solves the problem, but I can't comment yet so I have to submit an answer. Please update the code if you've fixed it.
Upvotes: 2