MetalKit 视图 MTKView 显示模糊笔划并推断其指定 path/size

MetalKit view MTKView showing blurry stroke and extrapolating their designated path/size

我正在尝试使用 MetalKit 绘制正方形。每个正方形都有一个原点和一个大小,像这样:

Origin:

▿ (204.5746214852199, 62.83450704225352)
  - x : 204.5746214852199
  - y : 62.83450704225352

Size:

▿ (1.4612472963229992, 1.4612676056338028)
  - width : 1.4612472963229992
  - height : 1.4612676056338028

问题是,当 MetalKit 绘制这些时,每个正方形都以不同的奇怪方式绘制,超出了正方形应有的预期面积和形状(见下图)- 是的,每个红色簇应代表一个与下面那些灰色方块大小相同的单个 1x1 正方形。此外,它的边界也很模糊(这是一张放大的图像)。我正在使用这个采样器:

constexpr sampler textureSampler(mag_filter::nearest,
                                 min_filter::nearest);

在上图中,灰度方块是每个红色方块应该适合的(它们的边界和确切位置)。

知道如何实现吗? MetalKit 会不会在这个过程中失去小数精度?我怎样才能让方块的边缘变得尖锐?

这是我的顶点函数和位置结构:https://github.com/s1ddok/MetalCoreGraphics/blob/d32c680a156548e20e9e9deb06e14cc260bcdea1/MetalCoreGraphics/Shaders.metal#L12-L30

任何线索在这里都会非常有帮助!点赞!

根据 Metal Shader Language Specification Metal 将 Vertex 的位置值存储在 single-precision floating-point format.

Type Description
float A 32-bit floating-point. The float data type must conform to the IEEE 754 single precision storage format.

这适用于可以精确表示的小值,但由于 floating-point 舍入误差,精度会随着值的增加而降低。因此,远离原点渲染的 Actor 定位不准确(它们稍微错位)。

我建议你通过https://developer.apple.com/documentation/metal/developing_and_debugging_metal_shaders调试看起来不正确的片段 您将能够检查对每个输出片段进行了哪些计算,以及它是否是意外的。

我终于想通了。这是几件事的结合。

  1. 小方块(此处称为像素)超出了预期范围,因为它们正在抗锯齿。由于我使用 CGContext 桥接 CPU 和 GPU 内存 (strategy taken from here),因此我必须添加以下代码(两行!):
context.setShouldAntialias(false)
context.setAllowsAntialiasing(false)
  1. 放大时像素模糊是因为 CALayer 放大过滤器,而不是 Metal 的。解决方案非常简单:
layer.magnificationFilter = .nearest // Disables pixel interpolation when zooming in
  1. 最后但同样重要的是,像素坐标(和大小)与底层 pixel-perfect chess-looking 板不匹配,因为我绘制的像素实际上是 CGRectscontext.addRects()),那些 CGRects 有一个 too-precise width/height,通常小于 1.00(即使在原始问题中不是这种情况,它有浮点数,这并不是一个真正的绘制单个像素时的事情 - 没有半个像素这样的东西)。所以解决这个问题的方法是使用具有所需像素的确切数量的 canvas,并让我绘制的所有 CGRects 具有 1x1pt 大小。这样它不仅性能更高(因为不会一直进行浮点计算),而且它始终是像素完美的。

查看下面的最终结果(此视图使用 UIScrollView 放大了 150 倍):

希望这对外面的人有帮助!感谢大家的贡献!