Making opaque layer in OpenGL ES 2.0 on iOS. - ios

I'm working on a simple 3D application with OpenGL ES 2 on iOS.
I just followed steps in "OpenGL ES Programming Guide for iOS" in Apple Developer Site.
I wanted make the OpenGL View entirely opaque for better performance as suggested in the document. So, I did as below.
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = TRUE;
And, I ran the application with the Core Animation instrument. Then, I turned on 'Color Blended Layers' in Debug Options in Core Animation instrument.
Then, the entire screen became reddish which means the entire view was being blended. I tested another example OpenGL apps from Apple, but they were all greenish with the instrument.
The document dosen't say anything about this except making the layer opaque just like I did.
What else could there be possible cause for this problem?

Be sure to set the alpha component to 1.0 when you call glClearColor(0.0, 0.0, 0.0, 1.0).

Related

GLKit Multi-sampling with OpenGL ES 3.0

I am in the process of migrating a small iPad application from OpenGL ES 2.0 to OpenGL ES 3.0. In the App, I use a subclass of GLKView to handle all my drawing, though the only GLKit features I use are:
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; // Or 2
self.drawableDepthFormat = GLKViewDrawableDepthFormatNone;
self.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
self.drawableMultisample = GLKViewDrawableMultisample4X;
self.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
self.enableSetNeedsDisplay = YES;
// ... gl code following
My -drawRect method looks like this:
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
[_currentProgram use]; // Use program
glUniformMatrix4fv([_currentProgram getUniformLocation:#"modelViewProjectionMatrix"], 1, 0, modelViewProjectionMatrix.m);
// ...
if (isES3) {
glBindVertexArray(vertexArray);
}
else {
glBindVertexArrayOES(vertexArray);
}
glDrawArrays(GL_TRIANGLE_STRIP, 0, verticiesLength);
I do not yet have a OpenGL ES 3.0-capable device so all of my OpenGL ES 3.0 testing is being done in the iOS Simulator. OpenGL ES 2.0 testing is done on-device and in-simulator.
As expected, in ES2, the screen is cleared to white immediately on startup (-drawRect having been called once and no vertices to draw yet). However, when I make the swap to ES3, the context is successfully created, no gl calls fail, and yet the screen does not clear as it should - it just appears as a black screen. Fishing around for what was going wrong, I decided to remove multi-sampling:
self.drawableMultisample = GLKViewDrawableMultisampleNone;
And it worked! (Albeit without antialiasing.) My question is therefore, are there any known issues with GLKit multi-sampling with OpenGL ES 3.0 in the iOS Simulator (iPad, iPad Retina and iPad Retina (64-Bit))? My laptop has more than enough free memory to cope with the multi-sampling.
OpenGL is a very asynchronous API. For example, if you call glClear, you should not expect the screen to be cleared when the call returns. You can only reliably look at the result of the rendering you produced after you finished rendering the frame, and it is displayed (typically by swapping the buffers when using double buffered rendering).
So what you're observing most likely does not mean anything. Does everything look fine at the end of the frame? If yes, there's no reason to be worried.
The difference is likely caused in the different rendering process if multisampling is enabled. In this case, rendering goes to a higher resolution buffer first, and is only downsampled to the actual framebuffer at the end of the frame.
When you deploy, chose the device type to be iPad, not universal, from the General>Deployment Info menu, that will fix it.

GLPaint based OpenGL ES Blending Issue

I'm working on an app based on Apple's GLPaint sample code. I've changed the clear color to transparent black and have added an opacity slider, however when I mix colors together with a low opacity setting they don't mix the way I'm expecting. They seem to mix the way light mixes, not the way paint mixes. Here is an example of what I mean:
The "Desired Result" was obtained by using glReadPixels to render each color separately and merge it with the previous rendered image (i.e. using apple's default blending).
However, mixing each frame with the previous is too time consuming to be done on the fly, how can I get OpenGL to blend the colors properly? I've been researching online for quite a while and have yet to find a solution that works for me, please let me know if you need any other info to help!
From the looks of it, with your current setup, there is no easy solution. For what you are trying to do, you need custom shaders. Which is not possible using just GLKit.
Luckily you can mix GLKit and OpenGL ES.
My recommendation would be to:
Stop using GLKit for everything except setting up your rendering
surface with GLKView (which is tedious without GLKit).
Use an OpenGl program with custom shaders to draw to a texture that is backing an FBO.
Use a second program with custom shaders that does post processing (after drawing above texture to a quad which is then rendered to the screen).
A good starting point would be to load up the OpenGl template that comes with Xcode. And start modifying it. Be warned: If you don't understand shaders, the code here will make little sense. It draws 2 cubes, one using GLKit, and one without - using custom shaders.
References to start learning:
Intro to shaders
Rendering to a Texture
Shader Toy - This should help you experiment with your post processing frag shader.
GLEssentials example - This shows how to render to texture using OpenGL ( a bit outdated.)
Finally, if you are really serious about using OpenGL ES to it's full potential, you really should invest the time to read through OpenGL ES 2.0 programming guide. Even though it is 6 years old, it is still relevant and the only book I've found that explains all the concepts correctly.
Your "Current Result" is additive color, which is how OpenGL is supposed to work. To work like mixing paint would be substractive color. You don't have control over this with OpenGL ES 1.1, but you could write a custom fragment shader for OpenGL ES 2.0 that would do substractive color. If you are blending textures images from iOS, you need to know if the image data has been premultiplied by alpha or not, in order to do blending. OpenGL ES expects the non-premultiplied format.
You need to write that code in the function which is called on color change.
and each time you need to set BlendFunc.
CGFloat red , green, blue;
// set red, green ,blue with desire color combination
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(red* kBrushOpacity,
green * kBrushOpacity,
blue* kBrushOpacity,
kBrushOpacity);
To do more things by using BlendFunc use this link
Please specify if it works or not. It work for me.

Upgrading from CoreGraphics

I've written my first iOS app, Amaziograph, which uses Core Graphics.
My app is a drawing app and it employs drawing a lot of lines (Up to 30 lines one by one, at different locations + some shadow to simulate brush blur, and it needs to appear as if all lines are drawn at the same time) with CG, which I find to be slow. In fact, when I switch to Retina and try drawing just a single line with my finger, I need to wait a second or so before it is drawn.
I realised that Core Graphics no longer meets my app's requirements as I'd like to make it use the Retina display's advantages and add some photoshop-style brushes.
My question is, is there a graphics library more faster and powerful than Core Graphics, but with simple interface. All I need is drawing simple lines with size, opacity, softness and possibly with some more advanced brushes. I'm thinking of OpenGL after I saw Apple's GLPaint app, but it seems a bit complicated for me with all those framebuffers, contexts and so on. I am looking for something that has similar to CG's ideology, so it wouldn't take much time rewriting my code. Also, right now I'm doing all my drawing in UIImage views, so it would be nice to draw on top of UIImages directly.
Here is an extract of the code I'm using to draw right now:
//...Begin image contest >> draw the previous image in >> set stroke style >>
CGContextBeginPath(currentContext);
CGContextMoveToPoint(currentContext, lastPoint.x, lastPoint.y-offset);
CGContextAddLineToPoint(currentContext, currentPoint.x, currentPoint.y-offset);
CGContextStrokePath(currentContext);
//Send to an UIImage and end image contest...
You are not going to find another graphics library with better performance than Core Graphics for the iOS platforms. Most likely your application can be significantly optimised, there are many tricks to use. You might be interested in the WWDC video 506 from 2012:
http://developer.apple.com/videos/wwdc/2012/

Optimizing 2D Graphics and Animation Performance
They demonstrate a paint application using Core Graphics that works at full frame rate.

Strange blending effect in OpenGL ES 2.0 using GLKit

This happens on GLKit with MonoTouch 5.3, but I think the problem may be of general OpenGL ES 2.0 nature.
I have three faces, one of them red, one green and one blue, all with an alpha value of 1.0, so they should be opaque. When they are rendered on the black background, everything is okay. If the green face is in front of the others, everything is okay as well. But if
the red face is in front of the green
or the blue face is in front of one of the others
the foreground color is not rendered, but the background face is fully visible. This seems to be some kind of blending effect, but I don't see anything special in my code, and I have tried out several things like glBlendFunc, but it didn't change anything.
I could post my code, but since the code is quite simple, I thought perhaps someone knows the answer immediately.
Update: As this seems to be a Depth-Sorting issue, here are some important parts of the code:
var aContext = new EAGLContext(EAGLRenderingAPI.OpenGLES2);
var view = this.View as GLKView;
view.Delegate = new GenericGLKViewDelegate(this);
view.Context = aContext;
view.DrawableColorFormat = GLKViewDrawableColorFormat.RGBA8888;
view.DrawableDepthFormat = GLKViewDrawableDepthFormat.Format16;
view.DrawableMultisample = GLKViewDrawableMultisample.Sample4x;
here is the DrawInRect method:
_baseEffect.PrepareToDraw();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.EnableVertexAttribArray((int)GLKVertexAttrib.Position);
GL.EnableVertexAttribArray((int)GLKVertexAttrib.Color);
GL.VertexAttribPointer((int)GLKVertexAttrib.Position, 3, VertexAttribPointerType.Float, false, 0, _squareVertices);
GL.VertexAttribPointer((int)GLKVertexAttrib.Color, 4, VertexAttribPointerType.UnsignedByte, true, 0, _squareColors);
GL.DrawArrays(BeginMode.TriangleStrip, 0, 9);
GL.DisableVertexAttribArray((int)GLKVertexAttrib.Position);
GL.DisableVertexAttribArray((int)GLKVertexAttrib.Color);
I tried every possible combination of ColorFormat, DepthFormat and Multisample, but it's still the same.
Solution:
I was missing some calls to enable the depth buffer, these calls were missing in the ViewDidLoad method:
GL.ClearDepth(30);
GL.Enable(EnableCap.DepthTest);
GL.DepthFunc(DepthFunction.Lequal);
This does not sound like a blending issue- rather a depth-sorting issue.
Is the depth buffer enabled? Are you clearing it with each frame?

How to set Background image in GLKViewController iPhone OpenGLES?

I'm drawing a line using OpenGL on the iPhone. I used GLView and GLKView delegates to draw the line. But now I want to set a background image to GLKViewController, and on the background image, I want to draw the line. I have tried to set a background image using UIImageView, but the image is appearing above on the (GLKView) drawn line.
How can I set a background image to the GLKViewController?
The easiest way should be to add additional view with background image (such as you proposed - but you need to set it behind OpenGL view). Try this:
[RootViewController.view addSubview: BackgroundView belowSubview: OpenGLView];
OpenGLView.opaque = NO;
But this will bring some FPS penalty (Apple recommends to use opaque OpenGL view for performance reason). More correct approach is to draw background via OpenGL as fullscreen quad.
I just want to state that the accepted answer is a very bad one... You will lose an almost immediate 20fps even on the newer devices (iPhone 5, iPad 2 & newer) by turning off opaque. The performance penalty is horrible and should not be taken lightly.
You can set a background in OpenGL and keep your opaque. Convert the UIImage to an OpenGL texture and render it. Depending on your OpenGL environment, this can be done a number of ways easily.

Resources