Abstrakta shadergrafer för hårdvarushaders med multipla shaderspråk Richard Svensson

Relevanta dokument
Shaders. Renderingssystem. Renderingssystem. Renderingssystem. Hårdvara för 3D-rendering. Hårdvara för 3D-rendering

Shaders. Gustav Taxén

Grafiska pipelinens funktion

Universe Engine Rapport

Procedurell renderingsmotor i Javascript och HTML5

Procedurell grottgenerator och eld i GLSL. Marcus Widegren

Avalanche Studios. OpenGL. Vår teknik. Våra spel. Lite inspiration... Stora, öppna spelvärldar. Sandbox-gameplay. Hög audiovisuell standard

Laboration - Shaders

Procedurella Grottor TNM084. Sammanfattning. Alexander Steen

Spelutveckling 3d-grafik och modellering. Grunder för 3d-grafik Blender Animering

Designing a Shading System. David Larsson

Tentamen TNM061, 3D-grafik och animering för MT2. Tisdag 3/ kl 8-12 TP51, TP52, TP54, TP56, TP41, TP43. Inga hjälpmedel

Inledning. Vad är ett datorprogram, egentligen? Olika språk. Problemlösning och algoritmer. 1DV433 Strukturerad programmering med C Mats Loock

Tentamen TNM061, 3D-grafik och animering för MT2. Onsdag 20/ kl SP71. Inga hjälpmedel

TNM022 Proceduella Bilder Rendering av proceduell päls i realtid

Teknik för avancerade datorspel!

Paneler - VCPXX.2. Programmeringsmanual för VCP-paneler. Revision 2

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 11 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Grunderna i C++ T A. Skapad av Matz Johansson BergströmLIMY

Teknik för avancerade datorspel!

Grafiska pipelinen. Edvin Fischer

Procedurell 3D-eld på grafikkortet

Försättsblad till skriftlig tentamen vid Linköpings Universitet

Innehålls förteckning

F5: Högnivåprogrammering

F5: Högnivåprogrammering

Procedurell Terräng med LOD i OpenGL 4

Mälardalens högskola Västerås, Maj 2006 Institutionen för Datavetenskap och Elektronik, IDE Student: Alexander Andersson E-post:

Användarhandledning Version 1.2

PROCEDUELL TERRÄNG. Proceduella metoder för bilder (TNM084) Jimmy Liikala Institutionen för teknik och naturvetenskap

Bakgrund och motivation. Definition av algoritmer Beskrivningssätt Algoritmanalys. Algoritmer. Lars Larsson VT Lars Larsson Algoritmer 1

TDIU01 - Programmering i C++, grundkurs

Föreläsning 2. Operativsystem och programmering

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Felsökning. Datatyper. Referenstyper. Metoder / funktioner

Programmering med Java. Grunderna. Programspråket Java. Programmering med Java. Källkodsexempel. Java API-exempel In- och utmatning.

Laboration 1: Figurer i hierarki

Introduktion till programmering och Python Grundkurs i programmering med Python

Introduktion till programmering D0009E. Föreläsning 1: Programmets väg

Objektorienterad Programmering (TDDC77)

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

Programmering B med Visual C

Classes och Interfaces, Objects och References Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

NetBeans 5.5. Avsikt. Projektfönster

Grafiska användargränssnitt i Java

Introduktion till objektorientering. Vad är objektorientering egentligen? Hur relaterar det till datatyper? Hur relaterar det till verkligheten?

I Skapa Hej.java och skriv programmet. I Kompilera med javac Hej.java. I Rätta fel och repetera tills du lyckas kompilera ditt program

Editering, Kompilering och Exekvering av Javaprogram

OOP Objekt-orienterad programmering

Spelutveckling - Scenegrafer. Scenegrafer Optimeringar Culling

Introduktion till programmering. Programspråk och paradigmer

Classes och Interfaces, Objects och References, Initialization

Programmering i C++ En manual för kursen Datavetenskaplig introduktionskurs 5p

Inledning. Kapitel Bakgrund. 1.2 Syfte

Föreläsning 2 Programmeringsteknik och C DD1316. Mikael Djurfeldt

Inledande programmering med C# (1DV402) Introduktion till C#

3.0. Tips och Trix Sida 1 av 18

LUNDS UNIVERSITET. Parallell exekvering av Float32 och INT32 operationer

Introduktion. Byggstenar TDBA

Programutvecklingsprojekt Projektgrupp Elvin. Detailed Design Document

Grafiska användargränssnitt i Java

Programmering = modellering

Här är ett väldigt bra tidpunkt att spara scenen. Jag har valt att bygga ett litet pyramidtorn.

Realtidsskuggalgoritmer för virtuella 3D-världar på modern grafikhårdvara M A R C U S B E A U S A N G

729G75: Programmering och algoritmiskt tänkande. Tema 1. Föreläsning 1 Jody Foo

MATLAB. Python. Det finns flera andra program som liknar MATLAB. Sage, Octave, Maple och...

Medieteknologi Webbprogrammering och databaser MEB725, 5p (7,5 ECTS) Klientprogrammering JavaScript Program på flera sidor

TBSK 03 Teknik för Advancerade Datorspel

Arv. Fundamental objekt-orienterad teknik. arv i Java modifieraren protected Lägga till och modifiera metoder med hjälp av arv Klass hierarkier

Objektorienterad programmering, allmänt

Viktiga egenskaper hos ett program (Meyer): Objektorienterad programmering, allmänt. Vilka egenskaper vill vi att våra program ska ha?

Imperativ programmering. Föreläsning 4

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Opponenter: Erik Hansen Mats Almgren Respondent: Martin Landälv ioftpd-verktyg

Objektorienterad programmering med Java Swing: Händelser, lyssnare och applets

+Överskådlighet Normalt sätt blir ett program skrivet i det procedurella paradigmet överskådligt. Modifikationer på delproblem kan ske med lätthet.

Grafik raytracing. Mattias Axblom.

Quickstart manual. Rev SHTOOL Quickstart manual Smart-House

JavaScript. Innehåll. Historia. Document object model DHTML. Varför Javascript?

729G75: Programmering och algoritmiskt tänkande. Tema 1, föreläsning 1 Jody Foo

Introduktion till arv

Model View Controller. Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

Introduktion till objektorientering. Vad är objektorientering egentligen? Hur relaterar det till datatyper? Hur relaterar det till verkligheten?

Guide för Innehållsleverantörer

Tentamen ID1004 Objektorienterad programmering October 29, 2013

Mjukvarudesign. Designprocessen. Teknisk design. Konceptuell design

Java: Utvecklingsverktyg, datatyper, kontrollstrukturer

Programmering av NXT Lego- robot Labbrapport för programmering av en Lego- robot

International Olympiad in Informatics July 2011, Pattaya City, Thailand Tävlingsuppgifter Dag 2 Svenska 1.3. Papegojor

SKAPA DET FÖRSTA PROJEKTET I mikrobasic PRO for AVR

Programmeringspalett. Pr o gr a mvar a

Utvecklingen av ett tidregistrerings- och faktureringssystem

Realtidsalgoritmer för ljusets spridning och absorption mot partiklar i luften P E T E R L Ö N N Q U I S T

Så här skriver du ditt första program i C++

Mer OOP. Variation i typ. Medlen repetition. Generiska klasser. Gränssnitt - Interface. Mer om klasser Några exempel UML

A comparison study between OpenGL 4.3, OpenGL ES 3.0 and WebGL 1.0 With focus on rendering pipeline and texture handling

TDDC30 Programmering i Java, Datastrukturer och Algoritmer Lektion 5. Laboration 4 Lådplanering Exempel på grafik, ett avancerat program Frågor

Innehåll i detta dokument

NetBeans 7. Avsikt. Projektfönster

Föreläsning 17 UTBLICK: FORTSÄTTNINGSKURSER I DATAVETENSKAP + ANDROID

Objektorienterad programmering Föreläsning 2

Transkript:

Institutionen för kommunikation och information Examensarbete i datavetenskap 30hp C-nivå Vårterminen 2008 Abstrakta shadergrafer för hårdvarushaders med multipla shaderspråk Richard Svensson

Abstrakta shadergrafer för hårdvarushaders med multipla shaderspråk Examensrapport inlämnad av Richard Svensson till Högskolan i Skövde, för Kandidatexamen (B.Sc.) vid Institutionen för kommunikation och information. Arbetet har handletts av Mikael Thieme. 2 juni 2008 Härmed intygas att allt material i denna rapport, vilket inte är mitt eget, har blivit tydligt identifierat och att inget material är inkluderat som tidigare använts för erhållande av annan examen. Signerat:

Abstrakta shadergrafer för hårdvarushaders med multipla shaderspråk Richard Svensson Sammanfattning Målet med detta arbete är att utveckla och utvärdera ett shadergrafsystem med stöd för flera shaderspråk. Fokus ligger på implementationen av en prototyp och hur dess delar fungerar. Prototypen utvärderas med hjälp av ett par experiment för att se hur användbart systemet för datorspel. Experimenten visar att systemet kan användas istället för traditionellt handskrivna shaders och på så vis avlasta programmerare och ge mer kontroll till grafiker. Nyckelord: Datorgrafik, Shadergraf, Shader

Innehåll Innehåll 1 1 Introduktion 2 2 Bakgrund 3 2.1 Grafik i datorspel............................. 3 2.2 Realtidsrendering............................. 4 2.3 Hårdvarushaders.............................. 5 2.4 Shadergrafer................................ 6 2.5 Just in time compilation (JIT)....................... 7 2.6 Tidigare arbeten.............................. 7 2.6.1 Building block shaders, Abram & Whitted (1990)....... 8 2.6.2 Abstract Shader Trees, McGuire et al. (2006).......... 8 2.6.3 Interactive shader development, Jensen et al. (1984)...... 8 3 Problem 9 3.1 Delmål 1: Utveckling........................... 9 3.2 Delmål 2: Utvärdering.......................... 10 4 Metod 11 4.1 Delmål 1: Utveckling........................... 11 4.2 Delmål 2: Utvärdering.......................... 11 5 Genomförande 12 5.1 Utveckling................................. 12 5.1.1 Noder............................... 13 5.1.2 Datatyper............................. 15 5.1.3 Slots................................ 16 5.1.4 Extern data............................ 16 5.1.5 Just in time compilation...................... 16 5.1.6 Shader backend.......................... 17 5.1.7 Grafeditor............................. 17 5.2 Utvärdering................................ 19 5.2.1 Flexibilitet............................. 19 5.2.2 Komplexitet............................ 22 6 Resultat och analys 24 6.1 Flexibilitet................................. 24 6.2 Komplexitet................................ 24 7 Slutsats 26 7.1 Sammanfattning.............................. 26 7.2 Diskussion................................. 26 7.3 Framtida arbete.............................. 27 8 Referenser 29 1

1 Introduktion Idag är detaljrikedomen och komplexiteten i datorspel högre än någonsin, det är inte ovanligt med spelvärldar stora som städer med hundratals byggnader, bilar och och människor. Med detaljer från skräpet som kantar gatorna till porer i ansiktet på spelarkaraktären. Varje yta i spelvärlden kan nu ges unika visuella egenskaper med hjälp av hårdvarushaders (St-Laurent 2004). Hårdvarushaders ger utvecklare större möjlighet att ge sitt spel en mer unik visuell stil än tidigare möjligt, och begränsas till stor del bara av fantasin. Denna ökning av realism och detaljrikedom leder till att grafikresurser i spel blir mer och mer svårhanterliga, stora mängder kontent i form av modeller, texturer och shaders måste kunna hanteras på ett lätthanterligt vis. Shaders får mer och mer betydande roll för det visuella utseendet i spel. komplexiteten i shaders gör dem svåröverskådliga och den komplexa matematiken gör dem svårtillgängliga för grafiker. Det behövs en mer överskådlig och mer lättillgänglig metod för att skapa shaders. Den metod som undersöks i detta arbete är shadergrafer. En shadergraf är en visuell abstrahering av programkoden i en shader. Genom att abstrahera shaderkoden på detta vis kan man göra en shader mer överskådlig och mer lättförstådd. Målet med detta arbete är att utveckla och utvärdera en prototyp för ett shadergrafsystem för hårdvarushaders. Systemet är först och främst tänkt att användas för realtidsrendering i datorspel, men det kan även användas till offlinerendering som inte är relaterad till datorspel. Fokus ligger på implementationen av prototypen och hur dess delar fungerar. Shadergrafen och dess noder kommer att vara abstrakta på så vis att de är frikopplad från underliggande shaderspråk. Systemet kommer att vara utbyggbart för att stödja flera shaderspråk med hjälp av ett utbytbart shadersspecifikt backend. Grafsystemet kommer att använda sig av en gemensam graf för både vertex- och fragmentshaders och kopplingar mellan vertex- och fragmentnoder kommer att automatiseras. Slutligen kommer systemet att utvärderas med hjälp av ett par experiment. Det första experimentet utvärderar hur flexibelt systemet är och hur väl det hanterar olika typer av shaders, detta genom att skapa några olika typer shaders och observera arbetet som krävs. Det andra experimentet utvärderar hur väl systemet och framför allt editorn hanterar större och mer komplexa shaders genom att skapa en relativt stor och komplex shader. 2

2 Bakgrund För att förstå innebörden av detta arbete så kommer detta kapitel att gå igenom vad realtidsgrafik för spel innebär, vad som skiljer grafik i datorspel från grafik i tillexempel filmer. Kapitlet kommer även ge en bakgrund för hur hårdvarushaders och shadergrafer fungerar i allmänhet. En läsare som redan är införstådd i detta kan hoppa över detta kapitel. 2.1 Grafik i datorspel Grafiken i datorspel har utvecklats otroligt de senaste 15 åren. Den har gått från enkel lågupplöst 2D-grafik till dagens högupplösta 3D-grafik. I början av 90-talet så började 3D-grafik i datorspel bli allt mer populärt. Grafiken renderades då utan hjälp av specialanpassad 3d-hårdvara och spel som Doom och Descent Figur 1 pressade dåtidens persondatorer till gränserna. Figur 1. Några spel från tidigt 90-tal. Från vänster Commander keen (ID software, 1990), Moonstone: A Hard Days Knight (Mindscape, 1991), Doom 2 (ID software, 1994) och Descent (Parallax Software, 1995) Hårdvaruaccelererad 3D-grafik slog spelmarknaden med storm i slutet av 90-talet det dröjde inte länge för än alla nya spel utnyttjad 3D-hårdvara. Exempel på spel med hårdvaruaccelererad 3D-grafik är Quake 2 från id software och och Unreal tournament från Epic games Figur 2. Figur 2. Quake 3 (ID software, 1999) och Unreal tournament (Epic Games, 1999) Så vad kan vi förvänta oss av morgondagens spel? Grafiken i morgondagens datorspel kommer i många fall sträva mot ännu mer realism. Denna trend kommer förmodligen 3

att fortsätta tills dess att den visuella skillnaden mellan den virtuella världen och den verkliga världen blir näst intill obefintlig. Man kan nog påstå att denna gräns redan är nådd när det gäller icke realtids grafik i filmer (CGI). Realtidsgrafik (realtidsrendering) har dock lång väg kvar. Grafiken i dagens datorspel ligger på ungefär samma nivå som CGI i filmer var för ca 10 år sedan. Exempel på modernt datorspel med avancerad grafik är Unreal tournament 3 Figur 3. Figur 3. Unreal tournament 3 (Epic Games, 2007) 2.2 Realtidsrendering Realtidsrendering innebär att bilden uppdateras så ofta att åskådaren kan interagera och påverka utritningen och se resultatet direkt. Hur snabbt bilden uppdateras brukar mätas i frames per second (fps) eller bilder per sekund på svenska. Hur snabbt grafiken kan uppdateras beror på många faktorer tillexempel den underliggande hårdvaran, vilka algoritmer som används vid utritningen och hur komplex scen som ritas. För mer information om realtidsrendering se Wikipedia (2008). Som motsats till realtidsrendering finns offline-rendering. Med offline-rendering så är inte renderingshastighet något som prioriteras, istället så fokuserar man på att producera så hög kvalite på bilden som möjligt. Offline-rendering används mycket inom filmindustrin men används även inom datorspel för att producera tillexempel mellansekvenser och förrenderade bakgrunder. En av de mer kända offline-renderings systemen är RenderMan (The RenderMan Interface 2005, Apodaca & Gritz 2000). RenderMan skapades av Pixar i slutet av 80-talet och har sedan dess varit en standard för 3D-grafik inom filmindustrin. RenderMan s shaderspråk RenderMan Shading Language (RSL) har stått som förebild för dagens hårdvarushaders för realtidsgrafik. 4

2.3 Hårdvarushaders Ett modernt grafikkort kan liknas vid en fabrik med ett löpandeband-system. I den ena ändan stoppas geometri och texturdata in och i den andra ändan visas resultatet på skärmen. Vad som görs längs det löpandebandet och hur det görs definierades förr i tiden på ett färdigbestämt vis. De tidigare 3d-accelaratorerna till PC s hade enbart fixed function rendering vilket innebär att renderingen var helt begränsad till de funktioner som utvecklaren av hårdvaran lagt till. Den enda möjlighet som fanns för att styra utritningen var genom att kombinera den färdiga funktionalitet som hårdvarutillverkarna försett grafikhårdvaran med. Denna begränsning gjorde att många spel som släpptes under denna tidseran var förhållandevis lika varandra. det fanns inte så mycket effekter att välja bland för att definiera en yta. Nvidia introducerade register-combiners med sin GeForce serie i slutet av 90-talet (Kilgard 2003, Nvidia 2000). Register-combiners gav programmerare möjlighet att göra enkla operationer för varje pixel som skrevs till skärmen. Man kunde med hjälp av detta göra enklare effekter så som bumpmapping. De var det första steget mot dagens hårdvarushaders. En hårdvarushader är ett program som ersätter en del av den fixerade renderings pipelinen, eller ersätter en sektion av det löpandebandet om vi skall använda vår tidigare liknelse. De vanligaste typerna av hårdvarushaders idag är vertexshaders och fragmentshaders. Vertexshaders ger programmeraren möjligheter att styra hur individuella vertiser skall transformeras innan de rastreras. Fragmentshaders ger på liknande sätt möjligheter att styra hur individuella fragment(pixlar) skall ritas på skärmen. En ny typ av shaders har introducerats med DirectX-10 kallat geometryshaders, som gör det möjligt att på något högre nivå än vertexshaders göra operationer på geometri. En hårdvarushader får input från det underliggande renderingssystemet i form av uniformvariabler eller vertexattribut. En uniform variabel är en variabel vars värde är konstant under den tid shadern körs. En uniform variabel går att komma åt i både vertex- och fragmentshaders. Vertexattribut är värden som sätts per vertex, detta kan tillexempel vara en färg eller vikter för andvändningen i benanimationer. Vertexattribut går enbart att komma åt i en vertexshader och är inte tillgängliga i en fragmentshader. För att få tillgång till ett vertexattribut i en fragmentshader så måsten attributet skickas vidare i form av en varying-variabel. En varying-variabel är en speciell typ av variabel som som används för kommunikation mellan vertex- och fragmentshaders. En varying-variabel sätts per vertex och interpoleras sedan över polygonen för varje pixel och anrop till fragmentshadern. Varying-variabler är det enda sättet att kommunicera mellan en vertex och en fragmentshader. Som nämnts tidigare så används en vertexshader för att styra transformeringen av individuella vertiser. Detta fungerar så att en instans av vertexshadern körs en gång för varje vertex. Vertexshadern får information om den aktuella vertisen så som position, normal och uv-kordinater. En vertexshader får enbart tillgång till information om just en vertis och inga andra. En vertexshader måste åtminstone alltid skriva ut en position som sedan kan användas av rasterings-processen. En vertexshader kan även skriva ut ytterligare information som sedan kan användas av fragmentshadern i form av varying-variabler som beskrevs ovan. En fragmentshader har likt en vertexshader ett krav att den alltid måste skriva ut en färg. 5

Det finns även en del valfri data så som djup till djupbufferten och färger till ytterligare färgbuffertar. Från början så programmerades hårdvarushaders med hjälp av ett assembler språk. Men detta har sedan blivit ersatt av mer högnivåspråk så som CG (Cg Language Specification 2008), HLSL (Peeper & Mitchell 2004) eller GLSL (Kessenich et al. 2006). Dessa språk är alla baserade på programmeringsspråket C och är förhållandevis lika varandra. Vissa skillnader finns i tillexempel syntax och vilka datatyper som finns tillgängligt. Men i grunden så är de väldigt lika. CG är utvecklat av Nvidia och stöds på alla större hårdvaruplattformar med DirectX eller OpenGL stöd. HLSL är Microsofts shaderspråk och är det primära språket vid utvecklingen av DirectX applikationer. GLSL är motsvarande ett språk som enbart stöds av GLSL, och har sedan OpenGL version 2.0 varit en integrerad del av OpenGL-API t. Detta arbete kommer främst att fokusera på GLSL, Men de metoder som använder bör fungera förhållandevis bra i de andra större shaderspråken också. Möjligheten att styra hårdvaran och göra mer och mer avancerade visuella effekter ökar för varje ny generation av grafikhårdvara. Vad som även ökar är komplexiteten i shaderkoden som behövs för att åstadkomma mer avancerade effekter. Det finns även ett ökande krav på mer unika ytstrukturer, där mer än bara olika texturer skiljer dem åt. Exempelvis så skiljer sig ett marmorgolv stort från en gräsmatta, eller lacken på en sportbil jämfört med asfalten den kör på. Att kunna kombinera ytors egenskaper på olika vis innebär vissa problem. Shader program blir långa och komplexa. Många unika ytor innebär att man får en stor mängd shaderprogram, vilket leder problem med underhåll. 2.4 Shadergrafer Shadergrafer är inte något nytt koncept utan har länge använts för offline-rendering. På senare år har grafbaserade shadereditorer för hårdvarushaders börjat dyka upp lite här och var. Många moderna spelmotorer så som Offset engine och Unreal engine 3 kommer med en shadereditor. Figur 4 föreställer shadergraf editorn Lucifered som utvecklats för detta arbete. Figur 4. Lucifered 6

Shadergrafer är ett sätt att abstrahera en shader till en nivå som gör den mer lättförståelig. Detta genom att dela upp shadern i logiska delar (noder) som sedan kopplas samman för att få ett önskat beteende. Hur en shadergraf är uppbygd och vilka delar den består av är väldigt implementationsspecifikt och beror på vad användaren har för krav på systemet. Grundläggande för de flesta shadergrafer är att de består av sammankopplade noder. En nod kan ha kopplingar för inkommande och utgående data. Man kan klassificera noder i tre olika typer beroende på vad de har för typer av kopplingar. Indata-, utdata- och funktionsnoder. En indatanod har enbart utgående kopplingar, och ansvarar för att hämta in extern data från underliggande renderare så som textursamples eller vertexattribut. En utdatanod har enbart inkommande kopplingar och ger ut data från shadern tillbaka till renderings systemet, detta kan tillexempel vara en pixelfärg eller en vertexposition. Funktionsnoder utför någon operation på indata som den sedan skickar vidare. En shadergraf är en så kallad directed acyclic graph (DAG) eller riktad acyklisk graf. Det innebär att det inte får förekomma några cykler i grafen och alla kopplingar går från en utgång till en ingång på en annan nod och aldrig åt andra hållet. 2.5 Just in time compilation (JIT) Just in time compilation innebär att kod kompileras precis innan den skall användas. Detta skiljer sig mot traditionell kompilering då hela programkoden kompileras innan programmet exekveras. Detta används bland annat i java där bytecode kompileras till maskinkod under tiden programmet körs. Fördelen med detta är att bytekoden i sig inte är plattforms-specifik vilket innebär att ett java program kan köras på alla plattformar som har en java JIT kompilator. Att kompilera koden under tiden den körs ger även möjligheten att göra vissa optimeringar på baserat på hur koden körs som annars inte är möjligt. För mer information om just in time kompilering se Aycock (2003). 2.6 Tidigare arbeten Ett av de första arbeten relaterat till shadergrafer var Shade tree s av Cook (1984). Med Cooks system sattes atomära operationer samman i en trädstruktur (se figur 5) där utdata från en operation kunde skickas vidare till en annan. Tekniken som beskrivs i detta arbete beskriver enbart ett språka för att bygga shaders men inget grafisktgränssnitt. Cooks arbete kom att bli grunden för renderman och så småningom till dagens hårdvarushaders. 7

final color * + copper color * * weight of ambient component ambient weight of specular component specular normal viewer surface roughness Figur 5. cook s shade tree 2.6.1 Building block shaders, Abram & Whitted (1990) Detta arbete går vidare med Cooks arbete och implementerar ett grafissktgränssnitt till det språk som Cook beskriver. Detta gränssnitt ger användaren möjlighet att bygga komplexa shaders genom att koppla samman shader-element i ett nätverk. 2.6.2 Abstract Shader Trees, McGuire et al. (2006) I detta arbete diskuteras mer intelligenta kopplingar mellan noder. Här ges noder information om vilken data de tar och ger för att förenkla och minska mängden kopplingar i grafen. Detta innebär att det aldrig finns mer än en koppling mellan noderna. Noderna avgör själva vilken data som skall skickas mellan dem. 2.6.3 Interactive shader development, Jensen et al. (1984) Detta arbete tar upp automatisk omvandling av data mellan noder. Tillexempel hur systemet automatisk kan konvertera koordinater från modelspace till viewspace utan att användaren explicit måste ange detta. Detta arbete tar även upp hur denna typ av konverteringsoperationer kan optimeras och även hur shadern kan optimeras genom att automatisk flytta kod i shadern (tillexempel flytta kod från fragment shadern till vertexshadern). 8

3 Problem Målet med detta arbete är att utveckla och utvärdera en prototyp för ett shadergrafsystem för hårdvarushaders. Systemet är först och främst tänkt att användas för realtidsrendering i datorspel, men det kan även användas till offlinerendering som inte är relaterad till datorspel. Att handkoda shaders är ingen enkel uppgift, allt eftersom grafikhårdvara blir allt kraftigare så blir mer och mer effekter en möjlighet vilket leder tills större och mer komplexa shaders. Att konstruera shaders med grafer kan ge en mer översiktlig kod där dataflödena är lätta att följa. Att handkoda shaders utan någon direkt visuella feedback är något av en mardröm för de flesta grafiker, en visuell grafbaserad lösning är betydligt mer intuitiv och lätthanterlig för de flesta. Ett visuellt verktyg där användaren kan göra ändringar i en graf och direkt få visuellfeedback vore till stor hjälp. I ett spel så finns det ofta mängder av shaders som delar större delen av koden, en grafstruktur gör återanvändning av kod enklare. Varje shader byggs upp vad en begränsad mängd noder som var och en representerar ett stycke kod. På detta vis skapas ingen ny otestad kod för varje ny shader, utan enbart gammal kod återanvänds. Portabel kod är viktigt idag då många spel utvecklas samtidigt för flera plattformar som tillexempel PC,OS X och Playstation 3. Många av dessa plattformar stödjer ej samma shaderspråk eller samma grafik-api. Grafsystemet som skall utvecklas skall vara abstraherat från underliggande shaderspråk och på så vis göra det möjligt att med en shadergraf stödja flera shaderspråk. Intresset för denna typ av system är stort bland spelutvecklare idag och arbetet har redan fått positiv respons från ett flertal spelföretag. 3.1 Delmål 1: Utveckling Det första delmålet är att utveckla en prototyp. Hur utvecklingen skall gå till diskuteras mer i metodkapitlet. Följande punkter skall beaktas under utvecklingen av prototypen. Noder. Hur skall noder implementeras och hur skall de beskrivas? Vad för egenskaper har en nod i en shadergraf och vilken data behövs för att beskriva dem. Kopplingar mellan noder. Vad för egenskaper har en koppling mellan två noder. Hur implementeras dessa kopplingar och hur överförs kopplingarna till en hårdvarushader. Hur hanteras kopplingar mellan vertex- och fragmentshaders. Grafens indata och utdata. Vilka in- och utdata har en shadergraf och hur relaterar det till hårdvarushaders. Just In Time kompilering (JIT). Stöd för just in time kompilering med cache funktioner. Detta innebär att man kan göra ändringar i shadern direkt i applikationen och automatiskt få den omkompilerad med de nya ändringarna. 9

Abstrahering. Grafen skall vara frikopplad från underliggande shaderspråk. Ett utbytbart plugin skall hantera kopplingar till ett specifikt språk. Vad behövs för att göra detta möjligt. Visualisering av grafen. Hur skall grafen visualiseras och hur skall skapandet av grafen gå till. 3.2 Delmål 2: Utvärdering Följande krav har satts som mål för grafsystemet. Dessa skall utvärderas med hjälp av den prototyp som implementeras i delmål 1. Flexibilitet. Systemet skall vara flexibelt och kunna hantera så många typer av shaders som möjligt. Det skall vara enkelt att återanvända kod. Komplexitet. Systemet skall kunna hantera stora och komplexa shaders och den grafiska editorn skall kunna visualisera stora grafer på ett överskådligt sätt. 10

4 Metod I detta kapitel diskuteras vilka metoder som används i detta arbete och även några alternativa metoder som skulle kunna användas. 4.1 Delmål 1: Utveckling Intervjuer skulle kunna användas som en metod för att ta fram en specifikation för systemet. Detta genom att intervjua programmerare som har djupa kunskaper inom shaderprogrammering och grafiker som är intresserade av att använda systemet. Och på så vis skulle en specifikation för systemet kunna diskuteras fram. Implementation har valts som metod för det första delmålet. Motiveringen till detta är att få fram implementationsspecifika detaljer i systemet och inte bara teoretiska. Många teoretiska arbeten har redan gjorts inom området. För att kunna utvärdera systemet i delmål 2 så behövs också tillgång till en implementation. 4.2 Delmål 2: Utvärdering För att utvärdera systemets användbarhet så har experiment valts som metod. Motivering till detta är att experimenten lätt kan anpassas för att fokusera på specifika delar i systemet. En serie experiment skall sättas upp som täcker de kriterier som satts upp. För att kunna genomföra dessa experiment så behövs en prototyp som fås från implementationen i delmål 1. De experiment som görs baseras på de kriterier som satts upp för systemet. Flexibilitet, här skall några olika typer av shaders implementeras för att se hur systemet klarar olika typer av shaders och vad det innebär att skapa nya shaders i systemet. Detta för att se hur väl detta system kan ersätta handskriva shaders i ett modernt spel. Komplexitet. för att utvärdera hur enkelt det är att hantera stora komplexa shaders i systemet skall en shader skapas som implementerar en mängd moderna effekter. Detta testar till stor del hur lätthanterliga stora shaders är i den grafiska editorn. En alternativ metod för att utvärdera system är att göra en undersökning där en flertal personer med olika bakgrund tillexempel grafiker och programmerare får testa och utvärdera systemet. Detta skulle ge en bred uppfattning av systemets användbarhet. 11

5 Genomförande Detta kapitel går igenom hur arbetet har genomförts från utvecklingen av prototypen för delmål 1 till utvärderingen av de krav som ställs på systemet i delmål 2. 5.1 Utveckling Systemet kallat Lucifer är uppdelat i tre delar, först själva grafsystemet som ansvarar för inladdning av en shader, kopplingar mellan noder och all den information som beskriver den abstrakta grafen. Bakom detta så har vi ett pluginsystem för backends som ansvarar för allt shaderspråkspecifikt så som kompilering och bindning av en shader. Slutligen har vi en editor kallad Lucifered för att skapa och testa shadergrafer. Uppdelningen av frontend och backend gör det möjlighet att göra shaders som är portabla mellan flera shaderspråk. Detta gör även shadergraferna mer portabla mellan plattformar då alla shaderspråk inte stöds på alla plattformar. Figur 6 ger en överblick över klasstrukturen i lucifer. ShaderManager 1 * Shader 1 Backend ShaderBackend * Node 1 GLSLBackend GLSLShaderBackend Extern * * Slot 1 * ExternBinding Value Figur 6. UML-diagram för lucifer 12

5.1.1 Noder Figur 7. En textur nod En nod är den grundläggande beståndsdelen i shadergrafen, en nod representerar ett funktionsanrop. Varje nod innehåller en representation av funktionen i ett eller flera shaderspråk. På detta vis kan en shadergraf skapas och sedan användas för att kompilera shaders till ett flertal olika shaderspråk. Varje kan ha ett antal slots som representerar inoch utdata. Extern data från applikationen fås genom speciella extern slots. Nodtyper (vertex/fragment) En nod är antingen en vertex eller fragment nod, vilket bestämmer om noden skall ligga i vertex- eller fragmentshadern. Detta gör det möjligt att i den grafeditorn enkelt flytta kod mellan vertex och fragment shadern och på så sätt balansera belastningen på vertex resp fragment pipelinen på GPUn. Eftersom en vertexshader exekveras en gång för vare vertex medans fragmentshadern exekveras en gång för varje fragment så innebär detta att fragmentshadern kommer att exekveras många flera gånger än vertexshadern. Detta innebär att det ofta är en fördel att flytta så mycket kod som möjligt till vertexshadern. Möjligheten att snabbt byta en nods typ mellan vertex till fragment gör denna balansering enkel. Eftersom vertexshadern alltid exekverar före fragmentshadern så är det inte möjligt att koppla utgående data från en fragmentnod till en vertexnod. Nod namespace Källkoden som beskriver en nod skrivs på ett speciellt vis. Exakt hur en nods källkod expanderas i den slutliga shadern är språkspecifikt. Varje nod fungerar som ett självständigt litet program med en egen main- funktion. Problemet med detta är att källkoden för alla noder kommer att sättas ihop till en färdig shader innan den kompileras. Vilket leder till namnkonflikter kan ske mellan noder dvs funktioner och globala variabler med samma namn kan existera i flera noder. Ingen enkel lösning har funnits för detta problem i glsl. En lösning är att helt enkelt ge varje funktion och variabel i en nod ett nodspecifikt namn då den expanderas. En enkel men kanske inte den bästa lösningen på detta problem är att specificerat att alla funktioner i en nod måste ges en prefix local_, vid expandering ersäts denna prefix med nodens namn. En mer praktisk lösning hade varit att söka igenom källkoden i varje varje nod efter funktioner och globala variabler och 13

och ge dem nodspecifika prefix. XML-representation av nod Varje nod beskrivs i en XML fil. Layouten är ganska simpel,en parameters -tag listar alla slots och extern s. Och en lista med source -taggar anger en implementation av noden i ett angivet språk. I figur 8 ser vi en nod som implementerar en sinus funktion. Den har två slots, en input som anger argumentet till sin-funktionen. och en output-slot som ger tillbaka värdet av sin funktionen. Den har en Source -tag som innehåller en implementation av funktionen för GLSL. Den observanta läsaren ser att main funktionen saknar argument, detta pga att argumenten till main-funktionen expanderas automatiskt av glsl-backendet beroende på vilka parametrar som finns definierade i noden och hur vida de har kopplingar eller inte (mer om det i slot sektionen). <main> <Name>Sin</Name> <Description>Sin function</description> <Type>Vertex</Type> <Parameters> <Slot Direction="Input" Name="Value" DataType="Float" /> <Slot Direction="Output" Name="Result" DataType="Float" /> </Parameters> <Source Language="glsl"><![CDATA[ void local_main() { Result = sin(value); } ]]></Source> </main> XML-representation av shader Figur 8. Sin-nod En färdig shadergraf lagras också i form av en xml-fil. Denna xml-fil fungerar för applikationen som vanlig shaderkod. Den kompileras inte till någon simplare form utan laddas i denna form i applikationen med hjälp av lucifer-bibliteket. Detta kan tänkas bli något långsammare än att ladda färdig shaderkod, men med hjälp av en cache för kompilerade shaders borde detta gå att minimera. En genomgång av delarna i xml-filen i figur 9. Först i filen ligger en tagg kallad previewmodell, detta beskriver vilken modell som skall användas i Lucifered för att visa en preview av shadern. Efter det följer en lista med de noder som finns i grafen. Varje nod har ett namn, vilken fil dom skall skapas ifrån och om det är en vertex eller fragment nod. Varje nod har även en position som även den används av Lucifered för att placera nodens grafiska representation. Varje nod har även en lista med parametrar som sätter standardvärden för slots. Slutligen i filen är en lista med connections som beskriver vilka slots som skall kopplas samman i grafen. <root> <PreviewModel>preview_teapot.zbm</PreviewModel> <Nodes> <Node Name="Node0" File="lucifer/input/glstate.xml" Type="Vertex"> <Position x="184.189" y="135.436" /> 14

<Parameters /> </Node> <Node Name="Node3" File="lucifer/math/build_float4.xml" Type="Vertex"> <Position x="215.928" y="152.225" /> <Parameters> <Slot Name="X" Value="1" /> <Slot Name="Y" Value="0" /> <Slot Name="Z" Value="0" /> <Slot Name="W" Value="0" /> </Parameters> </Node> <Node Name="Node1" File="lucifer/output/vertex_output.xml" Type="Vertex"> <Position x="219.053" y="128.682" /> <Parameters> <Slot Name="Position" Value="" /> </Parameters> </Node> <Node Name="Node2" File="lucifer/output/fragment_output.xml" Type="Fragment"> <Position x="238.193" y="158.596" /> <Parameters> <Slot Name="Color" Value="1,1,1,1" /> <Slot Name="AlphaTest" Value="false" /> <Slot Name="AlphaTreshold" Value="0.2" /> <Slot Name="LinearGamma" Value="true" /> </Parameters> </Node> </Nodes> <Connections> <Connection Node1="Node0" Slot1="FTransform" Node2="Node1" Slot2="Position" /> <Connection Node1="Node3" Slot1="XYZW" Node2="Node2" Slot2="Color" /> </Connections> </root> 5.1.2 Datatyper Figur 9. Exempel shader Namn på datatyper är oftast inte samma mellan språk, dock finns de flesta datatyper representerade i alla shaderspråk. Det vore krångligt om grafsystemet var tvunget att ha olika datatyper beroende på vilket backend som används. Detta löses genom att skapa egna datatyper som efterliknar de typer som finns i de flesta shaderspråk. Alla datatyper finns dock inte i alla shaderspråk så vissa kompromisser får göras. Jag har definierat upp en lista med egna datatyper som används i shadergrafen. Sedan är det upp till det språkspecifika backendet att översätta denna typen till en typ som finns i det språket. Eftersom prototypen i detta arbete enbart implementerar stöd för GLSL så finns det inga garantier för att de datatyper som valts räcker, kanske behövs ytterligare typer. CG har tillexempel datatypen half vilket inte existerar i GLSL, en lösning på detta vore att lägga till datatypen half i systemet och sedan låta backendet för GLSL översätta half till float medans ett CG backend kan använda den mer specifika datatypen half. Några exempel på datatyper. Datatyp GLSL CG F loat float float Int3 ivec3 int3 F loat4x4 mat4 f loat4x4 15

5.1.3 Slots Slots används för att dirigera in- och utdata till noder, Det finns två typer av slots, indata och utdata slots. Ett slot har en associerad datatyp, och enbart slots av samma datatyp kan kopplas samman. Enbart utdata slots går att koppla till indata slots. När en utdata-slot i en vertexnod kopplas till en indata-slot i en fragmentnod så ansvarar backendet för att en varying variabel skapas och datan skickas igenom denna till fragment shadern. Konstanter En ingående slot som inte har någon koppling kan istället ha ett standardvärde. Denna slot fungerar då som en konstant i shadern och sätts i compiletime dvs den går inte att ändra efter att en shader byggts. Det är dock möjligt att ändra på konstanter och låta systemet automatiskt bygga om shadern. Mer om detta i sektion 5.1.5. Arrayer Slots har inget stöd för arrayer i den aktuella implementationen. Detta kan enkelt införas i framtiden på samma vis som beskrivs för extern data nedan. 5.1.4 Extern data En extern -slot representerar någon extern data som fås från applikationen. Detta kan tillexempel vara vertexdata eller en textur. I shadertermer så representerar en extern antingen ett vertexattribut eller en uniform variabel. Varje extern har ett source name som används av applikationen vid bindning av externa data. Tillexempel kan source name på en textur vara Diffuse vilket säger applikationen att en Diffuse -textur önskas bindas till den. Vid kompilering skapas en lista med bindningar som applikationen bör göra innan användningen av shadern, för att shadern skall fungera korrekt. Språk backendet ansvarar för att applikationen ett interface att sätta bindningar med. Arrayer Systemet har inget stöd för arrayer som en specifik datatyp. Istället anges antal element explicit i en extern. Denna information används vid kompilering för att deklarera variabeln som en array av angiven storlek. Antal element är även tillgängligt i bindningslistan som ges till applikationen så applikationen kan skicka in rätt antal element till shadern. 5.1.5 Just in time compilation Tanken med detta system är inte att det skall användas för att producera shaderkod som CG eller GLSL som sedan kan användas i en applikation, utan istället så fungerar lucifer som ett frontend till shaderspråket. Man bygger sin shadergraf i editorn och sedan används den grafen direkt i applikationen. Systemet använder sig av en JIT ( just in time ) approach för kompileringen vilket innebär att shadern kompileras först då den används. Shadergrafen fungerar som java s bytecode, grafen är en plattforms-oberoende representation av programmet som sedan kompileras till ett plattforms-specifik program då den används. Detta gör det möjligt att göra ändringar i grafen direkt i applikationen för att tillexempel slå på och av olika funktioner i grafen. För att slippa kompilera- om shadern 16

vid varje ändring i grafen så används ett enkelt cache system som cachar varje bygd version tillsammans med en unik identifierare beroende på inställningarna i grafen. Denna implementation har stöd för att ändra på konstanter i shadern. Detta är användbart för att tillexempel kunna ändra antalet aktiva ljuskällor i shadern. En möjlig utökning är någon form av switch-nod som kan slå av och på delar av grafen. 5.1.6 Shader backend Själva grafsystemet är abstraherat från underliggande shaderspråk. Med detta menas att den graf som skapas inte är gjort för att fungera med ett shaderspråk. Istället så finns det ett utbytbart backend som bestämmer vilket språk som shadern skall kompileras för. Backendet kan ses som ett utbytbart lågnivå-interface mot ett specifikt shaderspråk som lucifer-biblioteket använder sig av utan att det behöver vara medveten om vilket språk det egentligen använder sig av. Detta gör det möjlighet att skapa en shadergraf som sedan kan användas på flera plattformar än om shadern skulle kodats för hand. Dock måste varje nod fortfarande ha en källkods-implementation i de shaderspråk den är tänkt att användas i. I denna prototyp finns det enbart ett implementerat shaderbackend, detta backend implementerar stöd för GLSL. 5.1.7 Grafeditor Lucifered är en grafeditor som utvecklats för att enklare kunna testa funktionaliteten i systemet. Editorn är byggd ovanpå en existerande spelmotor kallad ZeroFps. ZeroFps är ett hobby projekt som utvecklats under att par år, det hade redan ett välutvecklat gui och renderings system så det passade bra att använda som grund för grafeditorn. För mer information se Zero Point Gameplay (2008). Figur 10. Lucifered Interface Editorn består följande delar, först och främst en arbetsyta där man lägger ut noder och kopplar dem samman. Ytan går att flytta runt och zooma genom att dra och släppa med musen och använda scrollhjulet. I det över högra hörnet finns en lista med alla tillgängliga noder. För att skapa en ny nod dubbelklickar man på den önskade noden i listan och en ny nod skapas i mitten av skärmen. 17

I det nedre vänstra hörnet finns en textlogg som visar medelanden till användaren. Detta kan tillexempel vara ett felmedelande om användaren försöker göra en koppling som inte är tillåten. I det nedre högra hörnet finns det en test knapp som provar att kompilera shadern. Om något fel inträffar så skrivs detta ut i loggen. Om inget fel inträffade så visas en förhandsvisning av shadern. Noder I figur 11 kan man se att vertex-noder visas med gul färg och fragment-noder visas med blå färg. En nod består till stor del av en lista med alla dess slots, input-slots visas på nodens vänstra kant och output-noder visas på dess högra. För att koppla samman en output-slot i en nod till en input-slot i en annan nod klickar man på en av slotsen så den blir grön, sedan klickar man på den slot man vill koppla till. Om kopplingen är tillåten kommer en ny kant skapas mellan dessa. Standardvärden för slots går att ange i ett textfält. Externa data listas på liknande sätt men saknar den runda kopplings ikonen. Extern data har heller inget textfält för standardvärden utan ett textfält för att sätta källnamn. Detta är användbart för att tillexempel sätta texturnamn på en texturnod. Figur 11. Några noder Preview Preview-systemet förhandsvisar en angiven modell med shadern. Användaren kan byta preview-modell för att få en bättre uppfattning om hur slutresultatet kommer att bli. Detta preview-system är enbart avsett att användas för shaders som används som en ytshader på en modell. Preview systemet har inget stöd för att tillexempel förhandsvisa postprocess effekter. 18

5.2 Utvärdering Detta kapitel går igenom hur utvärderingen har genomförts. Experiment valdes som metod för utvärderingen i metodkapitlet. 5.2.1 Flexibilitet För att testa flexibiliteten i systemet så har några experiment utförts då några olika typer av shaders har skapats. Deferred gbuffer shader Denna shader används för så kallad deferred-shading (Hargreaves & Harris 2004). Deferredshading innebär att geometridata skrivs till en eller flera färgbuffertar som används i ett senare renderingspass för att göra själva ljussättningen av scenen. Till skillnad mot vanlig forward-rendering så slipper man på detta vis rita en modell flera gånger för att addera ihop ljuset från flera ljuskällor. Följande noder används i denna shader. Figur 12. Deferred GBuffer shader GLState Ger tillgång till OpenGL s interna data. Denna används av praktiska skäl istället för att manuellt skicka data så som modelvymatriser och texturkoordinater till noden via extern s. Tangents Ger tillgång till tangent och binormal. Animation Utför bentransformationer för benanimation. viewspace Förenklar omvandling från modelspace till viewspace. 2DTexture Läser in ett sample från en 2d-textur.. ColorToNormal Konverterar ett RGB färgvärde till en normal. 19

GBufferOutput Den mest specifika noden för denna typ av shader. Denna output nod packar ihop all data som behövs i det senare ljussättnings-passet i två texturer som kallas för en gbuffert. Deferred composition Denna shader utför ett ljussättnings-pass för deferred-shading. Den läser in geometridata från två texturer och utför sedan ljussättning med hjälp av detta. Ett ljus hanteras per pass så flera pass måste adderas ihop för att få med alla ljus i den färdiga bilden. Dessa pass ritar till skillnad mot vanlig forward-rendering enbart en kvadrat över skärmen beståendes av 4st vertiser istället för att behöva rita hela modellen för varje ljus. Figur 13. Deferred composition shader Nya noder i denna shader. Deferred quad Denna nod mappar texturkoordinaterna Deferred input Läser ut geometridata från gbufferten (två rgba-texturer). Shadowmap Evaluerar en skugsampling från en shadowmap som genererats av shadowmap-shadern som beskrivs nedan. Detta ger ett flyttal mellan 0 och 1 som säger om det aktuella fragmentet ligger i skugga eller inte. Lighting Gör ljussättning enligt Phongs reflektionsmodell. Multiply float4 Multiplicerar elementen i två vektorer. Fragment output Skriver ut det slutliga färgvärdet till skärmen. Forward rendering En shader som ljussätter en modell med en ljuskälla, Flera pass körs för att slå ihop utdatan från flera ljuskällor till den slutlig bilden. Resultatet blir detsamma som i ovanstående deferred-shader. 20

Figur 14. forward render Denna graf innehåller inga nya nodtyper. Utan återanvänder de noder som skapats för ovanstående gbuffert och composition shader. Shadowmap Denna shader skriver djupvärden till en färgbuffert kallad shadowmap (Everitt et al. 2005). Shadowmappen skapas genom att rendera scenen sett från ljuskällan och används senare för att avgöra om ett fragment ligger i skugga eller inte. Detta är en ganska enkel shader med en ny nod kallad Shadow out som sparar avståndet från kameran till det aktuella fragmentet i en textur. Figur 15. Shadowmap 21

Depth pass Detta är en enkel shader som skall användas för ett så kallat djup-pass. Ett djup-pass är ett renderings pass som görs före alla andra pass för att avgöra vilka fragment som är synliga. De mer avancerade renderingspassen behöver sedan enbart rita de fragment som djuppasset anser synliga. Detta pass skall vara så simpelt som möjligt för att det skall vara till någon nytta. Denna shader har enbart vertexnoder och inga fragment noder. Inga nya noder behövdes skapas för denna shader. Figur 16. djuppass shader 5.2.2 Komplexitet För att se hur bra systemet klarar av mer komplexa shaders så skall en shader skapas med några välanvända moderna effekter. De effekter som skall implementeras är normalmapping, specular-mapping, parallax-mapping, shadow-mapping och animationer. Figur 17. En mer komplex graf 22

Animationer Animationerna består först och främst av en animationsnod som tar position,normal och tangenter i modelspace och transformerar dessa med hjälp av benanimationer. För att göra benanimationer behövs en indexlista som beskriver vilka ben som skall påverka varje vertis, index listan hämtas som ett vertexattribut via en extern. Bentransformationerna lagras som en positionsvector och en quaternion för rotationen, dessa skickas in som uniform arrayer via extern s. Normal mapping Normal mappingen består av en nod som tar färgvärden från en textur och omvandlar dessa till normaler som sedan skickas vidare till ljussättningen. Parallax mapping Parallax mapping består av en en nod som med hjälp av höjdvärden från en textur ändrar på texturkoordinaterna för att ge en känsla av djup. Noden ger ut ut nya texturkoordinater som sedan används för diffus,specular och normal-mapps. Shadowmapping Shadowmapnoden utvärderar om det aktuella fragmentet ligger i skugga och skickar resultatet vidare till ljussättningsnoden. Ljussättning Ljussättningen består även den huvudsakligen av en nod som beräknar ljussättningen med Phongs reflektionsmodell. Ljusnoden tar emot en position från animationsnoden, en normal från normalmapping-noden, skugga från shadowmapnoden och reflektionsintensitet från en specularmapp. Resultatet från ljussättningen är ett intensitetsvärde som sedan multipliceras med färgen från en diffusemapp. 23

6 Resultat och analys I detta kapitel presenteras resultaten från de experiment som gjorts för att utvärdera prototypen. I metod kapitlet sattes några krav upp för implementationen som skulle utvärderas med hjälp av experiment. Följande två kapitel analyserar resultaten från dessa experiment. 6.1 Flexibilitet I metod kapitlet bestämdes att systemets flexibilitet skulle utvärderas på följande vis. Några olika typer av shaders skulle implementeras för att se hur väl det det fungerar att skapa olika typer av shaders i systemet. Detta för att se hur väl detta system kan ersätta handskriva shaders i ett modernt spel. I de shaders som utvecklats så märker man snart att många av noderna kan återanvändas. I de första experimenten så behöva många nya noder skapas för att implementation skulle vara möjlig men i de senare så behövdes få nya noder. Dessa shaders är förhållandevis lika vilket ofta är fallet i spelutveckling. Ofta är det en fråga om några mindre ändringar för varje ny shader som skapas. Återanvändning av noder tillsammans med just in time kompilering förenklar skapandet av shaders med små skillnader. Man kan med en ganska begränsad mängd noder skapa många olika shaders. Exakt hur återanvändbar en nod är har att göra med hur generell den är, mer generella noder innehåller vanligtvis mindre kod och därför behövs fler noder för att bygga upp ett önskat beteende. Medans större mer specialiserade noder innehåller mer kod och är mer specialanpassade för ett speciellt ändamål. Genom att skapa noder som är mer eller mindre generella så kan man balansera återanvändbarhet och lättanvändbarhet. En grafiker med mindre erfarenhet av programmering föredrar förmodligen att ha större mer specialiserade noder. Medans en erfaren programmerare vill ha mer generella noder som kan användas för att bygga mer komplexa shaders. De shaders som skapats täcker en stor del av de typer av shaders som används för att rendera själva spelvärlden i ett modernt spel. Vissa typer av shaders har dock utelämnats helt i detta experiment tillexempel så har inga experiment gjorts för att skapa posteffekter så som bloom eller motionblur. 6.2 Komplexitet I metod kapitlet bestämdes att systemets förmåga att hantera komplexa shaders skulle utvärderas genom att skapa en relativt stor och komplex shadergraf som implementerar en mängd moderna effekter. Resultatet från detta experiment handlar till stor del om vad som påverkar visualiseringen av grafen. Antal noder i grafen påverkar hur överskådlig den är. Färre men mer specialiserade noder skulle kunna göra grafen mer överskådlig och mer lättanvänd. Tillexempel så kan man välja att skapa en nod för normal-mapping som själv läser in en textur istället för att den skall ta input från en textur, detta gör noden mer specialiserad och mindre generell men möjligtvis mer lättanvänd. En annan möjlighet vore att slå samman en mängd noder till en grupp-nod vilket implementerats i Mental mill (Version: 1.0 beta) [Datorprogram] 24

(2008). Detta skulle kunna förenkla översikten utan bekostnad av flexibilitet. Hur kopplingar mellan noder visualiseras påverkar också hur överskådlig grafen är. Färgkodning av kopplingar gör det lättare att skilja en koppling från mängden. En möjlig utökning skulle kunna vara att visualisera datatypen på något vis, möjligen med olika typer av ikoner liknande det i Goetz et al. (2004). Färgkoderna slumpas fram från den övre ljusa delen av färgspektrat. Valet av kopplings-visualisering verkar vara en av de viktigare detaljerna för att få en översiktlig graf. Några olika typer kurvor för att visualisera kopplingar har testats se Figur 18, 19 och 20. Figur 18. Raka linjer Figur 19. s-kurva (sigmoid kurva) Figur 20. Kantig s-kurva 25

7 Slutsats Detta kapitel sammanfattar arbetet och resultatet samt diskuterar arbetets betydelse. 7.1 Sammanfattning I detta arbete har ett shadergrafsystem för hårdvarushaders designats,implementerats och slutligen utvärderats. Målet med designen har varit att skapa ett system som förenklar skapandet av shaders först och främst för datorspel. Detta genom att bland annat förenkla återanvändning av kod med hjälp av återanvändbara noder och möjligheten att skapa permutationer av shaders med hjälp av just in time kompilering. Prototypen har utvecklats med mål att kunna skapa abstrakta grafer utan någon direkt koppling till något specifikt shaderspråk. Detta gör en shader skapad som en shadergraf mer portabel än en handskriven shader i ett specifikt shaderspråk. Ett utbytbart backend gör det möjligt att kompilera en shadergraf i flera shaderspråk. En grafeditor har utvecklats för att enklare kunna utföra experiment på själva grafsystemet och för att kunna utvärdera själva visualiseringen av grafen. Grafeditorn gör det enkelt att flytta en nod mellan vertex- och fragmentshadern och på detta vis ger användaren möjligt att optimera en shader genom att att välja om kod skall exekveras per fragment eller per vertex. Två mål sattes upp för att utvärdera prototypens användbarhet, det första var att systemet skulle vara flexibelt och kunna hantera många typer av shaders och det andra var att systemet och framför allt grafeditorn skulle kunna hantera stora komplexa shaders. Från dessa experiment kan följande slutsatser dras. I de shaders som skapats för att utvärdera flexibilitet kan man se att många av de noder som skapas kan återanvändas i de senare experimenten. De shaders som skapats i dessa shaders är förhållandevis lika så att noder kan återanvändas är inte speciellt konstigt. Ofta är detta fallet även i spel, många shaders med mindre skillnader. Att helatiden återanvända noder och att sällan ny otestad kod måste införas i nya shaders borde leda till mer buggfria shaders. Hurvida noder går att återanvända beror på hur generella de är dvs om de går att applicera på mer än ett problem. Mer specialiserade noder kan vara att föredra då de kan vara enklare att hantera för grafiker. Men mer generella noder kan vara lättare att återanvända. Detta innebär att man får balansera mellan generalitet och specialisering då man skapar nya noder. Hur överskådlig visualiseringen av grafen är påverkas mycket av hur lätta kopplingar är att följa, några olika typer av kurvor för att visualisera kopplingar presenteras i resultatkapitlet. Visualiseringen av grafen påverkas också stort av hur många noder det finns i grafen. En graf med många små noder blir lätt rörig och svårförstådd. Ett system där man kan klumpa ihop flera noder i en gruppnod skulle kunna lösa detta problem genom att göra det möjligt att slå samman generella noder till mer specialiserade noder. 7.2 Diskussion I detta arbete har några enkla experiment utvärderat om detta shadergrafsystem kan ersätta vanliga handskrivna shaders i datorspel, och utfallet har varit mycket positivt. De lösningar som presenteras i detta arbete gör utvecklingen av shaders enklare i många av- 26