OpenGL纹理初始化/渲染问题
Posted
技术标签:
【中文标题】OpenGL纹理初始化/渲染问题【英文标题】:Problem with OpenGL Texture Initialisation/Rendering 【发布时间】:2011-07-15 14:58:00 【问题描述】:我尝试使用创建纹理并存储其 ID 和大小(感谢 ADC 和另一个 *** 成员)的模型类渲染非 2 次幂纹理,以及创建 VBO 并渲染它的附加代码(代码VBO 和渲染是出于测试目的,在我的模型中正确划分)。
当我使用此代码但删除特定于纹理的代码时,它可以正常工作。然而,当添加纹理特定代码时,它只渲染我认为是右下角的像素,通过尝试多个复杂图像并使用 DigitalColor Meter 检查图像和输出。
我不认为在使用此设置时必须明确指定纹理坐标,如果这样做,我会怎么做?
主要的 OpenGL 代码
// Create vertex buffer
GLuint memoryPointer = 0;
GLuint colourMemoryPointer = 0;
GLfloat *vertices;
size_t vertex_size = 0;
int check = AllocateVertexBuffer(2, 4, &vertices, &vertex_size);
CDMeshVertexesCreateRectangle(200, 200, vertices);
// Create colour buffer
GLfloat *colors;
size_t color_size;
int check2 = AllocateVertexBuffer(4, 4, &colors, &color_size);
CDMeshColorsCreateGrey(1.0, 4, colors);
// Create texture buffer
CDTexture *texture = [CDTexture loadPngTexture:@"Rawr"];
// Allocate the buffer
glGenBuffers(1, &memoryPointer);
// Bind the buffer object (tell OpenGL what to use)
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
// Allocate space for the VBO
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW);
// Allocate the buffer
glGenBuffers(1, &colourMemoryPointer);
// Bind the buffer object (tell OpenGL what to use)
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
// Allocate space for the VBO
glBufferData(GL_ARRAY_BUFFER, color_size, colors, GL_STATIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY); // Activate vertex coordinates array
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture.ID);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
//[texture render];
//render
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY); // Deactivate vertex coordinates array
glDisableClientState(GL_COLOR_ARRAY);
free(vertices);
free(colors);
CDTexture loadPngTexture: 方法
CFURLRef textureURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
(CFStringRef)fileName,
CFSTR("png"),
NULL);
NSAssert(textureURL, @"Texture name invalid");
// Get the image source using a file path
CGImageSourceRef myImageSourceRef = CGImageSourceCreateWithURL(textureURL, NULL);
NSAssert(myImageSourceRef, @"Invalid Image Path.");
NSAssert((CGImageSourceGetCount(myImageSourceRef) > 0), @"No Image in Image Source.");
// Get the image reference using the source reference, -_-
CGImageRef myImageRef = CGImageSourceCreateImageAtIndex (myImageSourceRef, 0, NULL);
NSAssert(myImageSourceRef, @"Image not created.");
// Start gathering data from the image, before releasing it
GLuint myTextureName;
size_t width = CGImageGetWidth(myImageRef);
size_t height = CGImageGetHeight(myImageRef);
CGRect rect = 0, 0, width, height;
void * myData = calloc(width * 4, height);
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef myBitmapContext = CGBitmapContextCreate (myData,
width, height, 8,
width*4, space,
kCGBitmapByteOrder32Host |
kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(space);
// Flip so that it isn't upside-down
CGContextTranslateCTM(myBitmapContext, 0, height);
CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
CGContextSetBlendMode(myBitmapContext, kCGBlendModeCopy);
CGContextDrawImage(myBitmapContext, rect, myImageRef);
CGContextRelease(myBitmapContext);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
// Generate texture buffer
glGenTextures(1, &myTextureName);
// Bind buffer for use
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
// Set storage methods
glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Set the parameter required for non power of two textures
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB,
GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Load the texture data into the buffer
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, width, height,
0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, myData);
// Free the data used, as it's now in the buffer
free(myData);
// Return information on texture object
CDTexture *texture = [[CDTexture alloc] init];
texture.ID = myTextureName;
texture.size = NSMakeSize(width, height);
return texture;
更新 我尝试使用纹理指针来定义区域,这会导致同样的问题。即使没有绑定和使用指针,它绘制的颜色/纹理也会这样做。我也尝试过在使用和渲染之前和之后启用和禁用 GL_TEXTURE_COORD_ARRAY,并导致同样的问题。
除非我做错了什么,否则问题似乎与纹理指针无关。
GLfloat texCoords[8] =
0.0, 0.0,
0.0, 1.0,
1.0, 1.0,
1.0, 0.0
;
...
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture.ID);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
//[texture render];
//render
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
更新 2 我已经尝试从 OpenGL 获取错误代码来尝试解决问题,但没有打印任何错误代码。
更新 3 我尝试使用不同的方法来获取原始图像数据,但结果相同(尽管有些变色,因为我不能使用正确的颜色设置)。 OpenGL对数据的解释在这里肯定是有缺陷的。我已经尝试过 glPixelStorei() 但到目前为止没有任何改变。由于OpenGL没有报告任何错误,它必须与数据的程序解释有关,所以要么是我为数据存储方式设置的参数,要么是导致仅显示1个像素的顶点问题,尽管因为这个精度,最有可能是参数。
原始图像数据的新流程(感谢另一个 *** 用户)。发布以供参考。
NSBitmapImageRep *theImage;
int bitsPPixel, bytesPRow;
NSSize size;
unsigned char *theImageData;
NSData* imgData = [NSData dataWithContentsOfFile:fileName options:NSUncachedRead error:nil]; // use FileURL
theImage = [NSBitmapImageRep imageRepWithData:imgData];
if( theImage != nil )
bitsPPixel = [theImage bitsPerPixel];
bytesPRow = [theImage bytesPerRow];
size.width = [theImage pixelsWide];
size.height = [theImage pixelsHigh];
enter code here
更新 4 更改为 GL_TEXTURE_2D 以提高效率。左下角的像素仍然只被渲染。以下是代码的完整顺序:
// Create vertex buffer
GLuint memoryPointer = 0;
GLuint colourMemoryPointer = 0;
GLfloat *vertices;
size_t vertex_size = 0;
AllocateVertexBuffer(2, 4, &vertices, &vertex_size);
CDMeshVertexesCreateRectangle(200, 200, vertices);
// Create colour buffer
GLfloat *colors;
size_t color_size;
AllocateVertexBuffer(4, 4, &colors, &color_size);
CDMeshColorsCreateGrey(1.0, 4, colors);
// Create Texture UV Coordinates
GLfloat *texture;
size_t texture_size;
AllocateVertexBuffer(4, 2, &texture, &texture_size);
CDMeshVertexesCreateRectangle(1, 1, texture);
// Create texture buffer
NSString *fileName = @"Rawr3";
CFURLRef textureURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
(CFStringRef)fileName,
CFSTR("png"),
NULL);
NSAssert(textureURL, @"Texture name invalid");
// Get the image source using a file path
CGImageSourceRef myImageSourceRef = CGImageSourceCreateWithURL(textureURL, NULL);
NSAssert(myImageSourceRef, @"Invalid Image Path.");
NSAssert((CGImageSourceGetCount(myImageSourceRef) > 0), @"No Image in Image Source.");
// Get the image reference using the source reference, -_-
CGImageRef myImageRef = CGImageSourceCreateImageAtIndex (myImageSourceRef, 0, NULL);
NSAssert(myImageSourceRef, @"Image not created.");
// Start gathering data from the image, before releasing it
GLuint myTextureName;
size_t width = CGImageGetWidth(myImageRef);
size_t height = CGImageGetHeight(myImageRef);
CGRect rect = 0, 0, width, height; //Doesnt need fiddling
void * myData = calloc(width * 4, height); //Fiddled
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef myBitmapContext = CGBitmapContextCreate (myData,
width, height, 8,
width*4, space,
kCGBitmapByteOrder32Host |
kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(space);
// Flip so that it isn't upside-down
CGContextTranslateCTM(myBitmapContext, 0, height);
CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
CGContextSetBlendMode(myBitmapContext, kCGBlendModeCopy);
CGContextDrawImage(myBitmapContext, rect, myImageRef);
CGContextRelease(myBitmapContext);
// Generate texture buffer
glGenTextures(1, &myTextureName);
// Bind buffer for use
glBindTexture(GL_TEXTURE_2D, myTextureName);
// Set storage methods
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_CACHED_APPLE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
// Set clamping and rendering preferences
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
// Load the texture data into the buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
0, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, myData);
glGetError();
// Free the data used, as it's now in the buffer
free(myData);
// Return information on texture object
CDTexture *textureObj = [[CDTexture alloc] init];
textureObj.ID = myTextureName;
textureObj.size = NSMakeSize(width, height);
// Allocate the buffer
glGenBuffers(1, &memoryPointer);
// Bind the buffer object (tell OpenGL what to use)
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
// Allocate space for the VBO
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW);
// Allocate the buffer
glGenBuffers(1, &colourMemoryPointer);
// Bind the buffer object (tell OpenGL what to use)
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
// Allocate space for the VBO
glBufferData(GL_ARRAY_BUFFER, color_size, colors, GL_STATIC_DRAW);
glEnableClientState(GL_VERTEX_ARRAY); // Activate vertex coordinates array
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_2D, textureObj.ID);
glTexCoordPointer(2, GL_FLOAT, 0, texture);
GetGLError();
//render
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY); // Deactivate vertex coordinates array
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glDeleteBuffers(1, &memoryPointer);
glDeleteBuffers(1, &colourMemoryPointer);
GLuint texID = textureObj.ID;
glDeleteBuffers(1, &texID);
free(vertices);
free(colors);
free(texture);
更新 5 从 glTexImage2D() 开始,即使我不绑定纹理并为其添加坐标,它也会渲染纹理的左下角像素,考虑到它应该使用 glTexCoordPointer() 绘制,这看起来很奇怪。
更新 6 可能是最后一次更新,将纹理初始化代码与另一种“手动”绘图技术一起使用,并且效果很好。我已经删除了 Apple 特定的元素。从这段代码中删除颜色 VBO 和指针时,由于某种奇怪的原因,仍然会呈现一个白框。问题出在 VBO 上,但我不明白为什么。 GL_TEXTURE_RECTANGLE_ARB 目前只是用于我的彩色纹理,等问题解决后会更改。
// Create vertex buffer
GLuint memoryPointer = 0;
GLuint colourMemoryPointer = 0;
GLfloat *vertices;
size_t vertex_size = 0;
AllocateVertexBuffer(2, 4, &vertices, &vertex_size);
CDMeshVertexesCreateRectangle(200, 200, vertices);
GetGLError();
// Create colour buffer
GLfloat *colors;
size_t color_size;
AllocateVertexBuffer(4, 4, &colors, &color_size);
CDMeshColorsCreateGrey(0.4, 4, colors);
// Allocate the buffer
glGenBuffers(1, &memoryPointer);
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW);
// Allocate the buffer
glGenBuffers(1, &colourMemoryPointer);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glBufferData(GL_ARRAY_BUFFER, color_size, colors, GL_STATIC_DRAW);
// Enable client states for drawing the various arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Bind each buffer and use the VBO's to draw (apart from the texture buffer)
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName); //
glTexCoordPointer(2, GL_FLOAT, 0, texture);
//render
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Disale client states as were done with them.
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
GetGLError();
// Delete buffers to avoid problems
glDeleteBuffers(1, &memoryPointer);
glDeleteBuffers(1, &colourMemoryPointer);
glDeleteBuffers(1, &myTextureName);
free(vertices);
free(colors);
free(texture);
【问题讨论】:
提示:不要使用 GL_TEXTURE_RECTANGLE_ARB,它不能在所有 gfx 卡上工作,并且对于那些可以工作的卡来说它的超慢速度,它也不支持 mipmapping。始终使用 GL_TEXTURE_2D ! @Rookie,感谢您的提示,我已尝试将其与两个图像的幂和 UV 坐标集一起使用,但它现在根本不输出图像。不过会继续使用 GL_TEXTURE_2D。 【参考方案1】:当然你必须提供纹理坐标。作为顶点属性向量的一部分,或者通过生成它们(在着色器中)。但是你必须以某种方式提供纹理坐标,你无法绕过这个。
【讨论】:
@Croc,阅读我的提示,GL_TEXTURE_RECTANGLE_ARB 也以像素为单位,而不是 0-1 值。只需将 GL_TEXTURE_RECTANGLE_ARB 更改为 GL_TEXTURE_2D【参考方案2】:我(最终)通过为纹理创建顶点缓冲区对象 (VBO) 解决了这个问题,而不是尝试将顶点数据直接提供给 glTextureCoordPointer()。我想这里的教训是,如果您要使用 VBO,请使用它们!作为参考,这里是完整的代码:
纹理创建
// Create texture buffer, start with the name of the image.
NSString *fileName = @"Rawr";
CFURLRef textureURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
(CFStringRef)fileName,
CFSTR("png"),
NULL);
NSAssert(textureURL, @"Texture name invalid");
// Get the image source using a file path
CGImageSourceRef myImageSourceRef = CGImageSourceCreateWithURL(textureURL, NULL);
NSAssert(myImageSourceRef, @"Invalid Image Path.");
NSAssert((CGImageSourceGetCount(myImageSourceRef) > 0), @"No Image in Image Source.");
// Get the image reference using the source reference, -_-
CGImageRef myImageRef = CGImageSourceCreateImageAtIndex (myImageSourceRef, 0, NULL);
NSAssert(myImageSourceRef, @"Image not created.");
// Start gathering data from the image, before releasing it
GLuint myTextureName;
size_t width = CGImageGetWidth(myImageRef);
size_t height = CGImageGetHeight(myImageRef);
CGRect rect = 0, 0, width, height; //Doesnt need fiddling
void * myData = calloc(width * 4, height); //Fiddled
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGContextRef myBitmapContext = CGBitmapContextCreate (myData,
width, height, 8,
width*4, space,
kCGBitmapByteOrder32Host |
kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(space);
// Flip so that it isn't upside-down
CGContextTranslateCTM(myBitmapContext, 0, height);
CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
CGContextSetBlendMode(myBitmapContext, kCGBlendModeCopy);
CGContextDrawImage(myBitmapContext, rect, myImageRef);
CGContextRelease(myBitmapContext);
GetGLError();
// The extension GL_TEXTURE_RECTANGLE_ARB can be used for non-power of two textures, but it is slower than GL_TEXTURE_2D and not
// supported by all graphics cards.
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glGenTextures(1, &myTextureName);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, myData);
//glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT ,GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,myTextureName, 0);
free(myData);
VBO 创作
// Create vertex buffer
GLuint memoryPointer = 0;
GLuint colourMemoryPointer = 0;
GLuint texPointer = 0;
GLfloat *vertices;
size_t vertex_size = 0;
AllocateVertexBuffer(2, 4, &vertices, &vertex_size);
CDMeshVertexesCreateRectangle(200, 200, vertices);
GetGLError();
// Create colour buffer
GLfloat *colors;
size_t color_size;
AllocateVertexBuffer(4, 4, &colors, &color_size);
CDMeshColorsCreateGrey(0.0, 4, colors);
// Create Texture UV Coordinates
GLfloat *texture;
size_t texture_size;
AllocateVertexBuffer(2, 4, &texture, &texture_size);
CDMeshVertexesCreateRectangle(200, 200, texture);
// Allocate the vertex VBO
glGenBuffers(1, &memoryPointer);
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glBufferData(GL_ARRAY_BUFFER, vertex_size, vertices, GL_STATIC_DRAW);
// Allocate the colour VBO
glGenBuffers(1, &colourMemoryPointer);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glBufferData(GL_ARRAY_BUFFER, color_size, colors, GL_STATIC_DRAW);
// Allocate the texture VBO
glGenBuffers(1, &texPointer);
glBindBuffer(GL_ARRAY_BUFFER, texPointer);
glBufferData(GL_ARRAY_BUFFER, texture_size, texture, GL_STATIC_DRAW);
渲染和删除 VBO 和数据
// Enable client states for drawing the various arrays
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Bind each buffer and use the VBO's to draw
glBindBuffer(GL_ARRAY_BUFFER, memoryPointer);
glVertexPointer(2, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, colourMemoryPointer);
glColorPointer(4, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, texPointer);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, myTextureName);
// RENDER!
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
// Disale client states as were done with them.
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
GetGLError();
// Delete buffers when they arent being used.
glDeleteBuffers(1, &memoryPointer);
glDeleteBuffers(1, &colourMemoryPointer);
glDeleteBuffers(1, &myTextureName);
glGenTextures(GL_TEXTURE_RECTANGLE_ARB, 0);
// Free vertexes when done using them
free(vertices);
free(colors);
free(texture);
【讨论】:
以上是关于OpenGL纹理初始化/渲染问题的主要内容,如果未能解决你的问题,请参考以下文章