Cameron Lowell Palmer
Cameron Lowell Palmer

Reputation: 22245

Programmatically writing a texture and reading it in fragment shader

I've written a Compute shader that outputs to a Texture. The coordinate system of the output texture is in pixels. I then have a basic vertex and fragment shader that should simply sample the value and respond with what I thought would be in normalised coordinates. However, I thought this mapping between my programmatically drawn texture and the vertices of my rendering surface would match up.

The Compute Function

Can be summarized as

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

where x and y are integer pixel locations.

The Vertex Data

// 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)

The Metal Shader

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);
}

The Sampler

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)

In this experiment the only value that seems to work is coords, based upon the normalized in.position value. in.texCoords seems to always be zero. Shouldn't the texcoords and position received by the vertex and fragment shader be values be in the range of values defined in the vertex data?

Upvotes: 3

Views: 1357

Answers (1)

Cameron Lowell Palmer
Cameron Lowell Palmer

Reputation: 22245

My Vertex Buffer was right, but wrong

In the process of converting Obj-C code to Swift I failed to copy the vertex completely.

The Correct Copy

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

The Source of my Woes

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

The Complete Vertex Buffer Creation

// 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

Upvotes: 1

Related Questions