Ios 如果转换为纹理,MTLTexture将不正确地显示UIImage
我有这个方法Ios 如果转换为纹理,MTLTexture将不正确地显示UIImage,ios,objective-c,metal,Ios,Objective C,Metal,我有这个方法 - (id<MTLTexture>) createTextureFromImage:(UIImage*) image device:(id<MTLDevice>) device { CGImageRef imageRef = image.CGImage; // size_t width = CGImageGetWidth(imageRef); // size_t height = CGImageGetHeight(imageRef);
- (id<MTLTexture>) createTextureFromImage:(UIImage*) image device:(id<MTLDevice>) device
{
CGImageRef imageRef = image.CGImage;
// size_t width = CGImageGetWidth(imageRef);
// size_t height = CGImageGetHeight(imageRef);
size_t width = self.view.frame.size.width;
size_t height = self.view.frame.size.height;
size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef);
size_t bitsPerPixel = CGImageGetBitsPerPixel(imageRef);
CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef);
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
NSLog(@"%@", colorSpace);
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | alphaInfo;
NSLog(@"bitmap info %u", bitmapInfo);
CGContextRef context = CGBitmapContextCreate( NULL, width, height, bitsPerComponent, (bitsPerPixel / 8) * width, colorSpace, bitmapInfo);
if( !context )
{
NSLog(@"Failed to load image, probably an unsupported texture type");
return nil;
}
CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image.CGImage );
MTLPixelFormat format = MTLPixelFormatBGRA8Unorm;
MTLTextureDescriptor *texDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
width:width
height:height
mipmapped:NO];
id<MTLTexture> texture = [device newTextureWithDescriptor:texDesc];
[texture replaceRegion:MTLRegionMake2D(0, 0, width, height)
mipmapLevel:0
withBytes:CGBitmapContextGetData(context)
bytesPerRow:4 * width];
return texture;
}
唯一的问题是,我看不到在哪里设置帧缓冲区像素格式
谢谢
编辑-这是我的图像分割成像素阵列后经过的处理代码
-(UIImage *) script:(NSArray*)pixelArray {
float width = self.view.frame.size.width;
float height = self.view.frame.size.height;
//create drawing context
UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
int k = 0;
do {
for (int y = 0; y < height + 1; y++)
{
for (int x = 1; x < width; x++)
{
if (k < array.count){
UIColor* pixelColor = array[k];
CGContextSetFillColorWithColor(context, pixelColor.CGColor);
CGContextFillRect(context, CGRectMake(x, y, 1.0f, 1.0f));
}
} else {
CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);
CGContextFillRect(context, CGRectMake(x, y, 1.0f, 1.0f));
}
k++;
}
k++;
}
} while (k < 62791);
//capture resultant image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
这里有两个不同的关注点:在渲染管道状态和帧缓冲区之间匹配像素格式,以及在图像数据和从中创建的纹理的像素格式之间匹配像素格式 在第一种情况下,使用MTLPixelFormatBGRA8Unorm是明智的。这必须在CametLayer或MTKView以及渲染管道状态的主颜色附件上设置。如果他们不同意,你会得到你提到的例外。此配置如下所示:
metalView.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
// and elsewhere...
pipelineStateDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
在后一种情况下,重要的是图像数据的组件顺序与为纹理选择的格式匹配。从UIImage获得的颜色空间是sRGB,因此需要指定MTLPixelFormatRGBA8Unorm作为纹理的像素格式,其中当前纹理创建代码中有MTLPixelFormatBGRA8Unorm,或者手动交换红色和蓝色通道中的字节
视图的像素格式和从图像创建的纹理不必相同。采样纹理和写入帧缓冲区时,Metal会切换颜色,因此在着色器中,始终可以采用RGBA顺序。这里有两个不同的问题:在渲染管道状态和帧缓冲区之间匹配像素格式,以及在图像数据和从中创建的纹理的像素格式之间匹配像素格式 在第一种情况下,使用MTLPixelFormatBGRA8Unorm是明智的。这必须在CametLayer或MTKView以及渲染管道状态的主颜色附件上设置。如果他们不同意,你会得到你提到的例外。此配置如下所示:
metalView.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
// and elsewhere...
pipelineStateDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
在后一种情况下,重要的是图像数据的组件顺序与为纹理选择的格式匹配。从UIImage获得的颜色空间是sRGB,因此需要指定MTLPixelFormatRGBA8Unorm作为纹理的像素格式,其中当前纹理创建代码中有MTLPixelFormatBGRA8Unorm,或者手动交换红色和蓝色通道中的字节
视图的像素格式和从图像创建的纹理不必相同。采样纹理和写入帧缓冲区时,Metal会切换颜色,因此在着色器中,您始终可以假定RGBA顺序。您需要支持哪种最低iOS版本?您的目标仅仅是从图像创建MTLTexture吗?是的,我的目标是从图像创建MTLTexture,正如您所看到的,我在上面所做的。问题在于RGBA频道的切换,我想我只是想说,你可以用更少的代码实现同样的目标。如果您打算只支持9+个iOS,则可以使用MetalKit中的MTKTextureLoader,如viewDidLoad方法所述。您需要支持的最低iOS版本是什么?您的目标仅仅是从图像创建MTLTexture吗?是的,我的目标是从图像创建MTLTexture,正如您所看到的,我在上面所做的。问题在于RGBA频道的切换,我想我只是想说,你可以用更少的代码实现同样的目标。如果您打算只支持9+个iOS,则可以按照viewDidLoad方法使用MetalKit中的MTKTextureLoader。感谢您的回复。我遇到的问题是,即使纹理的MTLPixelFormat和管道格式匹配,图像仍然会出现混乱。我认为这是因为传递到函数中的图像的颜色格式是RGBA,所以从逻辑上来说,我认为我需要更改它,但是如果我重新创建图像并将RGB值替换为BGR值,这并不能解决问题=[我在上面添加了更多的细节,希望能有所帮助。在将图像纹理的像素格式从BGRA更改为RGBA后,您的代码似乎在一个示例项目中为我工作。为了扩展这一点,我输入的uiimage是通过执行一个过于复杂的函数来处理的,其中它获取原始图像,读取UIC每个像素的颜色值,将其保存到数组中,然后使用某些像素的变化将其重建为UIImage。我将添加该部分的代码作为编辑。感谢您的回复。我遇到的问题是,即使纹理的MTLPixelFormat和管道格式匹配,图像仍然会出现混乱。我认为这是我的错误因为传递到函数中的图像的颜色格式为RGBA,所以从逻辑上讲,我认为我需要更改它,但是如果我重新创建图像并将RGB值替换为BGR值,这并不能解决问题=[我在上面添加了一点细节,这将使
我很乐意帮忙。在将图像纹理的像素格式从BGRA更改为RGBA后,您的代码似乎在一个示例项目中为我工作。为了扩展此功能,我输入的uiimage通过执行一个过于复杂的函数进行处理,其中它获取原始图像,读取每个像素的UIColor值,将其保存到数组中,然后将其重建为具有某些像素变化的UIImage。我将添加该部件的代码作为编辑。