iOS Development--metal Tutorial

Source: Internet
Author: User

Metal Swift Tutorials

Learn new api:metal! for accelerating 3D graphics with Apple GPU In iOS 8, Apple released a new interface called Metal, an API that supports GPU-accelerated 3D drawing. Similar to metal and OpenGL ES, it is also an underlying API that interacts with 3D drawing hardware. The difference between them is that metal is not cross-platform. By contrast, it has been designed to run extremely efficiently on Apple hardware, providing faster speeds and lower overhead than OpenGL ES. In this tutorial, you will get your own experience, using metal and Swift to create an application with a basic context: draw a simple triangle. In this process, you will learn some of the most important classes in metal, such as devices, command queues, and so on. This tutorial is designed for anyone to read clearly, whether you have studied 3D drawing or not. But we're going to have a very fast time. If you have had 3D programming or OpenGL programming experience before, you will find it very simple, because many of the concepts inside you are already familiar with. This tutorial assumes that you are already familiar with Swift. If you're still a swift novice, learn these tutorials first, Apple Swift site, and some swift tutorials.Note: Metal apps don't run on iOS simulators, they need a device that's loaded with an Apple A7 chip or a newer chip. So to learn this tutorial, you need a device like this (IPhone 5s,ipad air,ipad mini2) to complete the code test. Metal vs. Sprite kit, Scene Kit, or UnityBefore we get started, I want to discuss how to compare metal and some less basic frameworks, such as Sprite kit,scene Kit or unity. Metal is a low-level 3D drawing API similar to OpenGL, but it costs less. It is a simple package on a GPU, so it can do almost anything, like rendering a Sprite (sprite) on the screen or a 3D model. But you have to write all the code to accomplish these things. The price of this hassle is that you have the power and control of the GPU. There is no underlying game frame, like the sprite kit, Scene kit, or unity built on the underlying 3D drawing API (like metal or OpenGL ES). They provide most of the underlying package code you need to write in the game, such as rendering a Sprite (sprite) or a 3D model on the screen. If all you want to do is make a game, in most cases I would recommend you use a library that is not so low-level, like a Sprite kit, Scene kit, or unity, because it makes your job easier. If you like this, we have a lot of tutorials to help you learn these frameworks. However, there are two good reasons to learn metal:1. The peak of the operating efficiency of the hardware: Because the metal is very low, it allows you to achieve peak operating efficiency of your hardware and gives you complete control over how your game works. 2. This is a good learning experience: Learning metal teaches you a lot about 3D drawing programming concepts, writing your own game engine, and how the high-level higher game framework works. If any of the above is a good reason for you, read on! Metal vs OpenGL ESLet's look at the differences between metal and OpenGL ES. OpenGL ES is designed as a cross-platform. That means you can use the C++opengl es code, and in most cases you can make it run on another platform, such as Android, with little change. Apple realizes that while OpenGL ES is great for cross-platform support, it lacks the basic idea of some apple-designed products: Apple integrates the operating system, hardware, and software. So Apple seriously considered what would happen if they designed a specific drawing API based on their hardware? Its goal is to run fast, with low overhead, and to support the latest and best features. So metal was born. It compares OpenGL ES and can increase the number of draw calls up to 10 times times for your application unit time. This can produce awesome effects, likeWWDC KeynoteA sample of the Zen garden. Let's start by looking at some metal code! StartXcode's iOS game template has a metal option, but you don't have to choose it here. This is because I want to show you how to write a metal application, so you can understand every step of the process. Open Xcode 6 to create a new project from the Ios\application\single View application template. Using Hellometal as the project name, set the development language to swift and set the device as a universal device (Universal). Click Next, select a directory, and click Create. There are seven steps to set up metal:1. Create a MTLDevice2. Create a CAMetalLayer3. Create a vertex Buffer4. Create a vertex Shader5. Create a fragment Shader6. Create a render Pipeline7. Create a command Queue Let's look at them.1) Create a mtldeviceUsing metal the first thing you need to do is get a mtldevice reference. You can think of a mtldevice as a direct connection between you and the CPU. You will create all the other metal objects you need by using Mtldevice (like command queues,buffers,textures). To do this, open Viewcontroller.swift and add the following import statement to the top of the file:
    1. Import Metal
This imports the metal framework, so you can use the metal class (like the Mtldevice in this file). Next, add the following attributes in the Viewcontroller class:
    1. var device:mtldevice! = Nil
You are going to initialize this property within the Viewdidload function, not in an init function, so it has to be a optional. Now that you know you'll be sure to initialize it before using it, you can mark it as an implicit non-wrapped optional for convenience. Finally, add this line to the end of the Viewdidload function.
    1. device = Mtlcreatesystemdefaultdevice ()
This function returns a default Mtldevice reference, which your code will use.2) Create a cametallayerIn iOS, everything you see on the screen is hosted by a calayer. Subclasses of Calayer that have different effects, such as gradient layers (gradient layers), shape layers (shape layers), repeating layers (replicator layers), and so on. Well, if you want to draw something on the screen with metal, you need to use a special Calayer subclass, Cametallayer. So add a viewcontroller to your list. First, add an import statement above this file.
    1. Import Quartzcore
You need it because Cametallayer is part of the Quartzcore framework, not the metal frame. Then add the new attribute to the class:
    1. var metallayer:cametallayer! = Nil
This will store a reference to your new layer. Finally, add this line of code to the Viewdidload method at the end.
    1. metallayer = cametallayer ()            // 1 
    2. metallayer.device =  Device           // 2 
    3. METALLAYER.PIXELFORMAT = . Bgra8unorm // 3 
    4. metallayer.framebufferonly = < span class= "keyword" >true    // 4 
    5. metallayer.frame = view.layer.frame  // 5 
    6. view.layer.addSublayer (metallayer)    // 6 
Let's look at it in a row: A. You create a cametallayerb. You must specify the Mtldevice that the layer uses, and you simply set up the device you acquired earlier. C. You set the pixel format (pixel format) to Bgra8unorm, which stands for "8 bytes for blue, green, red, and transparency, represented by a value that is expressed in units between 0 and 1." This is one of the two pixel formats used in Cametallayer, which you can normally write. D. Apple encourages you to set framebufferonly to true to increase performance efficiency. Unless you need to sample a texture generated from layer (textures), or you need to activate some compute cores in the layer drawing texture (drawable textures), you don't need to set it up. (Most of the cases you don't have to set) E. You set the frame of the layer to the frame of the view. F. You add the layer as a sub-layer under View.layer.3) Create a vertex BufferEvery thing in the metal is a triangle. In this application, you only need to draw a triangle, but even the most complex 3D shape can be deconstructed into a series of triangles. In metal, the default coordinate system is the vector coordinate system, which means that by default, a 2x2x1 cube, the center point is (0,0,0.5). If you think Z=0 is a plane, then ( -1,-1,0) is the lower left corner, (0,0,0) is the center, (1,1,0) is the upper right corner. In this tutorial, you want to draw a triangle on these points: let's create a buffer. Add the following constant properties to your class:
    1. Let vertexdata:[float] = [
    2. 0.0, 1.0, 0.0,
    3. -1.0,-1.0, 0.0,
    4. 1.0,-1.0, 0.0]
This creates a floating-point array on the CPU-you need to send this data to the GPU by moving it to a thing called Mtlbuffer. To add another new property:
    1. var vertexbuffer:mtlbuffer! = Nil
Then add the following code at the end of the Viewdidload method:
    1. Let datasize = Vertexdata.count * Sizeofvalue (vertexdata[0]) //1
    2. VertexBuffer = Device.newbufferwithbytes (VertexData, Length:datasize, Options:nil) //2
Let's look at the line: a. You need to get the byte size of vertex data. You get by multiplying the size of the first element and the number of elements in the array. B. You raise the Mtldevice with Newbufferwithbytes (length:options:), create a new buffer on the GPU, and transfer data from the CPU. You pass nil to accept the default option.4) Create a vertex ShaderThe vertices you created earlier will be the input of a small program called Vertext shader that you write next. A vertex shader is a small program that runs on the GPU, written in a language like C + +, which is calledMetal Shading Language。 A vertex shader is called by each vertex, and its work is to accept the vertex information (such as position and color, texture coordinates), return a potential correction location (there may be other related information). To keep things simple, your vertex shader will return a position that is the same as the delivery position. The simplest way to learn about vertex shader is to experience it yourself. Click File\new\file, select Ios\source\metal File, and then click Next. Enter Shader.metal as the file name, press ENTER, and then click Create. Note: In metal, you can include multiple shaders in a metal file. You can also scatter your shader in multiple metal files. Metal will load the shaders contained in your project from any metal file. Add the following code at the bottom of the shaders.metal:
  1. Vertex float4 Basic_vertex ( //1
  2. Const device PACKED_FLOAT3* vertex_array [[Buffer (0)], //2
  3. unsigned int vid [[vertex_id]]) { //3
  4. return Float4 (Vertex_array[vid], 1.0); //4
  5. }
Let's look at the line: A. All vertex shaders must start with the keyword vertex. The function must return at least the final position of the vertex-you specify FLOAT4 (a vector of 4 floating-point numbers for an element). Then you give a name to Vetex shader, in the future you will use this name to visit this vertex shader. B. The first parameter is a pointer to an array with an element of PACKED_FLOAT3 (a vector containing 3 floating-point numbers), such as: the position of each vertex. This [[...]] syntax is used to declare attributes that can be used as specific additional information, such as resource location, shader input, and built-in variables. Here you mark this parameter with [[Buffer (0)]] to indicate that this parameter will be traversed by the first buffer data in your code that you send to your vertex shader. C.vertex shader will accept a specific parameter of a property called vertex_id, which means it will be loaded by a particular vertex in the vertex array. D. Now you retrieve the vertex of the corresponding position in the vertex array based on the vertex ID and return it. At the same time you convert this vector to a float4 type, and the last value is set to 1.0 (in a nutshell, this is the 3D math requirement).5) Create a fragment ShaderAfter completing our vertex shader, another shader, which is called by each fragment (think pixel) on the screen, is fragment shader. The output of the fragment shader vertex shader via interpolation (interpolating) also obtains its own input. For example: Think of the input value of the fragment:fragment between the two bottom vertices of the triangle will be made up of 50% of the lower left corner vertices and 50% of the lower right corner vertices. Fragment shader's job is to return the final color to each fragment. For simplicity, you will return each fragment to white. Add the following code at the bottom of the shader.metal:
    1. Fragment Half4 basic_fragment () { //1
    2. return Half4 (1.0); //2
    3. }
Let's look at the line: A. All fragment shaders must start with the Fragment keyword. This function must return at least the final color of the fragment-you accomplish this task by specifying HALF4 (an RGBA value of a color). Note that HALF4 is more efficient in memory than FLOAT4 because you write less GPU memory. B. Here you return (1,1,1,1) the color, which is white.6) Create a render PipelineNow that you have created a vertex shader and a fragment shader, you need to combine them (plus some configuration data) into a special object called Render pipeline. Metal a cool place is that the renderer (shaders) is precompiled, and the render pipeline configuration is compiled the first time you set it up, so everything is extremely efficient. First add an attribute to the Viewcontroller.swift:
    1. var pipelinestate:mtlrenderpipelinestate! = Nil
This will be traced to the render pipeline you are about to create, after it has been compiled. Next, add the following code at the end of the Viewdidload method:
  1. 1
  2. Let defaultlibrary = Device.newdefaultlibrary ()
  3. Let Fragmentprogram = Defaultlibrary.newfunctionwithname ("basic_fragment")
  4. Let Vertexprogram = Defaultlibrary.newfunctionwithname ("Basic_vertex")
  5. 2
  6. Let Pipelinestatedescriptor = Mtlrenderpipelinedescriptor ()
  7. Pipelinestatedescriptor.vertexfunction = Vertexprogram
  8. Pipelinestatedescriptor.fragmentfunction = Fragmentprogram
  9. Pipelinestatedescriptor.colorattachments[0].pixelformat =. Bgra8unorm
  10. 3
  11. var pipelineerror:nserror?
  12. Pipelinestate = Device.newrenderpipelinestatewithdescriptor (pipelinestatedescriptor, error: &pipelineError)
  13. If!pipelinestate {
  14. println ("Failed to create pipeline state, error \ (pipelineerror)")
  15. }
Let's look at the code in part: A. You can access the precompiled shaders in your project by invoking the Mtlibrary object obtained by the Device.newdefaultlibrary method. Then you can retrieve each shader by name. B. You are here to set your render pipeline. It contains the pixel format (pixel format) that you want to use for the shaders, color attachments (attachment). (Example: the input buffer you render to, that is, Cametallayer). C. Finally, you compile this pipeline configuration into a pipeline state, which makes it efficient to use.7) Create a command QueueThe final one-time setup step you need to make is to create a mtlcommandqueue. Think of this as a list that loads the commands you tell the GPU to execute at once. To create a command queue, simply add a property:
    1. var commandqueue:mtlcommandqueue! = Nil
Add the following line to the end of the viewdidload:
    1. Commandqueue = Device.newcommandqueue ()
Congratulations, your pre-set code is done. Render TrianglesNow it's time to learn the code that executes every frame to render the triangle! It will be completed in five steps: 1. Create a display link. 2. Create a render Pass Descriptor3. Create a command Buffer4. Create a render command ENCODER5. Submit the contents of your command buffer. Let's take a closer look!Note: In theory, this application does not actually need to render every frame, because the triangle is not moved after it is drawn. However, most applications will have objects moving, so we will do that. It also lays the groundwork for future tutorials. 1) Create a display LinkYou want a function that is called every time the device screen refreshes, so you can redraw the screen. On the iOS platform, you do this through the Cadisplaylink class. To use it, add a new attribute to the class:
    1. var timer:cadisplaylink! = Nil
Then initialize it like this at the end of the Viewdidload method:
    1. Timer = Cadisplaylink (target:self, Selector:selector ("Gameloop"))
    2. Timer.addtorunloop (Nsrunloop.mainrunloop (), Formode:nsdefaultrunloopmode)
This will set your code to call a method called Gameloop each time it refreshes the screen.
    1. Func render () {
    2. //TODO
    3. }
    4. Func Gameloop () {
    5. Autoreleasepool {
    6. Self.render ()
    7. }
    8. }
Here the Gameloop function simply calls the render function, when the render function has only one NULL implementation. Let's make it come true!2) Create a render Pass descriptorThe next step is to create a mtlrenderpassdescriptor that configures what textures will be rendered to, what is clear color, and other configurations. Simply add the following line to the render function:
    1. var drawable = metallayer.nextdrawable ()
    2. Let Renderpassdescriptor = Mtlrenderpassdescriptor ()
    3. Renderpassdescriptor.colorattachments[0].texture = Drawable.texture
    4. Renderpassdescriptor.colorattachments[0].loadaction =. Clear
    5. Renderpassdescriptor.colorattachments[0].clearcolor = Mtlclearcolor (red:0.0, green:104.0/255.0, blue:5.0/255.0, alpha:1.0)
First you raise the Nextdrawable () on the previous metal layer, and it returns the texture (texture) you need to draw to the screen. Next, you configure your render pass descriptor to use it. You set the load action to clear, which means that the texture is emptied before drawing. Then you set the painted background color to green.3) Create a command BufferThe next step is to create a command buffer. You can think of it as a series of render commands that you want to execute. The cool thing is that nothing really happens until you submit the command buffer, which gives you a good control over when things happen. Creating a command buffer is as simple as adding this line of code at the end of the render function:
    1. Let Commandbuffer = Commandqueue.commandbuffer ()
A command buffer contains one or more render instructions (render commands). Let's create one below.4) Create a render command encoder (render order Encoder)In order to create a render command, you use an object called render-command encoder. Add the following code at the end of the render function:
    1. Let Renderencoder = Commandbuffer.rendercommandencoderwithdescriptor (renderpassdescriptor)
    2. Renderencoder.setrenderpipelinestate (Pipelinestate)
    3. Renderencoder.setvertexbuffer (VertexBuffer, offset:0, atindex:0)
    4. Renderencoder.drawprimitives (. Triangle, vertexstart:0, Vertexcount:3, instancecount:1)
    5. Renderencoder.endencoding ()
Here you create a command encoder and specify the pipeline and vertices you created earlier. The most important part is to call Drawprimitives (VertexStart:vertexCount:instanceCount:). Here you tell the GPU to draw a series of triangles based on vertex buffer. Each triangle consists of three vertices, starting with a vertex labeled 0 from vertex buffer, with a total of one triangle. When you're done, you just call endencoding (). 5) Submit your command BufferThe final step is to submit the command buffer. Add the code at the end of the render function:
    1. Commandbuffer.presentdrawable (drawable)
    2. Commandbuffer.commit ()
The first line needs to ensure that the new texture appears immediately after the drawing is completed. Then you commit the transaction (transaction) and give the task to the GPU. We used to hit a lot of code, but it's finally over. Compile and run the app: I've seen the best triangles!Note: If your app crashes, make sure you're running on a real computer with A7 chip (IPhone 5s,ipad Air,ipad mini2, non-emulator).
finallyThis is our tutorialThe final project. Congratulations, you learned a lot about the metal API! You are now familiar with some important concepts of metal, such as shaders, devices, command buffers,pipeline, and so on. I might write more tutorials on this series, covering uniforms,3d, textures, lighting, and importing models. If you feel interested and want to see more tutorials, please leave a comment. Also, make sure to look at some of Apple's great resources: AppleMetal Developer Documentation, there are many links to documents, videos, sample code. Apple'sMetal Programming GuideApple'sMetal Shading Language GuideWWDC2014 Metal Video

iOS Development--metal Tutorial

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.