3D software rendering med Delphi

Tags:    delphi
Skrevet af Bruger #1474 @ 11.08.2008

Render klasse

Denne klasse vil indeholde hele vores scene som bliver skabt i klassens konstruktion. Derudover indeholder klassen nogle renderings funktioner. Den mest fundamentale er funktionen: RenderImage. Denne funktion har tre parameter som definer bredden og højden på den færdig renderet billede samt billedefilens navn. Funktionen vil starte renderings forløbet eller renderings pipeline. Lad os tage et nærmere kig på dette renderings forløb.

Først vil vi gå igennem hver enkel pixel i vores billede ved hjælp af to løkker: X og Y. For hver pixel vil vi bruge to vektor (der tilsammen udgør en segment). Disse to vektorer kalder vi for RayNear og RayFar.

RayNear vil, I vores tilfælde, altid være havde en abolut nul værdi. Denne vektor kan opfattes som kameraets eller viewportens position. Den vil altså altid ligge på præcis nul.

Vores RayFar vil altid ligge langs Z aksens negative side. Det vil dermed sige at alt der ligger i den negative del vil være foran vores kamera eller viewport og alt der ligger i den positive side vil ligge bagved. Z aksen vil altså med andre ord repræsentere dybden i vores billede, Y aksen vil repræsentere den vertikale eller lodrette akse og X aksen vil repræsentere den horisontale eller vandrette akse. Akserne kunne selvfølgelig sagtens byttes rundt så enten Y eller X akserne vil komme til at repræsentere dybden, men det er mest almindeligt at Z aksen antages for at være dybden fordi vi allerede kender X og Y akserne fra vores 2D verden.

Afstanden mellem vores RayNear og RayFar vil altid være på 1.000 enheder i denne artikel. Vi kunne sagten gøre denne afstand langt større men dette tal passer fint for vores små scener.

I renderings forløbets begyndelse vil vi lægge RayFar vektoren til venstre for vores kamera eller viewport. For hver renderet pixel vil vi så gå et skridt til højre ved hjælp af vores X løkke. Når vi er nået til enden af X løkken vil vi gå et skridt ned langs Y aksen inden vi påbegynder en ny linje af pixels. Her er en illustration set fra oven og ned.



Som du kan se på illustrationen vil Z aksen blive vores dybde og X aksen vil blive bredden. Alt geometri der befinder sig inde i den markeret trekant vil blive renderet alt udenfor vil blive ignoreret.

For at rendere en pixel bliver vi nødt til at gå igennem alt geometri i vores scene ved hjælp af en tredje løkke: J.

For hver geometri vi går igennem vil vi også skulle gå igennem alle dens trekanter ved hjælp af en fjerde og sidste løkke: I. Vi vil nu skulle bruge Interect funktionen i vektor klassen. I vores tilfælde vil vi kalde vores skæringsvektor for RayPixel. Hvis algoritmen finder en skæringspunkt i en given trekant, vil vi blot give den en farve. Funktionen ShadePixel bliver kaldt når en skæringspunkt er blevet fundet og en fragment skal tegnes eller shades. Vi kalder det geometriske stykke som kan ses gennem en pixel for en fragment. Når vi beregner en farve for en fragment kalder vi det at shade vores fragment. Funktionen returnere en farve klasse som derefter vil blive gemt i det færdig renderet billede. Renderings klassen ser således ud:

Fold kodeboks ind/udKode 


Vi vil nu lave en instans af renderings klassen i vores projekts DPR fil.

Fold kodeboks ind/udKode 


Som du kan se er billedet formatet sat til 320x240. Billedet vil blive gemt i samme mappe som den kompileret exe fil. Billedefilen har jeg kaldt for: Billede.tga. Den eneste klasse vi vil komme til at ændre på i vores forskellige eksempler fremover er renderings klassen. De andre klasser vil vi stort set lade være som de er skrevet. I vores første eksempel vil vi lave vi en hvid trekant der befinder sig lidt væk fra vores kamera eller viewport. Vi vil derfor lave en trekant i renderings klassens konstruktion:

Fold kodeboks ind/udKode 


Da vi allerede har defineret en hvid farve i vores ShadePixel funktion vil vi prøve at kompile eksemplet.



Det renderede billede skulle gerne vise en hvid trekant med en sort baggrund.

Lad os lave en trekant der har forskellige vertex farver. Vi vil lave den klassiske trekant, hvor et hjørne er rød, en anden grøn og den sidste er blå. Funktionen: ShadePixel, i renderings klassen vil nu blive udvidet til følgende:

Fold kodeboks ind/udKode 


Tilføj farverne til trekantens tre hjørner i renderings klassens konstruktion:

Fold kodeboks ind/udKode 


Resultatet skulle nu gerne se således ud:



Denne shading metode, hvor man blander vertex farver sammen, kaldes for Gauraud shading.
Lad lægge en tekstur ovenpå trekantens flade og kombiner den med vores Gauraud shading. Jeg har lavet en lille tekstur som jeg ofte bruger i forskellige sammenhænge. Den ser således ud:



Du kan downloade billedet og ændre den til et TGA format i et billedebehandlingsprogram. Jeg kalder den blot for Test.tga Vi vil nu igen ændre lidt på vores ShadePixel funktion i renderings klassen:

Fold kodeboks ind/udKode 


Vi bør nu indsætte tekstur (texture) koordinaterne til vores trekant og tilføje en TGA klasse som kan indlæse teksturen.

Fold kodeboks ind/udKode 


Læg TGA filen: Test.tga, i samme mappe som programmets exe fil! Resultatet skulle nu gerne blive til en trekant med vores tekstur (texture) lagt ovenpå.



Lad os gøre vores scene en smule mere interessant ved at bruge nogle af geometri klassens funktioner.

Fold kodeboks ind/udKode 




Så langt så godt!
Nu skal vi til en mere interessant del af vores rendering. Vi vil tilføje en lyskilde til scenen!


Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (2)

User
Bruger #14855 @ 17.06.09 15:33
Hmm, god artikel, men ringe du har lavet PRÆCIS den samme artikel, bare med C++!
User
Bruger #1474 @ 29.06.09 19:03
Koden er jo ikke den samme!
Du skal være logget ind for at skrive en kommentar.
t