OpenGL sprites are trembling slightly at rendering - iphone

I made a class which manage sprites in an iphone application by using opengl es.
rendering works well but when the sprite sheet is large (more than 512x512px) and the sprite has a part which doesn't move, this part seems trembling slightly (like if antialiasing was computed differently for each frame).
Is it normal or is it a bug in my code ?
Here is the code :
//set bounds of the cell
int t_x1 = position.x;
int t_y1 = MAX_SPRITE_HEIGHT - position.y;
int t_x2 = t_x1 + width;
int t_y2 = t_y1 - height;
//set vertices position
GLshort verticesBuffer[4*3];
verticesBuffer[0] = t_x1;
verticesBuffer[1] = t_y1;
verticesBuffer[2] = depth;
verticesBuffer[3] = t_x1;
verticesBuffer[4] = t_y2;
verticesBuffer[5] = depth;
verticesBuffer[6] = t_x2;
verticesBuffer[7] = t_y1;
verticesBuffer[8] = depth;
verticesBuffer[9] = t_x2;
verticesBuffer[10] = t_y2;
verticesBuffer[11] = depth;
//set texture coordinates
GLfloat texCoordBuffer[2*4]
texCoordBuffer[0] = a_cellLayer.origin.x / CGImageGetWidth(texture.textureImage);
texCoordBuffer[1] = a_cellLayer.origin.y / CGImageGetHeight(texture.textureImage);
texCoordBuffer[2] = texCoordBuffer[0];
texCoordBuffer[3] = texCoordBuffer[1] + (float)(t_y1-t_y2) / CGImageGetHeight(texture.textureImage);
texCoordBuffer[4] = texCoordBuffer[6];
texCoordBuffer[5] = texCoordBuffer[1];
texCoordBuffer[6] = texCoordBuffer[0] + (float)(t_x2-t_x1) / CGImageGetWidth(texture.textureImage);
texCoordBuffer[7] = texCoordBuffer[3];
//set texture
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, [texture getTexture]);
//set vertices
glVertexPointer(3, GL_SHORT, 0, verticesBuffer);
glEnableClientState(GL_VERTEX_ARRAY);
//apply texture
glTexCoordPointer(2, GL_FLOAT, 0, texCoordBuffer);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//render
glColor4f(1.0, 1.0, 1.0, 1.0); // R V B Alpha
glNormal3f(0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4*nbOfXSudivisions*nbOfYSudivisions);
I tried to change the type of my texture coordinates with GL_FIXED but it doesn't change anything
Does anybody have an idea ?

I don't use depth buffer and I've set the projection matrix like that :
const GLfloat zNear = 100, zFar = 1000, fieldOfView = 22.5;
glMatrixMode(GL_PROJECTION);
GLfloat size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
CGRect rect = oGLView.bounds;
glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size /
(rect.size.width / rect.size.height), zNear, zFar);
glViewport(0, 0, rect.size.width, rect.size.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//set perspective
gluLookAt(PAGE_WIDTH/2, PAGE_HEIGHT/2, PAGE_WIDTH/2.0f/(tanf(DEGREES_TO_RADIANS(fieldOfView/2.0f))),
PAGE_WIDTH/2, PAGE_HEIGHT/2, 0,
0, 1, 0);

Related

Texture Mapping - Cocos2d/OpenGL ES 1.0

This lightning is really affecting my game's performance because I am constantly adding and removing the lightning, but also each lighting strike is composed of 3 anti aliased lines using:
void ccDrawSmoothLine(CGPoint pos1, CGPoint pos2, float width)
{
GLfloat lineVertices[12], curc[4];
GLint ir, ig, ib, ia;
CGPoint dir, tan;
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_VERTEX_ARRAY,
// Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
//glEnable(GL_LINE_SMOOTH);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
pos1.x *= CC_CONTENT_SCALE_FACTOR();
pos1.y *= CC_CONTENT_SCALE_FACTOR();
pos2.x *= CC_CONTENT_SCALE_FACTOR();
pos2.y *= CC_CONTENT_SCALE_FACTOR();
width *= CC_CONTENT_SCALE_FACTOR();
width = width*2;
dir.x = pos2.x - pos1.x;
dir.y = pos2.y - pos1.y;
float len = sqrtf(dir.x*dir.x+dir.y*dir.y);
if(len<0.00001)
return;
dir.x = dir.x/len;
dir.y = dir.y/len;
tan.x = -width*dir.y;
tan.y = width*dir.x;
lineVertices[0] = pos1.x + tan.x;
lineVertices[1] = pos1.y + tan.y;
lineVertices[2] = pos2.x + tan.x;
lineVertices[3] = pos2.y + tan.y;
lineVertices[4] = pos1.x;
lineVertices[5] = pos1.y;
lineVertices[6] = pos2.x;
lineVertices[7] = pos2.y;
lineVertices[8] = pos1.x - tan.x;
lineVertices[9] = pos1.y - tan.y;
lineVertices[10] = pos2.x - tan.x;
lineVertices[11] = pos2.y - tan.y;
glGetFloatv(GL_CURRENT_COLOR,curc);
ir = 255.0*curc[0];
ig = 255.0*curc[1];
ib = 255.0*curc[2];
ia = 255.0*curc[3];
const GLubyte lineColors[] = {
ir, ig, ib, 0,
ir, ig, ib, 0,
ir, ig, ib, ia,
ir, ig, ib, ia,
ir, ig, ib, 0,
ir, ig, ib, 0,
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, lineVertices);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, lineColors);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
glDisableClientState(GL_COLOR_ARRAY);
// restore default state
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
}
My FPS will drop to about 40, then shoot back up to 60. I've read that texture mapping the line could improve my game's performance.
I have been trying to figure this out for several weeks now, with no luck. Can someone PLEASE help me with this?
This is my current ccDrawLines and draw method
-(void) draw
{
numPoints_ = 0;
glColor4ub(_color.r, _color.g, _color.b, _opacity);
if (_opacity != 255)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawLightning(_strikePoint2, _strikePoint, _displacement, _minDisplacement, _seed, lightningPoints_, &numPoints_);
ccDrawLines(lightningPoints_, numPoints_, texture);
if (_opacity != 255)
glBlendFunc(CC_BLEND_SRC, CC_BLEND_DST);
glColor4f(1.0, 1.0, 1.0, 1.0);
}
void ccDrawLines( CGPoint* points, uint numberOfPoints, CCTexture2D* texture )
{
//layout of points [0] = origin, [1] = destination and so on
ccVertex2F vertices[numberOfPoints];
if (CC_CONTENT_SCALE_FACTOR() != 1 )
{
for (int i = 0; i < numberOfPoints; i++)
{
vertices[i].x = points[i].x * CC_CONTENT_SCALE_FACTOR();
vertices[i].y= points[i].y * CC_CONTENT_SCALE_FACTOR();
}
glVertexPointer(2, GL_FLOAT, 0, vertices);
}
else glVertexPointer(2, GL_FLOAT, 0, points);
ccTex2F texCoords[numberOfPoints];
float width = texture.pixelsWide;
float height = texture.pixelsHigh;
if (CC_CONTENT_SCALE_FACTOR() != 1 )
{
for (int i = 0; i < numberOfPoints; i++)
{
texCoords[i].u = (vertices[i].x * CC_CONTENT_SCALE_FACTOR()) / width;
texCoords[i].v = (vertices[i].y * CC_CONTENT_SCALE_FACTOR()) / height;
}
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
}
else glTexCoordPointer(2, GL_FLOAT, 0, points);
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
// Needed states: GL_VERTEX_ARRAY,
// Unneeded states: GL_TEXTURE_2D, GL_TEXTURE_COORD_ARRAY, GL_COLOR_ARRAY
glPushMatrix();
glBindTexture(GL_TEXTURE_2D, [texture name]);
glDisableClientState(GL_COLOR_ARRAY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glDrawArrays(GL_TRIANGLE_STRIP, 0, numberOfPoints);
// restore default state
glEnableClientState(GL_COLOR_ARRAY);
glPopMatrix();
}
The texture is just a 32x32 .png file with a small blue dot.
If you look at ccDrawLines I have added the code to texture map the line. The problem with it is, gaps in the line, multiple lines being drawn, and it looks horrible.
EDIT:
I decided not to texture map the line and use ccDrawSmoothLine.
All I did was allocate the lightning in my gamelayer's init
lightningStrike_ = [Lightning lightningWithStrikePoint:ccp(-100, -100) strikePoint2:ccp(-100, -100)];
[self addChild:lightningStrike_ z:1];
Then, I created an instance method to set the _strikePoint and _strikePoint2 properties and call the strikeRandom method.
-(Lightning *)lightningStrike:(CGPoint)p end:(CGPoint)p2
{
lightningStrike_.strikePoint = ccp(p.x, p.y);
lightningStrike_.strikePoint2 = ccp(p2.x, p2.y);
[lightningStrike_ strikeRandom];
return lightningStrike_;
}
Usage:
[self lightningStrike:ccp(100, 100) end:ccp(100, 100)];
This fixed the FPS drop. After 24 hours I will answer and accept my own answer.
EDIT: I decided not to texture map the line and use ccDrawSmoothLine.
All I did was allocate the lightning in my gamelayer's init
lightningStrike_ = [Lightning lightningWithStrikePoint:ccp(-100, -100) strikePoint2:ccp(-100, -100)];
[self addChild:lightningStrike_ z:1];
Then, I created an instance method to set the _strikePoint and _strikePoint2 properties and call the strikeRandom method.
-(Lightning *)lightningStrike:(CGPoint)p end:(CGPoint)p2
{
    lightningStrike_.strikePoint = ccp(p.x, p.y);
    lightningStrike_.strikePoint2 = ccp(p2.x, p2.y);
    [lightningStrike_ strikeRandom];
    return lightningStrike_;
}
Usage:
[self lightningStrike:ccp(100, 100) end:ccp(100, 100)];
This fixed the FPS drop. After 24 hours I will answer and accept my own answer.

Mesh creation in openGL iphone sdk

I am using this source code as my base and trying to change the code as per my requirements. I have included the following code to create a mesh on image.
-(void)populateMesh{
verticalDivisions = kVerticalDivisions;
horizontalDivisions = kHorisontalDivisions;
unsigned int verticesArrsize = (kVerticalDivisions * ((2 + kHorisontalDivisions * 2) * 3));
unsigned int textureCoordsArraySize = kVerticalDivisions * ((2 + kHorisontalDivisions * 2) * 2);
verticesArr = (GLfloat *)malloc(verticesArrsize * sizeof(GLfloat));
textureCoordsArr = (GLfloat*)malloc(textureCoordsArraySize * sizeof(GLfloat));
if (verticesArr == NULL) {
NSLog(#"verticesArr = NULL!");
}
float height = kWindowHeight/verticalDivisions;
float width = kWindowWidth/horizontalDivisions;
int i,j, count;
count = 0;
for (j=0; j<verticalDivisions; j++) {
for (i=0; i<=horizontalDivisions; i++, count+=6) { //2 vertices each time...
float currX = i * width;
float currY = j * height;
verticesArr[count] = currX;
verticesArr[count+1] = currY + height;
verticesArr[count+2] = 0.0f;
verticesArr[count+3] = currX;
verticesArr[count+4] = currY;
verticesArr[count+5] = 0.0f;
}
}
float xIncrease = 1.0f/horizontalDivisions;
float yIncrease = 1.0f/verticalDivisions;
int x,y;
//int elements;
count = 0;
for (y=0; y<verticalDivisions; y++) {
for (x=0; x<horizontalDivisions+1; x++, count+=4) {
float currX = x *xIncrease;
float currY = y * yIncrease;
textureCoordsArr[count] = (float)currX;
textureCoordsArr[count+1] = (float)currY + yIncrease;
textureCoordsArr[count+2] = (float)currX;
textureCoordsArr[count+3] = (float)currY;
}
}
// int cnt;
// int cnt = 0;
NSLog(#"expected %i vertices, and %i vertices were done",(verticalDivisions * ((2 + horizontalDivisions*2 ) * 2) ) , count );
}
Following is the drawView code.
- (void)drawView:(GLView*)view;
{
static GLfloat rot = 0.0;
glBindTexture(GL_TEXTURE_2D, texture[0]);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, textureCoordsArr);
glVertexPointer(3, GL_FLOAT, 0, verticesArr);
glPushMatrix();{
int i;
for (i=0; i<verticalDivisions; i++) {
glDrawArrays(GL_TRIANGLE_STRIP, i*(horizontalDivisions*2+2), horizontalDivisions*2+2);
}
}glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
In the setup view I have called [self populateMesh]; at the end of the function.
My problem is after changing the code, a blank rather say black view is appeared on the screen. Can anyone figure out where I am doing some mistake. I am newbie for openGL and trying to manipulate images through mesh. Please help asap. Thanks in advance.
Following is the setup view code.
-(void)setupView:(GLView*)view {
const GLfloat zNear = 0.01, zFar = 1000.0, fieldOfView = 45.0;
GLfloat size;
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
CGRect rect = view.bounds;
glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / (rect.size.width / rect.size.height), zNear, zFar);
glViewport(0, 0, rect.size.width, rect.size.height);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_SRC_COLOR);
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:#"texture" 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 context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
CGContextTranslateCTM (context, 0, height);
CGContextScaleCTM (context, 1.0, -1.0);
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
CGContextDrawImage( context, CGRectMake( 0, 0, width, height ),image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(context);
free(imageData);
[image release];
[texData release];
[self populateMesh];
}
EDIT This is what I am getting as an out put. While expected is regular grid...
Guessing the mesh is cut out with zNear value. Try to change z value to -2.
verticesArr[count+2] = -2.0f;
verticesArr[count+5] = -2.0f;
By default, the camera is situated at the origin, points down the negative z-axis, and has an up-vector of (0, 1, 0).
Notice that your mesh is out of view frustum (pyramid). Check it out in OpenGL red book:
http://glprogramming.com/red/chapter03.html
The grid is not regular because of the way how vertices are ordered. Also are you sure that GL_TRIANGLE_STRIP is desired option. Maybe, GL_TRIANGLES is that what you need.
I propose simpler solution with using indices array. For example in initialization code make vertices and texture array for your grid in normal order as:
0 1 2
3 4 5
6 7 8
Update:
- (void) setup
{
vertices = (GLfloat*)malloc(rows*colums*3*sizeof(GLfloat));
texCoords = (GLfloat*)malloc(rows*columns*2*sizeof(GLfloat));
indices = (GLubyte*)malloc((rows-1)*(columns-1)*6*sizeof(GLubyte));
float xDelta = horizontalDivisions/columns;
float yDelta = verticalDivisions/rows;
for (int i=0;i<columns;i++) {
for(int j=0;j<rows; j++) {
int index = j*columns+i;
vertices[3*index+0] = i*xDelta; //x
vertices[3*index+1] = j*yDelta; //y
vertices[3*index+2] = -10; //z
texCoords[2*index+0] = i/(float)(columns-1); //x texture coordinate
texCoords[2*index+1] = j/(float)(rows-1); //y tex coordinate
}
}
for (int i=0;i<columns-1;i++) {
for(int j=0;j<rows-1; j++) {
indices[6*(j*columns+i)+0] = j*columns+i;
indices[6*(j*columns+i)+1] = j*columns+i+1;
indices[6*(j*columns+i)+2] = (j+1)*columns+i;
indices[6*(j*columns+i)+3] = j*columns+i+1;
indices[6*(j*columns+i)+4] = (j+1)*columns+i+1;
indices[6*(j*columns+i)+5] = (j+1)*columns+i;
}
}
}
- (void) dealloc {
free(vertices); free(texCoords); free(indices);
}
Practically this indices order means that tringles are rendered as following:
(013)(143)(124)(254)(346)(476)... and so on.
In render method use the following lines:
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawElements(GL_TRIANGLES, 6*(columns-1)*(rows-1), GL_UNSIGNED_BYTE, indices);
Hope that will help.
This is a great tutorial on drawing a grid in 3D. It should have the code necessary to help you. I'm not sure if you are working in 3D or 2D, but even if it is 2D, it should be fairly easy to adapt to your needs. Hope that helps!

Draw Square with OpenGL ES for iOS

I am trying to draw a rectangle using the GLPaint example project provided by apple. I have tried modifying the vertices but cannot get a rectangle to appear on the screen. The finger painting works perfectly. Am I missing something in my renderRect method?
- (void)renderRect {
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
// Replace the implementation of this method to do your own custom drawing.
static const GLfloat squareVertices[] = {
-0.5f, -0.33f,
0.5f, -0.33f,
-0.5f, 0.33f,
0.5f, 0.33f,
};
static float transY = 0.0f;
glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f);
// Render the vertex array
glVertexPointer(2, GL_FLOAT, 0, squareVertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Display the buffer
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
The rest of the project is set up stock to allow drawing on the screen but just for reference these are the gl settings that are set.
// Set the view's scale factor
self.contentScaleFactor = 1.0;
// Setup OpenGL states
glMatrixMode(GL_PROJECTION);
CGRect frame = self.bounds;
CGFloat scale = self.contentScaleFactor;
// Setup the view port in Pixels
glOrthof(0, frame.size.width * scale, 0, frame.size.height * scale, -1, 1);
glViewport(0, 0, frame.size.width * scale, frame.size.height * scale);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DITHER);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_BLEND);
// Set a blending function appropriate for premultiplied alpha pixel data
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_POINT_SPRITE_OES);
glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
glPointSize(width / brushScale);
static const GLfloat squareVertices[] = {
30.0f, 300.0f,//-0.5f, -0.33f,
280.0f, 300.0f,//0.5f, -0.33f,
30.0f, 170.0f,//-0.5f, 0.33f,
280.0f, 170.0f,//0.5f, 0.33f,
};
That's definitely too much. OpenGL has normalized screen coords in range [-1..1]. So you have to convert device coords to normalized ones.
Issues are:
(1) the following code:
glMatrixMode(GL_PROJECTION);
CGRect frame = self.bounds;
CGFloat scale = self.contentScaleFactor;
// Setup the view port in Pixels
glOrthof(0, frame.size.width * scale, 0, frame.size.height * scale, -1, 1);
glViewport(0, 0, frame.size.width * scale, frame.size.height * scale);
Establishes that the on-screen coordinates range from (0, 0) in the lower left to frame.size in the upper right. In other words, one OpenGL unit is one iPhone point. So your array of:
static const GLfloat squareVertices[] = {
-0.5f, -0.33f,
0.5f, -0.33f,
-0.5f, 0.33f,
0.5f, 0.33f,
};
Is less than 1 pixel in size.
(2) you have the following in the setup:
brushImage = [UIImage imageNamed:#"Particle.png"].CGImage;
/* ...brushImage eventually becomes the current texture... */
glEnable(GL_TEXTURE_2D);
You subsequently fail to supply texture coordinates for your quad. Probably you want to disable GL_TEXTURE_2D.
So the following:
static const GLfloat squareVertices[] = {
0.0f, 0.0f,
0.0, 10.0f,
90.0, 0.0f,
90.0f, 10.0f,
};
glDisable(GL_TEXTURE_2D);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// Render the vertex array
glVertexPointer(2, GL_FLOAT, 0, squareVertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
Will produce a white quad 90 points wide and 10 points tlal in the lower left of the screen.

glFrustumf displays only clear color, glOrthof displays as expected (OpenGL ES)

I'm new to OpenGL, so I'm sure this is a dummy mistake, but I've read every post, and reviewed sample code, and I can't find a difference, explaining why glFrustum wont display as I'd like it to.
I initialize OpenGL like:
- (void) initOpenGL{
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
//glLoadIdentity();
//glOrthof(0.0f, self.bounds.size.width, self.bounds.size.height, 0.0f, -10.0f, 10.0f);
const GLfloat zNear = -0.1, zFar = 1000.0, fieldOfView = 60.0;
GLfloat size;
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
// This give us the size of the iPhone display
CGRect rect = self.bounds;
glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / (rect.size.width / rect.size.height), zNear, zFar);
glViewport(0, 0, rect.size.width, rect.size.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
#if 0
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
#endif
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
#if TARGET_IPHONE_SIMULATOR
glColor4f(0.0, 0.0, 0.0, 0.0f);
#else
glColor4f(0.0, 0.0, 0.0, 0.0f);
#endif
[[Texture2D alloc] initWithImage:[UIImage imageNamed:#"GreenLineTex.png"] filter:GL_LINEAR];
glInitialised = YES;
And my drawing is done like:
- (void)drawView {
if(!glInitialised) {
[self initOpenGL];
}
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
static const GLfloat texCoords[] = {
0.0, 0.0,
1.0, 0.0,
0.0, 1.0,
1.0, 1.0
};
// draw the edges
glEnableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glBindTexture(GL_TEXTURE_2D, 1);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
for (int i = 0; i < connectionNumber; i++){
Vertex2DSet(&vertices[0], connectionLines[i].lineVertexBeginPoint.x, connectionLines[i].lineVertexBeginPoint.y);
Vertex2DSet(&vertices[1], connectionLines[i].lineVertexBeginPoint.x+connectionLines[i].normalVector.x, connectionLines[i].lineVertexBeginPoint.y+connectionLines[i].normalVector.y);
Vertex2DSet(&vertices[2], connectionLines[i].lineVertexEndPoint.x, connectionLines[i].lineVertexEndPoint.y);
Vertex2DSet(&vertices[3], connectionLines[i].lineVertexEndPoint.x+connectionLines[i].normalVector.x, connectionLines[i].lineVertexEndPoint.y+connectionLines[i].normalVector.y);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
Where the block in the for loop is a set of vertices that make up some triangle strips.
If I uncomment the glOrthof() line, then I can see my display, however it's orthographic, and I'd like to move the camera in and out, to change the scaling of the whole scene.
What have I done incorrectly that causes glFrustumf() to display only the clear color?
Short answer: you are looking in the wrong direction.
Long answer:
Your frustum is symmetric while your orthographic matrix isn't. So if your model is set up to be visible in the glOrtho case, it may not be visible with your glFrustum.
Also you shouldn't use glOrtho AND glFrustum together, because the matrices are multiplied and will surely yield a funny projection matrix.
You can use Nate Robins' GL tutors at http://www.xmission.com/~nate/tutors.html to experiment with glFrustum and glOrtho (in the "projection" application).

How do I implement AABB ray cast hit checking on the iPhone

Basically, I draw a 3D cube, I can spin it around but I want to be able to touch it and know where on my cube's surface the user touched.
I'm using for setting up, generating and spinning. Its based on the Molecules code and NeHe tutorial #5.
Any help, links, tutorials and code would be greatly appreciated. I have lots of development experience but nothing much in the way of openGL and 3d.
//
// GLViewController.h
// NeHe Lesson 05
//
// Created by Jeff LaMarche on 12/12/08.
// Copyright Jeff LaMarche Consulting 2008. All rights reserved.
//
#import "GLViewController.h"
#import "GLView.h"
#implementation GLViewController
- (void)drawBox
{
static const GLfloat cubeVertices[] = {
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f,-1.0f, 1.0f,
-1.0f,-1.0f, 1.0f,
-1.0f, 1.0f,-1.0f,
1.0f, 1.0f,-1.0f,
1.0f,-1.0f,-1.0f,
-1.0f,-1.0f,-1.0f
};
static const GLubyte cubeNumberOfIndices = 36;
const GLubyte cubeVertexFaces[] = {
0, 1, 5, // Half of top face
0, 5, 4, // Other half of top face
4, 6, 5, // Half of front face
4, 6, 7, // Other half of front face
0, 1, 2, // Half of back face
0, 3, 2, // Other half of back face
1, 2, 5, // Half of right face
2, 5, 6, // Other half of right face
0, 3, 4, // Half of left face
7, 4, 3, // Other half of left face
3, 6, 2, // Half of bottom face
6, 7, 3, // Other half of bottom face
};
const GLubyte cubeFaceColors[] = {
0, 255, 0, 255,
255, 125, 0, 255,
255, 0, 0, 255,
255, 255, 0, 255,
0, 0, 255, 255,
255, 0, 255, 255
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
int colorIndex = 0;
for(int i = 0; i < cubeNumberOfIndices; i += 3)
{
glColor4ub(cubeFaceColors[colorIndex], cubeFaceColors[colorIndex+1], cubeFaceColors[colorIndex+2], cubeFaceColors[colorIndex+3]);
int face = (i / 3.0);
if (face%2 != 0.0)
colorIndex+=4;
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &cubeVertexFaces[i]);
}
glDisableClientState(GL_VERTEX_ARRAY);
}
//move this to a data model later!
- (GLfixed)floatToFixed:(GLfloat)aValue;
{
return (GLfixed) (aValue * 65536.0f);
}
- (void)drawViewByRotatingAroundX:(float)xRotation rotatingAroundY:(float)yRotation scaling:(float)scaleFactor translationInX:(float)xTranslation translationInY:(float)yTranslation view:(GLView*)view;
{
glMatrixMode(GL_MODELVIEW);
GLfixed currentModelViewMatrix[16] = { 45146, 47441, 2485, 0,
-25149, 26775,-54274, 0,
-40303, 36435, 36650, 0,
0, 0, 0, 65536 };
/*
GLfixed currentModelViewMatrix[16] = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 65536 };
*/
//glLoadIdentity();
//glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -10.0f, 4.0f);
// Reset rotation system
if (isFirstDrawing)
{
//glLoadIdentity();
glMultMatrixx(currentModelViewMatrix);
[self configureLighting];
isFirstDrawing = NO;
}
// Scale the view to fit current multitouch scaling
GLfixed fixedPointScaleFactor = [self floatToFixed:scaleFactor];
glScalex(fixedPointScaleFactor, fixedPointScaleFactor, fixedPointScaleFactor);
// Perform incremental rotation based on current angles in X and Y
glGetFixedv(GL_MODELVIEW_MATRIX, currentModelViewMatrix);
GLfloat totalRotation = sqrt(xRotation*xRotation + yRotation*yRotation);
glRotatex([self floatToFixed:totalRotation],
(GLfixed)((xRotation/totalRotation) * (GLfloat)currentModelViewMatrix[1] + (yRotation/totalRotation) * (GLfloat)currentModelViewMatrix[0]),
(GLfixed)((xRotation/totalRotation) * (GLfloat)currentModelViewMatrix[5] + (yRotation/totalRotation) * (GLfloat)currentModelViewMatrix[4]),
(GLfixed)((xRotation/totalRotation) * (GLfloat)currentModelViewMatrix[9] + (yRotation/totalRotation) * (GLfloat)currentModelViewMatrix[8])
);
// Translate the model by the accumulated amount
glGetFixedv(GL_MODELVIEW_MATRIX, currentModelViewMatrix);
float currentScaleFactor = sqrt(pow((GLfloat)currentModelViewMatrix[0] / 65536.0f, 2.0f) + pow((GLfloat)currentModelViewMatrix[1] / 65536.0f, 2.0f) + pow((GLfloat)currentModelViewMatrix[2] / 65536.0f, 2.0f));
xTranslation = xTranslation / (currentScaleFactor * currentScaleFactor);
yTranslation = yTranslation / (currentScaleFactor * currentScaleFactor);
// Grab the current model matrix, and use the (0,4,8) components to figure the eye's X axis in the model coordinate system, translate along that
glTranslatef(xTranslation * (GLfloat)currentModelViewMatrix[0] / 65536.0f, xTranslation * (GLfloat)currentModelViewMatrix[4] / 65536.0f, xTranslation * (GLfloat)currentModelViewMatrix[8] / 65536.0f);
// Grab the current model matrix, and use the (1,5,9) components to figure the eye's Y axis in the model coordinate system, translate along that
glTranslatef(yTranslation * (GLfloat)currentModelViewMatrix[1] / 65536.0f, yTranslation * (GLfloat)currentModelViewMatrix[5] / 65536.0f, yTranslation * (GLfloat)currentModelViewMatrix[9] / 65536.0f);
// Black background, with depth buffer enabled
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[self drawBox];
}
- (void)configureLighting;
{
const GLfixed lightAmbient[] = {13107, 13107, 13107, 65535};
const GLfixed lightDiffuse[] = {65535, 65535, 65535, 65535};
const GLfixed matAmbient[] = {65535, 65535, 65535, 65535};
const GLfixed matDiffuse[] = {65535, 65535, 65535, 65535};
const GLfixed lightPosition[] = {30535, -30535, 0, 0};
const GLfixed lightShininess = 20;
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glMaterialxv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmbient);
glMaterialxv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiffuse);
glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, lightShininess);
glLightxv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
glLightxv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
glLightxv(GL_LIGHT0, GL_POSITION, lightPosition);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_NORMALIZE);
}
-(void)setupView:(GLView*)view
{
const GLfloat zNear = 0.1,
zFar = 1000.0,
fieldOfView = 60.0;
GLfloat size;
glMatrixMode(GL_PROJECTION);
glEnable(GL_DEPTH_TEST);
size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0);
CGRect rect = view.bounds;
glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size /
(rect.size.width / rect.size.height), zNear, zFar);
glViewport(0, 0, rect.size.width, rect.size.height);
glScissor(0, 0, rect.size.width, rect.size.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glTranslatef(0.0f, 0.0f, -6.0f);
isFirstDrawing = YES;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)dealloc
{
[super dealloc];
}
#end
In order to implement Ray cast hit checking, you should check these sources:
http://www.mvps.org/directx/articles/rayproj.htm
http://bookofhook.com/mousepick.pdf
http://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html
Basically, first, create a 3D ray from a 2D touch. Then use that ray to check for intersection with objects in your world. You should create the matrix inverse of your current matrix, and from the inverse matrix you can create start and end position using your near and far clip plane. and then when calculating the near and far points you should apply the projection settings.
BTW: In my project, my point recognition is based on color unique pixel comparison rather than ray cast hit check. It is much easier to implement hit check with just finding unique colors. Only a suggestion, hope it helps :)
cheers,
Guvener