Het einde van de pijpleiding met vaste functieregeneratie (en hoe verder te gaan)

Fixed-function pijplijnen hebben geen zaken meer met onze videokaarten. Hier is wat u moet weten over hen - en hoe u de overstap van hen kunt maken, als u dit nog steeds niet heeft gedaan.

In het begin: de opkomst van grafische hardware

Once upon a time, toen game-ontwikkeling (of het coderen van alles wat te maken heeft met real-time graphics, echt) was beperkt tot het schrijven naar een relatief kleine matrix van kleurintensiteiten (de framebuffer) en door het naar de hardware te verzenden, zou je er alles mee kunnen doen wat je wilde. Je zou een, tien of honderd keer naar de afbeelding kunnen tekenen. Je zou de framebuffer opnieuw kunnen passeren om wat nette FX te doen. Kortom, wat uw processor ook kon doen, u zou het kunnen doen met de afbeelding die naar de monitor wordt gestuurd. Dit stelde je in staat om echt geweldige en creatieve dingen te doen, maar mensen gebruikten het nooit (of zelden) in die mate. Maar waarom?

Het antwoord: omdat het traag was. Een 640 × 480px-afbeelding (een gebruikelijke resolutie op dat moment) bevat 307.200 pixels. En de CPU's waren zo langzamer dan dat je niet echt veel kon doen in de korte tijd die je kreeg om dat frame te tekenen. Immers, als je wilt blijven tekenen op 30FPS, heb je slechts ongeveer 30ms om je spellogica en render naar het scherm bij te werken, en dat moet de overhead van intercommunicatie met de hardware omvatten. Het was niet veel.

Toen kwam langs de coole GPU's met pijpleidingen renderen. Jij, de ontwikkelaar, zou zorgen voor het updaten van de spellogica en het sturen van je texturen en driehoeken naar de GPU, en het zou het zware werk en het aantal malen dat ze aan het crunchen waren, doen. Dat waren ze paden voor het renderen van vaste functies (FFP's): wat betekent dat u de .niet kon configureren functies ze presteerden. Je zou kunnen zeggen "maak de mist donkergrijs" of "doe de verlichting niet voor mij!" en je zou veel van de ander kunnen configureren parameters, maar de functies zelf zijn gebleven. 

De hardware was bekabeld en nauw gespecialiseerd, zodat het een aantal standaardbewerkingen op uw gegevens uitvoerde. En omdat het op die manier was bedraad, was het zo veel sneller dan ze op je processor te doen. Maar een nadeel was dat je veel voor die snelheid betaalde: je betaalde in flexibiliteit. Maar als je ooit iets ingewikkelds wilde tekenen, was de CPU gewoon niet snel genoeg en was het de enige keuze om je vertices in te dienen bij de GPU.

Dit is ongeveer hoe de pijplijn met vaste functie werkte. Het beeld is niet bedoeld als een nauwkeurige weergave, maar om u een idee te geven van hoe het allemaal is uitgevoerd.

De eisen voor beter realisme

De grafische wereld veranderde nog steeds snel. Net als alle creatieve en getalenteerde mensen houden game-ontwikkelaars van uitdagingen en een van de uitdagingen voor hen waren (en zullen blijven!), voor een lange tijd, om steeds beter uitziende, realistische beelden te maken. 

De pijplijn met vaste functie leverde een aantal aardige functies op, zoals meerdere overvloeimodi, per-vertex Gouraud-arcering, misteffecten, stencilbuffers (voor schaduwvolumes) en dergelijke, dus de ontwikkelaars gebruikten wat ze konden. Al snel waren er een aantal echt indrukwekkende effecten aan de gang, allemaal door middel van real-life fenomenen die werden gesimuleerd met behulp van een paar goedkope tricks (goed, goedkoop volgens de huidige normen). 

Dit ging allemaal goed, maar het werd nog steeds beperkt door de hoeveelheid functies die de vaste pijplijn kon doen. De echte wereld heeft immers zoveel verschillende materialen en voor het simuleren ervan, was de enige variatie die ze mochten uitvoeren, het veranderen van sommige mengmodi, wat meer texturen toevoegen of de lichtreflectiekleuren aanpassen.

Toen gebeurde het: de eerste programmeerbare GPU's kwamen langs. Ze kwamen natuurlijk niet van de ene op de andere dag en ze zouden op een dag aankomen, maar dit zorgde nog steeds voor opwinding. Deze GPU's hadden een zogenaamde a programmeerbare renderingpijplijn: je zou nu programma's kunnen schrijven, genaamd shaders, in een beperkte assembleertaal en laat ze uitvoeren voor elk hoekpunt of fragment, op de videokaart. Dit was een grote stap voorwaarts en het werd alleen maar beter. 

Al snel namen de assembleertalen toe in complexiteit en expressiviteit, en er ontstonden talen op hoog niveau voor GPU-programmering, zoals HLSL, GLSL en later Cg. Vandaag hebben we geometry shaders die zelfs nieuwe hoekpunten kunnen streamen, of shaders die tessellation en mozaïek met driehoeken dynamisch besturen, en daarbinnen kunnen we ontzettend veel texturen samplen, dynamisch vertakken en allerlei gekke wiskunde op de invoerwaarden doen.

Wanneer je ontwikkelaars deze voordelen geeft, worden ze wild; al snel waren ze shaders aan het schrijven voor allerlei dingen: parallax-mapping, aangepaste belichtingsmodellen, breking, noem maar op. Later ontstonden zelfs volledig op maat gemaakte verlichtingssystemen, zoals uitgestelde zonwering en lichte pre-pass, en kon je complexe post-processing effecten zien, zoals schermomgevingsatmosfeerocclusie en horizon-gebaseerde omgevingsocclusie. Sommigen maakten zelfs "misbruik" van shaders om repetitieve, mathematische taken uit te voeren, zoals statistische verwerking of het doorbreken van string hashes. (Dit was voordat algemene computergebruik op GPU's mainstream-ondersteuning kreeg.) 

Kortom, computergraphics explodeerden met de introductie van shaders, en met goede reden: de mogelijkheid om te programmeren wat er precies gebeurde met hoekpunten, fragmenten, texturen, enzovoort, en om het te doen snel, bijna eindeloze mogelijkheden.

Een vereenvoudigde weergave van de programmeerbare pipeline. Merk op hoe de specifieke transformatie-, schaduw- of textuurstadia werden vervangen door gespecialiseerde shaders. (Tessellation is weggelaten omwille van de duidelijkheid.)

De complete schakelaar

Al snel waren vaste functiepijplijnen overbodig, tenminste voor game-ontwikkelaars. Immers, waarom moeite doen met dergelijke ommuurde tuinen als u precies kunt programmeren wat er met uw gegevens gebeurt? Ze bleven langer in gebruik in sommige toepassingen waar realisme geen probleem was, zoals voor CAD. Maar over het algemeen werden ze genegeerd. 

OpenGL ES 2.0, uitgebracht in 2007, heeft de pijplijn met vaste functie gedeprecieerd of verwijderd ten gunste van een programmeerbare pijplijn. OpenGL 3.2, al in 2009, heeft eindelijk alle notie van de vertex- en fragmentverwerkingsfunctie met vaste functie verwijderd (het blijft echter beschikbaar voor legacy-gebruik via een compatibiliteitsprofiel). Het is duidelijk dat het tegenwoordig weinig zin heeft om met de beperkte pijplijn te werken als je krachtige GPU's hebt die geweldige dingen tot je beschikking hebben.

Omdat deze API's u dwingen om shaders te gebruiken (en dit omvat DirectX, dat, hoewel de functionaliteit niet expliciet wordt verwijderd, hulpmiddelen bevat om te helpen migreren vanuit de oude aanpak, en vrijwel geen nieuwe documentatie heeft met betrekking tot de FFP), het is moeilijk om gelijk te krijgen voor een beginner. Als je alleen begint als een 3D-programmeer rookie, is het een stuk eenvoudiger om de API je matrices, verlichtingsparameters en wat dan ook te vertellen, en laat het alles voor je doen. 

Maar op de lange termijn zal het u veel meer ten goede komen als u leert programma's te schrijven die het proces nauwkeurig beschrijven. Je zult ingewikkeld begrijpen wat er gaande is onder de motorkap, enkele zeer belangrijke concepten begrijpen die de FFP niet vereist, en in staat zijn om je materialen heel gemakkelijk te tweaken om iets complexs te doen wat de vaste functie nooit voor je kan doen (en het is nuttig ook voor foutopsporing!).

Ik heb OpenGL ES genoemd en laat me daar verder op inwerken. Naarmate gaming op mobiel steeds populairder wordt, is het logisch om virtuele werelden te creëren die steeds complexer worden. De meeste vaste-functieaanroepen zijn verwijderd in ES 2.0 (wat uiteraard betekent dat ze ook in de volgende versies ontbreken). Dit betekent in feite dat je, om een ​​van de functies na ES 1.1 te gebruiken, shaders moet gebruiken. 

ES 2.0 wordt ondersteund door iPhones sinds 3GS, iPads sinds de eerste release en iPod Touch-apparaten van generatie 3 en hoger. Qualcomm Snapdragon, een chip die veel wordt gebruikt in de productie van Android-telefoons, ondersteunt ook OpenGL ES 2.0. Dat is heel breed ondersteuning, omdat ES 2.0 niet bepaald "nieuw" is: het is nu meer dan 7 jaar oud. Om het meeste uit deze architecturen te halen, je moet de vaste pijplijn loslaten

Ik neem aan dat de meesten van jullie dat al lang, lang geleden hebben gedaan, maar het is niet zo moeilijk voor me om me een 2D-grafische engine of legacy-game voor te stellen die nog steeds een vaste functie gebruikt (omdat er geen behoefte aan meer is). Dit is allemaal goed, maar het gebruiken ervan voor nieuwe projecten of het trainen van programmeurs daarin lijkt tijdverspilling. Dit wordt versterkt door het feit dat veel tutorials die je op internet kunt vinden schromelijk verouderd zijn en je leren hoe je de FFP vanaf het begin kunt gebruiken - en voordat je je realiseert wat er aan de hand is, zit je daar diep in.

Mijn eerste penseel met 3D-graphics was een oude handleiding van DirectX 7 geschreven in Visual Basic. Op dat moment was het gebruik van de pijplijn met vaste functie over het algemeen zinvol, omdat de hardware niet geavanceerd genoeg was om dezelfde functionaliteit te bereiken met shaders met dezelfde snelheid. Maar vandaag zien we dat grafische API's beginnen af ​​te nemen of de ondersteuning ervan sterk afzweren, en het wordt pas echt een artefact uit het verleden. Het is een goed en nuttig artefact dat ons nostalgisch maakt, maar we zouden er vanaf moeten blijven. Het is oud en niet meer gebruikt.

Deze zoete fresnel reflecties en brekingen, gegenereerd door een demo van OGRE (Open-source Graphics Rendering Engine), hadden nooit gedaan kunnen worden als je vasthield aan de manieren waarop oude DirectX 8 of OpenGL 1.1 tutorials adviseren.

Conclusie

Als je serieus bezig bent met het ontwikkelen van games, is vasthouden aan de pijplijn met vaste functie een overblijfsel van vervlogen dagen. Als je denkt aan 3D-graphics, is mijn advies (en het advies van vele, vele ontwikkelaars daar) om het simpelweg te vermijden. 

Als u lichtposities doorgeeft aan de grafische API (niet als een arceringsparameter), of API-functieaanroepen zoals glFogv, rennen zoals de wind en kijk niet achterom. Er is daar een dappere nieuwe wereld van programmeerbare GPU's, en die bestaat al heel lang. Al het andere verspilt waarschijnlijk net je tijd.

Zelfs als je alleen in 2D-graphics zit, is het nog steeds een verstandig idee om niet meer afhankelijk te zijn van de FFP. (Natuurlijk is dat zolang je het goed vindt om geen oude hardware te ondersteunen.) Shaders kunnen je geweldige, razendsnelle effecten bieden. Vervaging van afbeeldingen, verscherping, warp-rasters, vectorweergave en grootschalige deeltjes- of fysica-simulatie kunnen allemaal op de GPU worden uitgevoerd, en ze kunnen allemaal zowel 2D- als 3D-games ten goede komen. 

Dus nogmaals, mijn advies, zelfs als je niet expliciet gaat leren over 3D-game-ontwikkeling, is om te leren om shaders te schrijven. Ze zijn leuk om mee te werken en ik garandeer je dat je vele leuke uren zult doorbrengen om een ​​cool shader-effect te perfectioneren: een dynamische luchtbak, autolak of parallel gescheurde schaduwmapping, of wat je hartje begeert. Tenminste dat is me overkomen: als je eenmaal gewend bent om met de vaste pijplijn te werken vanwege een beperking (zoals ik vroeger moest doen om acceptabele prestaties op mijn 5200FX te krijgen), is het programmeren van de GPU een ontploffing en heel veel plezier.

Ik hoop dat ik aan degenen voor wie het onduidelijk was uitgelegd hoe 3D-afbeeldingen lang geleden werkten en hoe het nu werkt, en ik hoop dat ik de weinigen van u heb overtuigd die op het punt stonden om NeHe of Swiftless tutorials te volgen om te doen anders en ga kijken naar iets moderners. Zoals altijd heb ik misschien een aantal fouten gemaakt, dus aarzel niet om ze in de opmerkingen te vermelden. Tot de volgende keer!