[英]Problem with OpenGL Texture Initialisation/Rendering
我嘗試使用 model class 渲染非 2 次冪紋理,該紋理創建紋理並存儲其 ID 和大小(感謝 ADC 和另一個 stackoverflow 成員),以及創建 VBO 並渲染它的附加代碼(VBO 和渲染的代碼用於測試目的,它在我的模型中正確划分)。
當我使用此代碼但刪除特定於紋理的代碼時,它可以正常工作。 然而,當添加紋理特定代碼時,它只渲染我認為是右下角的像素,從嘗試多個復雜圖像並使用 DigitalColor Meter 檢查圖像和 output。
我不認為在使用此設置時必須明確指定紋理坐標,如果他們這樣做,我會怎么做?
主要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 個像素的頂點問題,盡管因為這個精度,它最有可能是參數。
原始圖像數據的新流程(感謝另一個 stackoverflow 用戶)。 貼出來供參考。
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);
當然,您必須提供紋理坐標。 作為頂點屬性向量的一部分,或者通過生成它們(在着色器中)。 但是你必須以某種方式提供紋理坐標,你無法解決這個問題。
我(最終)通過為紋理創建頂點緩沖區 Object (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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.