Andrey Lyubimov
Andrey Lyubimov

Reputation: 673

Metal API won't draw simple triangle followed by WWDC2014 lecture

I've followed the lecture given on WWDC2014 on how to use Metal API where they're creating "Hello world" app with a simple triangle. I'm expecting to see a red triangle on green background. Everything is great, but the triangle itself isn't there and I can't figure out why. Please help!

these lines are metal shaders:

struct Vertex
{
    float3 position;
};

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

vertex VertexOut myVertexShader(
                            device Vertex* vertexArray [[ buffer(0) ]],
                            unsigned int vid                 [[ vertex_id ]])
{
    VertexOut out;
    float3 pos = vertexArray[vid].position;
    out.position = float4(pos[0], pos[1], pos[2], 0.0);
    out.color    = float4(1.0, 0.0, 0.0, 1.0);
    return out;
}

fragment float4 myFragmentShader(VertexOut interpolated [[ stage_in ]])
{
    return interpolated.color;
}

these are view:

@implementation MyView

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];

    if(self)
    {
        _device = MTLCreateSystemDefaultDevice();
    }
    NSLog(@"MyView::initWithCoder called");
    return self;
}

+(id)layerClass
{
    return [CAMetalLayer class];
}

@end

and these are view controller:

static const float zcoord = 0.f;
static const float vertexArrayData[] =
{
     -0.3,   -0.5, zcoord,
     0.3,    -0.5, zcoord,
     0.f,    0.2, zcoord
};

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    MyView* view = (MyView*) self.view;

    id<MTLCommandQueue> queue = [view.device newCommandQueue];
    id<MTLBuffer> vertexArray = [view.device newBufferWithBytes:vertexArrayData
                                                         length:sizeof(vertexArrayData)
                                                        options:0];

    MTLRenderPipelineDescriptor* desc = [MTLRenderPipelineDescriptor new];
    id<MTLLibrary> lib = [view.device newDefaultLibrary];
    desc.vertexFunction = [lib newFunctionWithName:@"myVertexShader"];
    desc.fragmentFunction = [lib newFunctionWithName:@"myFragmentShader"];
    desc.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;

    id<MTLRenderPipelineState> renderPipeline = [view.device newRenderPipelineStateWithDescriptor:desc error:nil];

    id<MTLCommandBuffer> commandBuffer = [queue commandBuffer];
    id<CAMetalDrawable> drawable = [(CAMetalLayer*)view.layer nextDrawable];

    MTLRenderPassDescriptor* renderDesc = [MTLRenderPassDescriptor new];
    renderDesc.colorAttachments[0].texture = drawable.texture;
    renderDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
    renderDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 1.0, 0.0, 1.0);

    id<MTLRenderCommandEncoder> render = [commandBuffer renderCommandEncoderWithDescriptor:renderDesc];
    [render setRenderPipelineState:renderPipeline];
    [render setVertexBuffer:vertexArray offset:0 atIndex:0];
    [render drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
    [render endEncoding];

    [commandBuffer presentDrawable:drawable];

    [commandBuffer commit];
}

Upvotes: 1

Views: 231

Answers (1)

Andrey Lyubimov
Andrey Lyubimov

Reputation: 673

I've got it, fellas.

The problem is in this line:

out.position = float4(pos[0], pos[1], pos[2], 0.0);

the last component of float4 shouldn't be zero. Putting 1.0 helped.

Regards

Upvotes: 2

Related Questions