我的场景由一个平面组成,我用两个纹理对其进行着色。第一个,最底部的纹理是来自 iPhone 相机的实心图像,第二个图像是一种取景器,我需要覆盖在相机输入上(具有透明度)。我在透明纹理中的实体边界处出现了这些黑色暗线。
我一直在对此进行一些研究,并了解到该工件是插值与预乘 alpha 相结合的结果。由于 XCode 将所有 PNG 图像自动转换为预乘 png,并且我编写的加载图像的代码也尊重预乘 alpha 上下文,所以我有点卡在确切问题所在的位置。
我尝试了以下解决方案:
- 确保 alpha 值为 0 的像素的 rgb 值也设置为 0
- 关闭 xcode 的自动 png 压缩,使其保留我提供的纹理
- 摆弄片段着色器以避免 mix() 调用
- 创建位图上下文时更改了 AlphaInfo 值
重要提示:我没有使用 glBlendFunc(),我将两个纹理一起提供给 1 个片段着色器并尝试将它们混合在一起。所以通过这个 gl-call 的解决方案不会让我更进一步。
这是我用来加载透明纹理的代码:
shared_ptr<ImageData> IOSFileSystem::loadImageFile(string path, bool flip) const
{
cout << path << endl;
// Result
shared_ptr<ImageData> result = shared_ptr<ImageData>();
// Convert cpp string to nsstring
NSString *convertedPathString = [NSString stringWithCString:path.c_str() encoding:[NSString defaultCStringEncoding]];
NSString *fullPath = [NSString stringWithFormat:@"%@%@", [[NSBundle mainBundle] resourcePath], convertedPathString];
// Check if file exists
if([[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:NO])
{
// Load image
UIImage *image = [[[UIImage alloc] initWithContentsOfFile:fullPath] autorelease];
CGImageRef imageRef = image.CGImage;
// Allocate memory for the image
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
GLubyte *spriteData = (GLubyte*) calloc(width * height * 4, sizeof(GLubyte));
// Create drawing context
CGContextRef context = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(imageRef), kCGImageAlphaPremultipliedLast);
// Flip for OpenGL coord system
if(flip)
{
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
}
// Draw & release
CGContextDrawImage(context, CGRectMake(0.0, 0.0, width, height), imageRef);
CGContextRelease(context);
// Put result in shared ptr
// Don't free() the spritedata because our shared pointer will take care of that
// Since the shared pointer doesn't know how to free "calloc" data, we have to teach it how: &std::free
shared_ptr<GLubyte> spriteDataPtr = shared_ptr<GLubyte>(spriteData, &std::free);
result = shared_ptr<ImageData>(new ImageData(path, width, height, spriteDataPtr));
}
else
{
cout << "IOSFileSystem::loadImageFile -> File does not exist at path.\nPath: " + path;
exit(1);
}
return result;
}
这是我在纹理上设置像素的方法:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, pixels);
这是片段着色器的精简版本:
void main(void)
{
lowp vec4 camera = texture2D(texture0, destinationTexCoord);
lowp vec4 viewfinder = texture2D(texture1, destinationTexCoord);
lowp vec4 result = mix(camera, viewfinder, viewfinder.a);
gl_FragColor = result;
}