I am trying to get my texture to show up in a basic OpenGL view (subclass of UIView), but no matter which texture I use, it shows up black. The code for my view is as follows:
我试图让我的纹理显示在一个基本的OpenGL视图(UIView的子类)中,但是无论我使用哪个纹理,它都会显示为黑色。我的意见的代码如下:
@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
Vertex shader:
顶点着色器:
attribute vec4 Position;
attribute vec2 TexCoordIn;
varying vec2 TexCoordOut;
void main(void) {
gl_Position = Position;
TexCoordOut = TexCoordIn;
}
Fragment shader:
片段着色器:
varying lowp vec2 TexCoordOut;
uniform sampler2D Texture;
void main(void) {
gl_FragColor = texture2D(Texture, TexCoordOut);
}
I can create a gradient by changing the values for gl_FragColor, but I have tried several different textures and am at a loss.
我可以通过改变gl_FragColor的值来创建一个渐变,但是我已经尝试过几种不同的纹理,现在我不知所措。
1 个解决方案
#1
5
This could be depending on the fact that your textures are not power of 2 (i.e. 512X512)
这可能取决于你的材质不是2的力量(即512X512)
Some OpenGL drivers react in weird ways to this, some others just perform a rescaling of the textures to the nearest power of 2 size.
一些OpenGL驱动程序以奇怪的方式对此做出反应,另一些则只是将纹理缩小到2倍大小。
From OpenGL gold book you can find the below:
从OpenGL黄金书你可以找到以下:
You can find a quite good explanation in the OpenGL Gold Book, the OpenGL ES 2.0:
你可以在OpenGL黄金书OpenGL ES 2.0中找到一个很好的解释:
In OpenGL ES 2.0, textures can have non-power-of-two (npot) dimensions. In other words, the width and height do not need to be a power of two. However, OpenGL ES 2.0 does have a restriction on the wrap modes that can be used if the texture dimensions are not power of two. That is, for npot textures, the wrap mode can only be GL_CLAMP_TO_EDGE and the minifica- tion filter can only be GL_NEAREST or GL_LINEAR (in other words, not mip- mapped). The extension GL_OES_texture_npot relaxes these restrictions and allows wrap modes of GL_REPEAT and GL_MIRRORED_REPEAT and also allows npot textures to be mipmapped with the full set of minification filters.
在OpenGL ES 2.0中,纹理可以有两个(npot)维度。换句话说,宽度和高度不需要是2的幂。然而,OpenGL ES 2.0对于如果纹理尺寸不是2的幂,可以使用的包装模式是有限制的。也就是说,对于npot纹理,包装模式只能是GL_CLAMP_TO_EDGE,而minifica- tion过滤器只能是GL_NEAREST或GL_LINEAR(换句话说,不是mip- mapping)。扩展GL_OES_texture_npot可以放松这些限制,并允许使用GL_REPEAT和GL_MIRRORED_REPEAT的包装模式,并允许使用完整的迷你化过滤器将npot材质设置为mipmapped。
I hope this helps.
我希望这可以帮助。
Cheers
干杯
#1
5
This could be depending on the fact that your textures are not power of 2 (i.e. 512X512)
这可能取决于你的材质不是2的力量(即512X512)
Some OpenGL drivers react in weird ways to this, some others just perform a rescaling of the textures to the nearest power of 2 size.
一些OpenGL驱动程序以奇怪的方式对此做出反应,另一些则只是将纹理缩小到2倍大小。
From OpenGL gold book you can find the below:
从OpenGL黄金书你可以找到以下:
You can find a quite good explanation in the OpenGL Gold Book, the OpenGL ES 2.0:
你可以在OpenGL黄金书OpenGL ES 2.0中找到一个很好的解释:
In OpenGL ES 2.0, textures can have non-power-of-two (npot) dimensions. In other words, the width and height do not need to be a power of two. However, OpenGL ES 2.0 does have a restriction on the wrap modes that can be used if the texture dimensions are not power of two. That is, for npot textures, the wrap mode can only be GL_CLAMP_TO_EDGE and the minifica- tion filter can only be GL_NEAREST or GL_LINEAR (in other words, not mip- mapped). The extension GL_OES_texture_npot relaxes these restrictions and allows wrap modes of GL_REPEAT and GL_MIRRORED_REPEAT and also allows npot textures to be mipmapped with the full set of minification filters.
在OpenGL ES 2.0中,纹理可以有两个(npot)维度。换句话说,宽度和高度不需要是2的幂。然而,OpenGL ES 2.0对于如果纹理尺寸不是2的幂,可以使用的包装模式是有限制的。也就是说,对于npot纹理,包装模式只能是GL_CLAMP_TO_EDGE,而minifica- tion过滤器只能是GL_NEAREST或GL_LINEAR(换句话说,不是mip- mapping)。扩展GL_OES_texture_npot可以放松这些限制,并允许使用GL_REPEAT和GL_MIRRORED_REPEAT的包装模式,并允许使用完整的迷你化过滤器将npot材质设置为mipmapped。
I hope this helps.
我希望这可以帮助。
Cheers
干杯