Acest tutorial vă va arăta cum să începeți cu Metal, un cadru introdus în iOS 8 care susține redarea grafică grafică 3D accelerată de GPU și încărcările de date paralele de calcul. În acest tutorial, vom arunca o privire asupra conceptelor teoretice care subliniază Metalul. Veți învăța, de asemenea, cum să creați o aplicație Metal care stabilește starea hardware necesară pentru grafică, comitează comenzi pentru execuție în GPU și gestionează tampoane, obiecte de textură și shadere precompilate.
Acest tutorial presupune că sunteți familiarizat cu limba Objective-C și că aveți o experiență în OpenGL, OpenCL sau într-un grafic API comparabil.
De asemenea, este nevoie de un dispozitiv fizic cu un procesor Apple A7 sau A8. Aceasta înseamnă că veți avea nevoie de un iPhone 5S, 6 sau 6 Plus sau un iPad Air sau mini (a doua generație). Simulatorul iOS vă va oferi erori de compilare.
Acest tutorial se concentrează numai pe Metal și nu va acoperi limbajul Metal Shading. Vom crea un shader, dar vom acoperi doar operațiunile de bază pentru a interacționa cu el.
Dacă utilizați Xcode pentru prima dată, asigurați-vă că adăugați ID-ul Apple în Conturi secțiune a lui Xcode Preferințe. Acest lucru vă va asigura că nu vă confruntați cu probleme atunci când implementați o aplicație pe dispozitiv.
Xcode 6 include un șablon de proiect pentru Metal, dar pentru a vă ajuta să înțelegeți mai bine Metalul, vom crea un proiect de la zero.
Într-o notă finală, vom folosi obiectivul C în acest tutorial și este important să aveți o înțelegere de bază a acestui limbaj de programare.
Pentru cei care sunteți familiarizați cu OpenGL sau OpenGL ES, Metalul este un cadru de grafică 3D de nivel inferior, dar cu un nivel mai scăzut al cheltuielilor. Spre deosebire de platformele Apple Sprite Kit sau Scene Kit cu care, în mod implicit, nu puteți interacționa cu conducta de redare, Metal are puterea absolută de a crea, controla și modifica acea conductă.
Metalul are următoarele caracteristici:
Destul cu teoria, este timpul să înțelegem cum este construită o aplicație Metal.
O aplicație metalică este caracterizată printr-un set de pași necesari pentru prezentarea corectă a datelor pe ecran. Acești pași sunt de obicei creați în ordine și unele referințe sunt transmise de la unul la altul. Acești pași sunt:
Acest pas implică crearea unui MTLDevice
obiect, inima unei aplicații Metal. MTLDevice
clasa oferă o modalitate directă de a comunica cu driverul și hardware-ul GPU. Pentru a obține o referință la MTLDevice
de exemplu, trebuie să apelați Dispozitivul implicit pentru sistem așa cum se arată mai jos. Cu această referință, aveți acces direct la hardware-ul dispozitivului.
idmtlDevice = MTLCreateSystemDefaultDevice ();
MTLCommandQueue
clasa oferă o modalitate de a trimite comenzi sau instrucțiuni către GPU. Pentru a inițializa o instanță a MTLCommandQueue
clasa, trebuie să utilizați MTLDevice
obiect pe care l-am creat mai devreme și sunăm newCommandQueue
pe ea.
idmtlCommandQueue = [mtlDevice newCommandQueue];
Acest pas implică crearea obiectelor tampon, a texturilor și a altor resurse. În acest tutorial, veți crea noduri. Aceste obiecte sunt stocate pe partea server / GPU și pentru a comunica cu ele trebuie să creați o structură specifică de date care să conțină date similare cu cele disponibile în obiectul vertex.
De exemplu, dacă trebuie să transmiteți date pentru o poziție de vârf 2D, trebuie să declarați o structură de date care conține un obiect pentru acea poziție 2D. Apoi, trebuie să îl declarați atât în client, în aplicația dvs. iOS, cât și în partea de server, shaderul Metal. Uitați-vă la următorul exemplu de clarificare.
typedef struct poziția GLKVector2; YourDataStruct;
Rețineți că trebuie să importați GLKMath biblioteca din GLKit cadru, după cum se arată mai jos.
#import
Apoi declarați un obiect cu coordonatele corecte.
Triunghiul dvs.DataStruct [3] = -.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f;
Crearea conductei de redare este probabil cea mai dificilă etapă, deoarece trebuie să aveți grijă de mai multe inițializări și configurații, fiecare dintre acestea fiind ilustrată în diagrama următoare.
Conducta de randare este configurată utilizând două clase:
MTLRenderPipelineDescriptor
: oferă toate stările de conducte de randare, cum ar fi pozițiile vârfurilor, culoarea, adâncimea și tampoanele de stencil, printre alteleMTLRenderPipelineState
: versiunea compilate a MTLRenderPipelineDescriptor
și care vor fi instalate pe dispozitivRețineți că nu este necesar să creați toate obiectele din conducta de randare. Ar trebui doar să creați cele care să răspundă nevoilor dumneavoastră.
Următorul fragment de cod vă arată cum să creați MTLRenderPipelineDescriptor
obiect.
MTLRenderPipelineDescriptor * mtlRenderPipelineDescriptor = [MTLRenderPipelineDescriptor nou];
În acest moment, ați creat descriptorul, dar tot trebuie să îl configurați cu cel puțin formatul pixelilor. Aceasta este ceea ce facem în următorul bloc de coduri.
mtlRenderPipelineDescriptor.colorAtașamente [0] .pixelFormat = MTLPixelFormatBGRA8Unorm;
Pentru aplicațiile mai avansate, trebuie de asemenea să setați versiunea implicită și shaderele fragmentului după cum se arată mai jos.
idlib = [mtlDevice newDefaultLibrary]; mtlRenderPipelineDescriptor.vertexFunction = [lib nouFunctionWithName: @ "SomeVertexMethodName"]; mtlRenderPipelineDescriptor.fragmentFunction = [lib newFunctionWithName: @ "SomeFragmentMethodName"];
newFunctionWithName
metoda caută fișierul sursă de metale, căutând SomeVertexMethodName
metodă. Numele shader-ului în sine nu este important, deoarece căutarea se face direct prin numele de metode. Aceasta înseamnă că trebuie să definiți metode unice pentru operațiile de shader unice. Vom arăta mai adânc în Metal Shaders mai târziu.
Cu MTLRenderPipelineDescriptor
obiect creat și configurat, următorul pas este crearea și definirea MTLRenderPipelineState
prin trecerea în nou creat MTLRenderPipelineDescriptor
obiect.
NSError * eroare = [[NSError alloc] init]; idmtlRenderPipelineState = [mtlDevice newRenderPipelineStateWithDescriptor: eroare mtlRenderPipelineDescriptor: & eroare];
Pentru a crea o vizualizare Metal, trebuie să faceți subclasa UIView
și suprascrie layerClass
așa cum se arată mai jos.
+(id) layerClass retur [clasa CAMetalLayer];
În acest tutorial, vom examina un alt mod de a crea un CAMetalLayer
clasa care oferă dezvoltatorului mai mult control asupra caracteristicilor și configurației stratului.
Acum că am inițializat obiectele necesare, trebuie să începem să desenăm ceva pe ecran. La fel ca inițializarea, trebuie să urmați o serie de pași:
Pasul inițial este crearea unui obiect care stochează o listă serială de comenzi pentru a executa dispozitivul. Creați a MTLCommandBuffer
obiect și adăugați comenzi care vor fi executate secvențial de GPU. Următorul fragment de cod arată cum se creează un buffer de comandă. Noi folosim MTLCommandQueue
obiect creat mai devreme.
idmtlCommandBuffer = [mtlCommandQueue commandBuffer];
În Metal, configurația de randare este complexă și trebuie să indicați în mod explicit momentul în care începe procesul de render și când se termină. Trebuie să definiți configurațiile framebuffer în față pentru ca iOS să configureze hardware-ul corespunzător pentru configurația respectivă.
Pentru cei familiarizați cu OpenGL și OpenGL ES, acest pas este similar, deoarece framebuffer are aceleași proprietăți, Atașarea culorilor (0 până la 3), Adâncime, și vopsi configurații. Puteți vedea o reprezentare vizuală a acestui pas în diagrama de mai jos.
Mai întâi trebuie să creați o textură pentru a face. Textura este creată din CAMetalDrawable
clasa și utilizează nextDrawable
pentru a extrage următoarea textură pentru a desena în listă.
idframeDrawable; frameDrawable = [renderLayer nextDrawable];
Acest nextDrawable
apelul poate fi și va fi blocarea aplicației dvs., deoarece vă poate bloca cu ușurință aplicația. CPU-ul și GPU-ul pot fi desincronizate, iar celălalt trebuie să aștepte cealaltă, ceea ce poate provoca o declarație bloc. Există mecanisme sincrone care pot și trebuie întotdeauna implementate pentru a rezolva aceste probleme, dar nu le voi acoperi în acest tutorial introductiv.
Acum că aveți o textura pe care să o faceți, trebuie să creați un MTLRenderPassDescriptor
obiect pentru a stoca informațiile despre framebuffer și textură. Uitați-vă la următorul fragment de cod pentru a vedea cum funcționează acest lucru.
MTLRenderPassDescriptor * mtlRenderPassDescriptor; mtlRenderPassDescriptor = [MTLRenderPassDescriptor nou]; mtlRenderPassDescriptor.colorAttachments [0] .texture = frameDrawable.texture; mtlRenderPassDescriptor.colorAtașamente [0] .loadAction = MTLLoadActionClear; mtlRenderPassDescriptor.colorAttachments [0] .clearColor = MTLClearColorMake (0,75, 0,25, 1,0, 1,0);
Primul pas stabilește textura care trebuie desenată. Al doilea defineste o actiune specifica de luat, in acest caz curatarea texturii si prevenirea incarcarii continutului texturii in cache-ul GPU-ului. Pasul final modifică culoarea de fundal la o anumită culoare.
Cu framebuffer-ul și textura configurată, este timpul să creați o MTLRenderCommandEncoder
instanță. MTLRenderCommandEncoder
clasa este responsabilă pentru interacțiunile tradiționale cu ecranul și poate fi văzută ca un container pentru o stare de redare grafică. De asemenea, vă traduce codul într-un format de comandă specific pentru hardware care va fi executat de dispozitiv.
idrenderCommand = [mtlCommandBuffer renderCommandEncoderWithDescriptor: mtlRenderPassDescriptor]; // Setați MTLRenderPipelineState // Desenați obiecte aici [renderCommand endEncoding];
Acum avem un tampon și instrucțiuni care așteaptă în memorie. Următorul pas este să comiteți comenzile la tamponul de comandă și să vedeți graficul desenat pe ecran. Rețineți că GPU-ul va executa numai codul pe care îl obligați în mod specific pentru efect. Următoarele rânduri de cod vă permit să programați framebuffer-ul și să transferați tamponul de comandă către GPU.
[mtlCommandBuffer presentDrawable: frameDrawable]; [mtlCommandBuffer commit];
În acest moment, ar trebui să aveți o idee generală despre modul în care este structurată o aplicație Metal. Cu toate acestea, pentru a înțelege corect toate acestea, trebuie să o faceți singur. Acum este momentul să codificați prima aplicație Metal.
Porniți Xcode 6 și alegeți Nou> Proiect ... de la Fişier meniul. Selectați Vizualizare individuală din lista de șabloane și alegeți un nume de produs. A stabilit Obiectiv-C ca limba și selectați iPhone de la Dispozitive meniul.
Deschis ViewController.m și adăugați următoarele declarații de import în partea de sus.
#import#import
De asemenea, trebuie să adăugați Metal și QuartzCore cadrelor în Cadrele și bibliotecile asociate secțiune a obiectivului Construiți faze. De acum înainte, atenția dvs. ar trebui să vizeze dosarul de punere în aplicare a ViewController
clasă.
După cum am menționat mai devreme, prima dvs. sarcină este să setați și să inițializați obiectele de bază utilizate în întreaga aplicație. În următorul fragment de cod, declarăm un număr de variabile de instanță. Acestea ar trebui să pară familiare dacă ați citit prima parte a acestui tutorial.
@implementation ViewController idmtlDevice; id mtlCommandQueue; MTLRenderPassDescriptor * mtlRenderPassDescriptor; CAMetalLayer * metalLayer; id frameDrawable; CADisplayLink * displayLink;
În controlerul de vizualizare viewDidLoad
, inițializăm MTLDevice
și CommandQueue
instanțe.
mtlDevice = MTLCreateSystemDefaultDevice (); mtlCommandQueue = [mtlDevice newCommandQueue];
Acum puteți interacționa cu dispozitivul și puteți crea cozi de comandă. Acum este timpul să configurați CAMetalLayer
obiect. Ta CAMetalLayer
stratul trebuie să aibă o configurație specifică, în funcție de dispozitiv, de formatul pixel și de dimensiunea cadrului. De asemenea, trebuie să specificați că va folosi numai framebuffer și că ar trebui adăugat la stratul curent.
Dacă aveți o problemă de configurare CAMetalLayer
obiect, atunci fragmentul de cod de mai jos vă va ajuta în acest scop.
metalLayer = [stratul CAMetalLayer]; [metalLayer setDevice: mtlDevice]; [metalLayer setPixelFormat: MTLPixelFormatBGRA8Unorm]; metalLayer.framebufferOnly = DA; [metalLayer setFrame: self.view.layer.frame]; [auto.view.layer addSublayer: metalLayer];
De asemenea, trebuie să setați opacitatea vizuală, culoarea de fundal și factorul de scală a conținutului. Acest lucru este ilustrat în următorul fragment de cod.
[self.view setOpaque: YES]; [auto.view setBackgroundColor: nul]; [auto.view setContentScaleFactor: [UIScreen mainScreen] .scale];
Singurul pas rămas este de a face ceva pe ecran. Inițializați CADisplayLink
, trecerea de sine
ca țintă și @selector (renderScene)
ca selector. În cele din urmă, adăugați CADisplayLink
obiecte față de bucla de alergare curentă.
displayLink = [afișare CADisplayLinkLinkWithTarget: SELECTOR SELECTOR: @selector (renderScene)]; [displayLink addToRunLoop: [NSRunLoop currentRunLoop] pentruMode: NSDefaultRunLoopMode];
Aceasta este ceea ce a fost finalizat viewDidLoad
metoda ar trebui să arate ca.
- (vid) viewDidLoad [super viewDidLoad]; mtlDevice = MTLCreateSystemDefaultDevice (); mtlCommandQueue = [mtlDevice newCommandQueue]; metalLayer = [stratul CAMetalLayer]; [metalLayer setDevice: mtlDevice]; [metalLayer setPixelFormat: MTLPixelFormatBGRA8Unorm]; metalLayer.framebufferOnly = DA; [metalLayer setFrame: self.view.layer.frame]; [auto.view.layer addSublayer: metalLayer]; [self.view setOpaque: YES]; [auto.view setBackgroundColor: nul]; [auto.view setContentScaleFactor: [UIScreen mainScreen] .scale]; displayLink = [afișare CADisplayLinkLinkWithTarget: SELECTOR SELECTOR: @selector (renderScene)]; [displayLink addToRunLoop: [NSRunLoop currentRunLoop] pentruMode: NSDefaultRunLoopMode];
Dacă construiți proiectul, veți observa că Xcode ne dă un avertisment. Încă mai trebuie să punem în aplicare renderScene
metodă.
renderScene
metoda este executată în fiecare cadru. Există mai multe obiecte care trebuie inițializate pentru fiecare cadru nou, cum ar fi MTLCommandBuffer
și MTLRenderCommandEncoder
obiecte.
Pașii pe care trebuie să le luăm pentru a face un cadru sunt:
MTLCommandBuffer
obiectCAMetalDrawable
obiectMTLRenderPassDescriptor
obiecttextură
, loadAction
, clearColor
, și storeAction
proprietățile MTLRenderPassDescriptor
obiectMTLRenderCommandEncoder
obiectSimțiți-vă liber să revizuiți ceea ce am văzut până acum pentru a rezolva această provocare pe cont propriu. Dacă doriți să continuați cu acest tutorial, atunci aruncați o privire la soluția prezentată mai jos.
- (void) renderScene idmtlCommandBuffer = [mtlCommandQueue commandBuffer]; în timp ce (! frameDrawable) frameDrawable = [metalLayer nextDrawable]; dacă (! mtlRenderPassDescriptor) mtlRenderPassDescriptor = [MTLRenderPassDescriptor nou]; mtlRenderPassDescriptor.colorAttachments [0] .texture = frameDrawable.texture; mtlRenderPassDescriptor.colorAtașamente [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]; // Desenați obiectele aici // setați MTLRenderPipelineState ... [renderCommand endEncoding]; [mtlCommandBuffer presentDrawable: frameDrawable]; [mtlCommandBuffer commit]; mtlRenderPassDescriptor = zero; frameDrawable = zero;
De asemenea, trebuie să implementăm controlerul de vizualizare dealloc
în care ne invalidăm DisplayLink
obiect. Am setat mtlDevice
și mtlCommandQueue
obiecte pentru zero
.
-(void) dealloc [displayLink invalidate]; mtlDevice = nil; mtlCommandQueue = nil;
Acum aveți o aplicație Metal foarte fundamentală. Este timpul să adăugați prima dvs. primitivă grafică, un triunghi. Primul pas este crearea unei structuri pentru triunghi.
typedef struct poziția GLKVector2; Triunghi;
Nu uitați să adăugați o declarație de import pentru GLKMath bibliotecă în partea de sus a ViewController.m.
#import
Pentru a face triunghiul, trebuie să creați a MTLRenderPipelineDescriptor
obiect și a MTLRenderPipelineState
obiect. În plus, fiecare obiect care este tras pe ecran aparține MTLBuffer
clasă.
MTLRenderPipelineDescriptor * renderPipelineDescriptor; idrenderPipelineState; id obiect;
Cu aceste variabile de instanță declarate, ar trebui să le inițializați acum în viewDidLoad
așa cum am explicat anterior.
renderPipelineDescriptor = [MTLRenderPipelineDescriptor nou]; renderPipelineDescriptor.colorAttachments [0] .pixelFormat = MTLPixelFormatBGRA8Unorm;
Pentru a umbla triunghiul, vom avea nevoie de shadere de metal. Shaderele de metal trebuie să fie atribuite MTLRenderPipelineDescriptor
obiect și încapsulate printr-o MTLLibrary
protocol. Poate suna complex, dar trebuie doar să utilizați următoarele linii de cod:
idlib = [mtlDevice newDefaultLibrary]; renderPipelineDescriptor.vertexFunction = [lib newFunctionWithName: @ "VertexColor"]; renderPipelineDescriptor.fragmentFunction = [lib newFunctionWithName: @ "FragmentColor"]; renderPipelineState = [mtlDevice newRenderPipelineStateWithDescriptor: eroare renderPipelineDescriptor: nul];
Prima linie creează un obiect care este conform cu MTLLibrary
protocol. În al doilea rând, îi spunem bibliotecii ce metodă trebuie invocată în interiorul shader-ului pentru a acționa trecerea vertexului în interiorul conductei de randare. În a treia linie, repetăm acest pas la nivelul pixelilor, fragmentele. În cele din urmă, în ultima linie vom crea a MTLRenderPipelineState
obiect.
În Metal, puteți defini coordonatele sistemului, dar în acest tutorial veți folosi sistemul de coordonate implicit, adică coordonatele centrului ecranului (0,0)
.
În următorul bloc de coduri, vom crea un obiect triunghi cu trei coordonate, (-5f, 0,0f), (0,5f, 0,0f), (0,0f, 0,5f)
.
Triunghi triunghi [3] = -.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f;
Apoi adăugăm triunghiul la
obiect, care creează un buffer pentru triunghi.
obiect = [mtlDevice newBufferWithBytes: lungime triunghi: sizeof (Triangle [3]): MTLResourceOptionCPUCacheModeDefault];
Aceasta este ceea ce a fost finalizat viewDidLoad
metoda ar trebui să arate ca.
- (vid) viewDidLoad [super viewDidLoad]; mtlDevice = MTLCreateSystemDefaultDevice (); mtlCommandQueue = [mtlDevice newCommandQueue]; metalLayer = [stratul CAMetalLayer]; [metalLayer setDevice: mtlDevice]; [metalLayer setPixelFormat: MTLPixelFormatBGRA8Unorm]; metalLayer.framebufferOnly = DA; [metalLayer setFrame: self.view.layer.frame]; [auto.view.layer addSublayer: metalLayer]; [self.view setOpaque: YES]; [auto.view setBackgroundColor: nul]; [auto.view setContentScaleFactor: [UIScreen mainScreen] .scale]; // Creați o conductă reutilizabilă renderPipelineDescriptor = [MTLRenderPipelineDescriptor new]; renderPipelineDescriptor.colorAttachments [0] .pixelFormat = MTLPixelFormatBGRA8Unorm; idlib = [mtlDevice newDefaultLibrary]; renderPipelineDescriptor.vertexFunction = [lib newFunctionWithName: @ "VertexColor"]; renderPipelineDescriptor.fragmentFunction = [lib newFunctionWithName: @ "FragmentColor"]; renderPipelineState = [mtlDevice newRenderPipelineStateWithDescriptor: eroare renderPipelineDescriptor: nul]; Triunghi triunghi [3] = -.5f, 0.0f, 0.5f, 0.0f, 0.0f, 0.5f; obiect = [mtlDevice newBufferWithBytes: lungime triunghi: sizeof (Triangle [3]): MTLResourceOptionCPUCacheModeDefault]; displayLink = [afișare CADisplayLinkLinkWithTarget: SELECTOR SELECTOR: @selector (renderScene)]; [displayLink addToRunLoop: [NSRunLoop currentRunLoop] pentruMode: NSDefaultRunLoopMode];
viewDidLoad
metoda este completă, dar lipsește ultimul pas, creând shaderele.
Pentru a crea un shader de metal, selectați Nou> Fișier ... de la Fişier meniu, alegeți Sursă > Fișier metalic de la iOS și denumiți-o MyShader. Xcode va crea apoi un fișier nou pentru dvs., MyShader.metal.
În partea de sus, ar trebui să vedeți următoarele două linii de cod. Primul include Bibliotecă standard metalică în timp ce al doilea utilizează metal
Spațiu de nume.
#includefolosind spațiul din spațiul de nume;
Primul pas este să copiați structura triunghiului la shader. Shaderele sunt de obicei împărțite în două operații diferite, vertex și pixeli (fragmente). Primul este legat de poziția vârfului, în timp ce al doilea este legat de culoarea finală a acelui vârf și de toate pozițiile pixelilor din interiorul poligonului. Puteți să vă uitați în acest fel, primul va rasteriza poligonul, pixelii poligonului, iar al doilea va umbri aceiași pixeli.
Deoarece au nevoie să comunice într-un mod unidirecțional, de la vârf la fragment, este mai bine să creeze o structură pentru datele care vor fi transmise. În acest caz, vom trece doar poziția.
typedef struct float4 poziție [[poziție]]; TriangleOutput;
Acum, să creăm metodele vertex și fragment. Amintiți-vă când ați programat RenderPipelineDescriptor
obiect atât pentru vârf și fragment? Ai folosit newFunctionWithName
metoda, trecând într-un NSString
obiect. Șirul este numele metodei pe care o numiți în interiorul shaderului. Aceasta înseamnă că trebuie să declarați două metode cu aceste nume, VertexColor
și FragmentColor
.
Ce inseamna asta? Puteți crea shaderele și le puteți numi după cum doriți, dar trebuie să apelați metodele exact așa cum le declarați și ar trebui să aibă nume unice.
În interiorul shaderelor, adăugați următorul bloc de coduri.
vertex TriangleOutput VertexColor (const constă Triangle * Vertices [[buffer (0)]], const uint index [[vertex_id]]) TriangleOutput out; out.position = float4 (Vertices [index] .poziție, 0.0, 1.0); retur; fragment half4 FragmentColor (void) returnează jumătate4 (1.0, 0.0, 0.0, 1.0);
VertexColor
metoda va primi datele stocate în poziție 0
din memoria tampon (memoria alocată) și vertex_id
a vârfului. Deoarece am declarat un triunghi cu trei vârfuri, vertex_id
va fi 0
, 1
, și 2
. Se emite a TriangleOutput
obiect care este primit automat de către FragmentColor
. În cele din urmă, acesta va umbri fiecare pixel în interiorul celor trei noduri folosind o culoare roșie.
Asta e. Construiți și rulați aplicația dvs. și bucurați-vă de prima dvs. aplicație de metal 60fps.
Dacă doriți să aflați mai multe despre cadrul metalic și cum funcționează, puteți verifica câteva alte resurse:
Aceasta incheie tutorialul nostru introductiv pe noul cadru metalic. Dacă aveți întrebări sau comentarii, nu ezitați să renunțați la o linie în comentarii.