简介:我是 OpenGL 的新手。我首先在我的 PC 上熟悉 OpenGL 上的纹理映射和基本转换/翻译。现在看来我基本上是在重新学习一切,因为我试图使用 GLKit(GLKView 项目模板帮助很大)创建一个带有 PNG 纹理的简单多边形(四边形)。
事情是这样的:使用 GLKBasicEffect 渲染方式,使用项目模板的开箱即用实现,我实际上能够非常快速地启动和运行。但是,我在过去 24 小时内阅读了很多关于忽略这条路线并采用“OpenGL ES2”方式的建议。我对此的一般想法基本上是:固定流水线与可编程流水线。任何。
问题:使用“ES2”方法时,我可以看到我的四边形,但我无法在其上应用纹理。
问题:有人知道我可以遵循的简单教程/示例吗?或者更好的是,有人能弄清楚我做错了什么吗?
* 插入更新评论 *
我发现由于我的 openGL 设置中的两件事而引发了 glError:我正在调用 glEnable(GL_TEXTURE_2D) 和 glEnableClientState(GL_TEXTURE_COORD_ARRAY)。如果没有这些,我该如何启用纹理映射?或者也许某个地方有更大的错误?仅供参考,我正在使用 Opengl ES2。
* 更新插入结束 *
我的 ViewController 文件在下面。
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
// Uniform index.
enum
{
UNIFORM_MODELVIEWPROJECTION_MATRIX,
UNIFORM_NORMAL_MATRIX,
NUM_UNIFORMS
};
GLint uniforms[NUM_UNIFORMS];
// Attribute index.
enum
{
ATTRIB_VERTEX,
ATTRIB_NORMAL,
NUM_ATTRIBUTES
};
BOOL updateRotate = FALSE;
VertexData *p_meshVertexData = nil;
int g_numFaces = 0;
GLuint g_textures[2]; // 0: photo, 1: picture frame.
const int DataSize = 48;
GLfloat PortraitVertexData[DataSize] =
{
// CCW
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0,1,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0,0,
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1,0,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0,1,
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1,0,
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1,1,
};
@interface ViewController () {
GLuint _program;
GLKMatrix4 _modelViewProjectionMatrix;
GLKMatrix3 _normalMatrix;
float _rotation;
GLuint _vertexArray;
GLuint _vertexBuffer;
}
@property (strong, nonatomic) EAGLContext *context;
//@property (strong, nonatomic) GLKBaseEffect *effect;
@property (strong, nonatomic) GLKTextureInfo *texture;
@property (nonatomic, retain) CaptureEngine *engine;
- (void)setupGL;
- (void)tearDownGL;
- (BOOL)loadShaders;
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file;
- (BOOL)linkProgram:(GLuint)prog;
- (BOOL)validateProgram:(GLuint)prog;
@end
@implementation ViewController
@synthesize context = _context;
//@synthesize effect = _effect;
@synthesize texture = _texture;
@synthesize engine;
/// View did load.
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(@"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
[self initEngine];
[self setupGL];
}
/// Initialize engine object.
- (void) initEngine
{
self.engine = [[CaptureEngine alloc] init];
g_numFaces = DataSize / 8;
p_meshVertexData = (VertexData *)malloc(g_numFaces * sizeof(VertexData));
int numIndex = 0;
for (int i = 0; i < DataSize; i += 8)
{
float x = PortraitVertexData[i];
float y = PortraitVertexData[i + 1];
float z = PortraitVertexData[i + 2];
float nx = PortraitVertexData[i + 3];
float ny = PortraitVertexData[i + 4];
float nz = PortraitVertexData[i + 5];
float tx = PortraitVertexData[i + 6];
float ty = PortraitVertexData[i + 7];
VertexData data;
data.vertex.x = x;
data.vertex.y = y;
data.vertex.z = z;
data.normal.x = nx;
data.normal.y = ny;
data.normal.z = nz;
data.textureCoord.x = tx;
data.textureCoord.y = ty;
p_meshVertexData[numIndex++] = data;
}
// UIImage *testImage = [UIImage imageNamed:@"frame.png"];
// self.previewImage.image = [ImageLoader ConvertToGrayedImage:testImage];
}
// Dealloc.
- (void)dealloc
{
[self tearDownGL];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
}
// Memory warning.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
if ([self isViewLoaded] && ([[self view] window] == nil)) {
self.view = nil;
[self tearDownGL];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
self.context = nil;
}
// Dispose of any resources that can be recreated.
}
// Setup OpenlGL.
- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
[self loadShaders];
/*
self.effect = [[GLKBaseEffect alloc] init];
self.effect.light0.enabled = GL_TRUE;
self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 0.5f);
self.effect.lightingType = GLKLightingTypePerPixel;
*/
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData) * g_numFaces, p_meshVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), 0);
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char *)12);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char *)24);
//// texture sample
/*
glActiveTexture(GL_TEXTURE0);
NSString *path = [[NSBundle mainBundle] pathForResource:@"frame" ofType:@"png"];
NSError *error;
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:GLKTextureLoaderOriginBottomLeft];
self.texture = [GLKTextureLoader textureWithContentsOfFile:path
options:options error:&error];
if (self.texture == nil)
NSLog(@"Error loading texture: %@", [error localizedDescription]);
*/
/*
GLKEffectPropertyTexture *tex = [[GLKEffectPropertyTexture alloc] init];
tex.enabled = YES;
tex.envMode = GLKTextureEnvModeDecal;
tex.name = self.texture.name;
self.effect.texture2d0.name = tex.name;
*/
UIImage *textureImage = [UIImage imageNamed:@"frame.png"];
[self ApplyTexture: textureImage];
//// end of texture sample
glBindVertexArrayOES(0);
}
// Dealloc OpenlGL.
- (void)tearDownGL
{
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteVertexArraysOES(1, &_vertexArray);
//self.effect = nil;
if (_program)
{
glDeleteProgram(_program);
_program = 0;
}
}
#pragma mark - GLKView and GLKViewController delegate methods
// Update process.
- (void)update
{
/// Default OpenGL project template (2 cubes) ///
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(60.0f), aspect, 0.1f, 100.0f);
//self.effect.transform.projectionMatrix = projectionMatrix;
GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -2.0f);
baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, _rotation, 0.0f, 1.0f, 0.0f);
/*
// Compute the model view matrix for the object rendered with GLKit
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 0.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 0, 1.0f, 0);
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);
self.effect.transform.modelviewMatrix = modelViewMatrix;
*/
// Compute the model view matrix for the object rendered with ES2
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0, 0, 0);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 0, 1.0f, 0);
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);
_normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
_modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
if (updateRotate)
{
_rotation += self.timeSinceLastUpdate * 0.5f;
}
}
// Render process.
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(1, 1, 1, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArrayOES(_vertexArray);
/*
// Render the object with GLKit
[self.effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, g_numFaces);
*/
// Render the object again with ES2
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, g_numFaces);
}
- (int) ApplyTexture:(UIImage *)image
{
// 1
CGImageRef spriteImage = image.CGImage;
if (!spriteImage)
{
NSLog(@"Failed to apply texture.");
return -1;
}
// 2
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width * width * 4, sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData,
width,
width,
8,
width * 4,
CGImageGetColorSpace(spriteImage),
kCGImageAlphaPremultipliedLast);
// 3
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
// 4
glGenTextures(1, &g_textures[0]);
glBindTexture(GL_TEXTURE_2D, g_textures[0]);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
// glEnableClientState(GL_TEXTURE_COORD_ARRAY);
CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(spriteImage));
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, width, 0, GL_RGBA,
GL_UNSIGNED_BYTE, CFDataGetBytePtr(data));
free(spriteData);
return 0;
}
#pragma mark - OpenGL ES 2 shader compilation
- (BOOL)loadShaders
{
GLuint vertShader, fragShader;
NSString *vertShaderPathname, *fragShaderPathname;
// Create shader program.
_program = glCreateProgram();
// Create and compile vertex shader.
vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
NSLog(@"Failed to compile vertex shader");
return NO;
}
// Create and compile fragment shader.
fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
NSLog(@"Failed to compile fragment shader");
return NO;
}
// Attach vertex shader to program.
glAttachShader(_program, vertShader);
// Attach fragment shader to program.
glAttachShader(_program, fragShader);
// Bind attribute locations.
// This needs to be done prior to linking.
glBindAttribLocation(_program, GLKVertexAttribPosition, "position");
glBindAttribLocation(_program, GLKVertexAttribNormal, "normal");
// Link program.
if (![self linkProgram:_program]) {
NSLog(@"Failed to link program: %d", _program);
if (vertShader) {
glDeleteShader(vertShader);
vertShader = 0;
}
if (fragShader) {
glDeleteShader(fragShader);
fragShader = 0;
}
if (_program) {
glDeleteProgram(_program);
_program = 0;
}
return NO;
}
// Get uniform locations.
uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix");
uniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, "normalMatrix");
// Release vertex and fragment shaders.
if (vertShader) {
glDetachShader(_program, vertShader);
glDeleteShader(vertShader);
}
if (fragShader) {
glDetachShader(_program, fragShader);
glDeleteShader(fragShader);
}
return YES;
}
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
GLint status;
const GLchar *source;
source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
if (!source) {
NSLog(@"Failed to load vertex shader");
return NO;
}
*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;
}