Oktober 2014

Volume 29 Number 10

Dieser Artikel wurde maschinell übersetzt.

DirectX-Faktor - Pixel-Shader und die Reflexion des Lichtes

Charles Petzold | Oktober 2014

Charles PetzoldWenn du, Photonen sehen könntest... Na ja, Sie können sehen, dass Photonen, oder zumindest einige von ihnen. Photonen sind die Teilchen, aus denen elektromagnetische Strahlung besteht, und das Auge ist empfindlich auf Photonen mit Wellenlängen im Bereich des sichtbaren Lichts.

Aber Sie können Photonen nicht sehen, wie sie überall zu fliegen. Das wäre sicherlich interessant. Photonen gehen manchmal durch Objekte; Manchmal sind sie absorbiert; Manchmal sind sie reflektiert; aber oft ist es eine Kombination all dieser Effekte. Einige der Photonen, die von Objekten schließlich reflektiert erreichen der Augen, dass jedes Objekt seine besondere Farbe und Textur.

Für extrem hochwertige 3D Grafik kann eine Technik namens Ray-Tracing tatsächlich eine Simulation der Pfade von diesen unzähligen Photonen imitieren die Effekte von Reflexion und Schatten zeichnen. Aber viel einfacheren Techniken stehen für herkömmliche Bedürfnisse. Dies ist häufig der Fall, wenn Direct3D verwenden — oder, in meinem Fall schreiben Sie benutzerdefinierte Effekte in Direct2D, die 3D nutzen.

Wiederverwendung des Effekts

Wie Sie in früheren Ausgaben dieser Spalte gesehen haben, ist ein Direct2D-Effekt im Grunde ein Wrapper für Code, der auf der GPU ausgeführt. Solcher Code ist bekannt als ein Shader und die wichtigsten sind der Vertex-Shader und der Pixel-Shader. Der Code in jedem Shaders ist bei dem video von der Anzeige aufgerufen. Der Vertex-Shader nennt für jede der drei Vertices im einzelnen Dreiecke, aus denen die grafische Objekte, die durch den Effekt angezeigt, während der Pixel-Shader für jedes Pixel innerhalb dieser Dreiecke aufgerufen wird.

Natürlich wird der Pixel-Shader bezeichnet viel häufiger als die Vertex-Shader, so es Sinn macht, so viel wie möglich-Verarbeitung in der Vertex-Shader, anstatt der Pixel-Shader zu halten. Dies ist nicht immer möglich, jedoch, und wenn diese Shader verwenden, um die Lichtreflexion zu simulieren, ist es in der Regel das Gleichgewicht und die Interaktion zwischen zwei Shaders, die regelt die Komplexität und Flexibilität die Schattierung.

In der August-Ausgabe des Magazins stellte ich einen Direct2D-Effekt genannt RotatingTriangleEffect, die einen Vertexpuffer bestehend aus Buchstaben und Farben gebaut und erlaubt Sie standard Modell und Kamera Transformationen auf die Vertices anwenden. Ich habe diesen Effekt für drei Dreiecke zu drehen. Das ist keine große Datenmenge. Drei Dreiecke beinhalten nur insgesamt neun Eckpunkte, und zur Zeit erwähnt, die der gleiche Effekt könnte für einen viel größeren Vertexpuffer verwendet werden.

Wir probieren Sie es aus: Das Programm zum herunterladen (msdn.microsoft.com/magazine/msdnmag1014) für diese Spalte ShadedCircularText heißt, und es wird RotatingTriangleEffect, ohne eine einzige Änderung verwendet.

Das ShadedCircularText-Programm gibt für das Problem, dass ich begann die Erforschung der tesselierten 2D Textanzeige in drei Dimensionen in diesem Jahr. Der Konstruktor der Klasse ShadedCircularTextRenderer in einer Schriftartdatei lädt, erstellt eine Schriftart aus und ruft dann GetGlyphRunOutline um eine Pfadgeometrie der Charakter Konturen zu erhalten. Diese Pfadgeometrie ist dann im Mosaikprozess berücksichtigt, mit einer Klasse, die ich erstellt namens InterrogableTessellationSink, die die tatsächliche Dreiecke ansammelt.

Nach der Registrierung RotatingTriangleEffect, ShadedCircularText­Renderer erstellt ein ID2D1Effect-Objekt, das auf der Grundlage dieser Effekt. Er wandelt dann die Dreiecke des tesselierte Textes in Eckpunkte auf der Oberfläche einer Kugel, im Grunde Textumbruch um den Äquator und biegen sie in Richtung zu den Pfosten. Die Farbe für jeden Vertex basiert auf einen Farbton, abgeleitet von der X-Koordinate der ursprüngliche Text Geometrie. Dadurch entsteht einen Regenbogen-Effekt, und Abbildung 1 zeigt das Ergebnis.

3D-Text Rainbow von ShadedCircularText
Abbildung 1 3D-Text Rainbow von ShadedCircularText

Wie Sie sehen können, schmückt ein kleines Menü oben. Das Programm umfasst eigentlich drei Direct2D Zusatzeffekte, die eher traditionellen Schattierung Modelle implementieren. Alle von ihnen verwenden die gleichen Punkte, die gleichen Transformationen und die gleichen Animationen, so wechseln Sie zwischen ihnen, den Unterschied zu sehen. Die Unterschiede betreffen nur die Farbschattierung der Dreiecke.

Die unteren rechten Ecke hat eine Anzeige der Leistung in Frames pro Sekunde, aber Sie werden feststellen, dass nichts in diesem Programm dazu führt, dass zu viel unter 60 außer wenn etwas anderes vor sich geht.

Gouraud-Shading

Da Photonen überall um uns herum fliegen, springen sie oft aus Stickstoff und Sauerstoff-Moleküle in der Luft. Sogar an einem bedeckten Tag mit kein direktes Sonnenlicht gibt es noch viel Umgebungslicht. Umgebungslicht tendenziell Objekte sehr einheitlich zu beleuchten.

Vielleicht haben Sie ein Objekt, das ein grünliches blau, mit einem RGB-Wert (0, 0.5, 1.0). Wenn das Umgebungslicht ein Viertel ist voller Intensität weiß, können Sie einen RGB-Wert für das Licht (0,25, 0,25, 0,25). Die wahrgenommene Farbe dieses Objekts ist das Produkt der roten, grünen und blauen Komponenten diese Zahlen oder (0, 0,125, 0,25). Es ist immer noch ein grünliches blau, aber viel dunkler.

Aber einfache 3D-Szenen von Umgebungslicht Leben nicht allein. Im wirklichen Leben haben Objekte normalerweise viel Farbvariation auf ihren Oberflächen, so dass selbst wenn sie gleichmäßig beleuchtet sind, haben die Objekte noch sichtbare Texturen. Aber in einer einfachen 3D Szene, sieht ein grünlich-blau-Objekt nur durch Umgebungslicht beleuchtet nur wie eine undifferenzierte Platte von einheitlicher Farbe.

Aus diesem Grund profitieren einfache 3D-Szenen enorm einige gerichtetes Licht. Es ist anzunehmen, dass dieses Licht aus weiter Ferne (wie die Sonne), kommt am einfachsten damit die Richtung des Lichts nur einen einzigen Vektor ist, der für die gesamte Szene gilt. Ist nur eine Lichtquelle, wird in der Regel davon ausgegangen, kommen aus über der linken Schulter des Betrachters, also vielleicht der Vektor (1, -1, -1) in einem rechten Koordinatensystem ist. Diese gerichtete Licht hat auch eine Farbe, vielleicht (0,75, 0,75, 0,75), so dass zusammen mit dem Umgebungslicht (0,25, 0,25, 0,25), maximale Beleuchtung manchmal erreicht ist.

Gerichtetes Licht, das eine Oberfläche reflektiert hängt der Winkel, den das Licht mit der Oberfläche macht. (Dies ist ein Konzept, das in meinem Mai 2014 erforscht DirectX Faktor Spalte.) Die maximale Reflexion tritt auf, wenn das gerichtete Licht ist senkrecht zur Oberfläche reflektierte Licht sinkt auf NULL, wenn das Licht tangential an der Oberfläche oder kommen von irgendwo hinter der Oberfläche.

Die Lambert-Kosinus-Gesetz – benannt nach dem Mathematiker und Physiker Johann Heinrich Lambert (1728 – 1777) — sagt, dass der Anteil der von der Oberfläche reflektierte Licht ist der negative Kosinus des Winkels zwischen der Richtung des Lichts, und die Richtung eines Vektors senkrecht zur Oberfläche, die eine Oberfläche normal aufgerufen wird. Wenn diese zwei Vektoren normalisiert werden — das heißt, wenn sie eine Größenordnung von 1 haben — dieser Kosinus des Winkels zwischen den beiden Vektoren ist dasselbe wie das Skalarprodukt der Vektoren.

Beispielsweise wenn das Licht auf eine bestimmte Fläche in einem 45-Grad-Winkel zuschlägt, der Kosinus ist ca. 0,7, so vermehren, dass durch die Direc­Tional leichte Farbe (0,75, 0,75 0,75) und die Farbe des Objekts (0, 0.5, 1.0), die Farbe des Objekts von diffusem Licht (0, 0.26, 0.53) abgeleitet werden. Fügen Sie hinzu, die auf die Farbe vom Umgebungslicht.

Denken Sie daran, die Objekte in 3D Szenen gebogen sind nicht tatsächlich gebogen. Alles, was in der Szene besteht aus flachen Dreiecken. Wenn die Beleuchtung jedes Dreiecks auf einer Oberfläche normal senkrecht zum Dreieck selbst basiert, wird jedes Dreieck eine andere einheitliche Farbe haben. Dies ist gut für die platonischen Körper wie in meinem Artikel vom Mai 2014 angezeigt, aber nicht so gut für gekrümmte Flächen. Für gekrümmte Flächen möchten Sie die Farben der Dreiecke miteinander mischen.

Dies bedeutet, dass es notwendig für jedes Dreieck, eine abgestufte Farbe statt einer einheitlichen Farbe zu besitzen. Die Farbe von diffusem Licht kann nicht auf eine einzelne Fläche normal, dass das Dreieck beruhen. Jeder Eckpunkt des Dreiecks sollte stattdessen eine andere Farbe, basierend auf der Fläche senkrecht zum dieser Ecke haben. Diese Vertex Farben können dann über die Pixel des Dreiecks interpoliert werden. Angrenzender Dreiecke Mischung dann mit einander zu eine gekrümmte Fläche ähneln.

Diese Art von Schattierung ist eine Erfindung französischer Informatiker Henri Gouraud (b. 1944) in einem Papier 1971 veröffentlicht und gilt daher als Gouraud-Shading.

Gouraud-Shading ist die zweite Option implementiert in das ShadedCircularText-Programm. Der Effekt selbst heißt GouraudShadingEffect, und es erfordert einen Vertexpuffer mit etwas mehr Daten:

struct PositionNormalColorVertex
{
  DirectX::XMFLOAT3 position;
  DirectX::XMFLOAT3 normal;
  DirectX::XMFLOAT3 color;
  DirectX::XMFLOAT3 backColor;
};

Interessant ist, da der Text tatsächlich eingeschlossen wird auf eine Kugel auf den Punkt (0, 0, 0) zentriert der Fläche senkrecht zum jeden Vertex ist dasselbe wie die Position, aber normalisiert, damit eine Größenordnung von 1 haben. Der Effekt ermöglicht einzigartige Farben für jeden Vertex, aber in diesem Programm jeden Vertex wird die gleiche Farbe, die ist (0, 0.5, 1) und die gleiche BackColor (0.5, 0.5, 0.5), die ist die Farbe verwendet werden, wenn die Rückseite einer Fläche steht der Betrachter vor.

Die GouraudShadingEffect erfordert auch mehr Effekteigenschaften. Es muss die Umgebungsfarbe Licht, gerichtetes Licht Farbe und Vektorrichtung gerichtetes Licht festgelegt werden. Der GouraudShadingEffect überträgt alle diese Werte auf einen größeren Konstante Puffer für den Vertexshader. Der Vertex-Shader selbst erscheint Abbildung 2.

Abbildung 2 der Vertex-Shader für Gouraud-Shading

// Per-vertex data input to the vertex shader
struct VertexShaderInput
{
  float3 position : MESH_POSITION;
  float3 normal : NORMAL;
  float3 color : COLOR0;
  float3 backColor : COLOR1;
};
// Per-vertex data output from the vertex shader
struct VertexShaderOutput
{
  float4 clipSpaceOutput : SV_POSITION;
  float4 sceneSpaceOutput : SCENE_POSITION;
  float3 color : COLOR0;
};
// Constant buffer provided by effect.
cbuffer VertexShaderConstantBuffer : register(b1)
{
  float4x4 modelMatrix;
  float4x4 viewMatrix;
  float4x4 projectionMatrix;
  float4 ambientLight;
  float4 directionalLight;
  float4 lightDirection;
};
// Called for each vertex.
VertexShaderOutput main(VertexShaderInput input)
{
  // Output structure
  VertexShaderOutput output;
  // Get the input vertex, and include a W coordinate
  float4 pos = float4(input.position.xyz, 1.0f);
  // Pass through the resultant scene space output value
  //  (not necessary -- can be removed from both shaders)
  output.sceneSpaceOutput = pos;
  // Apply transforms to that vertex
  pos = mul(pos, modelMatrix);
  pos = mul(pos, viewMatrix);
  pos = mul(pos, projectionMatrix);
  // The result is clip space output
  output.clipSpaceOutput = pos;
  // Apply model transform to normal
  float4 normal = float4(input.normal, 0);
  normal = mul(normal, modelMatrix);
  // Find angle between light and normal
  float3 lightDir = normalize(lightDirection.xyz);
  float cosine = -dot(normal.xyz, lightDir);
  cosine = max(cosine, 0);
  // Apply view transform to normal
  normal = mul(normal, viewMatrix);
  // Check if normal pointing at viewer
  if (normal.z > 0)
  {
    output.color = (ambientLight.xyz + cosine *
                    directionalLight.xyz) * input.color;
  }
  else
  {
    output.color = input.backColor;
  }
  return output;
}

Der Pixel-Shader ist dasselbe wie für die RotatingTriangleEffect und zeigt Abbildung 3. Die Interpolation der Vertex Farben über das gesamte Dreieck tritt hinter den Kulissen zwischen der Vertex-Shader und der Pixel-Shader, so dass der Pixel-Shader übergibt einfach die Farbe an angezeigt werden.

Abbildung 3 der Pixel-Shader für Gouraud-Shading

// Per-pixel data input to the pixel shader
struct PixelShaderInput
{
  float4 clipSpaceOutput : SV_POSITION;
  float4 sceneSpaceOutput : SCENE_POSITION;
  float3 color : COLOR0;
};
// Called for each pixel
float4 main(PixelShaderInput input) : SV_TARGET
{
  // Simply return color with opacity of 1
  return float4(input.color, 1);
}

Das Ergebnis wird angezeigt, Abbildung 4, diesmal auf Windows Phone 8.1 anstatt Windows 8.1. Die ShadedCircularText-Lösung wurde im Visual Studio mit der neuen Universal App-Vorlage erstellt und kann für beide Plattformen kompiliert werden. Der gesamte Code wird zwischen den beiden Plattformen außer die App und DirectXPage Klassen geteilt. Der Unterschied in den Layouts der beiden Programme schlägt Warum, verschiedene Seitendefinitionen oft eine gute Idee ist, auch wenn die Funktionalität des Programms grundsätzlich dasselbe ist.

die Anzeige von der Gouraud Shading-Modell
Abbildung 4 die Anzeige von der Gouraud Shading-Modell

Wie Sie sehen können, ist die Figur leichter in ihrem oberen linken, deutlich die Auswirkungen von diffusem Licht und hilft in der Illusion ein abgerundetes Erscheinungsbild an die Oberfläche.

Der Phong-Verbesserungen

Gouraud-Shading ist eine bewährte Technik, aber es hat einen fundamentalen Fehler: In Gouraud-Shading ist der Betrag von diffusem Licht spiegelt sich in der Mitte eines Dreiecks einen interpolierten Wert an die Scheitelpunkte reflektierte Licht. An den Eckpunkten reflektierte Licht basiert auf den Kosinus des Winkels zwischen der Richtung des Lichtes und der Flächennormalen an diesen Eckpunkten.

Aber das Licht spiegelt sich in der Mitte des Dreiecks sollte wirklich auf der Grundlage der Fläche senkrecht zu diesem Zeitpunkt. Mit anderen Worten, sollte nicht die Farben auf dem Dreieck interpoliert werden; stattdessen die Flächennormalen sollte über das Dreieck Fläche interpoliert werden, und das reflektierte Licht für jedes Pixel auf der Grundlage dieser Normal berechnet.

Geben Sie Vietnamesisch-US-amerikanischer Informatiker Pui Tuong Phong (1942 – 1975), der im Alter von 32 Jahren an Leukämie starb. In seiner Doktorarbeit 1973 beschrieb Phong einen etwas andere Schattierung-Algorithmus. Anstatt Vertex Farben über das Dreieck interpoliert werden, werden die Vertex-normalen über das Dreieck interpoliert, und dann reflektierte Licht wird von den berechnet.

Im praktischen Sinne erfordert Phong Shading die Berechnung des reflektierten Lichts aus der Vertex-Shader in der Pixel-Shader, zusammen mit Abschnitt des Konstanten Puffers gewidmet den Job verschoben werden. Dies erhöht die Menge der pro-Pixel-Verarbeitung immens, aber glücklicherweise, es geschieht auf der GPU, wo Sie hoffen, dass es scheinen wird nicht viel Unterschied machen.

Der Vertex-Shader für das Phong-Shading-Modell erscheint Abbildung 5. Einige der Eingabedaten — wie die Farbe und Hintergrundfarbe — werden einfach auf die Pixel-Shader übergeben. Aber es ist immer noch nützlich, die Transformationen anzuwenden. Die globale Transformation und beide Kamera-Transformationen müssen auf die Positionen angewendet werden, während zwei senkrechten auch berechnet werden – mit nur die Modell-Transformation für das reflektierte Licht, und eine weitere mit der Ansichtstransformation zu bestimmen, ob eine Oberfläche hin oder vom Betrachter steht.

Abbildung 5 des Vertex-Shaders für die Phong Shading-Modell

// Per-vertex data input to the vertex shader
struct VertexShaderInput
{
  float3 position : MESH_POSITION;
  float3 normal : NORMAL;
  float3 color : COLOR0;
  float3 backColor : COLOR1;
};
// Per-vertex data output from the vertex shader
struct VertexShaderOutput
{
  float4 clipSpaceOutput : SV_POSITION;
  float4 sceneSpaceOutput : SCENE_POSITION;
  float3 normalModel : NORMAL0;
  float3 normalView : NORMAL1;
  float3 color : COLOR0;
  float3 backColor : COLOR1;
};
// Constant buffer provided by effect
cbuffer VertexShaderConstantBuffer : register(b1)
{
  float4x4 modelMatrix;
  float4x4 viewMatrix;
  float4x4 projectionMatrix;
};
// Called for each vertex
VertexShaderOutput main(VertexShaderInput input)
{
  // Output structure
  VertexShaderOutput output;
  // Get the input vertex, and include a W coordinate
  float4 pos = float4(input.position.xyz, 1.0f);
  // Pass through the resultant scene space output value
  // (not necessary — can be removed from both shaders)
  output.sceneSpaceOutput = pos;
  // Apply transforms to that vertex
  pos = mul(pos, modelMatrix);
  pos = mul(pos, viewMatrix);
  pos = mul(pos, projectionMatrix);
  // The result is clip space output
  output.clipSpaceOutput = pos;
  // Apply model transform to normal
  float4 normal = float4(input.normal, 0);
  normal = mul(normal, modelMatrix);
  output.normalModel = normal.xyz;
  // Apply view transform to normal
  normal = mul(normal, viewMatrix);
  output.normalView = normal.xyz;
  // Transfer colors
  output.color = input.color;
  output.backColor = input.backColor;
  return output;
}

Wie die Ausgabe der Vertex-Shader in der Pixel-Shader eingegeben wird, werden diese normalen über das Dreieck Fläche interpoliert. Der Pixel-Shader kann dann abschließend die Aufgabe berechnen das reflektierte Licht, wie in Abbildung 6.

Abbildung 6 des Pixel-Shaders für die Phong Shading-Modell

// Per-pixel data input to the pixel shader
struct PixelShaderInput
{
  float4 clipSpaceOutput : SV_POSITION;
  float4 sceneSpaceOutput : SCENE_POSITION;
  float3 normalModel : NORMAL0;
  float3 normalView : NORMAL1;
  float3 color : COLOR0;
  float3 backColor : COLOR1;
};
// Constant buffer provided by effect
cbuffer PixelShaderConstantBuffer : register(b0)
{
  float4 ambientLight;
  float4 directionalLight;
  float4 lightDirection;
};
// Called for each pixel
float4 main(PixelShaderInput input) : SV_TARGET
{
  // Find angle between light and normal
  float3 lightDir = normalize(lightDirection.xyz);
  float cosine = -dot(input.normalModel, lightDir);
  cosine = max(cosine, 0);
  float3 color;
  // Check if normal pointing at viewer
  if (input.normalView.z > 0)
  {
    color = (ambientLight.xyz + cosine *
      directionalLight.xyz) * input.color;
  }
  else
  {
    color = input.backColor;
  }
  // Return color with opacity of 1
  return float4(color, 1);
}

Jedoch werde ich nicht Sie zeigen einen Screenshot des Ergebnisses. Es ist ziemlich genau optisch identisch mit der Gouraud-Shading. Gouraud-Shading ist wirklich eine gute Annäherung.

Glanzlichter

Die wirkliche Bedeutung des Phong Shading ist, dass es andere Funktionen ermöglicht, die auf eine genauere Flächennormalen beruhen.

Bisher haben Sie in diesem Artikel Schattierung gesehen, die für diffuse Oberflächen geeignet ist. Dies sind die Flächen, die sind eher rau und stumpf und das tendenziell XY Licht reflektiert ihre Oberflächen.

Eine Oberfläche, die etwas Glänzendes ist reflektieren das Licht ein wenig unterschiedlich. Wenn eine Fläche geneigt wird konnte nur so, gerichtetes Licht abprallen und gehen direkt auf das Auge des Betrachters. Dies wird in der Regel als helles, weißes Licht wahrgenommen, und ist bekannt als ein Glanzlicht. Kann man die eher übertriebene Wirkung in Abbildung 7. Wenn die Figur schärfere Kurven hatte, würde das weisse Licht mehr lokalisiert werden.

die Glanzlicht-Anzeige
Abbildung 7 die Glanzlicht-Anzeige

Immer diesen Effekt scheint zunächst, als ob es möglicherweise Rechenaufwand, aber es nur ein paar Zeilen Code in der Pixel-Shader ist. Diese besondere Technik entwickelte sich durch NASA Grafiken Maven Jim Blinn (b. 1949).

Wir brauchen zuerst einen Vektor die Richtung, die der Betrachter der 3D-Szene sucht angibt. Dies ist sehr einfach, da die Ansicht Kamera Transformation alle Koordinaten angepasst hat, damit der Betrachter gerade die Z-Achse sucht:

float3 viewVector = float3(0, 0, -1);

Berechnen Sie einen Vektor, der auf halbem Weg zwischen dieser Ansicht-Vektor und die Lichtrichtung ist:

float3 halfway = -normalize(viewVector + lightDirection.xyz);

Beachten Sie die negativen Vorzeichen. Dadurch wird den Vektor in die entgegengesetzte Richtung zeigen — auf halbem Weg zwischen der Lichtquelle und dem Betrachter.

Wenn ein bestimmtes Dreieck eine Fläche senkrecht enthält, die genau mit dieser halb Vektor entspricht, bedeutet dies, dass Licht von der Oberfläche direkt in das Auge des Betrachters Prellen ist. Dadurch maximale specular highlighting.

Geringerem Hervorhebung resultiert aus ungleich Winkel zwischen der halbwegs Vektor und der Fläche senkrecht. Dies ist eine weitere Anwendung für den Kosinus zwischen den zwei Vektoren, die das gleiche wie das Skalarprodukt ist, wenn die beiden Vektoren normalisiert werden:

float dotProduct = max(0.0f, dot(input.normalView, halfway));

Dieser Wert Skalarprodukt reicht von 1 für maximale Spiegelung Hervorhebung der Winkel zwischen zwei Vektoren 0, 0 für keine Lichtreflexe Hervorhebung der auftritt, wenn die beiden Vektoren senkrecht stehen.

Jedoch sollte nicht das specular highlighting sichtbar für alle Winkel zwischen 0 und 90 Grad sein. Es sollte lokalisiert werden. Es sollte nur bei sehr kleinen Winkeln zwischen diesen zwei Vektoren vorhanden sein. Sie brauchen eine Funktion, die keine Auswirkungen auf ein Skalarprodukt von 1, aber bewirkt, dass Werte kleiner als 1 zu viel geringer geworden. Dies ist die pow-Funktion:

float specularLuminance = pow(dotProduct, 20);

Diese pow-Funktion sind das Skalarprodukt für die 20. macht. Wenn das Skalarprodukt 1 ist, gibt die pow-Funktion 1 zurück. Wenn das Skalarprodukt 0,7 (die aus einem Winkel von 45 Grad zwischen den beiden Vektoren ergibt), dann die pow-Funktion 0,0008, gibt die wirksam 0 so weit wie die Beleuchtung geht. Verwenden Sie höhere Exponentenwerte, um den Effekt noch mehr lokalisiert zu machen.

Jetzt notwendig ist, dass die direktionale helle Farbe dieser Faktor multiplizieren und fügen Sie es auf die Farbe bereits berechneten von Umgebungslicht und direktionale Licht:

color += specularLuminance * directionalLight.xyz;

Das schafft einen Spritzer von weißem Licht, die Animation die Figur stellt sich.

Abschied

Und damit kommt die DirectX-Faktor-Spalte zu Ende. Dieser Sprung in DirectX ist einer der schwierigsten Jobs in meiner Karriere, aber daher auch eines der lohnendsten gewesen, und ich hoffe auf die Möglichkeit eines Tages zurück nach dieser leistungsstarken Technologie haben.


Charles Petzold ist ein langjähriger Beitrag zum MSDN Magazine und Autor von "Programming Windows, 6th Edition" (Microsoft Press, 2013), ein Buch über das Schreiben von Anwendungen für Windows 8. Seiner Website lautet charlespetzold.com.

Unser Dank gilt dem folgenden technischen Experten von Microsoft für die Durchsicht dieses Artikels: Doug Erickson

Dieses Problem stellt Charles Petzold zuletzt als regelmäßiger Kolumnist in der MSDN Magazine. Charles verlässt das Team zu Xamarin, ein führender Anbieter von Cross-Plattform-Tools nutzt anzuschließen die Microsoft .NET Framework. Charles ist seit Jahrzehnten mit MSDN Magazine und ist Autor von zahlreichen regelmäßigen Spalten, einschließlich Fundamente, UI Grenz- und DirectX-Faktor. Wir wünschen ihm auch auf seine neuen Aufgaben.