我想从iOS中的一个文件中加载4通道纹理数据,所以我把纹理视为一个(连续的)地图
[0,1]x[0,1] -> [0,1]x[0,1]x[0,1]x[0,1]
如果我使用文件格式 .png
,XCodeiOS认为文件是一个图像,所以将每个组件乘以 rgb
与 a
(预乘α),破坏了我的数据。我应该如何解决这个问题?例子可能是
rgb
(3通道)其中,我认为最好的解决方案是使用另一种文件格式。GL压缩文件格式(PVRTC?)不是独立于苹果平台的,而且似乎分辨率很低(4位)(参考).
EDIT:如果我自己下面的回答是真的,那么在iOS中是不可能得到png的4通道数据的。因为OpenGL是要创建图像而不是呈现图像,所以应该可以通过某种方式加载4通道数据,png是图像的文件格式(和压缩取决于所有4个通道 但一个通道的压缩是独立于其他通道的),所以有人会说,我应该使用其他的文件格式。那么,我应该使用其他哪些压缩文件格式,这在iOS中是容易读取集成的?
更新:"combinatorial "提到了一种加载4通道非预增纹理的方法,所以我不得不给他正确的答案。然而,这个解决方案有一些限制,我不喜欢。那么我的下一个问题是 "在iOS中从png文件中访问原始4通道数据":)
我认为不使其能够读取4通道的png数据是一个糟糕的库设计。我不喜欢系统试图比自己更聪明。
由于你考虑的是PVRTC,那么使用 GLKit 可以作为一种选择。这包括 GLKTextureLoader 它允许你在加载纹理时不需要预先乘以alpha。例如,使用
+ (GLKTextureInfo *)textureWithContentsOfFile:(NSString *)fileName options:(NSDictionary *)textureOperations error:(NSError **)outError
并传递一个包含选项字典。
GLKTextureLoaderApplyPremultiplication = NO
您可以简单地要求Xcode不 "压缩 "您的PNG文件,在左上角点击您的项目,选择 "构建设置",找到 "压缩PNG文件"。点击左上角的项目,选择 "Build Settings",找到 "Compress PNG Files "并将选项设置为 "No"。
至于你的其他选项,postdividing不是一个不好的解决方案,但显然你会失去整体的精度,我相信TIFF和BMP也是支持的。PVRTC是PowerVR专用的,所以它不是苹果专用的,但它也不是完全独立于平台的,它是专门设计的有损压缩,在GPU上几乎不需要输入就可以解压。一般来说,你会提高你的纹理分辨率来改善每像素的低位数。
这是我尝试回答自己的问题。
加载非预增色的.png文件是不可能的。
选项 kCGImageAlphaLast
是一个有效的选项,但没有给出一个有效的组合,用于 CGBitmapContextCreate
(参考). 然而,它是一个有效的选择,对于 CGImageRef
's.
构建设置是什么 COMPRESS_PNG_FILES
在XCode上面提到的,是将.png文件转换为其他文件格式,并且还乘以通道。rgb
与 a
(参考). 我希望禁用这个选项可以使我的实际.png文件中的通道数据成为可能。但我不确定这是否可能。下面的例子是一个在低级别的访问.png数据的尝试,作为一个 CGImageRef
:
void test_cgimage(const char* path)
{
CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename(path);
CGImageRef cg_image = CGImageCreateWithPNGDataProvider(dataProvider, NULL, NO,
kCGRenderingIntentDefault);
CGImageAlphaInfo info = CGImageGetAlphaInfo(cg_image);
switch (info)
{
case kCGImageAlphaNone: printf("kCGImageAlphaNone\n"); break;
case kCGImageAlphaPremultipliedLast: printf("kCGImageAlphaPremultipliedLast\n"); break;
case kCGImageAlphaPremultipliedFirst: printf("kCGImageAlphaPremultipliedFirst\n"); break;
case kCGImageAlphaLast: printf("kCGImageAlphaLast\n"); break;
case kCGImageAlphaFirst: printf("kCGImageAlphaFirst\n"); break;
case kCGImageAlphaNoneSkipLast: printf("kCGImageAlphaNoneSkipLast\n"); break;
case kCGImageAlphaNoneSkipFirst: printf("kCGImageAlphaNoneSkipFirst\n"); break;
default: break;
}
}
其中,"kCGImageAlphaPremultipliedLast "为 "kCGImageAlphaPremultipliedLast"。COMPRESS_PNG_FILES
禁用。所以我认为iOS总是转换.png文件,甚至在运行时。
有更好的解决方案,速度更快(约3倍~5倍),而且是跨平台的。
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
// force 4 channel rgba, force flipy
// image: first pixel is top left, OpenGL assume first is bottom left, so need flipy
bool flipy = true;
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(flipy);
unsigned char *imageData = stbi_load(path.c_str(), &width, &height, &nrChannels, 4);
// load data to your texture
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bytes);
free(imageData);
不是100%你想要的,但我用这个方法解决了这个问题。把阿尔法通道放到一个单独的黑色& 白色的png中,然后保存没有阿尔法的原始png。所以占用的空间是差不多的。然后在我的纹理加载器中加载两张图片并组合成一个纹理。
我知道这只是一个变通的方法,但至少它给出了正确的结果。是的,这是非常恼人的,iOS不允许你从PNG加载纹理,没有预增的alpha。