Related
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:
Back tracing to original square code - it still works if I change the code back
Changing the location in the code where I add the texture - doesn't change anything, the triangle remains.
Why do I have a triangle and how can I get the square back?
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.
I'm trying to render a cube with a texture on its sides, on OpenGLES 2.0 iOS. Part of the texture has an alpha transparency, and I want to see the back of the face that is behind it. To render both sides of the cube side, I've used
glDisable(GL_CULL_FACE);
and to enable transparency,
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
before drawing. And my cubes are rendered creating instances of the following class:
// In MSTexturedCube.h
#import <Foundation/Foundation.h>
#import <GLKit/GLKit.h>
#interface MSTexturedCube : NSObject {
GLKVector3 _vertices[8];
GLKVector3 _triangleVertices[36];
GLKVector2 _textureVertices[36];
}
#property (nonatomic, assign) float xRotationAngle;
#property (nonatomic, assign) float yRotationAngle;
#property (nonatomic, assign) GLKVector3 scale; // x, y, z scale
#property (nonatomic, assign) GLKVector3 translation; // x, y, z translation
- (id)initWithTexture:(GLKTextureInfo *)textureInfo vertexData:(GLKVector2[36])textureVertexData;
- (id)initWithTexture:(GLKTextureInfo *)textureInfo frontFaceCoords:(GLKVector2[4])front right:(GLKVector2[4])right back:(GLKVector2[4])back left:(GLKVector2[4])left top:(GLKVector2[4])top bottom:(GLKVector2[4])bottom;
- (void)draw;
- (void)setVertices:(GLKVector3[8])verticesArray;
#end
// In MSTexturedCube.m
#import "MSTexturedCube.h"
static int vertexIndices[36] = {
// Front
0, 1, 2,
0, 2, 3,
// Right
1, 5, 6,
1, 6, 2,
// Back
5, 4, 7,
5, 7, 6,
// Left
4, 0, 3,
4, 3, 7,
// Top
3, 2, 6,
3, 6, 7,
// Bottom
4, 5, 1,
4, 1, 0,
};
#interface MSTexturedCube ()
#property (nonatomic, strong) GLKBaseEffect *effect;
#property (nonatomic, strong) GLKTextureInfo *textureInfo;
- (void)setupOpenGL;
#end
#implementation MSTexturedCube
#synthesize effect = _effect;
#synthesize textureInfo = _textureInfo;
#synthesize xRotationAngle = _xRotationAngle;
#synthesize yRotationAngle = _yRotationAngle;
#synthesize scale = _scale;
#synthesize translation = _translation;
// Init methods
...
- (void)draw {
// Create matrices
GLKMatrix4 yRotation = GLKMatrix4MakeYRotation(self.yRotationAngle);
GLKMatrix4 xRotation = GLKMatrix4MakeXRotation(self.xRotationAngle);
GLKMatrix4 scale = GLKMatrix4MakeScale(self.scale.x, self.scale.y, self.scale.z);
GLKMatrix4 translation = GLKMatrix4MakeTranslation(self.translation.x, self.translation.y, self.translation.z);
GLKMatrix4 modelMatrix = GLKMatrix4Multiply(translation, GLKMatrix4Multiply(xRotation, GLKMatrix4Multiply(yRotation, scale)));
GLKMatrix4 viewMatrix = GLKMatrix4MakeLookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
self.effect.transform.modelviewMatrix = GLKMatrix4Multiply(viewMatrix, modelMatrix);
self.effect.transform.projectionMatrix = GLKMatrix4MakePerspective(0.25 * M_PI, 1.0, 2.0, 500.0);
// Set texture properties if a texture is set
if (self.textureInfo) {
self.effect.texture2d0.envMode = GLKTextureEnvModeReplace;
self.effect.texture2d0.target = GLKTextureTarget2D;
self.effect.texture2d0.name = self.textureInfo.name;
}
// Prepare the effect to draw after creating matrices
[self.effect prepareToDraw];
// Set texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(self.textureInfo.target, self.textureInfo.name);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
// Set vertices
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, _triangleVertices);
// Set texture (if set)
if (self.textureInfo) {
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, _textureVertices);
}
// Draw
glDrawArrays(GL_TRIANGLES, 0, 36);
// Disable arrays
glDisableVertexAttribArray(GLKVertexAttribPosition);
glDisableVertexAttribArray(GLKVertexAttribTexCoord0);
}
// Getters & setters
...
#pragma mark - Private methods
- (void)setupOpenGL {
// Set vertices array
_vertices[0] = GLKVector3Make(-0.5, -0.5, 0.5); // Left bottom front
_vertices[1] = GLKVector3Make( 0.5, -0.5, 0.5); // Right bottom front
_vertices[2] = GLKVector3Make( 0.5, 0.5, 0.5); // Right top front
_vertices[3] = GLKVector3Make(-0.5, 0.5, 0.5); // Left top front
_vertices[4] = GLKVector3Make(-0.5, -0.5, -0.5); // Left bottom back
_vertices[5] = GLKVector3Make( 0.5, -0.5, -0.5); // Right bottom back
_vertices[6] = GLKVector3Make( 0.5, 0.5, -0.5); // Right top back
_vertices[7] = GLKVector3Make(-0.5, 0.5, -0.5); // Left top back
// Set the triangle vertices
for (int i = 0; i < 36; i++) {
_triangleVertices[i] = _vertices[vertexIndices[i]];
}
self.effect = [[GLKBaseEffect alloc] init];
}
Now, the problem is that when I create a cube with the front face transparent and all the others opaque, this face acts as if there were nothing behind, showing the background. However, if I put a smaller opaque cube inside, it's rendered perfectly and I can see it through the transparent face of the biggest cube. Does anyone know why this happens, and how I could fix it?
Thanks in advance! If you need more information about my code, ask me.
Finally I implemented a workaround. It consists in creating two MSTexturedCube objects, with exactly the same vertices and texture vertices, and render one with cull facing enabled and glCullFace(GL_BACK), and the other one with glCullFace(GL_FRONT). It works exactly as intended.
The reason for that is that transparent side was rendered first in your case and filled depth buffer, back sides did not pass depth test and were not drawn. To solve this you can draw opaque and transparent objects separately, first opaque ones then transparent, also you will have to draw transparent objects from back to front. Another option is to use discard for fully transparent pixels, but this only works for fully transparent case and usually quite slow.
I'm trying to learn OpenGL on iOS. I'm following this tutorial.
http://www.raywenderlich.com/5235/beginning-opengl-es-2-0-with-glkit-part-2
I'm sure I followed the steps carefully, but when I get to the end, only don't see any shapes on the screen.
https://gist.github.com/seanhess/5356598
I do see the background color changing, so OpenGL is working in general. Just the call to glDrawElements doesn't seem to be doing anything.
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
He has some demo code, but it's not the same as the code he has you write in the tutorial, and I want to understand why this doesn't work before pasting his in.
Where is the GLKBaseEffect supposed to be drawn? I don't see how we actually used it.
The following seems to be wrong, as all the vertices are the same:
// these are not TRIANGLES, they are vertices
const Vertex Vertices[] = {
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, -1, 0}, {1, 0, 0, 1}},
{{1, -1, 0}, {1, 0, 0, 1}},
};
Even if everything else is correct, your triangle is degenerate as
all is vertices are coincident. When you fix the coordinates, make
sure that the indices reference the vertices in a counter-clockwise
fashion or, even better for your first experiments, call
glDisable(GL_CULL_FACE);
before drawing. You could try to pick your vertices like this:
// these are not TRIANGLES, they are vertices
const Vertex Vertices[] = {
{{-.9, -.9, 0}, {1, 0, 0, 1}},
{{.9, -.9, 0}, {1, 0, 0, 1}},
{{-.9, .9, 0}, {1, 0, 0, 1}},
{{.9, .9, 0}, {1, 0, 0, 1}},
};
// These are the trianges. Just reference the vertices
const GLubyte Indices[] = {
0, 1, 2,
2, 1, 3
};
Edit
Try to comment away the second part of update:
/*
// Set the projection matrix of the effect. It defines the field of view
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 40., 10.0);
self.effect.transform.projectionMatrix = projectionMatrix;
// Rotate about z axis
// the model view matrix is the transform applied to any geometry that the effect renders
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0, 0, -6);
_rotation += 90 * self.timeSinceLastUpdate;
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(_rotation), 0, 0, 1);
self.effect.transform.modelviewMatrix = modelViewMatrix;
*/
The matrices you define put your object out of the final image. When you don't see anything on the screen one of the first things you should check are your transformation matrices. In your case, the problem is with the perspective transformation:
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 40., 10.0);
Your translated and rotated object must be located at a distance between the 3rd and 4th parameter of this call in order to be drawn, and actually the 3rd parameter is the distance of the so called near plane, and must be smaller than the 4th parameter, the far plane. A safe bet is usually 1 and 100 for these two parameters.
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 1.0, 100.0);
Edit 2
The following is a working version.
//
// HelloGLKitViewController.m
// OpenGL2Tutorial
//
// Created by Sean Hess on 4/10/13.
// Copyright (c) 2013 Sean Hess. All rights reserved.
//
#import "HelloGLKitViewController.h"
typedef struct {
float Position[3];
float Color[4];
} Vertex;
// these are not TRIANGLES, they are vertices
const Vertex Vertices[] = {
{{-.9, -.9, 0}, {1, 0, 0, 1}},
{{.9, -.9, 0}, {1, 0, 0, 1}},
{{-.9, .9, 0}, {1, 0, 0, 1}},
{{.9, .9, 0}, {1, 0, 0, 1}},
};
// These are the trianges. Just reference the vertices
const GLubyte Indices[] = {
0, 1, 2,
2, 1, 3
};
#interface HelloGLKitViewController () {
GLuint _vertexBuffer;
GLuint _indexBuffer;
float _rotation;
float _currentRed;
BOOL _increasing;
}
#property (nonatomic, strong) EAGLContext * context;
#property (nonatomic, strong) GLKBaseEffect * effect;
#end
#implementation HelloGLKitViewController
// I think this method just fills the objective-c stuff with the information from my c structs
- (void)setupGL {
[EAGLContext setCurrentContext:self.context];
self.effect = [GLKBaseEffect new];
glGenBuffers(1, &_vertexBuffer); // supposed to be an array of buffers, doing that trick again
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); // when I say "GL_ARRAY_BUFFER" I mean _vertexBuffer
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}
- (void)tearDownGL {
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteBuffers(1, &_indexBuffer);
self.effect = nil;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) NSLog(#"FAiled to create ES Context");
GLKView * view = (GLKView *)self.view;
view.context = self.context;
// will automatically pause when interrupted
self.pauseOnWillResignActive = YES;
[self setupGL];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
[self tearDownGL];
}
#pragma mark - GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
glClearColor(_currentRed, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// have to call after you change any properties in the effect, before drrawing
[self.effect prepareToDraw];
// We don't have to do this again, since we did it above in setupGL
// They're already bound to GL_ARRAY_BUFFER and GL_ELEMENT_ARRAYBUFFER
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
// remember my vertex array contains Vertex(s)
// so we're telling it how to read it
// position is 3 floats, the offset is based on that offsetof function
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) offsetof(Vertex, Position));
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) offsetof(Vertex, Color));
// 1. pretty much always use triangles
// 2. the number of vertices to render. tricky way to do .length on array
// 3. the data type
// 4. seems like should be pointer to indices. We're using VBOs, so it's already set to the GL_ELEMENT_ARRAY_BUFFER. So give it 0.
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
}
- (void)update {
if (_increasing) {
_currentRed += 1.0 * self.timeSinceLastUpdate;
} else {
_currentRed -= 1.0 * self.timeSinceLastUpdate;
}
if (_currentRed >= 1.0) {
_currentRed = 1.0;
_increasing = NO;
}
if (_currentRed <= 0.0) {
_currentRed = 0.0;
_increasing = YES;
}
// Set the projection matrix of the effect. It defines the field of view
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 1.0, 100.0);
self.effect.transform.projectionMatrix = projectionMatrix;
// Rotate about z axis
// the model view matrix is the transform applied to any geometry that the effect renders
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0, 0, -6);
_rotation += 90 * self.timeSinceLastUpdate;
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(_rotation), 0, 0, 1);
self.effect.transform.modelviewMatrix = modelViewMatrix;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.paused = !self.paused;
NSLog(#"timeSinceLastUpdate: %f", self.timeSinceLastUpdate);
NSLog(#"timeSinceLastDraw: %f", self.timeSinceLastDraw);
NSLog(#"timeSinceFirstResume: %f", self.timeSinceFirstResume);
NSLog(#"timeSinceLastResume: %f", self.timeSinceLastResume);
}
#end
I'm trying to load a texture that will be drawn on a simple square shape between four vertices. Unfortunately the only way this seems to work is if I put the code for loading the image data into the function that's called every frame. My code was originally based off an ARToolKit function (hence the drawCube name). Here is what my code looks like:
- (void) drawCube
{
glStateCacheEnableTex2D();
glStateCacheEnableBlend();
glStateCacheBlendFunc(GL_ONE, GL_SRC_COLOR);
glStateCacheEnableClientStateVertexArray();
glStateCacheEnableClientStateTexCoordArray();
glStateCacheEnableClientStateNormalArray();
const GLfloat cube_vertices [4][3] = {
{-1.0f, 1.0f, -1.0f}, {1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f} };
const GLfloat texCoords [4][2] = {
{0.0, 1.0}, {1.0, 1.0}, {0.0, 0.0}, {1.0, 0.0}
};
const GLfloat normals [4][3] = {
{0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}
};
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
NSString *path = [[NSBundle mainBundle] pathForResource:#"iTunesArtwork" ofType:#"png"];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil)
NSLog(#"Do real error checking here");
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef contextt = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
CGContextTranslateCTM (contextt, 0, height);
CGContextScaleCTM (contextt, 1.0, -1.0);
CGColorSpaceRelease( colorSpace );
CGContextClearRect(contextt, CGRectMake( 0, 0, width, height ) );
CGContextTranslateCTM(contextt, 0, height - height );
CGContextDrawImage(contextt, CGRectMake( 0, 0, width, height ), image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(contextt);
free(imageData);
[image release];
[texData release];
glPushMatrix(); // Save world coordinate system.
glScalef(20.0f, 20.0f, 20.0f);
glTranslatef(0.0f, 0.0f, 1.0f); // Place base of cube on marker surface.
glStateCacheDisableLighting();
glBindTexture(GL_TEXTURE_2D, texture[0]);
glStateCacheVertexPtr(3, GL_FLOAT, 0, cube_vertices);
glStateCacheNormalPtr(GL_FLOAT, 0, normals);
glStateCacheTexCoordPtr(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glStateCacheDisableClientStateNormalArray();
glStateCacheDisableClientStateTexCoordArray();
glStateCacheDisableClientStateVertexArray();
glPopMatrix(); // Restore world coordinate system.
}
This code works fine, the only problem is it gets called every frame an AR marker is visible to the camera, which is of course not OK. However, when I try to move the image data lines to the init function, I only get a white square without the texture. The lines I moved were the top 3 Enable Tex2D/Blend and BlendFunc. Then after the normal coordinates, everything down to [texData release]. I've been basing my code off of a tutorial that I read here: http://iphonedevelopment.blogspot.com/2009/05/opengl-es-from-ground-up-part-6_25.html
Everything seems like it would be in the right place to me but clearly that's not the case. Could anyone please shed some light on my problem?
Not seeing your init code, I can't tell for sure. Possibly you're running this code to load a texture before setting up your OpenGL context. Context creation is done in the viewDidLoad method of the view controller in Apple's OpenGL app templates for Xcode. I wasn't able to download the template from this blog series, as the server is off line. Maybe your template creates the context in the same method. Try moving the texture loading code so it runs after the context creation.
By the way, this tutorial is rather old. Since that blog entry was posted GLKit was added to the iOS SDK. GLKit includes very handy texture loading code.
I am building an iOS game with OpenGL ES 2.0 that contains a scene with around 100 different 'objects' which I need to be able to transform independently of one another. I am new to OpenGL ES. As such, I initially thought I should start with OpenGL ES 1.1, then later migrate the app to 2.0 to take advantage of the enhanced visual effects.
However, just as I was getting comfortable with 1.1, I realized, partly based on Apple's very 2.0-centric Xcode template for OpenGL, that it was going to be more trouble than it's worth to fight moving straight into 2.0, so I bit the bullet.
Now, I'm finding it difficult to grasp the concepts enough to do simple transforms on my vertex array objects independently of one another. I read in the OpenGLES 2.0 docs that the best way to do this would be to use multiple VBOs, one for each vertex array. However, I can't seem to transform one of them without affecting the entire scene.
I started the project with the Apple OpenGL ES template and streamlined it, such that the setupGL method looks like this:
-(void)setupGL
{
// Setup
[EAGLContext setCurrentContext:self.context];
[self loadShaders];
self.effect = [[GLKBaseEffect alloc] init];
self.effect.light0.enabled = GL_TRUE;
self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 0.4f, 0.4f, 1.0f);
glEnable(GL_DEPTH_TEST); // do depth comparisons and update the depth buffer
// Initialize first buffer
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(gPyramidVertexData), gPyramidVertexData, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glBindVertexArrayOES(0);
// Initialize second buffer
glGenVertexArraysOES(2, &_vertexArray2);
glBindVertexArrayOES(_vertexArray2);
glGenBuffers(2, &_vertexBuffer2);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData), gCubeVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));
glBindVertexArrayOES(0);
}
I know that's incredibly sloppy code- I basically copy-and-pasted the buffer creation portion to set myself up for experimenting with two different vertextArrays in separate buffers. It appears to have worked, as I can render both buffers in the drawInRect method:
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glBindVertexArrayOES(_vertexArray);
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, numberOfVerteces);
glBindVertexArrayOES(_vertexArray2);
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, numberOfVerteces2);
}
My problem comes when I try to do transforms on one vertex array without affecting the other one. I tried adding transforms in the above method just before the glDrawArrays calls, without success- I think that may only work with 1.1. It appears my transforms must be done within the update method:
-(void)update
{
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);
self.effect.transform.projectionMatrix = projectionMatrix;
GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation( 0.0f, 0.0f, -4.0f);
baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, _sceneRotation, 1.0f, 1.0f, 1.0f);
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, zoomFactor);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _objectRotation, 0.0f, 1.0f, 0.0f);
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);
_normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
_modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
}
However, this is where I get really confused-- it's not at all clear how I could modify this method to do transforms to one VBO or the other. It's not even clear that th above code is making any reference to one particular buffer at all.
Eventually I would like to expand my game by moving the code for each game object into an instance of a custom class, which would handle the transforms, etc. But I would like to know if I'm completely misguided in my approach before doing so.
In case this is helpful to anyone having similar issues, I found the answers I was looking for on Ian Terrell's excellent blog, Games by Ian Terrell.
In particular, this tutorial and its accompanying sample code were exactly what I needed to get a grip on this very complicated subject. Hope this helps!
GLKMatrix4 _modelViewProjectionMatrix[5]; // Al inicio
En - (void)update utiliza
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(-1.0f, 1.0f, -1.0f / aspect, 1.0f / aspect, -10.0f, 10.0f);
for (int i=0; i<5;i++) {
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(i*0.2+ 0.3f, 0.0f, 0.0f);
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeZRotation(0.0 - _rotation));
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeXRotation(0.0 - _rotation));
modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeYRotation(0.20 - _rotation));
_modelViewProjectionMatrix[i] = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
}