Zoeken…


Phong-verlichtingsmodel

OPMERKING: Dit voorbeeld is WIP, het zal worden bijgewerkt met diagrammen, afbeeldingen, meer voorbeelden, enz.

Wat is Phong?

Phong is een zeer eenvoudig, maar echt uitziend lichtmodel voor oppervlakken dat uit drie delen bestaat: omgevings-, diffuus en spiegelend licht.

Sfeerverlichting:

Sfeerverlichting is de eenvoudigste van de drie delen om te begrijpen en te berekenen. Sfeerverlichting is licht dat de scène overspoelt en het object gelijkmatig in alle richtingen verlicht.

De twee variabelen in sfeerverlichting zijn de sterkte van de omgeving en de kleur van de omgeving. In uw fragment-arcering werkt het volgende voor ambient:

in vec3 objColor;

out vec3 finalColor;

uniform vec3 lightColor;

void main() {
   float ambientStrength = 0.3f;
   vec3 ambient = lightColor * ambientStrength;
   finalColor = ambient * objColor;
}

Diffuse verlichting:

Diffuus licht is iets complexer dan omgevingslicht. Diffuus licht is gericht licht, wat in wezen betekent dat gezichten die naar de lichtbron zijn gericht beter zullen worden verlicht en gezichten die weg wijzen donkerder zullen zijn vanwege de manier waarop het licht hen raakt.

Opmerking: diffuse verlichting vereist het gebruik van normalen voor elk gezicht, wat ik hier niet zal laten zien hoe te berekenen. Als je wilt leren hoe je dit moet doen, kijk dan op de 3D-wiskundepagina.

Om de reflectie van licht in computergraphics te modelleren, wordt een bidirectionele reflectieverdelingsfunctie (BRDF) gebruikt. BRDF is een functie die de relatie geeft tussen het licht dat wordt gereflecteerd langs een uitgaande richting en het licht dat invalt vanuit een binnenkomende richting.

Een perfect diffuus oppervlak heeft een BRDF die dezelfde waarde heeft voor alle incidenten en uitgaande richtingen. Dit vermindert de berekeningen aanzienlijk en wordt daarom gewoonlijk gebruikt om diffuse oppervlakken te modelleren, aangezien het fysiek aannemelijk is, ook al zijn er in de echte wereld geen zuivere diffuse materialen. Deze BRDF wordt Lambertiaanse reflectie genoemd omdat deze de cosinuswet van Lambert gehoorzaamt.

Lambertiaanse reflectie wordt vaak gebruikt als model voor diffuse reflectie. Deze techniek zorgt ervoor dat alle gesloten polygonen (zoals een driehoek in een 3D-gaas) het licht in alle richtingen gelijk reflecteren. De diffusiecoëfficiënt wordt berekend uit de hoek tussen de normale vector en de lichtvector.

f_Lambertian = max( 0.0, dot( N, L )

waarbij N de normale vector van het oppervlak is en L de vector naar de lichtbron is.

Hoe het werkt

Over het algemeen is het puntproduct van 2 vectoren gelijk aan de cosinus van de hoek tussen de 2 vectoren vermenigvuldigd met de grootte (lengte) van beide vectoren.

dot( A, B ) == length( A ) * length( B ) * cos( angle_A_B ) 

Hieruit volgt dat het puntproduct van 2 eenheidsvectoren gelijk is aan de cosinus van de hoek tussen de 2 vectoren, omdat de lengte van een eenheidsvector 1 is.

uA = normalize( A )
uB = normalize( B )
cos( angle_A_B ) == dot( uA, uB )

voer hier de afbeeldingsbeschrijving in

Als we kijken naar de cos (x) -functie tussen de hoeken -90 ° en 90 °, dan kunnen we zien dat het een maximum van 1 heeft onder een hoek van 0 ° en het daalt naar 0 onder de hoeken van 90 ° en -90 °.

voer hier de afbeeldingsbeschrijving in

Dit gedrag is precies wat we willen voor het reflectiemodel. Wanneer de nromale vetor van het oppervlak en de richting naar de lichtbron in dezelfde richting zijn (de hoek tussen is 0 °), dan willen we een maximale reflectie. Als de vectoren daarentegen een orthonormalized zijn (de hoek ertussen is 90 °), dan willen we een minimum aan reflectie en willen we een soepele en continue functionele werking tussen de twee grenzen van 0 ° en 90 °.

voer hier de afbeeldingsbeschrijving in

Als het licht wordt berekend per hoekpunt, wordt de reflectie berekend voor elke hoek van de primitieve. Tussen de primitieven zijn de reflecties interpoleren volgens zijn barycentrische coördinaten. Zie de resulterende reflecties op een bolvormig oppervlak:

voer hier de afbeeldingsbeschrijving in

Ok, dus om te beginnen met onze fragment-shader, hebben we vier ingangen nodig.

  • Vertex-normalen (moet in buffer staan en worden gespecificeerd door vertex-kenmerkaanwijzers)
  • Fragmentpositie (moet worden uitgevoerd van hoekpuntshader naar frag shader)
  • Lichtbronpositie (uniform)
  • Lichte kleur (uniform)
in vec3 normal;
in vec3 fragPos;
    
out vec3 finalColor;
    
uniform vec3 lightColor;
uniform vec3 lightPos;
uniform vec3 objColor;

In het hoofdgedeelte moeten we wat wiskunde doen. Het hele concept van diffuse verlichting is gebaseerd op de hoek tussen de normale en de lichtrichting. Hoe groter de hoek, hoe minder licht er is tot 90 ° waar er helemaal geen licht is.

Voordat we kunnen beginnen met het berekenen van de hoeveelheid licht, hebben we de lichtrichtingsvector nodig. Dit kan worden opgehaald door eenvoudigweg de lichtpositie af te trekken van de fragmentpositie die een vector retourneert van de lichtpositie die naar de fragmentpositie wijst.

vec3 lightDir = lightPos-fragPos;

Ga ook door en normaliseer de normal en lightDir vectoren zodat ze even lang zijn om mee te werken.

normal  = normalize(normal);
lightDir = normalize(lightDir);

Nu we onze vectoren hebben, kunnen we het verschil ertussen berekenen. Om dit te doen, gaan we de dot-productfunctie gebruiken. Kortom, dit neemt 2 vectoren en retourneert de cos () van de gevormde hoek. Dit is perfect omdat het bij 90 graden 0 oplevert en bij 0 graden 1. Het resultaat is dat wanneer het licht direct op het object wijst, het volledig wordt verlicht en vice versa.

float diff = dot(normal, lightDir);

Er is nog een ding dat we moeten doen met het berekende aantal, we moeten ervoor zorgen dat het altijd positief is. Als je erover nadenkt, heeft een negatief getal geen zin in context, omdat dat betekent dat het licht achter het gezicht is. We kunnen een if-instructie gebruiken, of we kunnen de functie max() die het maximum van twee ingangen retourneert.

diff = max(diff, 0.0);

Als dat klaar is, zijn we nu klaar om de uiteindelijke uitvoerkleur voor het fragment te berekenen.

vec3 diffuse = diff * lightColor;
finalColor = diffuse * objColor;

Het zou er zo uit moeten zien: voer hier de afbeeldingsbeschrijving in

Spiegelende verlichting:

Werk in progres, kom later terug.

gecombineerde

Werk in uitvoering, kom later terug.

De onderstaande code en afbeelding tonen deze drie verlichtingsconcepten gecombineerd.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow