Draw viewport border

Hi,


I have continuing problems with my understanding of MVP matricies in 3D graphics (I know: I should probably give up! 🙂 but I'm far too stubborn).


I'm upgrading one of my app's to run with Metal instead of OpenGL. I'd like to be able to draw a border around a viewport. My original code just used the lines in opengl but I've read in Stack Overflow that Metal doesn't directly support line drawing: a line has to be drawn with a primitive quad 'squeezed' to the desired width of a line.


So that seems fine but my issue it keeping the 'line' in place while the MTKView is resized. I've got code all set up to account for resizing:


func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {
        metalViewPort.originX = 0
        metalViewPort.originY = 0
        metalViewPort.height = Double(size.height)
        metalViewPort.width = Double(size.width)
        viewPortAspect = Float(metalViewPort.width / metalViewPort.height)
        rendererStatesAndDescriptors.projectionMatrix.changeAspectRatio(newAspect: viewPortAspect)
    }


But the placed line won't stay put on the edge of the screen as I resize the window. Should I draw the line with an orthogonal projection? Or is there a method of keeping the line on the edge of the view at all sizes?


Thanks in advance,


Todd.

Accepted Reply

I just wouldn't use any projection. Use the following vertice



    static const vector_float4 positions[] =
    {
        { -1.0f,  -1.0f, 0.0f, 1.0f  },
        {  1.0f,  -1.0f, 0.0f, 1.0f, },
        { -1.0f,   1.0f, 0.0f, 1.0f, },
        { -1.0f,   1.0f, 0.0f, 1.0f },
        {  1.0f,   1.0f, 0.0f, 1.0f }
    };
    
    id positionBuffer = [metalDevice newBufferWithBytes:positions
                                                            length:sizeof(positions)
                                                           options:0];

and the following shader


struct VertexInOut
{
    float4 position  [[ position ]];
    float4 color;
};

vertex VertexInOut vertexFunc(const device float4   *positions [[ buffer(0) ]],
                              const device float4   *colors    [[ buffer(1) ]],
                              uint                   vid       [[ vertex_id ]])
{
    VertexInOut vertices;
    vertices.position  = positions[vid];
    vertices.color = colors[vid];
    return vertices;
}

fragment float4 fragmentFunc(VertexInOut frag         [[ stage_in   ]])
{
    return frag.color;
}

This will draw a 1 pixel width line just to the inside fo the viewport you specified with -[MTLRenderCommandEncoder setViewport:];

Replies

I just wouldn't use any projection. Use the following vertice



    static const vector_float4 positions[] =
    {
        { -1.0f,  -1.0f, 0.0f, 1.0f  },
        {  1.0f,  -1.0f, 0.0f, 1.0f, },
        { -1.0f,   1.0f, 0.0f, 1.0f, },
        { -1.0f,   1.0f, 0.0f, 1.0f },
        {  1.0f,   1.0f, 0.0f, 1.0f }
    };
    
    id positionBuffer = [metalDevice newBufferWithBytes:positions
                                                            length:sizeof(positions)
                                                           options:0];

and the following shader


struct VertexInOut
{
    float4 position  [[ position ]];
    float4 color;
};

vertex VertexInOut vertexFunc(const device float4   *positions [[ buffer(0) ]],
                              const device float4   *colors    [[ buffer(1) ]],
                              uint                   vid       [[ vertex_id ]])
{
    VertexInOut vertices;
    vertices.position  = positions[vid];
    vertices.color = colors[vid];
    return vertices;
}

fragment float4 fragmentFunc(VertexInOut frag         [[ stage_in   ]])
{
    return frag.color;
}

This will draw a 1 pixel width line just to the inside fo the viewport you specified with -[MTLRenderCommandEncoder setViewport:];

Sorry for a late response. Thanks for that I hope to give it a whirl later in the week. I did wonder about just dropping the projection part of the equation.