以编程方式编写纹理并在片段着色器中读取它

Programmatically writing a texture and reading it in fragment shader

我编写了一个输出到纹理的计算着色器。输出纹理的坐标系以像素为单位。然后我有一个基本的顶点和片段着色器,它应该简单地对值进行采样并响应我认为在归一化坐标中的内容。但是,我认为我以编程方式绘制的纹理和渲染表面的顶点之间的这种映射会匹配。

计算函数

可以概括为

texture.write(color, uint2(x, y));

其中 x 和 y 是整数像素位置。

顶点数据

// position.x, position.y, texCoords.x, texCoords.y
let vertexData = [Float](arrayLiteral:
    -1,  1, 0, 0,
    -1, -1, 0, 1,
     1, -1, 1, 1,
     1, -1, 1, 1,
     1,  1, 1, 0,
    -1,  1, 0, 0)

金属着色器

typedef struct {
    packed_float2 position;
    packed_float2 texCoords;
} VertexIn;

typedef struct {
    float4 position [[ position ]];
    float2 texCoords;
} FragmentVertex;

vertex FragmentVertex simple_vertex(device VertexIn *vertexArray [[ buffer(0) ]],
                                      uint vertexIndex [[ vertex_id ]])
{
    VertexIn in = vertexArray[vertexIndex];

    FragmentVertex out;
    out.position = float4(in.position, 0.f, 1.f);
    out.texCoords = in.texCoords;

    return out;
}

fragment float4 simple_fragment(FragmentVertex in [[ stage_in ]],
                               texture2d<uint, access::sample> inputTexture [[ texture(0) ]],
                               sampler linearSampler [[ sampler(0) ]])
{
    const uint2 imageSizeInPixels = uint2(360, 230);
    float imageSizeInPixelsWidth = imageSizeInPixels.x;
    float imageSizeInPixelsHeight = imageSizeInPixels.y;
    float2 coords = float2(in.position.x / 360.f, in.position.y / 230.f);
    float color = inputTexture.sample(linearSampler, in.texCoords).x / 255.f;

    return float4(float3(color), 1.f);
}

采样器

let samplerDescriptor = MTLSamplerDescriptor()
            samplerDescriptor.normalizedCoordinates = true
            samplerDescriptor.minFilter = .linear
            samplerDescriptor.magFilter = .linear
            samplerDescriptor.sAddressMode = .clampToZero
            samplerDescriptor.rAddressMode = .clampToZero
            self.samplerState = self.metalDevice?.makeSamplerState(descriptor: samplerDescriptor)

在这个实验中,唯一似乎有效的值是 coords,基于标准化的 in.position 值。 in.texCoords 似乎总是零。顶点和片段着色器接收到的纹理坐标和位置值不应该在顶点数据中定义的值范围内吗?

我的顶点缓冲区是对的,但错了

在将Obj-C代码转换为Swift的过程中,我未能完全复制顶点。

正确的副本

let byteCount = vertexData.count * MemoryLayout<Float>.size
let vertexBuffer = self.metalDevice?.makeBuffer(bytes: vertexData, length: byteCount, options: options)

我痛苦的根源

let vertexBuffer = self.metalDevice?.makeBuffer(bytes: vertexData, length: vertexData.count, options: options)

完整的顶点缓冲区创建

// Vertex data for a full-screen quad. The first two numbers in each row represent
// the x, y position of the point in normalized coordinates. The second two numbers
// represent the texture coordinates for the corresponding position.
let vertexData = [Float](arrayLiteral:
        -1,  1, 0, 0,
        -1, -1, 0, 1,
         1, -1, 1, 1,
         1, -1, 1, 1,
         1,  1, 1, 0,
        -1,  1, 0, 0)

// Create a buffer to hold the static vertex data

let options = MTLResourceOptions().union(.storageModeShared)
let byteCount = vertexData.count * MemoryLayout<Float>.size
let vertexBuffer = self.metalDevice?.makeBuffer(bytes: vertexData, length: byteCount, options: options)
vertexBuffer?.label = "Image Quad Vertices"
self.vertexBuffer = vertexBuffer