La oss bygge en 3D-grafikkmotor Dynamisk belysning

Hallo! Dette er den endelige artikkelen i serien vår om grunnleggende 3D-grafikksystemer, og denne gangen vil vi se på dynamisk belysning! Før du blir for spent eller for bekymret for hvor vanskelig en oppgave som dynamisk belysning kan være, slapp av. Vi skal bare dekke den mest grunnleggende formen for dynamisk belysning for øyeblikket (siden hele faget er stort, og andre har klart å fylle hele bøker på konseptet).

Spesielt skal vi bygge et enkeltpunkt, en farge, et dynamisk lyssystem med fast belysningsradio som gjør at vi kan begynne å dabble i emnet. Før vi går inn i det, la oss ta en titt på noen av våre tidligere laget klasser som vi skal bruke.


oppsummering

Vår dynamiske belysning skal håndteres på en punkt-for-punkt-basis som de er prepped for å bli trukket på skjermen. Dette betyr at vi skal gjøre omfattende bruk av to av våre tidligere klasser: Punkt klasse og Kamera klasse. Slik ser de ut:

Point Class Variables: num tuple [3]; // (x, y, z) Operatører: Point AddVectorToPoint (Vector); Punkt SubtraherVectorFromPoint (Vector); Vector SubtractPointFromPoint (punkt); Null SetPointToPoint (punkt); Funksjoner: drawPoint; // tegne et punkt på sin posisjon tuple Kamera klasse Vars: int minX, maxX; int minY, maxY; int minZ, maxZ; array objectsInWorld; // et utvalg av alle eksisterende objekter Funksjoner: null drawScene (); // trekker alle nødvendige objekter til skjermen

Ved hjelp av denne informasjonen, la oss sette sammen vår grunnleggende belysningsklasse.


Vår lysklasse

Et eksempel på dynamisk belysning. Kilde: http://redeyeware.zxq.net

Vår belysningsklasse trenger noen ting for å gjøre den funksjonell - nemlig en posisjon, en farge, en type og en intensitet (eller lysradius).

Som jeg sa tidligere, vil vår belysning beregnes på et punkt for punkt før hvert punkt trekkes. Ulemper av dette er at det er enklere for hvordan vi har organisert vår motor, og at det også skifter mer av programmets belastning til systemets prosessor. Hvis du skulle forhåndsberegne belysningen, ville den i stedet skifte lasten til systemets harddisk, og avhengig av hvordan motoren din er utformet, kan det være enklere eller mer komplekst.

Med alt dette i tankene kan vår klasse se slik ut:

Lyseklasse Variabler: num posisjon [3]; // (x, y, z) num rød = 255; // hva å legge til et punkts r-verdi ved full intensitet num green = 255; // hva skal du legge til til et punkts g-verdi ved full intensitet num blue = 255; // hva som skal legges til et punkts b-verdi ved full intensitetstreng lightType = "point"; // typen belysning num radius = 50; // lysets radius i piksler

Foreløpig skal vi legge alle verdiene hardt inn for enkelhet, men hvis du finner ut at du vil utvide funksjonene i belysningsklassene, kan du enkelt få hver av verdiene til å endres gjennom enten funksjoner, en konstruktør osv..

Alle de viktige matematikkene for vår dynamiske belysning kommer til å skje i kameraklassen vår, så la oss ta en titt på det.


Lights? Kamera? Motor.

Et annet eksempel på dynamisk belysning. Kilde: http://blog.illuminatelabs.com/2010/04/hdr-and-baked-lighting.html

Vi skal legge til en ny variabel i kameraklassen vår, som vi skal bruke til å lagre vår lyskilde. For øyeblikket vil variabelen kun lagre en belysningsinstans, men det kan lett bli skalert opp for å tillate flere lyspunkter.

Rett før et punkt er tegnet, skal vi sjekke for å se om det er innenfor lysets radius. Når vi vet at det er innenfor lysets rekkevidde, må vi finne avstanden mellom punktet og lysets posisjon, og da må vi justere punktets farge basert på den avstanden.

Med alt dette i tankene kan vi legge til kode som ligner dette på kameraets Metoden drawscene () funksjon:

hvis (currentPoint.x> = (light.x - light.radius)) // hvis punktet er innenfor lysets venstre bundet hvis (currentPoint.x <= (light.x + light.radius)) //if the point is within the light's right bound if(currentPoint.y >= (light.y - light.radius)) // hvis punktet er innenfor lysets øverste bundet hvis (currentPoint.y <= (light.y + light.radius)) //if the point is within the light's bottom bound //calculate distance between point and light (distance) //calculate percentage of light to apply (percentage = distance / radius) point.red += (light.red * percentage); //add the light's red, scaled to distance point.green += (light.green * percentage); //add the light's green, scaled to distance point.blue += (light.blue * percentage); //add the light's blue, scaled to distance    

Som du kan se, er vår metode for å justere et punkts farge for tiden ikke alt som er avansert (det er mange som er om, hvis du ønsker å bruke dem i stedet). Avhengig av et punkts avstand fra lysets midtpunkt, lyser vi fargen med en prosentandel. Vår belysningsmetode tar ikke hensyn til skyggelegging i det hele tatt, for øyeblikket vil områder som er langt borte fra lyset ikke bli mørkere, og gjenstander vil ikke blokkere lys fra andre gjenstander som kan ligge bak dem.


Følg lyset

For vårt program denne gangen kommer vi til å ha noen pre-gjengitte former på skjermen. Disse kan være alt du vil, men for vårt eksempel skal jeg bare bruke noen enkle punkter. Nå, når en bruker klikker hvor som helst på skjermen, skal vi lage en lyskilde på det tidspunktet. Neste gang de klikker, flytter vi poenget til den posisjonen og så videre. Dette vil tillate oss å se vår dynamiske belysning i aksjon!

Slik ser programmet ut:

main // setup for din favoritt grafikk-API her // oppsett for tastaturinngang (kanskje ikke nødvendig) her var kamera = nytt kamera (); // lage en forekomst av kameraklassen // sett kameraets visning space camera.minX = 0; camera.maxX = screenWidth; kamera.minY = 0; camera.maxY = screenHeight; camera.minZ = 0; camera.maxZ = 100; // tegne opprinnelige objekter og sett dem til kamerarommet mens (key! = esc) if (mouseClick) if (firstClick) // opprett det opprinnelige lysobjektet på musposisjon annet // endre lysobjektets posisjon  kamera.drawScene (); 

Nå bør du kunne oppleve din dynamiske belysning i aksjon, og forhåpentligvis se hvor mye mer dybde den kan legge til i en spillmotor. Sjekk ut min demo her - bruk EN og S nøkler til skala, og Y, H, U, J, Jeg og K nøkler for å rotere.


Konklusjon

Mens vår dynamiske belysning er enkel, kan den sikkert bli bedre hvis du føler deg tilbøyelig til å gjøre det. Noen ting som ville være ganske kule, og også ganske enkle å legge inn er:

  • justerbar lysradius
  • Justerbar lysfarge (i stedet for å lette en farge jevnt, lette den med en brøkdel av sin farge)
  • blokkere lys fra å reise forbi faste gjenstander
  • håndtere flere lyspunkter
  • legg til en skygge til alle punkter utenfor lysets radius
  • eksperimentere med andre former for lys (retningsbestemt, kjegle, etc.)

Takk for at du sjekker ut vår serie, la oss bygge en 3D-spillmotor. Det har vært bra å skrive disse artiklene, og husk, hvis du har noen spørsmål, vær så snill å spørre dem i kommentarene nedenfor!

Du kan også få ekstra hjelp på Envato Studio, hvor du kan finne mange fantastiske 3D Design & Modeling-tjenester til rimelige priser. 

3D Design & Modeling-tjenester på Envato Studio