Hallo! Dit is het laatste artikel in onze serie over de basis van 3D grafische software voor software, en deze keer zullen we kijken naar dynamische verlichting! Voordat je te enthousiast of te bezorgd wordt over hoe moeilijk een taak als dynamische verlichting kan zijn, ontspan je. We gaan voorlopig alleen de meest elementaire vorm van dynamische verlichting behandelen (aangezien het hele onderwerp zelf enorm is en anderen erin geslaagd zijn hele boeken over het concept te vullen).
In het bijzonder zullen we een dynamisch verlichtingssysteem met één punt, een enkele kleur en een vaste verlichtingsstraal bouwen, waarmee we kunnen beginnen met het onderwerp. Voordat we daar echter ingaan, laten we eens kijken naar enkele van onze eerder gemaakte lessen die we zullen gebruiken.
Onze dynamische verlichting wordt punt voor punt behandeld, terwijl ze worden voorbereid om naar het scherm te worden getrokken. Dit betekent dat we uitgebreid gebruik zullen maken van twee van onze vorige lessen: de Punt
klasse en de Camera
klasse. Dit is hoe ze eruit zien:
Puntklasse variabelen: num tuple [3]; // (x, y, z) Operators: Point AddVectorToPoint (Vector); Point SubtractVectorFromPoint (Vector); Vector SubtractPointFromPoint (punt); Null SetPointToPoint (punt); Functies: drawPoint; // teken een punt op zijn positie tuple Cameraklasse Vars: int minX, maxX; intIJp, maxY; int minZ, maxZ; array objectsInWorld; // een array van alle bestaande objecten Functies: null drawScene (); // tekent alle benodigde objecten op het scherm
Aan de hand van deze info stellen we onze basisverlichtingsklasse samen.
Onze verlichtingsklasse heeft een paar dingen nodig om hem functioneel te maken - namelijk een positie, een kleur, een type en een intensiteit (of lichtstraal).
Zoals ik eerder al zei, zal onze verlichting punt voor punt worden berekend voordat elk punt wordt getekend. De voordelen hiervan zijn dat het eenvoudiger is voor hoe onze motor is georganiseerd, en ook dat het meer van de belasting van ons programma naar de processor van het systeem verschuift. Als u uw verlichting vooraf zou berekenen, zou het in plaats daarvan de belasting naar de harde schijf van uw systeem verplaatsen en afhankelijk van hoe uw motor is ontworpen, eenvoudiger of complexer zijn.
Met dit alles in gedachten zou onze klas er als volgt uit kunnen zien:
Lighting Class Variables: num position [3]; // (x, y, z) num red = 255; // wat toe te voegen aan de r-waarde van een punt bij volledige intensiteit num groen = 255; // wat toe te voegen aan de g-waarde van een punt bij volledige intensiteit num blue = 255; // wat toe te voegen aan de b-waarde van een punt bij volle intensiteit string lightType = "point"; // het type verlichting num radius = 50; // de straal van het licht in pixels
Momenteel laten we alle waarden hard coderen voor eenvoud, maar als u vindt dat u de functionaliteit van verlichtingsklassen wilt uitbreiden, kunt u eenvoudig elk van de waarden aanpassen via beide functies, een constructor, enz..
Alle belangrijke wiskunde voor onze dynamische verlichting zal echter plaatsvinden binnen onze cameraklasse, dus laten we daar eens naar kijken.
We gaan nu een nieuwe variabele aan onze cameraklasse toevoegen, die we zullen gebruiken om onze lichtbron op te slaan. Voor nu zal de variabele slechts één verlichtingsinstantie opslaan, maar deze kan eenvoudig worden opgeschaald om meer lichtpunten toe te staan.
Vlak voordat een punt getekend is, gaan we kijken of het binnen de straal van ons licht is. Zodra we weten dat het zich binnen het bereik van het licht bevindt, moeten we de afstand tussen het punt en de positie van het licht vinden en dan moeten we de kleur van het punt aanpassen op basis van die afstand.
Met dat alles in gedachten kunnen we een soortgelijke code toevoegen aan onze camera's drawScene ()
functie:
if (currentPoint.x> = (light.x - light.radius)) // als het punt binnen de linker links van het licht ligt (currentPoint.x <= (light.x + light.radius)) //if the point is within the light's right bound if(currentPoint.y >= (light.y - light.radius)) // als het punt binnen de bovengrens van het licht ligt if (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
Zoals u kunt zien, is onze methode om de kleur van een punt aan te passen momenteel nog niet zo geavanceerd (er zijn er echter veel die, als u ze in plaats daarvan wilt gebruiken). Afhankelijk van de afstand van een punt tot het midden van het licht, verlichten we zijn kleur met een percentage. Onze verlichtingsmethode is op dit moment niet verantwoordelijk voor schaduwen, dus gebieden ver weg van het licht worden niet donkerder en objecten blokkeren licht niet van andere objecten die erachter kunnen zijn.
Voor ons programma zullen we deze keer een paar vooraf gegenereerde vormen op het scherm hebben. Dit kunnen alles zijn wat je wilt, maar voor ons voorbeeld ga ik gewoon enkele eenvoudige punten gebruiken. Wanneer een gebruiker nu ergens op het scherm klikt, gaan we op dat moment een lichtbron maken. De volgende keer dat ze klikken, verplaatsen we het punt naar die positie, enzovoort. Hierdoor kunnen we onze dynamische verlichting in actie zien!
Dit is hoe uw programma eruit zou kunnen zien:
main // setup voor je favoriete grafische API hier // setup voor toetsenbordinvoer (is mogelijk niet nodig) var camera = new Camera (); // maak een instantie van de cameraklasse // stel de cameraruimte van de beeldruimte in.minX = 0; camera.maxX = schermbreedte; camera.minY = 0; camera.maxY = schermhoogte; camera.minZ = 0; camera.maxZ = 100; // teken aanvankelijke objecten en plaats ze op de camera-ruimte terwijl (toets! = esc) if (mouseClick) if (firstClick) // maak het initiële lichtobject op mouse pos else // wijzig de positie van het lichtobject camera.drawScene ();
Nu zou je je dynamische verlichting in actie moeten kunnen ervaren en hopelijk zien hoeveel meer diepte het kan toevoegen aan een game-engine. Bekijk hier mijn demo - gebruik de EEN en S toetsen om te schalen, en de Y, H, U, J, ik en K toetsen om te draaien.
Hoewel onze dynamische verlichting eenvoudig is, kan deze zeker worden verbeterd als u daartoe geneigd bent. Sommige dingen die best cool zouden zijn, en ook vrij eenvoudig toe te voegen zijn:
Bedankt voor het bekijken van onze serie: Laten we een 3D-spelengine bouwen. Het is geweldig om deze artikelen te schrijven en onthoud dat als u vragen heeft, aarzel dan niet om ze in de reacties hieronder te stellen!
U kunt ook extra hulp krijgen bij Envato Studio, waar u tal van fantastische 3D-ontwerp- en modelleringsdiensten kunt vinden voor betaalbare prijzen.
3D-ontwerp- en modelleringsdiensten op Envato Studio