Metal Draw Single Pixel

I'm trying to use metal to create a pixel art game and I don't know the best way to draw a single pixel. My goal is 1:1 screen to game pixel control so everything looks as sharp as possible.


It seems like drawing primitive points at given vertices results in the game vertices being drawn in between actual device screen pixels despite my best efforts to align them.


I'm wondering if the solution is to draw four vertices around a screen pixel, then using the fragment shader to fill in the color. But that seems like it would take 4 times larger vertex buffers, unless I'm missing something.


Here's an excerpt from my ViewController:


renderEncoder.setVertexBuffer(vertexBuffer, offset:ConstantBufferSize * bufferIndex * sizeof(Float) * 2, atIndex: 0)
renderEncoder.setVertexBuffer(colorBuffer, offset:ConstantBufferSize * bufferIndex * sizeof(Float) * 3, atIndex: 1)
renderEncoder.drawPrimitives(.Point, vertexStart: 0, vertexCount: self.vertexCount, instanceCount: 1)


And the entirety of my shader:

struct VertexInOut
{
    float4 position [[position]];
    float4 color;
    float pointSize [[ point_size ]];
};
constant float POINT_SIZE = 1.0f;
vertex VertexInOut passThroughVertex(uint vid [[ vertex_id ]],
                                     constant packed_float2* position  [[ buffer(0) ]],
                                     constant packed_float3* color    [[ buffer(1) ]])
{
    VertexInOut outVertex;
   
    outVertex.position = float4(position[vid], 0, 1);;
    outVertex.color    = float4(color[vid], 1);
    outVertex.pointSize = POINT_SIZE;
   
    return outVertex;
};
fragment half4 passThroughFragment(VertexInOut inFrag [[stage_in]])
{
    return half4(inFrag.color);
};


Thanks!

What you are doing is a recipe for disaster (and guarantee for very low performance) 🙂 You should use textures instead. I wouldn't even try to draw individual pixels.

I think POINT_SIZE should be 0.5 instead of 1.0.

How would I use textures?


It's a falling sand game where each screen pixel represents one piece of sand.

Have you seen Simon Gladman's particle tests with Metal?


If not, google them. You might find adding physics to what he's doing gives you amazing results.


----


On granularity to a grid of pixels for a sand game:


Pick a grid size, and then do the kind of operation that rounds every position to an exact position within that grid.


If our grid is edge/corner based, then values half of the grid size for a centred origin will correctly place the object to make it clean and tight within the grid. Which is what Prin_E is trying to suggest with his comment about 0.5 as opposed to 1.0

Metal Draw Single Pixel
 
 
Q