Opengl ES png 纹理渲染为黑色
Open GL ES png texture rendering as black
我只是想将全屏 .png
作为纹理绘制到 openGL 中。但是,我遇到了黑屏。我的代码可以很好地处理 jpeg,所以我只能假设这是透明度问题。
这是一个 png 示例,它不适用于:http://cl.ly/e5x4(虽然它是不透明的,但仍然无法呈现)(不,它必须是 .png)
这是我的代码:
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);
}
很抱歉转储所有这些代码,但我不确定问题出在哪里。关于我做错了什么有什么想法吗?
这似乎是经典的非二次方问题(例如,参见 Android OpenGL2.0 showing black textures)。您链接的纹理是 1005x335。
OpenGL ES 2.0 规范只允许 NPOT 纹理 'complete' 和 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S/T, GL_CLAMP_TO_EDGE)
。各种扩展允许 NPOT 纹理,但是,您的设备不一定支持这些,如果您获得黑色纹理,则可能不支持。如果纹理不完整,则根据规范将其采样为黑色。
我只是想将全屏 .png
作为纹理绘制到 openGL 中。但是,我遇到了黑屏。我的代码可以很好地处理 jpeg,所以我只能假设这是透明度问题。
这是一个 png 示例,它不适用于:http://cl.ly/e5x4(虽然它是不透明的,但仍然无法呈现)(不,它必须是 .png)
这是我的代码:
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);
}
很抱歉转储所有这些代码,但我不确定问题出在哪里。关于我做错了什么有什么想法吗?
这似乎是经典的非二次方问题(例如,参见 Android OpenGL2.0 showing black textures)。您链接的纹理是 1005x335。
OpenGL ES 2.0 规范只允许 NPOT 纹理 'complete' 和 glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S/T, GL_CLAMP_TO_EDGE)
。各种扩展允许 NPOT 纹理,但是,您的设备不一定支持这些,如果您获得黑色纹理,则可能不支持。如果纹理不完整,则根据规范将其采样为黑色。