【问题标题】:How do I correctly render a texture in a quad in Metal?如何在 Metal 中正确渲染四边形中的纹理?
【发布时间】:2020-05-09 18:20:22
【问题描述】:

我的问题是因为四边形只是两个三角形。纹理在每个三角形上的渲染不一致,并且纹理在两个三角形之间的边界处被破坏。我使用我可爱的 ​​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 很难看。我只是不喜欢它。无论如何,我如何正确地将纹理放置在由两个三角形组成的四边形中,这样它就不会看起来很奇怪?

【问题讨论】:

  • 您需要展示您的顶点和片段着色器,以便我们为您提供建议。

标签: macos rendering textures metal


【解决方案1】:

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

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

对于一个完全通用的解决方案,请咨询this answer,但是对于关于四边形垂直轴对称缩放的简单修复,使用float3纹理坐标而不是float2并设置xz 坐标使得 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);

【讨论】:

  • 我不是试图打开蠕虫的“3d 图形”罐头,我只是想正确地将纹理应用到四边形。你确定我需要做所有这些吗?
  • 需要做“所有”什么,在片段着色器中添加一个分区?是的,我很确定你会这样做。
  • 等等。关于四边形的水平轴的对称缩放怎么样?
猜你喜欢
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-01
  • 1970-01-01
相关资源
最近更新 更多