OpenGL ES 2.0 - iOS - Render to texture using FBO - ios
Based on the tutorial :
"http://www.raywenderlich.com/4404/opengl-es-2-0-for-iphone-tutorial-part-2-textures"
and the book "Open GL ES 2.0 Programming Guide"
I'm trying to render a scene to a FBO texture, and then render that FBO texture on the display window.
I don't know why, but I have a white screen..
Edit 1 : The white screen was due to binding the depth buffer in the render loop. Now the problem is that the cube rendered in the FBO texture is not rendered on screen..
Edit 2 : Updated the code and added shader files
Here is my code :
OpenGLView.h :
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#interface OpenGLView : UIView {
CAEAGLLayer* _eaglLayer;
EAGLContext* _context;
GLuint _viewFrameBuffer;
GLuint _colorRenderBuffer;
GLuint _depthRenderBuffer;
float _cubeCurrentRotation;
GLuint _cubeTexture;
GLuint _cubeVertexBuffer;
GLuint _cubeIndexBuffer;
GLuint _viewportSizedQuadVertexBuffer;
GLuint _viewportSizedQuadIndexBuffer;
GLuint _FBO;
GLuint _FBOTexture;
GLuint _FBODepthBuffer;
// shaders
// simple shader
GLuint _simpleShaderProgram;
GLuint _simpleVertexShader;
GLuint _simpleFragmentShader;
GLuint _positionSlot;
GLuint _colorSlot;
GLuint _projectionUniform;
GLuint _modelViewUniform;
GLuint _texCoordSlot;
GLuint _textureUniform;
// texture shader
GLuint _textureShaderProgram;
GLuint _textureVertexShader;
GLuint _texturePositionSlot;
GLuint _textureColorSlot;
GLuint _textureTexCoordSlot;
GLuint _textureTextureUniform;
}
#end
OpenGLView.m :
//
// OpenGLView.m
// HelloOpenGL
//
// Created by Ray Wenderlich on 5/24/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "OpenGLView.h"
#import "CC3GLMatrix.h"
#implementation OpenGLView
typedef struct {
float Position[3];
float Color[4];
float TexCoord[2];
} Vertex;
#define TEX_COORD_MAX 1
const Vertex cubeVertices[] = {
// Front
{{1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{-1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, -1, 0}, {0, 0, 0, 1}, {0, 0}},
// Back
{{1, 1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{-1, -1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{1, -1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, 1, -2}, {0, 0, 0, 1}, {0, 0}},
// Left
{{-1, -1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{-1, 1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{-1, 1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, -1, -2}, {0, 0, 0, 1}, {0, 0}},
// Right
{{1, -1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{1, 1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{1, 1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{1, -1, 0}, {0, 0, 0, 1}, {0, 0}},
// Top
{{1, 1, 0}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{1, 1, -2}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{-1, 1, -2}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, 1, 0}, {0, 0, 0, 1}, {0, 0}},
// Bottom
{{1, -1, -2}, {1, 0, 0, 1}, {TEX_COORD_MAX, 0}},
{{1, -1, 0}, {0, 1, 0, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{-1, -1, 0}, {0, 0, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, -1, -2}, {0, 0, 0, 1}, {0, 0}}
};
const GLubyte cubeIndices[] = {
// Front
0, 1, 2,
2, 3, 0,
// Back
4, 5, 6,
6, 7, 4,
// Left
8, 9, 10,
10, 11, 8,
// Right
12, 13, 14,
14, 15, 12,
// Top
16, 17, 18,
18, 19, 16,
// Bottom
20, 21, 22,
22, 23, 20
};
const Vertex viewPortQuadVertices[] = {
{{1, -1, 0}, {1, 1, 1, 1}, {TEX_COORD_MAX, 0}},
{{1, 1, 0}, {1, 1, 1, 1}, {TEX_COORD_MAX, TEX_COORD_MAX}},
{{-1, 1, 0}, {1, 1, 1, 1}, {0, TEX_COORD_MAX}},
{{-1, -1, 0}, {1, 1, 1, 1}, {0, 0}}
};
const GLubyte viewPortQuadIndices[] = {
0, 1, 2,
2, 3, 0,
};
+ (Class)layerClass {
return [CAEAGLLayer class];
}
- (void)dealloc {
[_context release];
_context = nil;
[super dealloc];
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setupLayer];
[self setupContext];
[self setupDepthBuffer];
[self setupRenderBuffer];
[self setupFrameBuffer];
[self setupFBOs];
[self compileShaders];
[self setupVBOs];
[self setupDisplayLink];
_cubeTexture = [self setupTexture:#"tile_floor.png"];
}
return self;
}
- (void)setupDisplayLink {
CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(render:)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)setupLayer {
_eaglLayer = (CAEAGLLayer*) self.layer;
_eaglLayer.opaque = YES;
}
- (void)setupContext {
EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2;
_context = [[EAGLContext alloc] initWithAPI:api];
if (!_context) {
NSLog(#"Failed to initialize OpenGLES 2.0 context");
exit(1);
}
if (![EAGLContext setCurrentContext:_context]) {
NSLog(#"Failed to set current OpenGL context");
exit(1);
}
}
- (void)setupRenderBuffer {
glGenRenderbuffers(1, &_colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
[_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];
}
- (void)setupDepthBuffer {
glGenRenderbuffers(1, &_depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, self.frame.size.width, self.frame.size.height);
}
- (void)setupFrameBuffer {
glGenFramebuffers(1, &_viewFrameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, _viewFrameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer);
}
-(void)setupFBOs {
GLint maxRenderBufferSize;
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxRenderBufferSize);
GLuint textureWidth = self.frame.size.width;
GLuint textureHeight = self.frame.size.height;
if(maxRenderBufferSize <= textureWidth
|| maxRenderBufferSize <= textureHeight) {
NSLog(#"FBO cant allocate that much space");
}
glGenFramebuffers(1, &_FBO);
glGenRenderbuffers(1, &_FBODepthBuffer);
glGenTextures(1, &_FBOTexture);
glBindTexture(GL_TEXTURE_2D, _FBOTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureWidth, textureHeight,
0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindRenderbuffer(GL_RENDERBUFFER, _FBODepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, textureWidth, textureHeight);
glBindFramebuffer(GL_FRAMEBUFFER, _FBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _FBOTexture, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _FBODepthBuffer);
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(#"FBO is not complete :%u", status);
}
}
- (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType {
NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:#"glsl"];
NSError* error;
NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
if (!shaderString) {
NSLog(#"Error loading shader: %#", error.localizedDescription);
exit(1);
}
GLuint shaderHandle = glCreateShader(shaderType);
const char * shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = [shaderString length];
glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
glCompileShader(shaderHandle);
GLint compileSuccess;
glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(#"%#", messageString);
exit(1);
}
return shaderHandle;
}
- (void)compileShaders {
_simpleVertexShader = [self compileShader:#"SimpleVertex" withType:GL_VERTEX_SHADER];
_simpleFragmentShader = [self compileShader:#"SimpleFragment" withType:GL_FRAGMENT_SHADER];
_textureVertexShader = [self compileShader:#"TextureVertex" withType:GL_VERTEX_SHADER];
_simpleShaderProgram = glCreateProgram();
glAttachShader(_simpleShaderProgram, _simpleVertexShader);
glAttachShader(_simpleShaderProgram, _simpleFragmentShader);
glLinkProgram(_simpleShaderProgram);
GLint linkSuccess;
glGetProgramiv(_simpleShaderProgram, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(_simpleShaderProgram, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(#"%#", messageString);
exit(1);
}
glUseProgram(_simpleShaderProgram);
_positionSlot = glGetAttribLocation(_simpleShaderProgram, "Position");
_colorSlot = glGetAttribLocation(_simpleShaderProgram, "SourceColor");
glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
_projectionUniform = glGetUniformLocation(_simpleShaderProgram, "Projection");
_modelViewUniform = glGetUniformLocation(_simpleShaderProgram, "Modelview");
_texCoordSlot = glGetAttribLocation(_simpleShaderProgram, "TexCoordIn");
glEnableVertexAttribArray(_texCoordSlot);
_textureUniform = glGetUniformLocation(_simpleShaderProgram, "Texture");
// Texture shader
_textureShaderProgram = glCreateProgram();
glAttachShader(_textureShaderProgram, _textureVertexShader);
glAttachShader(_textureShaderProgram, _simpleFragmentShader);
glLinkProgram(_textureShaderProgram);
glGetProgramiv(_textureShaderProgram, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(_textureShaderProgram, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(#"%#", messageString);
exit(1);
}
glUseProgram(_textureShaderProgram);
_texturePositionSlot = glGetAttribLocation(_textureShaderProgram, "texPosition");
_textureColorSlot = glGetAttribLocation(_textureShaderProgram, "texSourceColor");
glEnableVertexAttribArray(_texturePositionSlot);
glEnableVertexAttribArray(_textureColorSlot);
_textureTexCoordSlot = glGetAttribLocation(_textureShaderProgram, "texTexCoordIn");
glEnableVertexAttribArray(_textureTexCoordSlot);
_textureTextureUniform = glGetUniformLocation(_textureShaderProgram, "Texture");
}
- (void)setupVBOs {
glGenBuffers(1, &_cubeVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _cubeVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW);
glGenBuffers(1, &_cubeIndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _cubeIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);
glGenBuffers(1, &_viewportSizedQuadVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _viewportSizedQuadVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(viewPortQuadVertices), viewPortQuadVertices, GL_STATIC_DRAW);
glGenBuffers(1, &_viewportSizedQuadIndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _viewportSizedQuadIndexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(viewPortQuadIndices), viewPortQuadIndices, GL_STATIC_DRAW);
}
- (GLuint)setupTexture:(NSString *)fileName {
CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
if (!spriteImage) {
NSLog(#"Failed to load image %#", fileName);
exit(1);
}
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
GLuint texName;
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
free(spriteData);
return texName;
}
- (void)render:(CADisplayLink*)displayLink {
glBindFramebuffer(GL_FRAMEBUFFER, _FBO);
//glBindRenderbuffer(GL_RENDERBUFFER, _FBODepthBuffer);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glClearColor(255.0/255.0, 255.0/255.0, 255.0/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
glUseProgram(_simpleShaderProgram);
// Cube draw in FBO
CC3GLMatrix *projection = [CC3GLMatrix matrix];
float h = 4.0f * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:4 andFar:1000];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);
CC3GLMatrix *modelView = [CC3GLMatrix matrix];
[modelView populateFromTranslation:CC3VectorMake(sin(CACurrentMediaTime()), 0, -7)];
_cubeCurrentRotation += displayLink.duration * 90;
[modelView rotateBy:CC3VectorMake(_cubeCurrentRotation, _cubeCurrentRotation, 0)];
glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);
glBindBuffer(GL_ARRAY_BUFFER, _cubeVertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _cubeIndexBuffer);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _cubeTexture);
glUniform1i(_textureUniform, 0);
glDrawElements(GL_TRIANGLES, sizeof(cubeIndices)/sizeof(cubeIndices[0]), GL_UNSIGNED_BYTE, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// ---------------------------------------------------------------
// FBO -> window
glBindFramebuffer(GL_FRAMEBUFFER, _viewFrameBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glClearColor(0.0/255.0, 0.0/255.0, 0.0/255.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
glUseProgram(_textureShaderProgram);
glBindBuffer(GL_ARRAY_BUFFER, _viewportSizedQuadVertexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _viewportSizedQuadIndexBuffer);
glVertexAttribPointer(_texturePositionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(_textureColorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glVertexAttribPointer(_textureTexCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _FBOTexture);
glUniform1i(_textureTextureUniform, 0);
glDrawElements(GL_TRIANGLES, sizeof(viewPortQuadIndices)/sizeof(viewPortQuadIndices[0]), GL_UNSIGNED_BYTE, 0);
[_context presentRenderbuffer:GL_RENDERBUFFER];
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
#end
SimpleVertex.glsl :
attribute vec4 Position;
attribute vec4 SourceColor;
varying vec4 DestinationColor;
uniform mat4 Projection;
uniform mat4 Modelview;
attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;
void main(void) {
DestinationColor = SourceColor;
gl_Position = Projection * Modelview * Position;
TexCoordOut = TexCoordIn;
}
TextureVertex.glsl :
attribute vec4 texPosition;
attribute vec4 texSourceColor;
varying vec4 DestinationColor;
attribute vec2 texTexCoordIn;
varying vec2 TexCoordOut;
void main(void) {
DestinationColor = texSourceColor;
gl_Position = texPosition;
TexCoordOut = texTexCoordIn;
}
SimpleFragment.glsl :
varying lowp vec4 DestinationColor;
varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;
void main(void) {
gl_FragColor = DestinationColor * texture2D(Texture, TexCoordOut);
}
Ok I solved it by correcting the view port and not binding the depth buffer in the render loop, thanks to #FelixK !
Related
openGL render different on iPhone and iPad
I created an iOS app using OpenGL to render yuv420p from ffmpeg. It works fine on iPad, but on iPhone, it looks like the image below, the picture looks italic and the right bottom triangle part like below should be on the left. I can not found the reason, has anyone met this before? does OpenGL on iPad and iPhone different? below is my OpenGL view. SDL_Overlay is a struct that holds YUV plane data from ffmpeg. #import "EAGLView.h" // Uniform index. enum { UNIFORM_Y, UNIFORM_U, UNIFORM_V, NUM_UNIFORMS }; GLint uniforms[NUM_UNIFORMS]; // Attribute index. enum { ATTRIB_VERTEX, ATTRIB_TEXCOORD, NUM_ATTRIBUTES }; const GLubyte VertexIndexStruct[] = { 0, 1, 2, 2, 3, 0 }; #interface EAGLView () { // The pixel dimensions of the CAEAGLLayer. GLint _backingWidth; GLint _backingHeight; EAGLContext *m_context; GLuint _frameBufferHandle; GLuint _colorBufferHandle; BOOL _pause; } #property GLuint program; - (void)setupBuffers; - (BOOL)loadShaders; - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type URL:(NSURL *)URL; - (BOOL)linkProgram:(GLuint)prog; - (BOOL)validateProgram:(GLuint)prog; #end #implementation EAGLView +(Class) layerClass { return [CAEAGLLayer class]; } - (id) initWithCoder:(NSCoder*)coder { if ((self = [super initWithCoder:coder])) { [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; } return self; } -(void) applicationDidEnterBackground:(NSNotification *) notification { _pause = YES; } -(void) applicationWillEnterForeground:(NSNotification *) notification { _pause = NO; } -(void) destroyFrameBuffer { // tear down GL if (_frameBufferHandle) { glDeleteFramebuffers(1, &_frameBufferHandle); _frameBufferHandle = 0; } if (_colorBufferHandle) { glDeleteRenderbuffers(1, &_colorBufferHandle); _colorBufferHandle = 0; } if(self.program) { glDeleteProgram(self.program); } } -(void) setFrame:(CGRect)frame { [super setFrame:frame]; [self setupGL]; } # pragma mark - OpenGL setup - (void)setupGL { [self destroyFrameBuffer]; self.contentScaleFactor = [UIScreen mainScreen].scale; CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = TRUE; [eaglLayer setContentsScale:self.contentScaleFactor]; eaglLayer.drawableProperties = #{ kEAGLDrawablePropertyRetainedBacking :[NSNumber numberWithBool:NO], kEAGLDrawablePropertyColorFormat : kEAGLColorFormatRGBA8}; if(m_context) { [m_context release]; } m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; if(!m_context) { m_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; } if (!m_context || ![EAGLContext setCurrentContext:m_context] || ![self loadShaders]) { return; } [EAGLContext setCurrentContext:m_context]; [self setupBuffers]; [self loadShaders]; glUseProgram(self.program); // 0 and 1 are the texture IDs of _lumaTexture and _chromaTexture respectively. glUniform1i(uniforms[UNIFORM_Y], 0); glUniform1i(uniforms[UNIFORM_U], 1); glUniform1i(uniforms[UNIFORM_V], 2); } #pragma mark - Utilities - (void)setupBuffers { glDisable(GL_DEPTH_TEST); glEnableVertexAttribArray(ATTRIB_VERTEX); glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0); glEnableVertexAttribArray(ATTRIB_TEXCOORD); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0); glGenFramebuffers(1, &_frameBufferHandle); glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferHandle); glGenRenderbuffers(1, &_colorBufferHandle); glBindRenderbuffer(GL_RENDERBUFFER, _colorBufferHandle); CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = TRUE; [eaglLayer setContentsScale:self.contentScaleFactor]; [m_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer]; glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth); glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorBufferHandle); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { NSLog(#"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); } } - (void)dealloc { [self destroyFrameBuffer]; [super dealloc]; } #pragma mark - OpenGL ES 2 shader compilation - (BOOL)loadShaders { GLuint vertShader, fragShader; NSURL *vertShaderURL, *fragShaderURL; // Create the shader program. self.program = glCreateProgram(); // Create and compile the vertex shader. vertShaderURL = [[NSBundle mainBundle] URLForResource:#"shader" withExtension:#"vsh"]; if (![self compileShader:&vertShader type:GL_VERTEX_SHADER URL:vertShaderURL]) { NSLog(#"Failed to compile vertex shader"); return NO; } // Create and compile fragment shader. fragShaderURL = [[NSBundle mainBundle] URLForResource:#"shader" withExtension:#"fsh"]; if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER URL:fragShaderURL]) { NSLog(#"Failed to compile fragment shader"); return NO; } // Attach vertex shader to program. glAttachShader(self.program, vertShader); // Attach fragment shader to program. glAttachShader(self.program, fragShader); // Bind attribute locations. This needs to be done prior to linking. glBindAttribLocation(self.program, ATTRIB_VERTEX, "position"); glBindAttribLocation(self.program, ATTRIB_TEXCOORD, "texCoord"); // Link the program. if (![self linkProgram:self.program]) { NSLog(#"Failed to link program: %d", self.program); if (vertShader) { glDeleteShader(vertShader); vertShader = 0; } if (fragShader) { glDeleteShader(fragShader); fragShader = 0; } if (self.program) { glDeleteProgram(self.program); self.program = 0; } return NO; } // Get uniform locations. uniforms[UNIFORM_Y] = glGetUniformLocation(self.program, "SamplerY"); uniforms[UNIFORM_U] = glGetUniformLocation(self.program, "SamplerU"); uniforms[UNIFORM_V] = glGetUniformLocation(self.program, "SamplerV"); // Release vertex and fragment shaders. if (vertShader) { glDetachShader(self.program, vertShader); glDeleteShader(vertShader); } if (fragShader) { glDetachShader(self.program, fragShader); glDeleteShader(fragShader); } return YES; } - (BOOL)compileShader:(GLuint *)shader type:(GLenum)type URL:(NSURL *)URL { NSError *error; NSString *sourceString = [[NSString alloc] initWithContentsOfURL:URL encoding:NSUTF8StringEncoding error:&error]; if (sourceString == nil) { NSLog(#"Failed to load vertex shader: %#", [error localizedDescription]); return NO; } GLint status; const GLchar *source; source = (GLchar *)[sourceString UTF8String]; *shader = glCreateShader(type); glShaderSource(*shader, 1, &source, NULL); glCompileShader(*shader); #if defined(DEBUG) GLint logLength; glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength); if (logLength > 0) { GLchar *log = (GLchar *)malloc(logLength); glGetShaderInfoLog(*shader, logLength, &logLength, log); NSLog(#"Shader compile log:\n%s", log); free(log); } #endif glGetShaderiv(*shader, GL_COMPILE_STATUS, &status); if (status == 0) { glDeleteShader(*shader); return NO; } return YES; } - (BOOL)linkProgram:(GLuint)prog { GLint status; glLinkProgram(prog); #if defined(DEBUG) GLint logLength; glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength); if (logLength > 0) { GLchar *log = (GLchar *)malloc(logLength); glGetProgramInfoLog(prog, logLength, &logLength, log); NSLog(#"Program link log:\n%s", log); free(log); } #endif glGetProgramiv(prog, GL_LINK_STATUS, &status); if (status == 0) { return NO; } return YES; } - (BOOL)validateProgram:(GLuint)prog { GLint logLength, status; glValidateProgram(prog); glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength); if (logLength > 0) { GLchar *log = (GLchar *)malloc(logLength); glGetProgramInfoLog(prog, logLength, &logLength, log); NSLog(#"Program validate log:\n%s", log); free(log); } glGetProgramiv(prog, GL_VALIDATE_STATUS, &status); if (status == 0) { return NO; } return YES; } -(CGSize) renderSize { return CGSizeMake(_backingWidth/self.contentScaleFactor, _backingHeight/self.contentScaleFactor); } -(void) render:(SDL_Overlay*) overlay { if(_pause) { return; } //Create Y and UV textures from the pixel buffer glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, uniforms[UNIFORM_Y]); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, overlay->w, overlay->h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, overlay->data[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // U-plane. glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, uniforms[UNIFORM_U]); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, overlay->w/2, overlay->h/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, overlay->data[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // V-plane. glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, uniforms[UNIFORM_V]); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, overlay->w/2, overlay->h/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, overlay->data[2]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferHandle); CGFloat ratio = (CGFloat)overlay->w / overlay->h; GLfloat actualWidth = _backingWidth; GLfloat actualHeight = actualWidth / ratio; if(actualHeight > _backingHeight) { actualHeight = _backingHeight; actualWidth = actualHeight * ratio; } // Set the view port to the entire view. glViewport((_backingWidth - actualWidth) / 2, (_backingHeight - actualHeight) / 2, actualWidth, actualHeight); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // Use shader program. glUseProgram(self.program); /* The quad vertex data defines the region of 2D plane onto which we draw our pixel buffers. Vertex data formed using (-1,-1) and (1,1) as the bottom left and top right coordinates respectively, covers the entire screen. */ GLfloat quadVertexData [] = { 1, -1, 1, 1, -1, 1, -1, -1 }; // Update attribute values. glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, quadVertexData); glEnableVertexAttribArray(ATTRIB_VERTEX); /* The texture vertices are set up such that we flip the texture vertically. This is so that our top left origin buffers match OpenGL's bottom left texture coordinate system. */ GLfloat quadTextureData[] = { 1, 1, 1, 0, 0, 0, 0, 1, }; glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, 0, 0, quadTextureData); glEnableVertexAttribArray(ATTRIB_TEXCOORD); // glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawElements(GL_TRIANGLES, sizeof(VertexIndexStruct) / sizeof(VertexIndexStruct[0]), GL_UNSIGNED_BYTE, &VertexIndexStruct); glBindRenderbuffer(GL_RENDERBUFFER, _colorBufferHandle); [m_context presentRenderbuffer:GL_RENDERBUFFER]; } #end
Open GL ES png texture rendering as black
I am just trying to draw a full screen .png into openGL as a texture. However, I am met with a black screen. My code works fine with jpegs, so I can only assume it's an issue with transparency. Here is an example png, which it isn't working for: http://cl.ly/e5x4 (although it is opaque, it still doesn't render) (and no, it needs to be a .png) Here is my code: glView.m struct vertex { float position[3]; float color[4]; float texCoord[2]; }; typedef struct vertex vertex; const vertex vertices[] = { {{1, -1, 0}, {0, 167.0/255.0, 253.0/255.0, 1}, {1, 0}}, // BR (0) {{1, 1, 0}, {0, 222.0/255.0, 1.0, 1}, {1, 1}}, // TR (1) {{-1, 1, 0}, {0, 222.0/255.0, 1.0, 1}, {0, 1}}, // TL (2) {{-1, -1, 0}, {0, 167.0/255.0, 253.0/255.0, 1}, {0, 0}}, // BL (3) }; const GLubyte indicies[] = { 0, 1, 2, 0, 3, 2 }; #implementation glView { EAGLContext* context; GLuint positionSlot, colorSlot, textureCoordSlot; GLuint texture, textureUniform; GLuint vertexBuffer, indexBuffer; } -(GLuint) compileShader:(NSString*)shaderName withType:(GLenum)shaderType { NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:#"glsl"]; NSError* err; NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&err]; NSAssert(shaderString, #"Failed to load shader string: %#", err.localizedDescription); GLuint shaderHandle = glCreateShader(shaderType); const char* shaderStringUTF8 = [shaderString UTF8String]; int shaderStringLength = (int)[shaderString length]; glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength); glCompileShader(shaderHandle); GLint compileSuccess; glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess); if (compileSuccess == GL_FALSE) { GLchar messages[256]; glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); NSString* messageString = [NSString stringWithUTF8String:messages]; NSLog(#"%#", messageString); #throw NSInternalInconsistencyException; } return shaderHandle; } -(void) complileShaders { GLuint vertexShader = [self compileShader:#"vertexShader" withType:GL_VERTEX_SHADER]; GLuint fragmentShader = [self compileShader:#"fragmentShader" withType:GL_FRAGMENT_SHADER]; GLuint programHandle = glCreateProgram(); glAttachShader(programHandle, vertexShader); glAttachShader(programHandle, fragmentShader); glLinkProgram(programHandle); GLint linkSuccess; glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); if (linkSuccess == GL_FALSE) { GLchar messages[256]; glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]); NSString* messageString = [NSString stringWithUTF8String:messages]; NSLog(#"%#", messageString); #throw NSInternalInconsistencyException; } glUseProgram(programHandle); positionSlot = glGetAttribLocation(programHandle, "position"); colorSlot = glGetAttribLocation(programHandle, "sourceColor"); textureCoordSlot = glGetAttribLocation(programHandle, "texCoordIn"); glEnableVertexAttribArray(positionSlot); glEnableVertexAttribArray(colorSlot); glEnableVertexAttribArray(textureCoordSlot); textureUniform = glGetUniformLocation(programHandle, "tex"); } -(instancetype) initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.layer.opaque = YES; // Setup context context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; NSAssert(context, #"Failed to initialise context."); NSAssert([EAGLContext setCurrentContext:context], #"Failed to set the current context."); // Setup render buffer GLuint colorBuffer; glGenRenderbuffers(1, &colorBuffer); glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer); [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.layer]; // Setup frame buffer GLuint frameBuffer; glGenFramebuffers(1, &frameBuffer); glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer); // Setup vertex buffer glGenBuffers(1, &vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // Setup index buffer glGenBuffers(1, &indexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indicies), indicies, GL_STATIC_DRAW); [self complileShaders]; glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_SRC_COLOR); texture = [self loadTexture:#"justapng.png"]; [self render]; } return self; } -(GLuint) loadTexture:(NSString*)fileName { UIImage* textureImage = [UIImage imageNamed:fileName]; NSAssert1(textureImage, #"Unable to load texture %#.", fileName); return [self loadTextureFromImage:textureImage]; } -(GLuint) loadTextureFromImage:(UIImage*)image { CGImageRef textureImage = image.CGImage; size_t width = CGImageGetWidth(textureImage); size_t height = CGImageGetHeight(textureImage); GLubyte* spriteData = (GLubyte*) malloc(width*height*4); CGColorSpaceRef cs = CGImageGetColorSpace(textureImage); CGContextRef c = CGBitmapContextCreate(spriteData, width, height, 8, width*4, cs, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(cs); CGContextDrawImage(c, (CGRect){CGPointZero, {width, height}}, textureImage); CGContextRelease(c); GLuint glTex; glGenTextures(1, &glTex); glBindTexture(GL_TEXTURE_2D, glTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)width, (int)height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData); free(spriteData); return glTex; } -(void) render { glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, self.frame.size.width, self.frame.size.height); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(textureUniform, 0); glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), 0); glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)(sizeof(float)*3)); glVertexAttribPointer(textureCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)(sizeof(float)*7)); glDrawElements(GL_TRIANGLES, sizeof(indicies)/sizeof(indicies[0]), GL_UNSIGNED_BYTE, 0); [context presentRenderbuffer:GL_RENDERBUFFER]; } #end vertexShader.glsl attribute vec4 position; attribute vec4 sourceColor; varying vec4 destinationColor; attribute vec2 texCoordIn; varying vec2 texCoordOut; void main() { destinationColor = sourceColor; gl_Position = position; texCoordOut = texCoordIn; } fragmentShader.glsl varying lowp vec4 destinationColor; varying lowp vec2 texCoordOut; uniform sampler2D tex; void main() { gl_FragColor = destinationColor*texture2D(tex, texCoordOut); } Sorry for dumping all this code, but I am unsure where the problem is originating from. Any ideas as to what I am doing wrong?
This appears to be the classic non-power-of-two issue (eg. see Android OpenGL2.0 showing black textures). The texture you linked is 1005x335. The OpenGL ES 2.0 specification only allows for NPOT textures to be 'complete' with glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S/T, GL_CLAMP_TO_EDGE). Various extensions allow NPOT texturing, however, your device doesn't necessarily support these, and likely doesn't if you're getting black textures. If a texture isn't complete, it is sampled as black per the spec.
Rendering OpenGL ES 2.0 to UIImage
I am interested in writing some code which processes an image using OpenGL ES 2.0 and then reads out the image back to memory again (to eventually be saved). I have some other code which does some more complex processing and just renders the image to display which works. I now want some code which runs the same processing but just saves the image. It doesn't need to be rendered to the screen. I have created a frame buffer object which outputs to a texture. I then want to use glReadPixels to get the contents of the frame buffer back into memory. The following code snippet should just take a UIImage, resize it to fit onto a 512x512 canvas and then write it out as a 512x512 UIImage. I can't seem to get anything meaningful to display though. If I use an image smaller than 512x512 it does seem to render, but it's as if it is drawing straight from the texture storage (because I pad images to always be a power of 2 size). The image displays but if I change any of the drawing code, it doesn't affect it. I'd really appreciate if you could give me some insight? Thanks! Here is my Vertex Shader: attribute vec4 Position; attribute vec4 SourceColour; varying vec4 DestinationColour; uniform vec2 ScreenSize; attribute vec2 TexCoordIn; varying vec2 TexCoordOut; void main(void) { DestinationColour = SourceColour; vec4 newPosition = Position; newPosition.x = Position.x / ScreenSize.x; newPosition.y = Position.y / ScreenSize.y; gl_Position = Position; TexCoordOut = TexCoordIn; } Here is my fragment shader: varying lowp vec2 TexCoordOut; uniform sampler2D Texture; void main(void) { lowp vec4 pixel = texture2D(Texture, TexCoordOut); gl_FragColor = pixel; } Here is the main code body: #import "SERootViewController.h" #import <OpenGLES/ES2/gl.h> typedef struct { CGSize size; CGPoint percentage; GLuint id; } Texture; typedef struct { float Position[3]; float TexCoord[2]; } Vertex; size_t nextPowerOfTwo(size_t n) { size_t po2 = 2; while(po2<n) { po2 = po2*2; } return po2; } const GLubyte Indices[] = { 0, 1, 2, 2, 3, 0 }; #interface SERootViewController () { EAGLContext *_context; //OpenGL GLuint _vertexBufferHandle; GLuint _indexBufferHandle; GLuint _vertexShaderHandle; GLuint _fragmentShaderHandle; GLuint _programHandle; GLuint _positionHandle; GLuint _texCoordHandle; GLuint _textureHandle; GLuint _screenSizeHandle; GLuint _fbo; GLuint _fboTexture; Texture _imageTexture; GLfloat _defaultScale; Vertex *_vertices; CGSize _screenSize; //Cocoa UIImageView *_imageView; } #end #implementation SERootViewController ////////////////////////////////////////////////////////////////////////// #pragma mark - #pragma mark Lifecycle ////////////////////////////////////////////////////////////////////////// - (id)init { if ( (self = [super init]) != nil) { _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; _vertices = malloc(sizeof(Vertex) * 4); } return self; } - (void)viewDidLoad { [super viewDidLoad]; [self __setupFrameBuffer]; [self __setupShaders]; CGSize size = CGSizeMake(512, 512); [self __setScreenSize:size]; UIImage *image = [UIImage imageNamed:#"christmas.jpg"]; GLubyte *bytes = [self __bytesFromImage:image]; _imageTexture = [self __newTexture:bytes size:image.size]; free(bytes); [self __setupVBOs:_imageTexture screenSize:size]; [self __renderTexture:_imageTexture]; [self __bindFrameBuffer]; GLubyte *imageBytes = [self __renderImage:size]; UIImage *newImage = [self __imageFromBytes:imageBytes size:size]; free(imageBytes); _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; _imageView.image = newImage; _imageView.contentMode = UIViewContentModeScaleAspectFit; [self.view addSubview:_imageView]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } ////////////////////////////////////////////////////////////////////////// #pragma mark - #pragma mark Methods ////////////////////////////////////////////////////////////////////////// - (void)__setScreenSize:(CGSize)screenSize { _screenSize = screenSize; glUniform2f(_screenSizeHandle, _screenSize.width, _screenSize.height); } - (void)__setupFrameBuffer { glGenFramebuffers(1, &_fbo); glBindFramebuffer(GL_FRAMEBUFFER, _fbo); glActiveTexture(GL_TEXTURE0); glGenTextures(1, &_fboTexture); glBindTexture(GL_TEXTURE_2D, _fboTexture); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _fboTexture, 0); } - (void)__bindFrameBuffer { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _fboTexture); glBindFramebuffer(GL_FRAMEBUFFER, _fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _fboTexture, 0); } - (GLuint) __compileShader:(NSString *)shaderStr type:(GLenum) type { const char *str = shaderStr.UTF8String; int shaderStrLength = strlen(str); GLuint shaderHandle = glCreateShader(type); glShaderSource(shaderHandle, 1, &str, &shaderStrLength); glCompileShader(shaderHandle); GLint compileSuccess; glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess); if (compileSuccess == GL_FALSE) { GLchar messages[512]; glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); NSLog(#"Shader Error: %s", messages); } return shaderHandle; } - (void)__setupVBOs:(Texture)texture screenSize:(CGSize)screenSize { glDeleteBuffers(1, &_vertexBufferHandle); glDeleteBuffers(1, &_indexBufferHandle); _defaultScale = MIN( (screenSize.height/texture.size.height), (screenSize.width/texture.size.width) ); GLfloat width = texture.size.width*_defaultScale; GLfloat height = texture.size.height*_defaultScale; Vertex vertices[] = {{{ width/2, height/2, 0}, {texture.percentage.x, texture.percentage.y}}, {{ width/2, 0, 0}, {texture.percentage.x, 0}}, {{0, 0, 0}, {0, 0}}, {{0, height/2, 0}, {0, texture.percentage.y}} }; memcpy(_vertices, vertices, sizeof(vertices)); glGenBuffers(1, &_vertexBufferHandle); glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferHandle); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), _vertices, GL_STATIC_DRAW); glGenBuffers(1, &_indexBufferHandle); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferHandle); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW); } - (void) __setupShaders { NSString *vertexFilePath = [[NSBundle mainBundle] pathForResource:#"vertexShader" ofType:#"glsl"]; NSString *vertexShader = [NSString stringWithContentsOfFile:vertexFilePath encoding:NSUTF8StringEncoding error:nil]; NSString *fragmentFilePath = [[NSBundle mainBundle] pathForResource:#"fragmentShader" ofType:#"glsl"]; NSString *fragmentShader = [NSString stringWithContentsOfFile:fragmentFilePath encoding:NSUTF8StringEncoding error:nil]; _vertexShaderHandle = [self __compileShader:vertexShader type:GL_VERTEX_SHADER]; _fragmentShaderHandle = [self __compileShader:fragmentShader type:GL_FRAGMENT_SHADER]; _programHandle = glCreateProgram(); glAttachShader(_programHandle, _vertexShaderHandle); glAttachShader(_programHandle, _fragmentShaderHandle); glLinkProgram(_programHandle); GLint linkSuccess; glGetProgramiv(_programHandle, GL_LINK_STATUS, &linkSuccess); if (linkSuccess == GL_FALSE) { GLchar messages[512]; glGetProgramInfoLog(_programHandle, sizeof(messages), 0, &messages[0]); NSLog(#"GLSL ERROR: %s", messages); } glUseProgram(_programHandle); _positionHandle = glGetAttribLocation(_programHandle, "Position"); _texCoordHandle = glGetAttribLocation(_programHandle, "TexCoordIn"); _screenSizeHandle = glGetUniformLocation(_programHandle, "ScreenSize"); _textureHandle = glGetUniformLocation(_programHandle, "Texture"); glEnableVertexAttribArray(_positionHandle); glEnableVertexAttribArray(_texCoordHandle); } - (Texture)__newTexture:(void *)bytes size:(CGSize)size { Texture texture; size_t wpo2 = nextPowerOfTwo(size.width); size_t hpo2 = nextPowerOfTwo(size.height); texture.size = size; texture.percentage = CGPointMake((float)size.width / (float)wpo2, (float)size.height / (float)hpo2); void * texData = (GLubyte *) malloc(wpo2*hpo2*4*sizeof(GLubyte)); memset(texData, 1, sizeof(GLubyte)*size.width*4); for(GLuint i=0;i<size.height;i++) { memcpy(&texData[wpo2*i*4], &bytes[(int)size.width*i*4], sizeof(GLubyte)*(int)size.width*4); } glActiveTexture(GL_TEXTURE1); glGenTextures(1, &texture.id); glBindTexture(GL_TEXTURE_2D, texture.id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)wpo2, (GLsizei)hpo2, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData); free(texData); return texture; } -(void) __renderTexture:(Texture) texture { glClearColor(0.0f, 0.5, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glVertexAttribPointer(_positionHandle, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); glVertexAttribPointer(_texCoordHandle, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3)); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture.id); glUniform1i(_textureHandle, 1); glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]),GL_UNSIGNED_BYTE, 0); } - (GLubyte *)__renderImage:(CGSize)size { GLubyte *image = malloc(size.width*size.height*4*sizeof(GLubyte)); glReadPixels(0, 0, size.width, size.height, GL_RGBA, GL_UNSIGNED_BYTE, image); return image; } - (GLubyte *)__bytesFromImage:(UIImage *)image { GLint maxTextureSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); CGFloat maxSize = MAX(image.size.width, image.size.height); CGFloat width = image.size.width; CGFloat height = image.size.height; if (maxSize > maxTextureSize) { CGFloat scale = maxTextureSize/maxSize; width = roundf(width*scale); height = roundf(height*scale); } CGImageRef spriteImage = image.CGImage; if (!spriteImage) { NSLog(#"Failed to load image"); exit(1); } GLubyte * imgData = (GLubyte *) malloc(width*height*4*sizeof(GLubyte)); CGContextRef spriteContext = CGBitmapContextCreate(imgData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), (CGBitmapInfo)kCGImageAlphaPremultipliedLast); UIGraphicsPushContext(spriteContext); CGContextSaveGState(spriteContext); [image drawInRect:CGRectMake(0, 0, width, height)]; CGContextRestoreGState(spriteContext); UIGraphicsPopContext(); CGContextRelease(spriteContext); return imgData; } - (UIImage *)__imageFromBytes:(GLubyte *)bytes size:(CGSize)size { CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, bytes, (size.width * size.height * 4), NULL); // set up for CGImage creation int bitsPerComponent = 8; int bitsPerPixel = 32; int bytesPerRow = 4 * size.width; CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault; CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; CGImageRef imageRef = CGImageCreate(size.width, size.height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); // make UIImage from CGImage UIImage *newUIImage = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); return newUIImage; } #end
Vertex buffer object interfering with texture in OpenGL ES 2.0
I am using IOS 6.1, trying to draw a texture and a vertex buffer object. I setup a texture like this: typedef struct{ CGPoint geometryVertex; CGPoint textureVertex; } TexturedVertex; typedef struct { TexturedVertex bl; TexturedVertex br; TexturedVertex tl; TexturedVertex tr; } TexturedQuad; NSError *error; NSString *path = [[NSBundle mainBundle] pathForResource:#"img.png" ofType:nil]; NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], GLKTextureLoaderOriginBottomLeft, nil]; self.textureInfo = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error]; TexturedQuad quad; quad.bl.geometryVertex = CGPointMake(0, 0); quad.br.geometryVertex = CGPointMake(self.textureInfo.width, 0); quad.tl.geometryVertex = CGPointMake(0, self.textureInfo.height); quad.tr.geometryVertex = CGPointMake(self.textureInfo.width, self.textureInfo.height); quad.bl.textureVertex = CGPointMake(0, 0); quad.br.textureVertex = CGPointMake(1, 0); quad.tl.textureVertex = CGPointMake(0, 1); quad.tr.textureVertex = CGPointMake(1, 1); self.quad = quad; glClearColor(0, 0, 0, 0.5); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnableVertexAttribArray(GLKVertexAttribPosition); glEnableVertexAttribArray(GLKVertexAttribTexCoord0); Then draw it like this: - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { glClear(GL_COLOR_BUFFER_BIT); self.baseEffect.texture2d0.name = self.textureInfo.name; self.baseEffect.transform.modelviewMatrix = [self modelMatrix]; [self.baseEffect prepareToDraw]; long offset = (long)&_quad; glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)(offset + offsetof(TexturedVertex, geometryVertex))); glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)(offset + offsetof(TexturedVertex, textureVertex))); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } That all works, no problem. What I want to do next though is draw another object stored in a vertex buffer object that isn't a texture. So I add this to the setup code: typedef struct { float Position[3]; } Vertex; const Vertex Vertices[] = { {100, -100, 0}, {100, 100, 0}, {-100, 100, 0}, {-100, -100, 0} }; GLuint _vertexBuffer; glGenBuffers(1, &_vertexBuffer); // (1) glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); // (2) glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW); // (3) But even without trying to draw the new object, those lines crash my app. I have found that with just line (1) it doesn't crash. With (1) + (2) it still doesn't crash but profiling with Instruments tells me the draw call for the texture 'Exceeded array buffer bounds' and used 'Uninitialized buffer data', although it still draws the texture just fine. Adding line (3) causes the app to crash and Instruments to tell me there is no GL data. Does anyone know why this is happening?
The VBO was apparently interfering with the call to glVertexAttribPointer. Unbinding it like so stopped the crash: - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { glClear(GL_COLOR_BUFFER_BIT); self.baseEffect.texture2d0.name = self.textureInfo.name; self.baseEffect.transform.modelviewMatrix = [self modelMatrix]; [self.baseEffect prepareToDraw]; glBindBuffer(GL_ARRAY_BUFFER, 0); long offset = (long)&_quad; glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)(offset + offsetof(TexturedVertex, geometryVertex))); glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *)(offset + offsetof(TexturedVertex, textureVertex))); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } The texture as it is doesn't use a VBO so there shouldn't be one bound when the glVertexAttribPointer call is made.
yv12 to rgb using glsl in iOS ,result image attached
referred to this question i convert the yv12 frame data to rgb data using glsl shader,the raw image below: but the result image is not same with the former,attached below: following is my code for uploading the three planar data to textures: - (GLuint) textureY: (Byte*)imageData widthType: (int) width heightType: (int) height { GLuint texName; glGenTextures( 1, &texName ); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData ); //free(imageData); return texName; } - (GLuint) textureU: (Byte*)imageData widthType: (int) width heightType: (int) height { GLuint texName; glGenTextures( 1, &texName ); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData ); //free(imageData); return texName; } - (GLuint) textureV: (Byte*)imageData widthType: (int) width heightType: (int) height { GLuint texName; glGenTextures( 1, &texName ); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData ); //free(imageData); return texName; } - (void) readYUVFile { NSString *file = [[NSBundle mainBundle] pathForResource:#"video" ofType:#"yv12"]; NSLog(#"%#",file); NSData* fileData = [NSData dataWithContentsOfFile:file]; //NSLog(#"%#",[fileData description]); NSInteger width = 352; NSInteger height = 288; NSInteger uv_width = width / 2; NSInteger uv_height = height / 2; NSInteger dataSize = [fileData length]; NSLog(#"%i\n",dataSize); GLint nYsize = width * height; GLint nUVsize = uv_width * uv_height; GLint nCbOffSet = nYsize; GLint nCrOffSet = nCbOffSet + nUVsize; Byte *spriteData = (Byte *)malloc(dataSize); [fileData getBytes:spriteData length:dataSize]; Byte* uData = spriteData + nCbOffSet; //NSLog(#"%#\n",[[NSData dataWithBytes:uData length:nUVsize] description]); Byte* vData = spriteData + nCrOffSet; //NSLog(#"%#\n",[[NSData dataWithBytes:vData length:nUVsize] description]); /** Byte *YPlanarData = (Byte *)malloc(nYsize); for (int i=0; i<nYsize; i++) { YPlanarData[i]= spriteData[i]; } Byte *UPlanarData = (Byte *)malloc(nYsize); for (int i=0; i<height; i++) { for (int j=0; j<width; j++) { int numInUVsize = (i/2)*uv_width+j/2; UPlanarData[i*width+j]=uData[numInUVsize]; } } Byte *VPlanarData = (Byte *)malloc(nYsize); for (int i=0; i<height; i++) { for (int j=0; j<width; j++) { int numInUVsize = (i/2)*uv_width+j/2; VPlanarData[i*width+j]=vData[numInUVsize]; } } **/ _YPlanarTexture = [self textureY:spriteData widthType:width heightType:height]; _UPlanarTexture = [self textureU:uData widthType:uv_width heightType:uv_height]; _VPlanarTexture = [self textureV:vData widthType:uv_width heightType:uv_height]; free(spriteData); } and my fragment shaders code: precision highp float; uniform sampler2D SamplerY; uniform sampler2D SamplerU; uniform sampler2D SamplerV; varying highp vec2 coordinate; void main() { highp vec3 yuv,yuv1; highp vec3 rgb; yuv.x = texture2D(SamplerY, coordinate).r; yuv.y = texture2D(SamplerU, coordinate).r-0.5; yuv.z = texture2D(SamplerV, coordinate).r-0.5 ; rgb = mat3( 1, 1, 1, 0, -.34414, 1.772, 1.402, -.71414, 0) * yuv; gl_FragColor = vec4(rgb, 1); } my confusion is the conversion formula while i using this formula directly converting the yv12 data to rgb24,and draw a image with the CGImageCreate(iwidth, iheight, 8, 24, iwidth*3, colorSpace, bitmapInfo, provider, NULL, NO, kCGRenderingIntentDefault); the result image is correct. but using the shader (for the direct transform approach running on iOS device is dump) turns to this problem ,i've tried some tricks(expand the UV planers to (2*uv_width)*2(uv_height) rectangle and then upload the texture),but failed in the same more red image. How to resolve this issue? attached with my whole glView.m code: #import "OpenGLView.h" typedef struct { float Position[3]; float TexCoord[2]; } Vertex; const Vertex Vertices[] = { {{1, -1, 0},{1,1}}, {{1, 1, 0},{1,0}}, {{-1, 1, 0},{0,0}}, {{-1, -1, 0},{0,1}} }; const GLubyte Indices[] = { 0, 1, 2, 2, 3, 0 }; #interface OpenGLView () - (void)setupLayer; - (void)setupContext; - (void)setupRenderBuffer; - (void)setupFrameBuffer; - (void)render; - (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType; - (void)setupVBOs; - (void)compileShaders; - (void) readYUVFile; #end #implementation OpenGLView - (void)setupVBOs { GLuint vertexBuffer; glGenBuffers(1, &vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW); GLuint indexBuffer; glGenBuffers(1, &indexBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW); } - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // Initialization code[] self.backgroundColor = [UIColor redColor]; [self setupLayer]; [self setupContext]; [self setupRenderBuffer]; [self setupFrameBuffer]; [self setupVBOs]; [self compileShaders]; [self readYUVFile]; [self render]; } return self; } + (Class)layerClass{ return [CAEAGLLayer class]; } -(void)setupLayer{ _eaglLayer = (CAEAGLLayer *)self.layer; _eaglLayer.opaque = YES; } - (void)setupContext{ EAGLRenderingAPI api = kEAGLRenderingAPIOpenGLES2; _context = [[[EAGLContext alloc] initWithAPI:api] autorelease]; if (!_context) { NSLog(#"Failed to initialize OpenGLES 2.0 context"); exit(1); } if (![EAGLContext setCurrentContext:_context]) { NSLog(#"Failed to set current OpenGL context"); exit(1); } } - (void)setupRenderBuffer { glGenRenderbuffers(1, &_colorRenderBuffer); glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer); [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer]; } - (void)setupFrameBuffer { GLuint framebuffer; glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer); } - (GLuint) textureY: (Byte*)imageData widthType: (int) width heightType: (int) height { GLuint texName; glGenTextures( 1, &texName ); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData ); //free(imageData); return texName; } - (GLuint) textureU: (Byte*)imageData widthType: (int) width heightType: (int) height { GLuint texName; glGenTextures( 1, &texName ); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D( GL_TEXTURE_2D, 0, GL_RED_EXT, width, height, 0, GL_RED_EXT, GL_UNSIGNED_BYTE, imageData ); //free(imageData); return texName; } - (GLuint) textureV: (Byte*)imageData widthType: (int) width heightType: (int) height { GLuint texName; glGenTextures( 1, &texName ); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D( GL_TEXTURE_2D, 0, GL_RED_EXT, width, height, 0, GL_RED_EXT, GL_UNSIGNED_BYTE, imageData ); //free(imageData); return texName; } - (void) readYUVFile { NSString *file = [[NSBundle mainBundle] pathForResource:#"video" ofType:#"yv12"]; NSLog(#"%#",file); NSData* fileData = [NSData dataWithContentsOfFile:file]; //NSLog(#"%#",[fileData description]); NSInteger width = 352; NSInteger height = 288; NSInteger uv_width = width / 2; NSInteger uv_height = height / 2; NSInteger dataSize = [fileData length]; NSLog(#"%i\n",dataSize); GLint nYsize = width * height; GLint nUVsize = uv_width * uv_height; GLint nCbOffSet = nYsize; GLint nCrOffSet = nCbOffSet + nUVsize; Byte *spriteData = (Byte *)malloc(dataSize); [fileData getBytes:spriteData length:dataSize]; Byte* uData = spriteData + nCbOffSet; //NSLog(#"%#\n",[[NSData dataWithBytes:uData length:nUVsize] description]); Byte* vData = spriteData + nCrOffSet; //NSLog(#"%#\n",[[NSData dataWithBytes:vData length:nUVsize] description]); Byte *YPlanarData = (Byte *)malloc(nYsize); for (int i=0; i<nYsize; i++) { YPlanarData[i]= spriteData[i]; } Byte *UPlanarData = (Byte *)malloc(nYsize); for (int i=0; i<height; i++) { for (int j=0; j<width; j++) { int numInUVsize = (i/2)*uv_width+j/2; UPlanarData[i*width+j]=uData[numInUVsize]; } } Byte *VPlanarData = (Byte *)malloc(nYsize); for (int i=0; i<height; i++) { for (int j=0; j<width; j++) { int numInUVsize = (i/2)*uv_width+j/2; VPlanarData[i*width+j]=vData[numInUVsize]; } } _YPlanarTexture = [self textureY:YPlanarData widthType:width heightType:height]; _UPlanarTexture = [self textureU:UPlanarData widthType:width heightType:height]; _VPlanarTexture = [self textureV:VPlanarData widthType:width heightType:height]; free(spriteData); } - (void)render { glClearColor(0,0,0 , 1.0); glClear(GL_COLOR_BUFFER_BIT); // 1 glViewport(0, 200, self.frame.size.width, 558); // 2 glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) *3)); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _YPlanarTexture); glUniform1i(_textureUniformY, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _UPlanarTexture); glUniform1i(_textureUniformU, 1); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, _VPlanarTexture); glUniform1i(_textureUniformV, 2); // 3 glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0); [_context presentRenderbuffer:GL_RENDERBUFFER]; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. - (void)drawRect:(CGRect)rect { // Drawing code } */ - (GLuint)compileShader:(NSString*)shaderName withType:(GLenum)shaderType { // 1 NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:#"glsl"]; NSError* error; NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error]; if (!shaderString) { NSLog(#"Error loading shader: %#", error.localizedDescription); exit(1); } // 2 GLuint shaderHandle = glCreateShader(shaderType); // 3 const char* shaderStringUTF8 = [shaderString UTF8String]; int shaderStringLength = [shaderString length]; glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength); // 4 glCompileShader(shaderHandle); // 5 GLint compileSuccess; glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess); if (compileSuccess == GL_FALSE) { GLchar messages[256]; glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); NSString *messageString = [NSString stringWithUTF8String:messages]; NSLog(#"%#", messageString); exit(1); } return shaderHandle; } - (void)compileShaders { // 1 GLuint vertexShader = [self compileShader:#"SimpleVertex" withType:GL_VERTEX_SHADER]; GLuint fragmentShader = [self compileShader:#"SimpleFragment" withType:GL_FRAGMENT_SHADER]; // 2 GLuint programHandle = glCreateProgram(); glAttachShader(programHandle, vertexShader); glAttachShader(programHandle, fragmentShader); glLinkProgram(programHandle); // 3 GLint linkSuccess; glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); if (linkSuccess == GL_FALSE) { GLchar messages[256]; glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]); NSString *messageString = [NSString stringWithUTF8String:messages]; NSLog(#"%#", messageString); exit(1); } // 4 glUseProgram(programHandle); // 5 _positionSlot = glGetAttribLocation(programHandle, "position"); glEnableVertexAttribArray(_positionSlot); _texCoordSlot = glGetAttribLocation(programHandle, "textureCoordinate"); glEnableVertexAttribArray(_texCoordSlot); _YPlanarTexture = glGetUniformLocation(programHandle, "SamplerY"); _UPlanarTexture = glGetUniformLocation(programHandle, "SamplerU"); _VPlanarTexture = glGetUniformLocation(programHandle, "SamplerV"); } #end
my foolish mistake,the three uploading-texture process and fragment shader are correct ,but the following code are not compatible: glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, _YPlanarTexture); glUniform1i(_textureUniformY, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _UPlanarTexture); glUniform1i(_textureUniformU, 1); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, _VPlanarTexture); glUniform1i(_textureUniformV, 2); and below: _YPlanarTexture = glGetUniformLocation(programHandle, "SamplerY"); _UPlanarTexture = glGetUniformLocation(programHandle, "SamplerU"); _VPlanarTexture = glGetUniformLocation(programHandle, "SamplerV"); so replace with this: _textureUniformY = glGetUniformLocation(programHandle, "SamplerY"); _textureUniformU = glGetUniformLocation(programHandle, "SamplerU"); _textureUniformV = glGetUniformLocation(programHandle, "SamplerV"); then it will do right thing .