PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Verständnisprobleme mit 3D/Shader Programmierung


Gast
2007-05-27, 18:22:49
Hi Leute. Irgendwie fehlen mir echt essentielle Grundlagen für das Zeug was ich vorhab, und ich hätte wenn möglich gerne etwas Unterstützung, da mir der einschlägige Freundeskreis einfach fehlt.

Wenn das hier gegen irgendwelche Regeln verstösst oder nur RTFM Antworten hervorruft, könnt ihr Moderatoren natürlich gerne den Beitrag löschen, ich schiesse quasi ins Blaue.

Ich suche sowohl Dokumentation als auch Austausch, daher erschien mir das hier ganz passend.


So, also:
Im weitesten Sinne geht es um 3D Programmierung. Vor allem Shader.
Ich denke die Mathematischen Grundlagen habe ich soweit, es gibt allerdings riesige Verständnislücken.

Ich werfe einfach mal ein paar Vermutungen in den Raum, könnt ihr mir sagen, ob ich recht habe, wo ich nicht recht habe, und was ihr an Links und Literatur Empfehlungen im Petto habt?

Die Funktionsweise von Shadern
Für jeden Vertex eines Modelles werden dessen Shader durchlaufen.
Zuerst der

Vertex Shader
Diese können die Position eines Vertex verändern.
Sie ändern die Position des Vertex (und logischerweise die der an diesem anliegenden Faces) und geben diese weiter, an den

Pixel Shader
Dieser kann die Faces die an dem Vertex anliegen verändern, aber nicht die Geometrie, sondern lediglich die Farbe.
D. h. einen Pixel schwarz einfärben und einen anderen grün, einen anderen in der Farbe die die Textur des Objektes an diesem Punkt hat.
Ob der Pixel Shader jetzt echt jeden Pixel einzeln abläuft, oder einmal pro Vertex und dann alle Färbungen vornimmt, wüsste ich noch gerne.



Soviel dazu - hab ich Recht? Wenn nicht, bin ich sehr dankbar dafür, wenn jemand nen guten Link dazu hat wo der Ablauf erklärt wird, ich hab diese Schlüsse quasi in der Praxis beim dummen Rumprobieren gezogen.


Jetzt etwas, was ich konkret nicht verstehe:

Ich spiele derzeit mit der Testversion der Vision Engine von Trinigy.
Der Standard-Vertex Shader (der nichts tut) sieht so aus:


float4x4 matWVP : register(c8);

struct VS_IN
{
float4 ObjPos : POSITION;
float2 UV0 : TEXCOORD0;
};

struct VS_OUT
{
float4 ProjPos : POSITION;
float2 UV0 : TEXCOORD0;
};

VS_OUT vs_main( VS_IN In )
{
VS_OUT Out;
Out.ProjPos = mul( matWVP, In.ObjPos );
Out.UV0 = In.UV0;
return Out;
}


Das Register c8 ist bei der Engine die "Model View Projection Matrix", "Row 0".

Okay, also die erste Zeile der Model View Projection Matrix.
Huch? Es ist doch ne 4x4 Matrix. Nicht nur eine Zeile.

Was ist die Model View Projection Matrix? Höre ich oft, also nicht nur in Bezug auf diese Engine, aber ich finde nirgends eine Erklärung.


Gut, jetzt geht dieser Shader her, und setzt die ProjPos (wohl die Position des Vertex wenn der Shader mit ihm fertig ist) auf das Ergebnis der Matrixmultiplikation von eben dieser ersten Spalte und der ObjPos (Wohl die Position des Vertex) des Vertex Shaders.

Huch? Tut mir leid, aber ich verstehe es nicht. Kann mir jemand das evtl. erklären? Oder ist das zu Engine Spezifisch, und sollte ich mit was allgemeinerem Anfangen?

Jetzt zum Pixel Shader (der nichts macht):

sampler2D BaseTexture : register(s0);

struct PS_IN
{
float2 UV0 : TEXCOORD0;
};

float4 ps_main( PS_IN In ) : COLOR
{
float4 tc = tex2D(BaseTexture, In.UV0);
return tc * float4(0.2,0.2,0.8,1.0);
}


Sieht erstmal nicht nach nichts für mich aus. Der schnappt sich die neue Texturkoordinate die der Vertex Shader liefert. Damit macht er dann ein tex2D mit dem Register s0 (scheint die Farbe der Textur an diesem Pixel/Texel zu sein).
Was tex2D macht ist mir nach MSDN lookup immernoch absolut schleierhaft.

Ich kan nur vermuten, dass es den Texel entsprechend der Translation durch den Vertex Shader verschiebt.

Okay, jetzt wird dieser Vektor noch mit dem Vektor 0.2, 0.2, 0.8, 1.0 multipliziert. Warum? Seit wann kann man zwei Vektoren multiplizieren? Ist das "*" skalare Multiplikation?

Also:

(a, b, c) * (d, e, f) = (a*d, b*e, c*f)
oder wie?

Aber davon abgesehen dass ich die Arithmetik nicht verstehe, verstehe ich auch nicht, was damit erreicht wird.



So, bin für eure Hilfe ganz dankbar, und ist kein Problem wenn ihrs einfach löscht weils zu n00b ist oder so.


Weissheit und Hilfe erhoffend,
Gast

Coda
2007-05-27, 18:50:04
Der Vertexshader verändert nicht nur die Position der Eckpunkte sondern gibt auch Werte aus, die dann perspektivisch korrekt über das Dreieck interpoliert werden und die Inputs für den Pixelshader liefern. Der Pixelshader wird dann in der Tat für jeden Pixel durchlaufen.

Das Register c8 ist bei der Engine die "Model View Projection Matrix", "Row 0".
Es werden c8-c11 belegt.

Was ist die Model View Projection Matrix? Höre ich oft, also nicht nur in Bezug auf diese Engine, aber ich finde nirgends eine Erklärung.
Du solltest dir die mathematischen Grundlagen evtl. doch nochmal anschauen.

MVP = Projection * View * Model
Modelmatrix: Transformiert das Model von seinem lokalen ins globale Koordinatensystem
Viewmatrix: Transformiert die gesamte Szene (anhand der Kameraposition normalerweise)
Projection: Sollte klar sein.

Huch? Tut mir leid, aber ich verstehe es nicht. Kann mir jemand das evtl. erklären? Oder ist das zu Engine Spezifisch, und sollte ich mit was allgemeinerem Anfangen?
Das solltest du allgemein verstehen. Das ist die ganz normale Positionstransformation per Matrixmultiplikation.

Sieht erstmal nicht nach nichts für mich aus. Der schnappt sich die neue Texturkoordinate die der Vertex Shader liefert. Damit macht er dann ein tex2D mit dem Register s0 (scheint die Farbe der Textur an diesem Pixel/Texel zu sein).
s0 ist der Sampler an den in diesem Fall die Textur gebunden wird. Es gibt s0-s15.

Was tex2D macht ist mir nach MSDN lookup immernoch absolut schleierhaft.
Den Wert der Textur an der Stelle In.UV0 (UV0 ist die Texturkoordinate die über das Dreieck interpoliert wurde, siehe oben) aus der Textur die an Sampler s0 gebunden ist lesen. Kurz: Stinknormales Texturmapping.

Okay, jetzt wird dieser Vektor noch mit dem Vektor 0.2, 0.2, 0.8, 1.0 multipliziert. Warum? Seit wann kann man zwei Vektoren multiplizieren? Ist das "*" skalare Multiplikation?

Also:

(a, b, c) * (d, e, f) = (a*d, b*e, c*f)
oder wie?
Ja, ist korrekt. Er verändert damit die Farbe des resultierenden Pixel ins Blaue.

Neomi
2007-05-27, 19:49:44
Also dann mal der Reihe nach...


Die grobe Funktionsweise der Pipeline:

1. Die Engine setzt Renderstates (zur Konfiguration der nicht programmierbaren Teile der Pipeline), Shader (die programmierbaren Teile), Shaderkonstanten (beliebige Werte, auf die in den Shadern zugrgriffen wird, z.B. Matrizen) und Ressourcen (Vertex- und Indexbuffer, Rendertargets, Texturen). Dann wird ein Drawcall ausgeführt, also eine Anweisung zum Zeichnen. Im weiteren Verlauf beschränke ich mich mal auf Dreiecke, da das die am häufigsten genutzte Primitivart ist, es gibt aber auch noch andere.

2. Der Input Assembler greift auf die gesetzten Vertexbuffer (im simpelsten Fall nur einer, es können aber auch mehrere parallel sein) und (meistens, geht aber auch ohne) den aktuell gesetzten Indexbuffer (nur einer) zu. Er holt sich aus dem Indexbuffer mehrere Indices und holt sich die dazu passenden Vertexdaten aus den Vertexbuffern.

3. Zu jedem Vertex wird einmal der Vertexshader durchlaufen, bei kurz zuvor schonmal indizierten Vertices (durch den Indexbuffer, Wiederverwendung spart also Speicherplatz und Rechenzeit) kann auch das Ergebnis des vorigen Durchlaufs ohne Neuberechnung nochmal verwendet werden. Der Vertexshader berechnet nur einen einzigen Vertex, er weiß nichts von den anderen Vertices des aktuellen Dreiecks. Der Vertexshader berechnet grundsätzlich die Position des Eckpunktes im Screenspace (dazu später mehr) und optional dazu beliebige andere Werte (z.B. Texturkoordinaten), die später über das Dreieck interpoliert werden.

4. Jetzt wäre der Geometryshader dran. Der ist aber eh erst ab D3D10 verfügbar und außerdem rein optional, deshalb lasse ich den mal weg.

5. Im Trianglesetup werden die einzelnen fertig berechneten Vertices jedes Dreiecks wieder zusammengefügt bzw. als Ganzes betrachtet. Das Dreieck wird je nach Renderstates evtl. verworfen (Backfaceculling) oder geclippt (Entfernung von Teilen, die außerhalb des zu rendernden Rechtecks liegen).

6. Im Rasterizer werden alle Pixel bestimmt, die vom Dreieck überdeckt werden. Die vom Vertexshader zusätzlich ausgespuckten Werte werden interpoliert, zusätzlich zu der Position inklusive deren Z-Wert (für den Tiefentest nützlich).

7. Für jeden betroffenen Pixel wird einmal der Pixelshader ausgeführt. Er bekommt die für die jeweilige Pixelposition passend interpolierten Werte, die in deinem Beispiel Texturkoordinaten sind. Der Pixelshader kann auf diese Daten, auf Texturen (müssen erst an sogenannte Sampler gebunden werden, die dann vom Shader angesprochen werden) und auf Konstanten zugreifen. Das Ergebnis ( der Pixelshader kann allerdings vorzeitig verwerfen, dann wird für diesen Pixel die Berechnung abgebrochen) ist ein einzelner (in der Regel, MRTs sind für dich erstmal irrelevant) Farbwert mit den vier Komponenten Rot, Grün, Blau und Alpha. Der Pixelshader kann auch einen neuen (selbst berechneten) Z-Wert ausspucken, aber das ist für dich erstmal nicht wirklich interessant.

8. Dieser Farbwert und der vom Rasterizer interpolierte Z-Wert werden an die ROPs weitergegeben. Diese testen erstmal den Z-Wert (optional, meistens aktiv) gegen den Z-Buffer und verwerfen evtl. den Pixel, damit keine Farbwerte von bereits fertigen Dreiecken überschrieben werden, die näher an der Kamera sind. Der Test wird in der Regel vorgezogen, wenn der Pixelshader keinen eigenen Z-Wert ausspuckt. Optional (aber erstmal unwichtig) wird noch ein Stenciltest durchgeführt. Wenn der Z-Test und optional der Stenciltest bestanden wurden, wird je nach Konfiguration der ROPs der Farbwert an die entsprechende Pixelposition im Rendertarget geschrieben (oder im Falle von Alphablending mit dem darin befindlichen Farbwert verrechnet) und der Z-Wert im Z-Buffer aktualisiert (optional natürlich, ziemlich häufiges Wort heute).


Model-View-Projection Matrix:

Model Matrix (auch World Matrix):
Die Positionen in den einzelnen Vertices sind für zu zeichnende Objekte im Objectspace, also relativ zum Mittelpunkt des Objektes bei neutraler Ausrichtung und Skalierung. Ein Vektor (ObjPos in deinem Beispiel) mit den Komponenten x, y und z wird intern um w mit dem Wert 1 ergänzt, falls nicht explizit vorhanden, deshalb brauchst du einen float4 als Input. Die vierte Komponente ist für die Transformation wichtig, etwas anderes als eine implizit angehängte 1 ist eher selten. Jedenfalls sorgt diese Matrix dafür, daß ein Objekt mehrfach an beliebigen Positionen und mit beliebiger Ausrichtung und Skalierung gezeichnet werden kann, obwohl die Geometrie dafür nur einmal vorhanden ist. Vertices werden quasi von Objectspace in Worldspace gewandelt. Statische Levelgeometrie ist meistens schon in Worldspace vorhanden, die Matrix dazu ist daher die Identity-Matrix. Identity ist neutral, läßt einen Vertex also unangetastet, ähnlich der neutralen Multiplikation eines Skalars mit 1.

View Matrix:
Samtliche Worldspace-Vertices werden in Viewspace bzw. Cameraspace transformiert. Da die Kamera kein Objekt ist, das gezeichnet wird, muß sämtliche Geometrie relativ zur Kamera positioniert werden. Wenn du also die Kamera einen Meter vorwärts bewegen willst, bewegst du in der virtuellen Realität tatsächlich die ganze Welt einen meter auf dich zu.

Projection Matrix:
Das ist die komplizierteste der drei Komponenten, aber auch nicht schwierig. Die (perspektivische) Projektion sorgt dafür, daß Objekte weiter hinten kleiner dargestellt werden. Weitwinkel- und Teleobjektive bei einer echten Kamera ändern auch nur die Projektion. Erst durch diese Matrix bekommt ein normaler Vertex eine w-Komponente, die anders als 1 ist. Diese Komponente wird hinterher für die Verkleinerung nach hinten und zur Perspektivenkorrektur bei interpolierten Werten genutzt.

Durch Matrixmultiplikation werden diese drei Matrizen zu einer einzigen zusammengefaßt, die alles in einem Rutsch erledigt. Warum (am Beispiel mit Skalaren) 10000 Werte erst mit 2, dann mit 3 und zuletzt mit 4 multiplizieren, wenn man stattdessen jeden der Werte direkt mit 24 multiplizieren kann? Es spart einfach Zeit.

Das Register c8 markiert in deinem Vertexshader nur den Start der Matrix im Konstantenarray, für den float4x4 werden daher c8, c9, c10 und c11 genutzt. Dabei steht in c8 aus Effizienzgründen nicht die erste Zeile der Matrix, sondern die erste Spalte, weil sich dadurch die Multiplikation des Vektors mit der Matrix auf 4x dp4 beschränken läßt.


Pixelshader:

In deinem Pixelshader wird erst die Basistextur gesampelt (Register s0 ist der Sampler mit dem Index 0, keine Konstante), und zwar mit den Texturkoordinaten, die im Vertexbuffer enthalten sind, im Vertexshader unverändert weitergereicht werden im vom Rasterizer interpoliert werden. Das Ergebnis ist ein Vektor mit 4 Komponenten, RGBA. Ein Vektor muß keine Position sein, es ist einfach nur ein Wert mit mehreren Komponenten. In diesem Fall ist es eben eine Farbe. Die Konstante "float4(0.2,0.2,0.8,1.0)" ist auch eine Farbe, die wie du vermutest komponentenweise mit dem Texturwert multipliziert wird. Rot und Grün werden jeweils auf 20 % abgedunkelt, Blau auf 80 % und Alpha bleibt dank Multiplikation mit 1 unverändert (100 %).


Edit:
1 Stunde zu spät? Wie schnell doch die Zeit vergeht, wenn man nur nebenher tippt...

Gast
2007-05-27, 21:36:55
VIELEN Dank Coda und Neomi, war echt eine meiner guten Ideen, das ganze im 3DCenter Forum zu posten ;)

Das beantwortet meine akuten Fragen, allerdings muss ich echt noch mehr lernen. Könnt ihr mir zu dem Thema evtl. Literatur oder (fast besser) eine Seite empfehlen?

Ich hab schon die ein oder andere Einführung in die Materie durchgearbeitet, aber wenns ans Eingemacht geht, finde ich online irgendwie nichts mehr.

Ausserdem bin ich mit dem Denken noch nicht flüssig, es ist noch anstrengend, über die verschiebung oder ganz allgemein transformation von einem Objekt im dreidimensionalen Raum durch eine Matrix Multiplikation nachzudenken, auch wenn es nicht mehr unmöglich ist.

Erstmal werde ich aber eure Antworten so lange bearbeiten, bis ich es mit eigenen Worten erklären könnte, vielen Dank nochmal für eure Zeit ;)

Neomi
2007-05-27, 22:28:56
Das beantwortet meine akuten Fragen, allerdings muss ich echt noch mehr lernen. Könnt ihr mir zu dem Thema evtl. Literatur oder (fast besser) eine Seite empfehlen?

Die Dokumentation im DirectX SDK ist da recht ausführlich. Hier gibt es das SDK:
http://www.microsoft.com/downloads/details.aspx?familyid=86cf7fa2-e953-475c-abde-f016e4f7b61a&displaylang=en

Wenn du das SDK installiert oder einfach nur entpackt hast, findest du im Unterordner "Documentation\DirectX9" die Datei "directx_sdk.chm". Im Inhaltsverzeichnis findest du unter "DirectX Graphics\Direct3D 9\Programming Guide\Getting Started" einiges an Informationen.

Coda
2007-05-27, 22:43:56
Ich würd mich übrigens mal anmelden. Ich bin immer abgeneigt Gästen zu antworten, weil ich mich da ziemlich schnell verarscht fühle.

Xmas
2007-05-28, 00:29:42
Ausserdem bin ich mit dem Denken noch nicht flüssig, es ist noch anstrengend, über die verschiebung oder ganz allgemein transformation von einem Objekt im dreidimensionalen Raum durch eine Matrix Multiplikation nachzudenken, auch wenn es nicht mehr unmöglich ist.
Falls du sehr visuell orientiert denkst und du dir Vektoren gut als Pfeile im Raum vorstellen kannst, hilft vielleicht Folgendes:
Ein dreidimensionales Koordinatensystem wird ja durch 3 Achsen und die Position des Ursprungs definiert. Um jetzt ein Objekt zu transformieren kannst du einfach das Koordinatensystem neu definieren. Eine Transformationsmatrix besteht lediglich aus 4 Vektoren, die (Projektion mal außen vor gelassen) die Lage/Skalierung der 3 Achsen sowie die Position des Ursprungs im neuen Koordinatensystem relativ zum alten beschreiben.

Dabei steht in c8 aus Effizienzgründen nicht die erste Zeile der Matrix, sondern die erste Spalte, weil sich dadurch die Multiplikation des Vektors mit der Matrix auf 4x dp4 beschränken läßt.
Ob nun 4x dp4 oder mul + 3x mad dürfte von der Effizienz keinen Unterschied machen. Es ist einfach eine Konvention.

Neomi
2007-05-28, 00:55:22
Ob nun 4x dp4 oder mul + 3x mad dürfte von der Effizienz keinen Unterschied machen. Es ist einfach eine Konvention.

Hoppla, stimmt. Da hatte ich wohl float4x3 im Sinn, was ja auch recht häufig vorkommt.

Gast
2007-05-28, 21:08:24
@Xmas:
Danke für die Erklärung, ich verstehe es wirklich besser, wenn ich es "sehe" ;)

@Coda:
Ist bei mir ne Gewohnheitssache, als Gast zu posten. Bin seit ein paar Jahren in dem Board hier und immer als Gast, da ich mich nur bei der Hilfe aufhalte, sah ich bisher noch keinen Grund zum Registrieren.
Werd ich aber demnächst mal machen, verstehe auch irgendwo, dass du dir da veräppelt vorkommst.

Da ich jetzt endlich die Model View Projection Matrix verstanden habe, kann ich in neue Tiefen vorstossen.

Neue Fragen:

- Wie kommt es dass Online zu wichtigen und essentiellen Sachen nichts zu finden ist? Könnt ihr mir ein Buch empfehlen?

- Was ist/macht ein Texture Sampler?

- In HLSL gibt es verschiedene "Datentypen" für die Kommunikation zwischen den Shadern. "COLOR", "TEXCOORD" und so weiter. Kennt ihr irgendwo eine Erklärung dazu?

- Sehe ich folgendes richtig: (?)
Ein Model hat eine Texturkoordinate pro Face. Das ist der Punkt, an dem die obere Linke Ecke der Textur angelegt wird.

- Hat jemand von euch Jabber oder ICQ, und evtl. auch Zeit/Lust von mir hin und wieder angeschrieben zu werden? Es kommt halt öfters vor dass ich kleine Fragen hab, und wäre toll, ma jemanden der 3D Programmierung macht zu kennen.

futlib
2007-05-28, 21:17:17
So, hab mich jetzt mal registriert. Also wer es okay fände, mich in ICQ oder Jabber (/Google Talk) zu haben, kann mir gerne eine PN schreiben.

Coda
2007-05-28, 23:54:04
- Wie kommt es dass Online zu wichtigen und essentiellen Sachen nichts zu finden ist?
Weil es ziemlich viel Arbeit ist solche Dinge aufzuschreiben. Die beste Quelle ist wirklich die Direct3D-Dokumentation. Da steht eigentlich alles, man muss nur manchmal etwas tiefer graben.

- Was ist/macht ein Texture Sampler?
Das ist die virtuelle Einheit die aus Texturen ließt und filtert. Wenn du in einem Shader aus einer Textur lesen willst musst du diese an einen Sampler binden. Du kannst pro Sampler auch festlegen wie gefiltert werden soll (Pointsampling, bilinear, trilinear, anisotropisch)

- In HLSL gibt es verschiedene "Datentypen" für die Kommunikation zwischen den Shadern. "COLOR", "TEXCOORD" und so weiter. Kennt ihr irgendwo eine Erklärung dazu?
Direct3D-Dokumentation.

- Sehe ich folgendes richtig: (?)
Ein Model hat eine Texturkoordinate pro Face. Das ist der Punkt, an dem die obere Linke Ecke der Textur angelegt wird.
Nein. Ein Model hat normal eine Texturkoordinate pro Vertex, die dann über das Dreieck interpoliert werden.

Normal sage ich weil man auch Vertexdaten ohne Texturkoordinaten haben kann, was aber eher unüblich ist.

Neomi
2007-05-29, 00:18:29
- Wie kommt es dass Online zu wichtigen und essentiellen Sachen nichts zu finden ist? Könnt ihr mir ein Buch empfehlen?

"GPU Gems" behandelt einige interessante Themen, aber da geht es eher um konkrete und ergebnisorientierte Anwendungen, nicht um die Funktionsweise der API. Mit einem kleinen Vergleich ist das leichter zu erklären: ein solches Buch für Fahrtechniken würde dir z.B. erklären, wie man perfekt driftet. Wo sich Lenkrad, Handbremse und Pedale befinden und das Wissen darüber, was sie machen, würde so ein Buch aber vorraussetzen. Die essentiellen Dinge findest du alle in der DirectX Doku, Bücher dazu kenne ich nicht.

- Was ist/macht ein Texture Sampler?

Ein Shader hat keinen direkten Zugriff auf den Speicher, sondern muß über einen Vermittler darauf zugreifen. Da es mit Vergleichen einfacher wird, hier mal wieder eins: stell dir vor, du hast 200 DVDs im Schrank und willst eine abspielen. Du brauchst also ein Laufwerk, in das du die DVD einlegen mußt, damit der PC sie abspielen kann. Genauso mußt du eine Textur (entspricht der DVD) an einen Sampler (das Laufwerk) binden, damit der Shader darauf zugreifen kann. Der Sampler bekommt vom Shader Texturkoordinaten, liest die aktuell an ihn gebundene Textur an der passenden Stelle aus und liefert ein gefiltertes (z.B. bilinear interpoliertes) Ergebnis zurück.

- In HLSL gibt es verschiedene "Datentypen" für die Kommunikation zwischen den Shadern. "COLOR", "TEXCOORD" und so weiter. Kennt ihr irgendwo eine Erklärung dazu?

Das sind keine Datentypen, sondern Semantik. Darüber wird dem Fixed Function Teil der Hardware einfach nur mitgeteilt, was wohin gehört. Der Input im Vertexshader, der mit TEXCOORD2 benannt ist, wird dort aus dem Vertexbuffer geholt, wo die Vertexdeklaration sagt, daß sich TEXCOORD2 befindet. Denke darüber einfach als eine Art Etikett, so daß z.B. der Vertexshaderoutput in der richtigen Veriablen als Pixelshaderinput ankommt. Es kommt nicht darauf an, wie eine Semantik heißt, sondern darauf, daß sie bei der Übergabe zwischen verschiedenen Einheiten gleich lautet. Zumindest bei den programmierbaren Einheiten, die festverdrahteten Einheiten brauchen noch eine feste Semantik (z.B. wandert COLOR bzw. COLOR0 als Pixelshaderoutput in das Rendertarget bzw. erstmal in die ROPs). In D3D10 sind es deshalb auch nicht mehr vordefinierte Semantiken für frei verwendbare Daten (TEXCOORD z.B. ist beliebig verwendbar), sondern kurze Textstrings. Dann kommt das, was du im Vertexshaderoutput als "blub12" benennst, interpoliert in dem Pixelshaderinput an, den du als "blub12" benannt hast.

- Sehe ich folgendes richtig: (?)
Ein Model hat eine Texturkoordinate pro Face. Das ist der Punkt, an dem die obere Linke Ecke der Textur angelegt wird.

Abhängig von der Vertexdeklaration hat ein Vertex keine bis mehrere Sets an Texturkoordinaten, wobei das einfach nur frei verwendbare Zahlen sind, die dann eben zum samplen einer Textur genutzt werden. Ein Face bzw. Dreieck hat keine Texturkoordinaten, sondern indiziert einfach nur Vertices und hat dementsprechend alle Vertexdaten pro Eckpunkt.

Bei Direct3D ist die obere linke Ecke der Textur an den Koordinaten [0.0;0.0], unten rechts ist [1.0;1.0]. Entsprechend ist oben rechts [1.0;0.0] und unten links [0.0;1.0]. Das gilt aber nur für Direct3D, in OpenGL ist [0.0;0.0] die untere linke und [1.0;1.0] die obere rechte Ecke.

futlib
2007-05-29, 10:50:28
Ok danke ihr beiden, habt mir wieder geholfen ;)

Ich habe mir das Buch "GPU Gems" gekauft, da ich mich für Shader Programmierung interessiere, und die Bewertungen gut aussehen.

Da mir aber noch so viele Grundlagen fehlen, werde ich erstmal wirklich die DirectX Doku durcharbeiten. Bisher hatte ich noch nicht den Ansporn, das DirectX SDK zu installieren (ist ja bei der Vision dabei), aber jetzt mach ichs mal für die Doku. Hoffe nur, dass die besser als die MSDN ist.

Coda
2007-05-29, 11:04:27
Es ist die gleiche wie in der MSDN. Und es ist mit Abstand die beste API-Dokumentation die ich kenne.

del_4901
2007-05-29, 15:28:55
Naja Ob GPU-Gems, so das clevere Buch war, wenn man 0 von der Pipeline versteht. Im "CG-Tutorial" ist die Pipeline für einen Änfänger gut erklärt ... aber der Rest ist Dreck. Dann doch lieber das OpenGL Orange Book ... aber das würde ich mir auch nur mit dem Redbook zusammen genehmigen wollen.

futlib
2007-05-29, 15:58:20
Hm hm... das OpenGL Red Book sieht echt gut aus. Zumal ich mich mehr für OpenGL als für DirectX interessiere. (DirectX eigentlich jetzt nur grad wegen der Vision).

Und man kanns online lesen - danke AlphaTier ;)

Edit:
Also auch hier stelle ich fest, dass ich an Stelle einer grundlegenden Einführung lieber ein Nachschlagewerk hätte.
Ich treffe auf das Wort Clipping: Zack, will wissen was das ist.

(Ok, ich weiss was Clipping ist, war nur ein Beispiel)

Quasi ein Wikipedia für 3D Grafikprogrammierung... oder auch in Buchform... kennt ihr sowas?

Gast
2007-05-29, 17:57:35
Ich denke, jetzt bin ich soweit, die Pipeline noch mal (grob) in eigenen Worten zu erklären, Feedback wäre toll ;)

Eure Erklärungen haben sich ja um den Fall gedreht, in dem Shader verwendet werden. Um das besser zu verstehen, versuche ich die Schritte mit einzubeziehen, die bei der Verwendung von Shadern wegfallen.


Geometrie
1: Der Vertex kommt an, in Object Space (Relativ zum Mittelpunkt des Objektes zu dem er gehört positioniert)

Dann geht es entweder zu T&L (a) oder zum Vertex Shader (b)

2a: T&L, die Transformations und Lightning engine.
Diese hat unter anderem folgende Aufgaben:
- Die Vertexposition von Object in World Space umrechen. Daraufhin in View Space (relativ zur Kamera)
- Berechnen, ob diesen Vertex eine Lichtquelle trifft. Dies ist z. B. nicht der Fall, wenn er von einem anderen Objekt verdeckt wird.
- Jetzt wird von View Space in Projection Space (ein zweidimensionales Koordinatensystem, zur Anzeige auf dem Monitor) umgerechnet.
Hierbei wird unter anderem dafür gesorgt, dass weiter entfernte Objekte verkleinert werden, um eine perspektivisch korrekte zweidimensionale Illusion von 3D zu erzeugen.

2b: Der Vertex Shader
Der Vertex Shader kann jetzt hier andere Sachen machen, aber zumindestens die Umrechnung von Object Space in Projection Space sollte er machen, da der Vertex sonst nicht korrekt positioniert wird.

Was ich bei 2a und 2b nicht verstehe:
- Ich sehe hier generell nicht den Zusammenhang zu den Faces.
Ich habe einen Vertex - schön und gut. Aber wie kann ich mich jetzt um Lichtberechnungen kümmern? Dafür brauche ich doch die Faces, der Vertex alleine ist relativ Nutzlos, wenn man nicht weiss, mit welchen anderen zusammen er ein Face bildet.
- Warum wird vor dem Clipping in Projection Space umgerechnet?
Bei Punkt 3 sind ja auch noch andere Sachen, die, wie ich schätze, View oder World Space erfordern.

3: Clipping
- Hier werden Dreiecke die auf dem Bildschirm nicht mehr sichtbar sind abgeschnitten, so dass nur gerendert wird, was der User auch wirklich sieht.
- Hier ist noch mehr, das verstehe ich allerdings nicht ganz, da es sich meiner Meinung nach auf World oder View Space bezieht, nicht auf Projection Space, in dem wir ja jetzt sind.

Jetzt geht es entweder mit dem Multitexturing (a) oder dem Pixel Shader (b) weiter.

Texturierung und Blending
4a: Multitexturing
- Hier werden die Texturen der Objekte an die entsprechenden Flächen gebunden. Falls vorhanden werden auch Lightmaps geladen.

4b: Pixel Shader
- Dieser sollte zumindestens die Textur auf die Pixel klatschen.

Rasterization

5: Alpha und Stencil
- Hier wird die Helligkeit der einzelnen Pixel bestimmt, sprich
die Lichtintensität an verschiedenen Pixeln des Bildes wird umgesetzt (auch mit Hilfe der Maps).
- Mit einer Stencil Map kann man zum Beispiel Schlagschatten erstellen. Es ist eine Map die ein Objekt haben kann, die angibt, welche Schattenform es wirft, um die Berechnung zu vermeiden (stimmt das?)

6: Der fertig gerenderte Frame geht an den Frame Buffer, fertig zur Anzeige.


Tja, gerade beim Schreiben hab ich gemerkt, dass eine Ausführliche Darstellung der Rendering Pipeline bei mir noch fehlt. Ausserdem begreife ich die Grenze zwischen Hardware und Software dort nicht richtig: Was passiert wo?

Vor allen dingen kommt mir die Aufteilung jetzt nicht mehr schlüssig vor. Der Pixel Shader bestimmt die Alphawerte - warum also in Schritt 5 nochmal?

Und dann noch oben mein Verständnisproblem mit der Umrechnung zwischen den Spaces...

Davon abgesehen bin ich ganz zufrieden, was könnt ihr dazu sagen/korrigieren?

2b und 4b entsprechen so ziemlich genau dem, was der Standard Shader in meinem ersten Beitrag macht, es kommt mir also, wenigstens was diese Schritte angeht, in sich schlüssig vor ;)

del_4901
2007-05-29, 18:15:29
So:

Man kann nur berechnen, ob eine Lichtquelle einem Face zugewand oder abgewand ist. Was im Schatten liegt wird anders berechnet!

Mithilfe der Vertexnormalen, kann man rausfinden ob ein Vertex einer Lichtquelle zugewand ist oder nicht.

Das Triangle-Setup macht aus den Vertices für den Rasterizer die Polygone. An der Stelle kann man nicht in die Pipeline eingreifen.

Jetzt kommt der Rasterizer (zwischen Vertex-[VS] und Fragment-Shader[PS])
Da werden aus den Vertexdaten Fragmente gemacht (kann man sich als Pixel + Tiefe vorstellen) Der Rasterizer interpoliert die Vertexdaten linear auf dem Dreieck.

Jetzt habe ich Fragmente und kann im Fragmentshader deren Daten ändern, so kann man z.B mit einem sampler und (bereits interpolierten)texturkoordinaten den genauen wert innerhalb einer Textur bestimmen.

Jetzt habe ich ein fertiges Fragment, das ich mit dem Framebuffer abgleichen möchte. Das machen die RasterOperations (ROPs). Dazu gehört Stencil AlphaTest Z-Test etc. Hier wird eigendlich nichts an den Daten des Fragments verändert, sondern nur bestimmt, ob es in den Framebuffer kommt oder nicht. Beim Blending können hier die beiden Werte (einmal das Fragment und einmal der Pixel im Framebuffer) miteinander verrechnet werden.

Dann ist Pipelineende, wenn ich nochwas machen muss, dann muss ich mir ne Möglichkeit überlegen, wie ich das ganze nochmal durchwürge.


Ich würde dir empfehlen solange keine Shader und oder T&L anzufassen, bis du die Fixed-Function Pipline im Griff hast, sonst kommt eh nur Müll bei raus.

futlib
2007-05-29, 19:32:33
Mithilfe der Vertexnormalen, kann man rausfinden ob ein Vertex einer Lichtquelle zugewand ist oder nicht.


Moment. Wie können denn Vertices eine Normale haben?
Eine Normale ist doch die Senkrechte von einer Fläche?


Jetzt habe ich ein fertiges Fragment, das ich mit dem Framebuffer abgleichen möchte. Das machen die RasterOperations (ROPs). Dazu gehört Stencil AlphaTest Z-Test etc. Hier wird eigendlich nichts an den Daten des Fragments verändert, sondern nur bestimmt, ob es in den Framebuffer kommt oder nicht. Beim Blending können hier die beiden Werte (einmal das Fragment und einmal der Pixel im Framebuffer) miteinander verrechnet werden.


Ah, jetzt hab ich den Teil endlich begriffen, danke ;)


Ich würde dir empfehlen solange keine Shader und oder T&L anzufassen, bis du die Fixed-Function Pipline im Griff hast, sonst kommt eh nur Müll bei raus.

Glaub ich. Aber... T&L anfassen? Denke das wäre fest auf der Grafikkarte?


Stimmt denn mein Ablauf generell, oder ist quasi "alles falsch"?

Was die Rendering Pipeline (fixed function und programmable) angeht, so finde ich fast bei jedem Link eine völlig andere... das ist seltsam.

Coda
2007-05-29, 20:23:00
Moment. Wie können denn Vertices eine Normale haben?
Sie haben sie einfach. Entweder sie ist die interpolierte von den Faces die den Vertex enthalten (Gouraud Shading) oder der Vertex wird dupliziert und es ist die gleiche wie von dem Face (Flat Shading) wenn du jeweils das Lichtam Eckpunkt berechnest. Das lässt sich auch beliebig mischen.

Neomi
2007-05-30, 00:12:44
Moment. Wie können denn Vertices eine Normale haben?
Eine Normale ist doch die Senkrechte von einer Fläche?

Ein Vertex kann eine Normale auf die gleiche Art haben, wie eine Position oder Texturkoordinaten: die Applikation stellt diese Daten im Vertexbuffer zur Verfügung.

Die Normale, die für einen Vertex hinterlegt wird, ist in der Regel der Durchschnitt der Normalen aller Dreiecke, die diesen Vertex benutzen, und zwar gewichtet nach Fläche der Dreiecke, Winkel des Dreiecks in der relevanten Ecke, einer Mischung daraus oder was auch immer für das jeweilige Modell am besten paßt.

Du solltest wirklich erstmal die genannten Abschnitte in der Doku im DirectX SDK durchaubeiten, da werden all deine Fragen (zumindest alle, die du bisher gestellt hast) ausführlich beantwortet. Auch wenn du nachher lieber OpenGL nutzt, die Prinzipien sind gleich und helfen dir dort genauso. Wenn du irgendwas in der Doku nicht verstehst, wird dir hier bestimmt geholfen. Wenn du aber nur fragst, weil es bequemer ist, als in der Doku nachzuschlagen, dann sinkt zumindest meine Motivation zu ausführlichen Antworten sehr schnell.

futlib
2007-05-30, 13:52:58
Ok, verstehe ich.

Bei OpenGL sieht die rendering pipeline VÖLLIG anders aus, daher werd ich die mal lernen wie sie bei directx is.

Nur noch eine Frage... gibt es die Direct3D Doku auch online? Weil der Hauptgrund warum ich nie Microsoft Spezifisch geprogged hab ist, dass mit der Grauenhaften Suche und Bedienung der Online MSDN nichts anfangen kann.

Ist die, die man dabei hat wenn man das DXSDK installiert besser? Sonst muss ichs ja nicht installern, ist ja bei der Vision dabei.

Expandable@work
2007-05-30, 15:53:18
Ok, verstehe ich.

Bei OpenGL sieht die rendering pipeline VÖLLIG anders aus, daher werd ich die mal lernen wie sie bei directx ist.

Bitte? Nö! Ist exakt die gleiche - muss sie ja sein, immerhin ist die darunterliegende Hardware gleich.

Gast
2007-05-30, 16:07:09
OpenGL (aus dem Red Book):
http://www.glprogramming.com/red/images/Image26.gif

DirectX:
Finde da online sowieso die unterschiedlichsten Grafiken die völlig anders aussehen. Siehe meine Erklärung der Pipeline weiter oben, so hab ich sie gesehen.

futlib
2007-05-30, 16:09:37
Das war ich, aus Versehen als Gast.

Die Reihenfolge und der Ablauf ist im OpenGL book ganz anders.

Die Grafiken die ich zu DirectX gesehen habe haben alle einen linearen Ablauf gezeigt.

Diese Grafik da zeigt einen paralelen Ablauf (wie bei einer Pipeline zu erwarten).
Von Display Lists hab ich in DirectX noch nicht gehört, in OpenGL dafür schon.

Sind Teile dieser grafischen Darstellungen nicht API bezogen? Oder ist alles Hardware?

Xmas
2007-05-30, 16:18:39
Ok, verstehe ich.

Bei OpenGL sieht die rendering pipeline VÖLLIG anders aus, daher werd ich die mal lernen wie sie bei directx is.
Völlig anders? Die sind bis auf ein paar Kleinigkeiten (sowie andere Begriffe für dasselbe) identisch.

Dein Bild aus dem Red Book zeigt nur den Datenfluss auf höchster Ebene und ist nicht besonders genau. Ein Pipeline-Diagramm ist größtenteils Linear, wie ein Rohr eben: an einem Ende schiebt man etwas rein, am anderen Ende kommt was raus.

Nur noch eine Frage... gibt es die Direct3D Doku auch online? Weil der Hauptgrund warum ich nie Microsoft Spezifisch geprogged hab ist, dass mit der Grauenhaften Suche und Bedienung der Online MSDN nichts anfangen kann.

Ist die, die man dabei hat wenn man das DXSDK installiert besser? Sonst muss ichs ja nicht installern, ist ja bei der Vision dabei.
Inhalt und Struktur sind praktisch identisch, nur lässt sich HTML Help besser bedienen.


Moment. Wie können denn Vertices eine Normale haben?
Eine Normale ist doch die Senkrechte von einer Fläche?
... an einem Punkt der Fläche. Stell dir die Fläche nicht als ebene Dreiecke vor, sondern als unendlich genaue gekrümmte, stetige Oberfläche. Dreiecke sind fast immer nur eine Approximation.

futlib
2007-06-01, 00:55:45
Also hab in den letzten Tagen einiges gelernt.

Die MSDN ist GRAUENVOLL. Es gibt aber nen ganz einfachen Trick wie man plötzlich sinnvolle Suchergebnisse (nicht nur Vista Werbung) kriegt: Auf Englisch Schalten :(
Jetzt ist die richtig gut, und die Erklärungen sind spitze.

Mein GPU Gems ist da. Wie erwartet ist das Verständnis für die Sachen am Anfang zwar da, aber ich bin einfach unerfahren in der Shaderprogrammierung. Ganz schön komisch ohne Kontrollstrukturen zu arbeiten.

Naja wie auch immer, ich arbeite gerade die HLSL Dokumentation Schritt für Schritt durch, dann wird das schon.

Euch allen an dieser Stelle vielen Dank ;)

Coda
2007-06-01, 02:12:05
Es gibt Kontrollstrukturen in HLSL. Deutsch kannst du dir was 3D-Programmierung angeht eh abschminken.