iOS 8 Introduzione a Metal

Questo tutorial ti mostrerà come iniziare con Metal, un framework introdotto in iOS 8 che supporta il rendering grafico 3D accelerato GPU e carichi di lavoro di calcolo parallelo dei dati. In questo tutorial, daremo un'occhiata ai concetti teorici che sottostanno a Metal. Imparerai anche come creare un'applicazione Metal che imposta lo stato hardware richiesto per la grafica, impegna i comandi per l'esecuzione nella GPU e gestisce il buffer, gli oggetti texture e gli shader precompilati.

1. Prime cose prima

Questo tutorial presume che tu abbia familiarità con il linguaggio Objective-C e abbia esperienza con OpenGL, OpenCL o un'API grafica comparabile.

Richiede anche un dispositivo fisico con un processore Apple A7 o A8. Ciò significa che avrai bisogno di un iPhone 5S, 6 o 6 Plus o di un iPad Air o mini (2a generazione). Il simulatore iOS ti darà errori di compilazione.

Questo tutorial si concentra solo su Metal e non coprirà il Metal Shading Language. Creeremo uno shader, ma riguarderemo solo le operazioni di base per interagire con esso.

Se stai usando Xcode per la prima volta, assicurati di aggiungere il tuo ID Apple in conti sezione di Xcode Preferenze. Ciò garantirà che non si verifichino problemi durante la distribuzione di un'applicazione sul dispositivo.

Xcode 6 include un modello di progetto per Metal, ma per aiutarti a capire meglio Metal, creeremo un progetto da zero.

Una nota finale, useremo Objective-C in questo tutorial ed è importante avere una conoscenza di base di questo linguaggio di programmazione.

2. Introduzione

Per quelli di voi che hanno familiarità con OpenGL o OpenGL ES, Metal è un framework grafico 3D di basso livello, ma con un sovraccarico minore. In contrasto con i framework Sprite Kit o Scene Kit di Apple con i quali, per impostazione predefinita, non è possibile interagire con la pipeline di rendering, con Metal hai il potere assoluto di creare, controllare e modificare quella pipeline.

Il metallo ha le seguenti caratteristiche:

  • Il framework fornisce un accesso estremamente basso alle GPU A7 e A8, consentendo prestazioni incredibilmente elevate per rendering grafici sofisticati e attività computazionali.
  • Il metallo elimina molti colli di bottiglia nelle prestazioni, come la validazione dello stato costoso che si trova nelle API grafiche tradizionali.
  • È stato progettato esplicitamente per spostare tutte le costose operazioni di conversione e conversione dello stato dal runtime e dall'ambiente di rendering.
  • Fornisce shader precompilati, oggetti di stato e pianificazione esplicita dei comandi per garantire che l'applicazione raggiunga le massime prestazioni ed efficienza per il rendering grafico e le attività di calcolo.
  • Il framework è stato progettato per sfruttare le moderne considerazioni di architettura, come il multiprocessing e la memoria condivisa.
  • È profondamente integrato con iOS 8, i chipset A7 e A8 e l'hardware Apple, creando un framework unificato e indipendente.

Basta con la teoria, è ora di capire come viene costruita un'applicazione Metal.

3. Creazione di un'applicazione metallica

Un'applicazione Metal è caratterizzata da una serie di passaggi richiesti per presentare correttamente i dati sullo schermo. Questi passaggi vengono in genere creati nell'ordine e alcuni riferimenti vengono passati da uno all'altro. Questi passaggi sono:

  • prendi il dispositivo
  • creare una coda di comando
  • creare risorse, come buffer, trame e shader
  • creare una pipeline di rendering
  • creare una vista

Passaggio 1: Ottieni il dispositivo

Questo passaggio comporta la creazione di a MTLDevice oggetto, il cuore di un'applicazione Metal. Il MTLDevice la classe fornisce un modo diretto per comunicare con il driver e l'hardware della GPU. Per ottenere un riferimento a a MTLDevice esempio, è necessario chiamare il Dispositivo predefinito di sistema come mostrato di seguito. Con questo riferimento, si ha accesso diretto all'hardware del dispositivo.

id  mtlDevice = MTLCreateSystemDefaultDevice ();

Passaggio 2: creare una coda comandi

Il MTLCommandQueue class fornisce un modo per inviare comandi o istruzioni alla GPU. Per inizializzare un'istanza di MTLCommandQueue classe, è necessario utilizzare il MTLDevice oggetto che abbiamo creato in precedenza e chiamiamo il newCommandQueue metodo su di esso.

id  mtlCommandQueue = [mtlDevice newCommandQueue];

Passaggio 3: crea risorse

Questo passaggio comporta la creazione di oggetti buffer, trame e altre risorse. In questo tutorial, creerai i vertici. Questi oggetti sono memorizzati sul lato server / GPU e per comunicare con loro è necessario creare una struttura dati specifica che deve contenere dati simili a quelli disponibili nell'oggetto vertice.

Ad esempio, se è necessario passare i dati per una posizione vertice 2D, è necessario dichiarare una struttura dati contenente un oggetto per quella posizione 2D. Quindi, devi dichiararlo in entrambi i client, le tue applicazioni iOS e server, lo shader Metal. Dai un'occhiata al seguente esempio per chiarimenti.

strucedef struct GLKVector2 position;  YourDataStruct;

Si noti che è necessario importare il GLKMath libreria dal GLKit quadro come mostrato di seguito.

#importare 

Quindi dichiarare un oggetto con le coordinate corrette.

Triangolo YourDataStruct [3] = -.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f;

Passaggio 4: creare una pipeline di rendering

Creare la pipeline di rendering è probabilmente il passo più difficile, dal momento che devi occuparti di diverse inizializzazioni e configurazioni, ognuna delle quali è illustrata nello schema seguente.

La pipeline di rendering viene configurata utilizzando due classi:

  • MTLRenderPipelineDescriptor: fornisce tutti gli stati della pipeline di rendering, come posizioni dei vertici, colore, profondità e buffer degli stencil, tra gli altri
  • MTLRenderPipelineState: la versione compilata di MTLRenderPipelineDescriptor e che verranno distribuiti sul dispositivo

Si noti che non è necessario creare tutti gli oggetti della pipeline di rendering. Dovresti solo creare quelli che soddisfano le tue esigenze.

Il seguente frammento di codice mostra come creare il file MTLRenderPipelineDescriptor oggetto.

MTLRenderPipelineDescriptor * mtlRenderPipelineDescriptor = [MTLRenderPipelineDescriptor new]; 

A questo punto, hai creato il descrittore, ma devi comunque configurarlo con almeno il formato pixel. Questo è ciò che facciamo nel seguente blocco di codice.

mtlRenderPipelineDescriptor.colorAttachments [0] .pixelFormat = MTLPixelFormatBGRA8Unorm;

Per le applicazioni più avanzate, è inoltre necessario impostare gli ombreggiatori di vertici e frammenti predefiniti come mostrato di seguito.

id  lib = [mtlDevice newDefaultLibrary]; mtlRenderPipelineDescriptor.vertexFunction = [lib newFunctionWithName: @ "SomeVertexMethodName"]; mtlRenderPipelineDescriptor.fragmentFunction = [lib newFunctionWithName: @ "SomeFragmentMethodName"];

Il newFunctionWithName metodo cerca nel tuo file sorgente di Metal, cercando il file SomeVertexMethodName metodo. Il nome dello shader stesso non è importante poiché la ricerca viene effettuata direttamente attraverso i nomi dei metodi. Ciò significa che è necessario definire metodi univoci per operazioni di ombreggiamento uniche. Analizzeremo più in profondità gli shader di Metal in seguito.

Con il MTLRenderPipelineDescriptor oggetto creato e configurato, il passo successivo è quello di creare e definire il MTLRenderPipelineState passando nella nuova creazione MTLRenderPipelineDescriptor oggetto.

NSError * error = [[NSError alloc] init]; id  mtlRenderPipelineState = [mtlDevice newRenderPipelineStateWithDescriptor: mtlRenderPipelineDescriptor error: & error];

Passaggio 5: creare una vista

Per creare una vista Metallo, devi creare una sottoclasse UIView e scavalcare il layerClass metodo come mostrato di seguito.

+(id) layerClass return [classe CAMetalLayer]; 

In questo tutorial, vedremo un altro modo per creare un CAMetalLayer classe che offre allo sviluppatore un maggiore controllo sulle caratteristiche e sulla configurazione del livello.

4. Disegnare un'app di metallo

Ora che abbiamo inizializzato gli oggetti necessari, dobbiamo iniziare a disegnare qualcosa sullo schermo. Proprio come l'inizializzazione, devi seguire una serie di passaggi:

  • ottenere il buffer di comando
  • imposta un passaggio di rendering
  • disegnare.
  • commit al buffer dei comandi

Passaggio 1: Ottieni il buffer dei comandi

Il primo passaggio consiste nel creare un oggetto che memorizzi un elenco seriale di comandi per il dispositivo da eseguire. Tu crei a MTLCommandBuffer oggetto e aggiungi comandi che verranno eseguiti sequenzialmente dalla GPU. Il seguente frammento di codice mostra come creare un buffer di comandi. Noi usiamo il MTLCommandQueue oggetto che abbiamo creato in precedenza.

id  mtlCommandBuffer = [mtlCommandQueue commandBuffer];

Passaggio 2: avviare un passaggio di rendering

In Metal, la configurazione del rendering è complessa e devi indicare esplicitamente quando inizia il passaggio di rendering e quando finisce. È necessario definire le configurazioni del framebuffer in anticipo affinché iOS possa configurare correttamente l'hardware per quella specifica configurazione.

Per chi ha familiarità con OpenGL e OpenGL ES, questo passaggio è simile poiché il framebuffer ha le stesse proprietà, Colore allegato (Da 0 a 3), Profondità, e stampino configurazioni. Puoi vedere una rappresentazione visiva di questo passaggio nel diagramma sottostante.

Per prima cosa devi creare una trama per renderizzare. La trama viene creata dal CAMetalDrawable classe e usa il nextDrawable metodo per recuperare la texture successiva da disegnare nella lista.

id  frameDrawable; frameDrawable = [renderLayer nextDrawable];

Questo nextDrawable la chiamata può e sarebbe il collo di bottiglia dell'applicazione poiché può bloccare facilmente la tua applicazione. CPU e GPU possono essere desincronizzate e l'una deve attendere l'altra, il che può causare un'istruzione di blocco. Esistono meccanismi sincroni che possono e devono sempre essere implementati per risolvere questi problemi, ma non li tratteremo in questo tutorial introduttivo.

Ora che hai una texture su cui eseguire il rendering, devi creare un MTLRenderPassDescriptor oggetto per memorizzare il framebuffer e le informazioni sulla trama. Dai un'occhiata al seguente frammento di codice per vedere come funziona.

MTLRenderPassDescriptor * mtlRenderPassDescriptor; mtlRenderPassDescriptor = [MTLRenderPassDescriptor new]; mtlRenderPassDescriptor.colorAttachments [0] .texture = frameDrawable.texture; mtlRenderPassDescriptor.colorAttachments [0] .loadAction = MTLLoadActionClear; mtlRenderPassDescriptor.colorAttachments [0] .clearColor = MTLClearColorMake (0,75, 0,25, 1,0, 1,0);

Il primo passo imposta la trama per disegnare. Il secondo definisce un'azione specifica da intraprendere, in questo caso eliminando la trama e impedendo il caricamento del contenuto di tale texture nella cache della GPU. Il passaggio finale cambia il colore di sfondo in un colore specifico.

Passaggio 3: Disegna

Con il framebuffer e la texture configurata, è tempo di creare un MTLRenderCommandEncoder esempio. Il MTLRenderCommandEncoder la classe è responsabile delle interazioni tradizionali con lo schermo e può essere vista come un contenitore per uno stato di rendering grafico. Converte anche il tuo codice in un formato comando specifico per l'hardware che verrà eseguito dal dispositivo.

id  renderCommand = [mtlCommandBuffer renderCommandEncoderWithDescriptor: mtlRenderPassDescriptor]; // Imposta MTLRenderPipelineState // Disegna gli oggetti qui [renderCommand endEncoding];

Passaggio 4: eseguire il commit al buffer di comando

Ora abbiamo un buffer e le istruzioni in attesa in memoria. Il passaggio successivo consiste nel commettere i comandi nel buffer dei comandi e vedere la grafica disegnata sullo schermo. Si noti che la GPU eseguirà solo il codice che si è specificamente impegnato per l'effetto. Le seguenti righe di codice consentono di pianificare il framebuffer e il commit del buffer dei comandi sulla GPU.

[mtlCommandBuffer presentDrawable: frameDrawable]; [mtlCommandBuffer commit];

A questo punto, dovresti avere un'idea generale di come è strutturata un'applicazione Metal. Tuttavia, per comprendere correttamente tutto questo, devi farlo da solo. È giunto il momento di codificare la tua prima applicazione Metal.

5. Creazione di un'applicazione metallica

Avvia Xcode 6 e scegli Nuovo> Progetto ... dal File menu. Selezionare Applicazione vista singola dall'elenco di modelli e scegli un nome di prodotto. Impostato Objective-C come lingua e selezionare i phone dal dispositivi menu.

Aperto ViewController.m e aggiungere le seguenti istruzioni di importazione nella parte superiore.

#importare  #importare 

È inoltre necessario aggiungere il Metallo e QuartzCore strutture nel Quadri e biblioteche collegati sezione del bersaglio Costruisci fasi. D'ora in poi, la tua attenzione dovrebbe essere mirata al file di implementazione di ViewController classe.

6. Creazione della struttura metallica

Come accennato in precedenza, il primo compito è impostare e inizializzare gli oggetti core utilizzati nell'intera applicazione. Nel seguente frammento di codice, dichiariamo un numero di variabili di istanza. Questi dovrebbero sembrare familiari se hai letto la prima parte di questo tutorial.

@implementation ViewController id  mtlDevice; id  mtlCommandQueue; MTLRenderPassDescriptor * mtlRenderPassDescriptor; CAMetalLayer * metalLayer; id  frameDrawable; CADisplayLink * displayLink; 

Nel controller della vista viewDidLoad metodo, inizializziamo il MTLDevice e CommandQueue casi.

mtlDevice = MTLCreateSystemDefaultDevice (); mtlCommandQueue = [mtlDevice newCommandQueue];

Ora puoi interagire con il tuo dispositivo e creare code di comandi. Ora è il momento di configurare il CAMetalLayer oggetto. Il tuo CAMetalLayer il livello dovrebbe avere una configurazione specifica a seconda del dispositivo, del formato pixel e della dimensione del fotogramma. Dovresti anche specificare che userà solo il framebuffer e che dovrebbe essere aggiunto al layer corrente.

Se si verifica un problema durante la configurazione di CAMetalLayer oggetto, quindi il seguente frammento di codice ti aiuterà con questo.

metalLayer = [layer CAMetalLayer]; [metalLayer setDevice: mtlDevice]; [metalLayer setPixelFormat: MTLPixelFormatBGRA8Unorm]; metalLayer.framebufferOnly = YES; [metalLayer setFrame: self.view.layer.frame]; [self.view.layer addSublayer: metalLayer];

È inoltre necessario impostare l'opacità della vista, il colore di sfondo e il fattore di scala del contenuto. Questo è illustrato nel prossimo snippet di codice.

[self.view setOpaque: YES]; [self.view setBackgroundColor: nil]; [self.view setContentScaleFactor: [UIScreen mainScreen] .scale];

L'unico passo rimasto è quello di rendere qualcosa sullo schermo. Inizializza il CADisplayLink, passando dentro se stesso come bersaglio e @selector (renderScene) come il selettore. Infine, aggiungi il CADisplayLink oggetto al ciclo di esecuzione corrente.

displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector (renderScene)]; [displayLink addToRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];

Questo è ciò che è stato completato viewDidLoad il metodo dovrebbe assomigliare.

- (void) viewDidLoad [super viewDidLoad]; mtlDevice = MTLCreateSystemDefaultDevice (); mtlCommandQueue = [mtlDevice newCommandQueue]; metalLayer = [layer CAMetalLayer]; [metalLayer setDevice: mtlDevice]; [metalLayer setPixelFormat: MTLPixelFormatBGRA8Unorm]; metalLayer.framebufferOnly = YES; [metalLayer setFrame: self.view.layer.frame]; [self.view.layer addSublayer: metalLayer]; [self.view setOpaque: YES]; [self.view setBackgroundColor: nil]; [self.view setContentScaleFactor: [UIScreen mainScreen] .scale]; displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector (renderScene)]; [displayLink addToRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode]; 

Se costruisci il progetto, noterai che Xcode ci dà un avvertimento. Dobbiamo ancora implementare il renderScene metodo.

Il renderScene il metodo viene eseguito ogni frame. Ci sono diversi oggetti che devono essere inizializzati per ogni nuovo frame, come ad esempio MTLCommandBuffer e MTLRenderCommandEncoder oggetti.

I passi che dobbiamo compiere per rendere un frame sono:

  • creare un MTLCommandBuffer oggetto
  • inizializzare a CAMetalDrawable oggetto
  • inizializzare a MTLRenderPassDescriptor oggetto
  • configurare il struttura, loadAction, clearColor, e storeAction proprietà del MTLRenderPassDescriptor oggetto
  • crea un nuovo MTLRenderCommandEncoder oggetto
  • presenta il drawable e commette il buffer di comando

Sentiti libero di rivisitare ciò che abbiamo visto finora per risolvere questa sfida da solo. Se vuoi continuare con questo tutorial, dai un'occhiata alla soluzione mostrata di seguito.

- (void) renderScene id mtlCommandBuffer = [mtlCommandQueue commandBuffer]; while (! frameDrawable) frameDrawable = [metalLayer nextDrawable];  if (! mtlRenderPassDescriptor) mtlRenderPassDescriptor = [MTLRenderPassDescriptor new]; mtlRenderPassDescriptor.colorAttachments [0] .texture = frameDrawable.texture; mtlRenderPassDescriptor.colorAttachments [0] .loadAction = MTLLoadActionClear; mtlRenderPassDescriptor.colorAttachments [0] .clearColor = MTLClearColorMake (0,75, 0,25, 1,0, 1,0); mtlRenderPassDescriptor.colorAttachments [0] .storeAction = MTLStoreActionStore; id  renderCommand = [mtlCommandBuffer renderCommandEncoderWithDescriptor: mtlRenderPassDescriptor]; // Disegna oggetti qui // imposta MTLRenderPipelineState ... [renderCommand endEncoding]; [mtlCommandBuffer presentDrawable: frameDrawable]; [mtlCommandBuffer commit]; mtlRenderPassDescriptor = nil; frameDrawable = nil; 

Dobbiamo anche implementare il controller della vista dealloc metodo in cui invalidiamo il DisplayLink oggetto. Abbiamo impostato il mtlDevice e mtlCommandQueue oggetti a zero.

-(void) dealloc [displayLink invalidate]; mtlDevice = nil; mtlCommandQueue = nil; 

7. Disegnare un triangolo

Ora hai un'applicazione di base molto semplice. È ora di aggiungere la tua prima primitiva grafica, un triangolo. Il primo passo è creare una struttura per il triangolo.

strucedef struct GLKVector2 position; Triangolo;

Non dimenticare di aggiungere una dichiarazione di importazione per GLKMath libreria nella parte superiore di ViewController.m.

#importare 

Per rendere il triangolo, è necessario creare un MTLRenderPipelineDescriptor oggetto e a MTLRenderPipelineState oggetto. Inoltre, ogni oggetto che è disegnato sullo schermo appartiene al MTLBuffer classe.

MTLRenderPipelineDescriptor * renderPipelineDescriptor; id  renderPipelineState; id  oggetto;

Con queste variabili di istanza dichiarate, dovresti inizializzarle nel file viewDidLoad metodo come ho spiegato prima.

renderPipelineDescriptor = [MTLRenderPipelineDescriptor new]; renderPipelineDescriptor.colorAttachments [0] .pixelFormat = MTLPixelFormatBGRA8Unorm;

Per ombreggiare il triangolo, avremo bisogno di shader Metal. Gli shader Metal dovrebbero essere assegnati al MTLRenderPipelineDescriptor oggetto e incapsulato attraverso a MTLLibrary protocollo. Può sembrare complesso, ma è sufficiente utilizzare le seguenti righe di codice:

id  lib = [mtlDevice newDefaultLibrary]; renderPipelineDescriptor.vertexFunction = [lib newFunctionWithName: @ "VertexColor"]; renderPipelineDescriptor.fragmentFunction = [lib newFunctionWithName: @ "FragmentColor"]; renderPipelineState = [mtlDevice newRenderPipelineStateWithDescriptor: renderPipelineDescriptor error: nil];

La prima riga crea un oggetto conforme al MTLLibrary protocollo. Nella seconda riga, diciamo alla libreria quale metodo deve essere invocato all'interno dello shader per operare il vertice all'interno della pipeline di rendering. Nella terza riga, ripetiamo questo passaggio a livello di pixel, i frammenti. Infine, nell'ultima riga creiamo a MTLRenderPipelineState oggetto.

In Metal, puoi definire le coordinate del sistema, ma in questo tutorial userai il sistema di coordinate di default, cioè le coordinate del centro dello schermo sono (0,0).

Nel seguente blocco di codice, creiamo un oggetto triangolare con tre coordinate, (-.5f, 0.0f), (0.5f, 0.0f), (0.0f, 0.5f).

Triangolo triangolo [3] = -.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f;

Quindi aggiungiamo il triangolo al oggetto, che crea un buffer per il triangolo.

object = [mtlDevice newBufferWithBytes: & triangle length: sizeof (Triangle [3]) options: MTLResourceOptionCPUCacheModeDefault];

Questo è ciò che è stato completato viewDidLoad il metodo dovrebbe assomigliare.

- (void) viewDidLoad [super viewDidLoad]; mtlDevice = MTLCreateSystemDefaultDevice (); mtlCommandQueue = [mtlDevice newCommandQueue]; metalLayer = [layer CAMetalLayer]; [metalLayer setDevice: mtlDevice]; [metalLayer setPixelFormat: MTLPixelFormatBGRA8Unorm]; metalLayer.framebufferOnly = YES; [metalLayer setFrame: self.view.layer.frame]; [self.view.layer addSublayer: metalLayer]; [self.view setOpaque: YES]; [self.view setBackgroundColor: nil]; [self.view setContentScaleFactor: [UIScreen mainScreen] .scale]; // Crea una pipeline riutilizzabile renderPipelineDescriptor = [MTLRenderPipelineDescriptor new]; renderPipelineDescriptor.colorAttachments [0] .pixelFormat = MTLPixelFormatBGRA8Unorm; id  lib = [mtlDevice newDefaultLibrary]; renderPipelineDescriptor.vertexFunction = [lib newFunctionWithName: @ "VertexColor"]; renderPipelineDescriptor.fragmentFunction = [lib newFunctionWithName: @ "FragmentColor"]; renderPipelineState = [mtlDevice newRenderPipelineStateWithDescriptor: renderPipelineDescriptor error: nil]; Triangolo triangolo [3] = -.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f; object = [mtlDevice newBufferWithBytes: & triangle length: sizeof (Triangle [3]) options: MTLResourceOptionCPUCacheModeDefault]; displayLink = [CADisplayLink displayLinkWithTarget: self selector: @selector (renderScene)]; [displayLink addToRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode]; 

Il viewDidLoad il metodo è completo, ma manca un ultimo passaggio, creando gli shader.

8. Creazione di shader

Per creare uno shader di metallo, selezionare Nuovo> File ...  dal File menu, scegliere fonte > File di metallo dal iOS sezione, e nominarlo myshader. Xcode creerà quindi un nuovo file per te, MyShader.metal.

Nella parte superiore, dovresti vedere le seguenti due righe di codice. Il primo include il Libreria standard di metallo mentre il secondo usa il metallo namespace.

#includere  usando il namespace metal;

Il primo passo è copiare la struttura triangolare sullo shader. Gli shader sono solitamente divisi in due diverse operazioni, vertice e pixel (frammenti). Il primo è relativo alla posizione del vertice mentre il secondo è relativo al colore finale di quel vertice e tutte le posizioni dei pixel all'interno del poligono. Puoi guardarlo in questo modo, il primo rasterizzerà il poligono, i pixel del poligono e il secondo ombreggia quegli stessi pixel.

Dal momento che hanno bisogno di comunicare in modo unidirezionale, dal vertice al frammento, è meglio creare una struttura per i dati che verranno passati. In questo caso, passiamo solo la posizione.

typedef struct float4 position [[position]];  TriangleOutput;

Ora creiamo i metodi dei vertici e dei frammenti. Ricorda quando hai programmato il RenderPipelineDescriptor oggetto sia per vertice che per frammento? Hai usato il newFunctionWithName metodo, passando in un NSString oggetto. Quella stringa è il nome del metodo che chiami all'interno dello shader. Ciò significa che devi dichiarare due metodi con quei nomi, VertexColor e FragmentColor.

Cosa significa questo? Puoi creare i tuoi shader e nominarli come preferisci, ma devi chiamare i metodi esattamente come li dichiari e dovrebbero avere nomi univoci.

All'interno degli shader, aggiungi il seguente blocco di codice.

vertice TriangleOutput VertexColor (const device Triangle * Vertices [[buffer (0)]], const uint index [[vertex_id]]) TriangleOutput out; out.position = float4 (Vertices [index] .position, 0.0, 1.0); ritorna;  fragment half4 FragmentColor (void) return half4 (1.0, 0.0, 0.0, 1.0); 

Il VertexColor il metodo riceverà i dati memorizzati nella posizione 0 del buffer (memoria allocata) e il vertex_id del vertice. Dal momento che abbiamo dichiarato un triangolo a tre vertici, il vertex_id sarà 0, 1, e 2. Emette a TriangleOutput oggetto che viene automaticamente ricevuto dal FragmentColor. Infine, ombreggia ogni pixel all'interno di questi tre vertici usando un colore rosso.

Questo è tutto. Crea ed esegui la tua applicazione e goditi la tua prima, nuovissima applicazione Metal 60fps.

9. Risorse esterne

Se vuoi saperne di più sulla struttura metallica e su come funziona, puoi consultare diverse altre risorse:

  • WWDC 2014 (Lavorare con le sezioni di metallo)
  • Riferimento del quadro metallico
  • Guida alla programmazione dei metalli

Conclusione

Questo conclude il nostro tutorial introduttivo sul nuovo framework Metal. Se avete domande o commenti, sentitevi liberi di lasciare una riga nei commenti.