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。我将添加该部件的代码作为编辑。