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

时间:2017-03-09 14:11:33

标签: metal

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

计算功能

可以概括为

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.positionin.texCoords似乎总是为零。顶点和片段着色器接收的texcoords和位置值是否应该在顶点数据中定义的值范围内?

1 个答案:

答案 0 :(得分:1)

我的顶点缓冲区是正确的,但错误

在将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