Why my iPhone OpenGL-ES texture does not cover the viewport? - iphone

I have a square image of size 320x320, from which I create an OpenGL texture. I use the most basic Vertext and Fragment shaders and I want to display the texture in the entire view. The view (EAGLView derived from UIView as found in many OpenGL iOS samples) is also of size 320x320.
The problem is, the image is drawn on the top left corner, covering only around 50% of the entire view. It does not cover 100% of the view. I don't know why?
Here is my code:
position = glGetAttribLocation(m_shaderProgram, "position");
inputTextureCoordinate = glGetAttribLocation(m_shaderProgram, "inputTextureCoordinate");
inputImageTexture = glGetUniformLocation(m_shaderProgram, "inputImageTexture");
static const GLfloat textureCoordinates[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
static const GLfloat imageVertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
[EAGLContext setCurrentContext:context];
glViewport(0, 0, backingWidth, backingHeight); // These are 320, 320
glUseProgram(m_shaderProgram);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, sourceTextureID); // The texture is also of size 320x320
glUniform1i(inputImageTexture, 2);
glVertexAttribPointer(position, 2, GL_FLOAT, 0, 0, imageVertices);
glVertexAttribPointer(textureCoordinate, 2, GL_FLOAT, 0, 0, textureCoordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
Vertext Shader.
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
}
Fragment Shader.
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
void main()
{
gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
}

So the problem is that the texture's dimensions were not 2's power. So we need to scale the textureCoordinates accordingly. Inserting following lines solved the problem...
GLfloat textureCoordinates[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
float nearest2sPower = 2;
if (nearest2sPower < backingWidth) {
while (nearest2sPower < backingWidth) {
nearest2sPower *= 2;
}
}
verticalFlipTextureCoordinates[2] = backingWidth/nearest2sPower;
verticalFlipTextureCoordinates[6] = backingWidth/nearest2sPower;
nearest2sPower = 2;
if (nearest2sPower < backingWidth) {
while (nearest2sPower < backingWidth) {
nearest2sPower *= 2;
}
}
verticalFlipTextureCoordinates[1] = backingHeight/nearest2sPower;
verticalFlipTextureCoordinates[3] = backingHeight/nearest2sPower;

Related

Shaders iOS, OSX

I have problem with OpenGL's shaders.
#ifdef GL_ES
precision lowp float;
#endif
varying vec4 v_fragmentColor;
void main()
{
gl_FragColor = v_fragmentColor;
}
and the second one
attribute vec4 a_position;
attribute vec4 a_color;
uniform mat4 u_MVPMatrix;
#ifdef GL_ES
varying lowp vec4 v_fragmentColor;
#else
varying vec4 v_fragmentColor;
#endif
void main()
{
gl_Position = u_MVPMatrix * a_position;
v_fragmentColor = a_color;
}
Firs I make 2d projection
- (void)makeProjection2D
{
float scaleFactor = 1.0;
CGSize size = self.bounds.size;
glViewport(0, 0, size.width, size.height);
kmGLMatrixMode(KM_GL_PROJECTION);
kmGLLoadIdentity();
kmMat4 orthoMatrix;
kmMat4OrthographicProjection(&orthoMatrix, 0, size.width / scaleFactor, 0, size.height / scaleFactor, -size.width, size.width);
kmGLMultMatrix( &orthoMatrix );
kmGLMatrixMode(KM_GL_MODELVIEW);
kmGLLoadIdentity();
}
Next step is shaders creation.
Folowed by OpenGL initialization.
GLint dim[2] = {1025, 769};
CGLSetParameter([[self openGLContext] CGLContextObj], kCGLCPSurfaceBackingSize, dim);
CGLEnable([[self openGLContext] CGLContextObj], kCGLCESurfaceBackingSize);
// Setup OpenGL states
glMatrixMode(GL_PROJECTION);
CGRect frame = self.bounds;
glGetError();
// Setup the view port in Pixels
glOrtho(0, frame.size.width, 0, frame.size.height, -1, 1);
glViewport(0, 0, frame.size.width, frame.size.height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnableClientState(GL_VERTEX_ARRAY);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
self.pointSize = pointSizeForDrawing;
GLint zeroOpacity = 0;
[[self openGLContext] setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity];
If I try to draw domething on the screen like four big pixels
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, framebuffer);
glClearColor(1.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPointSize(100.0);
glColor3b(1.0, 1.0, 1.0);
GLfloat i[8] = {44.0, 44.0, 100.0, 100.0, 300.0, 300.0, 500.0, 500.0};
glVertexPointer(2, GL_FLOAT, 0, i);
glDrawArrays(GL_POINTS, 0, 4);
glBindFramebufferEXT( GL_READ_FRAMEBUFFER_EXT, framebuffer );
glBindFramebufferEXT( GL_DRAW_FRAMEBUFFER_EXT, 0 );
glViewport(0, 0, self.bounds.size.width, self.bounds.size.height);
glBlitFramebufferEXT( 0, 0, self.bounds.size.width, self.bounds.size.height, 0, 0, self.bounds.size.width, self.bounds.size.height, GL_COLOR_BUFFER_BIT, GL_NEAREST );
glSwapAPPLE();
Only one is visible, if I remove making 2d projection and shaders then all 4 are visible.
The code, which uses the shaders works on iOS, but not on OSX, any idea why? To initialize shaders I use CCGLProgram from cocos2d If you need more info, please let me know.

Drawing to the alpha channel of the frame buffer on with OpenGL while ignoring RGB values?

The opaque property is set to NO on my OpenGL view's CAEAGLLayer. There is a UIImageView behind the OpenGL view (the checkboard). A texture is drawn initially on the OpenGL view (the Emu bird photo). Now I want to draw another texture in the middle of the fame buffer. The new texture is completely black in color and the alpha changes from 0 to 255, from top to bottom.
This is my 2nd texture...
This is what I want...
This is what I get...
The checkboard texture is an UIImage in a UIImageView behind the EAGLView.
I do not want to disturb the RGB values in the frame buffer, I only want to write into the Alpha channel. I tried...
glDisable(GL_BLEND) and glColorMask(0, 0, 0, 1)
glEnable(GL_BLEND) and glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ZERO)
Nothing seems to work. The RGB values are always modified, the pixels become brighter.
If source RGBA is (r2, g2, b2, a2) and destination is (r1, g1, b1, a1). I want the final value to be (r1, g1, b1, a2) or preferably (r1, g1, b1, some_function_of(a1, a2)). How do I achieve this?
Here is my code...
Objective C code for drawing the second texture...
- (void) drawTexture {
GLfloat textureCoordinates[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
static const GLfloat imageVertices[] = {
-0.5f, -0.5f,
0.5f, -0.5f,
-0.5f, 0.5f,
0.5f, 0.5f,
};
[EAGLContext setCurrentContext:context];
glViewport(0, 0, backingWidth, backingHeight);
glUseProgram(program);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, texture);
glEnable (GL_BLEND);
glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ZERO);
glUniform1i(inputImageTexture, 2);
glVertexAttribPointer(position, 2, GL_FLOAT, 0, 0, imageVertices);
glVertexAttribPointer(inputTextureCoordinate, 2, GL_FLOAT, 0, 0, textureCoordinates);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindRenderbuffer(GL_RENDERBUFFER, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];
}
Vertex shader...
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
}
Fragment shader...
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
void main()
{
gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
}
glColorMask must work - it worked for me in my case. Also, as far as I know glBlendFuncSeparate works buggy on iOS.
(In theory) you can do the following:
set blending to multiply mode (GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA)
make your texture white
set glColorMask to all channels enabled
If you have iDevice with iOS 5+ you can look at framebuffer alpha in OpenGL Capture window in XCode.

Applying Translations to Entire OpenGL ES Scene - iPhone

I have an OpenGL ES scene which is made up of about 20 objects. In the render method for each object I have code which scales, rotates and positions (using glmultmatrix) that object in the correct place in each scene (see code below).
My question is how can I then apply a transformation to the entire scene as a whole ? E.g scale / enlarge the entire scene by 2 ?
glPushMatrix();
glLoadIdentity();
//Move some objects.
if (hasAnimations) {
glTranslatef(kBuildingOffset);
//scale
glScalef(kModelScale);
//glMultMatrixf(testAnimation);
zRotation = kBuildingzRotation
xRotation = kBuildingxRotation
yRotation = kBuildingyRotation
glRotatef(yRotation, 0.0f, 1.0, 0.0f);
glRotatef(xRotation, 1.0f, 0.0f, 0.0f);
glRotatef(zRotation, 0.0f, 0.0f, 1.0f);
//NSLog(#"ANIMATION FRAME IS %d", animationFrame);
//NSLog(#"MATRICE IS %f", animationArray[0][0]);
glMultMatrixf(animationArray[animationFrame]);
//glMultMatrixf(matricesArray);
glMultMatrixf(matricePivotArray);
//glMultMatrixf(testAnimation);
}
//First rotate our objects as required.
if ([objectName isEqualToString:#"movingobject1"]) {
glTranslatef(kFan1Position);
glScalef(kModelScale);
glMultMatrixf(matricesArray);
glTranslatef(0, 0, 0);
zRotation +=kFanRotateSpeed;
yRotation =kyFanFlip;
xRotation = kxFanRotation;
glRotatef(zRotation, 0.0f, 0.0f, 1.0f);
glRotatef(yRotation, 0.0f, 1.0f, 0.0f);
glRotatef(xRotation, 1.0f, 0.0, 0.0f);
glTranslatef(0.0, 0.0, -300);
}
if ([objectName isEqualToString:#"movingobject2"]) {
glTranslatef(kFan2Position);
glScalef(kModelScale);
glMultMatrixf(matricesArray);
glTranslatef(0, 0, 0);
zRotation +=kFanRotateSpeed;
yRotation = kyFanFlip;
xRotation = kxFanRotation;
glRotatef(-kFan3YOffset, 0.0, 1.0, 0.0);
glRotatef(zRotation, 0.0f, 0.0f, 1.0f);
glRotatef(yRotation, 0.0f, 1.0f, 0.0f);
glRotatef(xRotation, 1.0f, 0.0, 0.0f);
glRotatef(kFan3YOffset, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0, 0.0, -300);
}
if ([objectName isEqualToString:#"movingobject3"]) {
glTranslatef(kFan3Position);
glScalef(kModelScale);
glMultMatrixf(matricesArray);
glTranslatef(0, 0, 0);
zRotation +=kFanRotateSpeed;
yRotation =kyFanFlip;
xRotation =kxFanRotation;
glRotatef(-kFan2YOffSet, 0.0, 1.0, 0.0);
glRotatef(zRotation, 0.0f, 0.0f, 1.0f);
glRotatef(yRotation, 0.0f, 1.0f, 0.0f);
glRotatef(xRotation, 1.0f, 0.0f, 0.0f);
glRotatef(kFan2YOffSet, 0.0, 1.0, 0.0);
glTranslatef(0.0, 0.0, -300);
}
//Then position the rest of the scene objects.
if (![objectName isEqualToString:#"movingobject1"])
if (![objectName isEqualToString:#"movingobject2"])
if(![objectName isEqualToString:#"movingobject3"])
if (!hasAnimations) {
glLoadIdentity();
glTranslatef(kBuildingOffset);
//scale
glScalef(kModelScale);
zRotation = kBuildingzRotation
xRotation = kBuildingxRotation
yRotation = kBuildingyRotation
glRotatef(yRotation, 0.0f, 1.0, 0.0f);
glRotatef(xRotation, 1.0f, 0.0f, 0.0f);
glRotatef(zRotation, 0.0f, 0.0f, 1.0f);
if ([Matrices count]!=0) {
glMultMatrixf(matricesArray);
}
if (hasPivotNode) {
glMultMatrixf(matricePivotArray);
}
}
[mesh render];
glPopMatrix();
//restore the matrix
You should be able to achieve this easily enough by pushing the transform matrix you desire on to the matrix stack before you do any of your object-specifc transforms, but then don't load the identity matrix each time you push another matrix onto the stack. Practically speaking, this will transform all subsequent matrix operations. This is the basic pattern...
// Push an identity matrix on the bottom of the stack...
glPushMatrix();
glLoadIdentity();
// Now scale it, so all subsequent transforms will be
// scaled up 2x.
glScalef(2.f, 2.f, 2.f);
foreach(mesh) {
glPushMatrix();
//glLoadIdentity(); This will erase the scale set above.
glDoABunchOfTransforms();
[mesh render];
glPopMatrix();
}

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).