GLKit中的纹理映射在设备上无法正常工作

7
我使用这个链接里的代码来映射人脸纹理。这段代码使用GLKIT来渲染图像。在模拟器中,代码可以正常工作,但是在设备上,相同的代码却无法工作。下面是在设备和iPad上工作的图片截屏。
我用以下代码加载纹理:
- (void)loadTexture:(UIImage *)textureImage
{
    glGenTextures(1, &_texture);
    glBindTexture(GL_TEXTURE_2D, _texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    CGImageRef cgImage = textureImage.CGImage;
    float imageWidth = CGImageGetWidth(cgImage);
    float imageHeight = CGImageGetHeight(cgImage);
    CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA,  
    GL_UNSIGNED_BYTE, CFDataGetBytePtr(data));
}

模拟器中的图像:

Output in simulator

在设备上运行相同的代码会产生以下输出:

Output in Device

我是否漏掉了什么?


有人可以回答我的问题吗?! - 2vision2
1
请查看以下链接:https://dev59.com/E1zUa4cB1Zd3GeqP5rPP#7952288 - Khaled.K
3个回答

3
  1. 使用苹果内置的单行方法加载 -- 不要编写自己(错误的)实现!

    https://developer.apple.com/library/mac/#documentation/GLkit/Reference/GLKTextureLoader_ClassRef/Reference/Reference.html#//apple_ref/occ/clm/GLKTextureLoader/textureWithContentsOfFile:options:error


  1. 或者,如果您必须自己完成,您有两个可疑的部分:

    2.1. 摆脱这行代码:

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    2.2. 这行代码使用了一个超出作用域的数字,这并不好:

    glGenTextures(1, &_texture);


  1. If for some reason you cannot use Apple's code (e.g. you want to load raw data from in-memory image), here's a copy/paste of working code:

    NSData* imageData = ... // fill this yourself
    CGSize* imageSize = ... // fill this yourself
    
    GLuint integerForOpenGLToFill;
    glGenTextures(1, &integerForOpenGLToFill);
    
    glBindTexture( GL_TEXTURE_2D, integerForOpenGLToFill);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
    unsigned char* pixelData = (unsigned char*) malloc( [imageData length] * sizeof(unsigned char) );
    [imageData getBytes:pixelData];
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageSize.width, imageSize.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
    

你确定你的修复方法没问题吗,@Adam?我写了原始的纹理加载代码,并在另一个应用程序中使用了你的建议进行替换,但结果更糟。虽然我不是OpenGL专家,但我的实现可能仍然有误,但这段代码也无法工作。不过,你对超出范围的数字做出了正确的判断。 - Ricardo RendonCepeda
这是我使用两种方法(不同的应用程序,带有视网膜显示器的iPhone模拟器)的结果截图。 - Ricardo RendonCepeda
@RicardoRendonCepeda 哪一位?我的首要建议是使用苹果的代码,因为它总是有效的! - Adam
底部的复制/粘贴代码适用于在内存中实时生成数据的情况(这是苹果仅部分支持的),比苹果的代码性能要高得多。在这种情况下,您需要了解您的数据格式并适应我提供的格式(RGBA),或更改您向OpenGL提供的信息--但如果您使用自定义非标准图像数据格式,我假设您知道自己在做什么,并知道如何处理它 :)... - Adam
不,我也在使用标准的RGBA。说实话,我有一段时间没有好好关注这个项目了,而且对它最初的目的感到满意(此外,没有iPad = 没有彻底测试)。在GLKit之前,我开始使用OpenGL ES 2.0,因此我还需要更详细地查看GLKTextureLoader。 - Ricardo RendonCepeda
我的图像数据内存源是:创建一个位图图形上下文,并使用苹果方法将原始字节作为NSData获取。您所获得的是W * H *(每像素字节)字节 - 没有标题,没有页脚等。上面的代码假定这一点(这是最标准的图像数据原始表示方式 :)). 苹果的系统需要JPG或PNG头文件(这是未记录的,但我通过技术支持请求从苹果工程师那里获得了它) - Adam

2

看着截图...我想知道你是不是从iPhone到iPad的?

也就是从视网膜屏幕到非视网膜屏幕?

在我看来,你的图像加载可能忽略了视网膜屏幕的比例,因此在iPad上纹理地图“2倍过大”。

使用苹果的方法(我的另一个答案)应该会自动修复,但如果没有:您可以尝试制作两个图像副本,一个当前大小(命名为“image@2x.png”),一个缩小一半(在Photoshop /预览等中进行调整)(命名为“image.png”)。


谢谢你的回复。问题出现在模拟器和设备之间。在模拟器上它可以工作,在设备上却不行 :( - 2vision2
如果您使用RETINA模拟器和NON RETINA模拟器会发生什么?(使用硬件菜单进行切换) - Adam

2

我最终妥协并转向使用GLKTextureLoader。正如Adam所提到的,它非常稳定。

以下是一个可能适用于你的实现:

- (void)loadTexture:(NSString *)fileName
{
    NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES],
                             GLKTextureLoaderOriginBottomLeft,
                             nil];

    NSError* error;
    NSString* path = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
    GLKTextureInfo* texture = [GLKTextureLoader textureWithContentsOfFile:path options:options error:&error];
    if(texture == nil)
    {
        NSLog(@"Error loading file: %@", [error localizedDescription]);
    }

    glBindTexture(GL_TEXTURE_2D, texture.name);
}

我很快会为GitHub上的mtl2opengl项目进行更改...


谢谢你的回答,Ricardo。我会尝试并尽快回复你。非常感谢。 - 2vision2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接