Challenge: Draw with metal-cpp

Paint brush symbol and metal logo symbol on a dark background

Metal is the foundation for accelerated graphics and compute power on Apple platforms — and if you’re familiar with C++, now’s the perfect time to explore its incredible power. For this challenge, we're inviting you to try out metal-cpp and render your own triangle, sphere, or even a mesh in Xcode.

We also welcome you to visit the Graphics & Games Study Hall during the day to collaborate on this challenge! Ask questions, connect with other developers, and share your creations.

Study Hall: Draw with metal-cpp

Get ready to render: We're inviting you to try out metal-cpp and render your own triangle, sphere, or even a mesh in Xcode. Visit the Graphics & Games Study Hall to collaborate on the “Draw with metal-cpp” coding challenge. Ask questions, connect with other developers, and share your creations.

View now

Begin the challenge

Before you begin, you’ll want to watch “Program Metal in C++ with metal-cpp” and download the LearnMetalCPP project, which contains a series of C++ samples.

Program Metal in C++ with metal-cpp

Your C++ games and apps can now tap into the power of Metal. We'll show you how metal-cpp helps you bridge your C++ code to Metal, explore how each manages object lifecycles, and demonstrate utilities that can help these language cooperate in your app. We'll also share best practices for designing...

Watch now

Download the LearnMetalCPP project

Open the project in Xcode, and choose 00-window.cpp as your base code. To render your image, you’ll need to set up a few things within your project.

First, create a MTL::RenderPipelineState object with a MTL::RenderPipelineDescriptor. To do this, you’ll need to create a function, like buildShaders(). In the code snippet below, we’ve provided the shader code needed to render a single triangle.

void Renderer::buildShaders()
{
    using NS::StringEncoding::UTF8StringEncoding;

    const char* shaderSrc = R"(
        #include <metal_stdlib>
        using namespace metal;
        struct AAPLVertex
        {
            float3 position;
            half3  color;
        };
    
        // Welcome to modify the mesh as you want
        constant AAPLVertex triangles[] = {
            { float3{ -0.8f,  0.8f, 0.0f }, half3{  1.0, 0.3f, 0.2f } },
            { float3{  0.0f, -0.8f, 0.0f }, half3{  0.8f, 1.0, 0.0f } },
            { float3{ +0.8f,  0.8f, 0.0f }, half3{  0.8f, 0.0f, 1.0 } }
        };
    
        struct v2f
        {
            float4 position [[position]];
            half3 color;
        };

        v2f vertex vertexMain( uint vertexId [[vertex_id]])
        {
            v2f o;
            o.position = float4( triangles[ vertexId ].position, 1.0 );
            o.color = half3 ( triangles[ vertexId ].color );
            return o;
        }

        half4 fragment fragmentMain( v2f in [[stage_in]] )
        {
            return half4( in.color, 1.0 );
        }
    )";
    // TODO: Create a MTL::RenderPipelineDescriptor
    // TODO: Allocate a MTL::RenderPipelineState object
}

Then, extend the Renderer::draw( MTK::View* pView) function by setting a MTL::RenderPipelineState and inserting draw calls.

void Renderer::draw(  MTK::View* pView  )
{
...
    // TODO: Set MTL::RenderPipelineState
    // TODO: Draw a single triangle or more!
...
}

After that:

  • Create the MTL::RenderPipelineDescriptor object and set up some properties.
  • Create the MTL::RenderPipelineState object.
  • Tip: Be careful with object lifecycles.

Ready to share your metal-cpp art with the community? Show us what you’ve made on Twitter with the hashtag #WWDC22Challenges, or share your work in the Graphics & Games Study Hall. And if you'd like to discuss metal-cpp and other Graphics & Games topics, join the team at events all throughout the week at WWDC22.

Explore #WWDC22Challenges on social media

Read the WWDC22 Challenges Terms and Conditions