2012-07-19 156 views
3

我想让我的纹理显示在基本的OpenGL视图(UIView的子类)中,但无论使用哪种纹理,它都显示为黑色。对于我的视图中的代码如下:OpenGL ES 2.0纹理映射,但显示为黑色

@implementation SymGLView 

typedef struct { 
    float Position[3]; 
    float Color[4]; 
    float TexCoord[2]; 
} Vertex; 

const Vertex Vertices[] = { 
    {{1, -1, 0}, {1, 0, 0, 1}, {0, 0}}, 
    {{1, 1, 0}, {0, 1, 0, 1}, {0, 1}}, 
    {{-1, 1, 0}, {0, 0, 1, 1}, {1, 1}}, 
    {{-1, -1, 0}, {0, 0, 0, 1}, {1, 0}} 
}; 

const GLubyte Indices[] = { 
    0, 1, 2, 
    2, 3, 0 
}; 

+ (Class)layerClass { 
    return [CAEAGLLayer class]; 
} 

- (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 {  
    GLuint framebuffer; 
    glGenFramebuffers(1, &framebuffer); 
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer); 
} 

- (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 { 

    GLuint vertexShader = [self compileShader:@"SimpleVertex" withType:GL_VERTEX_SHADER]; 
    GLuint fragmentShader = [self compileShader:@"SimpleFragment" 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); 
     exit(1); 
    } 

    glUseProgram(programHandle); 

    _positionSlot = glGetAttribLocation(programHandle, "Position"); 
    _colorSlot = glGetAttribLocation(programHandle, "SourceColor"); 
    glEnableVertexAttribArray(_positionSlot); 
    glEnableVertexAttribArray(_colorSlot); 

    _modelViewUniform = glGetUniformLocation(programHandle, "Modelview"); 

    _texCoordSlot = glGetAttribLocation(programHandle, "TexCoordIn"); 
    glEnableVertexAttribArray(_texCoordSlot); 
    _textureUniform = glGetUniformLocation(programHandle, "Texture"); 
} 

- (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); 

} 

- (void)render { 
    glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0); 
    glClear(GL_COLOR_BUFFER_BIT); 

    glViewport(0, 0, self.frame.size.width, self.frame.size.height); 

    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, _floorTexture); 
    glUniform1i(_textureUniform, 0);  

    glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), 
        GL_UNSIGNED_BYTE, 0);  

    [_context presentRenderbuffer:GL_RENDERBUFFER]; 
} 


- (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_NEAREST); 

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, spriteData); 

    free(spriteData); 

    return texName;  
} 


- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 

    if (self) {   
     [self setupLayer];   
     [self setupContext];  
     [self setupDepthBuffer]; 
     [self setupRenderBuffer];   
     [self setupFrameBuffer];  
     [self compileShaders]; 
     [self setupVBOs]; 
     [self render];   
    } 
    _floorTexture = [self setupTexture:@"tile_floor.png"]; 
    return self; 
} 


@end 

顶点着色器:

attribute vec4 Position; 

attribute vec2 TexCoordIn; 
varying vec2 TexCoordOut; 

void main(void) { 
    gl_Position = Position; 
    TexCoordOut = TexCoordIn; 
} 

片段着色器:

varying lowp vec2 TexCoordOut; 
uniform sampler2D Texture; 

void main(void) { 
    gl_FragColor = texture2D(Texture, TexCoordOut); 
} 

我可以通过改变值gl_FragColor产生梯度,但我已经尝试了几种不同的纹理,并且无所适从。

+0

如果你不使用着色器,纹理是否可以粘贴?我试图确定问题是在纹理还是纹理的显示中。 – 2012-07-23 07:29:54

回答

5

这可能是取决于一个事实,即你的纹理不是2(即512×512)的功率

某些OpenGL驱动程序以怪异的方式对此做出何种反应,有些则只是进行纹理的缩放到最近的电源2尺寸。

从OpenGL的黄金书,你可以找到如下:

你可以在OpenGL的黄金书显示,OpenGL ES 2.0的一个相当不错的解释:

在OpenGL ES 2.0的,纹理可以有非二次幂(npot) 尺寸。换句话说,宽度和高度不需要是2的幂。但是,如果纹理尺寸不是 两者的功率,则OpenGL ES 2.0对 包装模式有限制。也就是说,对于npot纹理,换行模式只能是 GL_CLAMP_TO_EDGE,而缩小过滤器只能是GL_NEAREST 或GL_LINEAR(换句话说,不是mip-mapped)。扩展名为 GL_OES_texture_npot放宽了这些限制,并允许使用GL_REPEAT和GL_MIRRORED_REPEAT的包装模式 ,并且还允许使用全套缩小过滤器对npot纹理进行mipmap。

我希望这会有所帮助。

干杯

+0

这很有帮助。在iOS上,texture2D()在与NPOT大小的纹理一起使用时会返回黑色,并且会使用除钳位之外的包装模式。 – 2014-08-19 19:46:34