Stretched Drawing in OpenGL ES - iOS - iphone

I'm trying to draw a simple circle using OpenGL ES. The problem is that the circle is stretched vertically. It looks more like an ellipse than a circle. Could someone point out where the things are going wrong?
I played around with glViewPort to fix this but was not successful. As someone else suggested here on Stackoverflow, I also tried loading a different matrix instead of the identity matrix and that doesn't work too...
Here's the code of drawFrame:
- (void)drawFrame
{
[(EAGLView *)self.view setFramebuffer];
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
GLfloat vertices[720];
for (int i = 0; i < 720; i += 2)
{
vertices[i] = (cos(degreesToRadians(i)) * 1);
vertices[i+1] = (sin(degreesToRadians(i)) * 1);
}
glVertexPointer(2, GL_FLOAT, 0, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLE_FAN, 0, 360);
[(EAGLView *)self.view presentFramebuffer];
}

The code you are showing will draw a perfect circle in world co-ordinates. What you need to consider is how those world co-ordinates transform into window co-ordinates i.e. pixels.
If the glViewport is set to always match the window then it's the aspect ratio of the window that will determine what you see using the code sample you have shown. If the window is square it will work i.e. you will see a perfect circle. If the window is taller than it is wide then the circle will be stretched vertically.
To preserve the perfect circle you can use a projection matrix that gives you a viewing volume of the same aspect ratio as the viewport/window. I noticed that before your first edit you had a call to glOrthof in there. Set the aspect ratio to match there and that will do the job for you. If you want a perspective projection instead of an orthographic projection then use glFrustum.

Related

GL_POINT not rendering when center is off screen

I'm making an iPhone game that involves the use of GL_POINT to render a point. However, when the center of the point is off screen, I still want to draw whatever portion of the point that is still onscreen. Here is my code that I'm using to render the point.
-(void)render {
if (!fill || !outline || !active || dead)
return;
NSLog(#"rendering");
glPushMatrix();
glLoadIdentity();
glMultMatrixf(matrix);
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glPointSize(scale.x*2);
[outline render];
glPointSize(2*(scale.x-kLineWidth));
[fill render];
glPopMatrix();
}
note that it logs "rendering" when it should be rendering, so this method is getting called properly.
and the [outline render] and [fill render] methods look like this
-(void)render {
// load arrays into the engine
glVertexPointer(vertexSize, GL_FLOAT, 0, vertexes);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(colorSize, GL_FLOAT, 0, colors);
glEnableClientState(GL_COLOR_ARRAY);
//render
glDrawArrays(renderStyle, 0, vertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
}
and I'm using a "panning" effect using this code
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-kScreenWidth/2.0 + xPan, kScreenWidth/2.0 + xPan, -kScreenHeight/2.0 + yPan, kScreenHeight/2.0 + yPan, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
but when the point's center is not on the screen (after panning with glOrthof), the whole point is not drawn. How can I have the point still render even when the center is not on the screen?
I don't believe there is anything you can do for an easy fix. Primitives are clipped before rasterization, so if that point lies outside the view frustum, it's not going to be rasterized, even if the rasterization would create fragments that do lie inside the view frustum.
Either switch to real quads with GL_TRIANGLES/GL_QUADS, or if you really don't want to do that, you can render your points to an offscreen buffer with size slightly larger than the viewport, and then blit the center of that image back onto the main frame.

Setting Up ViewPort for Larger Vertice Values ? iPhone - OpenGL ES

I am working with some larger vertice values which I have parsed from a DAE file. E.g :
{-79.6536, -2230.43, -213.8},{-79.6536, 2377.36, -213.8},{79.6536, 2377.36, -213.8},{79.6536, -2230.43, -213.8},{-79.6536, -2230.43, 958.953},{79.6536, -2230.43, 958.953},{79.6536, 2377.36, 958.953},{-79.6536, 2377.36, 958.953},...
My question is what changes do I need to make to the setting up of my viewport in order to accomodate these larger vertices ? I currently have the following :
- (void)setupView
{
// Set up the window that we will view the scene through
glViewport(0, 0, backingWidth, backingHeight);
// switch to the projection matrix and setup our 'camera lens'
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
// switch to model mode and set our background color
glMatrixMode(GL_MODELVIEW);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
}
However when I run the code, I just get a screen filled with white - I presume because my object is zoomed in to an extreme degree.
Thanks for any advice in advance.
Use glScalef(max_s, max_s, max_s);
Where
max_s = 2.0 / max(max(Xi) - min(Xi), max(Yi) - min(Yi), max(Zi) - min(Zi))

UIView drawRect drawing lines of wrong width

I'm trying to add a little red line on the bottom of my UIView.
I want the line to be a 1px line.
Can someone tell me why the following code:
- (void)drawRect:(CGRect)rect {
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSaveGState(currentContext);
CGContextSetRGBFillColor(currentContext, 0.0f, 0.0f, 0.0f, 1.0f);
CGContextFillRect(currentContext, RECT(0, 0, rect.size.width, rect.size.height - 8));
CGContextSetLineWidth(currentContext, 1);
CGContextSetRGBStrokeColor(currentContext, 1.0f, 0.0f, 0.0f, 1.0f);
CGContextBeginPath(currentContext);
CGContextMoveToPoint(currentContext, 0, rect.size.height - 7);
CGContextAddLineToPoint(currentContext, rect.size.width, rect.size.height - 7);
CGContextStrokePath(currentContext);
CGContextRestoreGState(currentContext);
}
Draws a line that spans 2px in height?
The integral coordinates indicate places half-way between pixels; that is, (0,0) is in the upper-left corner, above and to the left of the upper-left pixel; similarly, (1,0) is between the first and second pixels; finally, (0.5,0.5) is at the center of the upper-left pixel.
According to the documentation for CGContextSetLineWidth, "when stroked, the line straddles the path, with half of the total width on either side." Thus, if the path is lying precisely in between the pixels, the line will be stroked half on one row of pixels, half on the other.
Hence, to get a sharp pixel line, you must offset your coordinates by half a pixel: for your x coordinate, use rect.size.height - 7.5 instead of - 7.
By the way, when drawing rectangles, it is handy to use CGRectInset(rect, 0.5, 0.5) to achieve this.
Do you use an iPhone 4? The iPhone 4 uses a coordinate system with a scale factor of 2. So you would need to set the line width to 0.5 in order to get what you want.
(The coordinate system is set up that way so the same code produces the same output on all models.)
Lines are by default drawn antialiased (unless you configure otherwise). Thus any line that's not strictly vertical or horizontal and starting and ending on a pixel will likely partially cover multiple pixels in some rows and/or columns, making it look like a wider grey line instead of a thin higher-contrast line.

Animating a texture across a surface in OpenGL

I'm working with the iPhone OpenGLES implementation and I wish to endlessly scroll a texture across a simple surface (two triangles making up a rectangle). This should be straightforward, but it's not something I've done before and I must be missing something. I can rotate the texture fine, but translate does not work at all. Do I have a minor implementation issue or am I doing something fundamentally wrong?
// move texture
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
// increment offset - no reset for demo purposes
wallOffset += 1.0;
// move the texture - this does not work
glTranslatef(wallOffset,wallOffset,0.0);
// rotate the texture - this does work
//glRotatef(wallOffset, 1.0, 0.0, 0.0);
glMatrixMode(GL_MODELVIEW);
glBindTexture(GL_TEXTURE_2D, WallTexture.name);
glTexCoordPointer(2, GL_FLOAT, 0, coordinates);
// simple drawing code
glNormalPointer(GL_FLOAT, 0, normals);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// push matrix back
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
You're incrementing your texture offset by 1.0f; but textures coordinates are considered in the range [0, 1], so you're not actually changing the texture coordinates (assuming you've enabled some sort of wrapping).
Try changing that increment (try .01f, or maybe something depending on the framerate) and see if it works. If not, then it may have something to do with the texture parameters you've got enabled.

How to handle a translation Matrix in an inverted Y axis point of view

My usercase is an iphone application where I do an animation on the scale, rotation and translation of an image.
So, I concat everything and feed it to the transform property, but there is one problem:
Since my images vary in size, it is a problem to position them correctly. I'm used to an inverted y axis coordinate system, so I want my image to positioned exactly at 60 pixels in the y axis.
So, how do I change from the original cartesian y axis to an inverted y axis point of view?
As smacl points out, the easiest way to do this is to shift your origin to the bottom-left of the screen by using (screenheight - viewheight - y) instead of y in the origins of your views.
However, you can flip the coordinate system of your main view's layers using a CATransform3D. I do this so that I can share the same Core Animation CALayer layout code between my iPhone application and a Mac client (the iPhone inverts the normal Quartz coordinate system for CALayers to match that of the UIViews). All you need to do to enable this is to place the line
self.layer.sublayerTransform = CATransform3DMakeScale(1.0f, -1.0f, 1.0f);
in your initialization code for your layer-hosting UIView. Remember that this will flip your CALayers, so any UIKit text rendering in those layers may also need to be flipped using code similar to the following:
CGContextSaveGState(context);
CGContextTranslateCTM(context, 0.0f, self.frame.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);
UIFont *theFont = [UIFont fontWithName:#"Helvetica" size:fontSize];
[text drawAtPoint:CGPointZero withFont:theFont];
CGContextRestoreGState(context);
You can do a similar sort of inversion using a CGAffineTransform, but you will also need to apply a translation to make that work:
CGAffineTransform flipTransform = CGAffineTransformMakeTranslation(0.0f, self.frame.size.height);
flipTransform = CGAffineTransformScale(flipTransform, 1.0f, -1.0f);
You may be able to use the affine transform to convert your origin coordinates using CGPointApplyAffineTransform().
For every y ordinate, y = top-y, where top is the y ordinate of the top of the bounding box you are drawing in.