macos - 如何在 Metal 的四边形中正确渲染纹理?

标签 macos rendering textures metal

我的问题是因为四边形只是两个三角形。纹理在每个三角形上的渲染不一致,并且纹理在两个三角形之间的边界上被破坏。我使用我可爱的 ​​Minecraft 房子的屏幕截图作为示例纹理:

Rendered textured quad

如您所见,从屏幕截图的左上角和右下角来看,它似乎被剪切或折叠过什么。它只是扭曲了。我所说的失真并不是因为它被应用于梯形,而是它被不一致地应用于构成梯形的两个三角形。

Original screenshot

那么我该如何解决这个问题?

在 viewDidLoad 中:

let VertexDescriptor = MTLVertexDescriptor()
let Attribute1Offset = MemoryLayout<simd_float3>.stride
let Attribute2Offset = Attribute1Offset+MemoryLayout<simd_float4>.stride
VertexDescriptor.attributes[0].format = .float3
VertexDescriptor.attributes[1].format = .float4
VertexDescriptor.attributes[1].offset = Attribute1Offset
VertexDescriptor.attributes[2].format = .float2
VertexDescriptor.attributes[2].offset = Attribute2Offset
VertexDescriptor.layouts[0].stride = Attribute2Offset+MemoryLayout<simd_float2>.stride
PipelineDescriptor.vertexDescriptor = VertexDescriptor
let TextureLoader = MTKTextureLoader(device: Device)
Texture = try? TextureLoader.newTexture(URL: Bundle.main.url(forResource: "Texture.png", withExtension: nil)!)

顶点:
//First four = position, second four = color, last two = texture coordinates
let Vertices: [Float] = [-0.5, 0.5, 0, 0, 1, 1, 0, 1, 0, 0,
                         0.5, 0.5, 0, 0, 0, 1, 1, 1, 1, 0,
                         1, -1, 0, 0, 0, 1, 0, 1, 1, 1,
                         -1, -1, 0, 0, 0, 0, 1, 1, 0, 1]

输入 Shaders.metal
typedef struct {
    float4 Position [[attribute(0)]];
    float4 Color [[attribute(1)]];
    float2 TexCoord [[attribute(2)]];
} VertexIn;
typedef struct {
    float4 Position [[position]];
    float4 Color;
    float2 TexCoord;
} VertexOut;

请耐心等待,我使用 PascalCase 是因为我认为 camelCase 很丑。我只是不喜欢它。无论如何,我如何正确地将纹理放置在由两个三角形组成的四边形中,这样它看起来就不会很奇怪了?

最佳答案

如您所知,Metal 执行 perspective-correct vertex attribute interpolation代表您使用顶点位置的 z 坐标提供的深度信息。

您通过扭曲四边形的“投影”形状而不向图形管道提供透视信息来颠覆此过程。这意味着您需要传递一些额外的信息才能获得正确的插值。具体来说,您需要在纹理坐标中包含“深度”信息,并在片段着色器中手动执行“透视”划分。

如需完全通用的解决方案,请咨询 this answer ,但要在关于四边形垂直轴对称缩放的情况下进行简单修复,请使用 float3纹理坐标而不是 float2并设置 x 和 z 坐标,使 z 是您的伪透视投影引入的比例因子,并且当 x 除以 z 时,结果就是没有除法的 x 。

例如,如果顶部两个顶点之间的距离是底部两个顶点之间的距离的一半(如您的屏幕截图所示),请将左上角纹理坐标设置为 (0, 0, 0.5),将左上角纹理坐标设置为右纹理坐标为 (0.5, 0, 0.5)。将这些“3D”纹理坐标传递给您的片段着色器,然后除以 z采样前:

half4 color = myTexture.sample(mySampler, in.texCoords.xy / in.texCoords.z);

关于macos - 如何在 Metal 的四边形中正确渲染纹理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61701624/

相关文章:

macos - 我怎样才能让 ZSH 使用最新的 git 版本?

wpf - 关于 WPF 呈现 UI 撕裂,我们可以做些什么?

Java GlassPanel 清晰透明背景

php - dompdf: "Maximum execution time of 30 seconds exceeded"

macos - Apple 听写 - 在应用程序中使用

macos - 迪尔德 : Library not loaded: Referenced from:/usr/local/bin/awk

opengl - 我的纹理在屏幕上一直显示为白色

c++ - OpenGL 纹理触发错误 1281 和奇怪的背景行为

macos - 显示新文档窗口的工作表

clone - 三个 js - 克隆着色器并更改统一值