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 会不会在这个过程中失去小数精度?我怎样才能让方块的边缘变得尖锐?
任何线索在这里都会非常有帮助!点赞!
根据 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调试看起来不正确的片段
您将能够检查对每个输出片段进行了哪些计算,以及它是否是意外的。
我终于想通了。这是几件事的结合。
- 小方块(此处称为像素)超出了预期范围,因为它们正在抗锯齿。由于我使用
CGContext
桥接 CPU 和 GPU 内存 (strategy taken from here),因此我必须添加以下代码(两行!):
context.setShouldAntialias(false)
context.setAllowsAntialiasing(false)
- 放大时像素模糊是因为 CALayer 放大过滤器,而不是 Metal 的。解决方案非常简单:
layer.magnificationFilter = .nearest // Disables pixel interpolation when zooming in
- 最后但同样重要的是,像素坐标(和大小)与底层 pixel-perfect chess-looking 板不匹配,因为我绘制的像素实际上是
CGRects
(context.addRects()
),那些 CGRects 有一个 too-precise width/height,通常小于 1.00(即使在原始问题中不是这种情况,它有浮点数,这并不是一个真正的绘制单个像素时的事情 - 没有半个像素这样的东西)。所以解决这个问题的方法是使用具有所需像素的确切数量的 canvas,并让我绘制的所有 CGRects 具有 1x1pt 大小。这样它不仅性能更高(因为不会一直进行浮点计算),而且它始终是像素完美的。
查看下面的最终结果(此视图使用 UIScrollView
放大了 150 倍):
希望这对外面的人有帮助!感谢大家的贡献!
我正在尝试使用 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 会不会在这个过程中失去小数精度?我怎样才能让方块的边缘变得尖锐?
任何线索在这里都会非常有帮助!点赞!
根据 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调试看起来不正确的片段 您将能够检查对每个输出片段进行了哪些计算,以及它是否是意外的。
我终于想通了。这是几件事的结合。
- 小方块(此处称为像素)超出了预期范围,因为它们正在抗锯齿。由于我使用
CGContext
桥接 CPU 和 GPU 内存 (strategy taken from here),因此我必须添加以下代码(两行!):
context.setShouldAntialias(false)
context.setAllowsAntialiasing(false)
- 放大时像素模糊是因为 CALayer 放大过滤器,而不是 Metal 的。解决方案非常简单:
layer.magnificationFilter = .nearest // Disables pixel interpolation when zooming in
- 最后但同样重要的是,像素坐标(和大小)与底层 pixel-perfect chess-looking 板不匹配,因为我绘制的像素实际上是
CGRects
(context.addRects()
),那些 CGRects 有一个 too-precise width/height,通常小于 1.00(即使在原始问题中不是这种情况,它有浮点数,这并不是一个真正的绘制单个像素时的事情 - 没有半个像素这样的东西)。所以解决这个问题的方法是使用具有所需像素的确切数量的 canvas,并让我绘制的所有 CGRects 具有 1x1pt 大小。这样它不仅性能更高(因为不会一直进行浮点计算),而且它始终是像素完美的。
查看下面的最终结果(此视图使用 UIScrollView
放大了 150 倍):
希望这对外面的人有帮助!感谢大家的贡献!