Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

1

10.03.2013, 14:12

HLSL; Array an Pixelshader übergeben

Hallo.
Folgendes Szenario: Ich habe ein Array in meinem Shader, welches global deklariert ist und welches von meinem Programm aus definiert wird. In bestimmten Fällen muss ich aber im Vertex-Shader nochmal ein Array-Element mit einer Matrix multiplizieren. Doch wenn ich das Ergebnis wieder in das Array schreiben will, meckert der Compiler, dass ich keine globalen Variablen verändern kann. MSDN sagt auch, dass globale Variablen immer mit const deklariert werden. Jetzt habe ich alle 32 Ergebnisse im Vertex-Shader in einem lokalen Array und möchte dieses Array dem Pixel-Shader übergeben. TEXCOORD0-TEXCOORD31 ist ja wohl Mist. Welche Möglichkeit habe ich denn nun ein Array an dem Pixel-Shader zu übergeben?

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

2

10.03.2013, 16:02

Was für ein Shadermodel verwendest du denn?
@D13_Dreinig

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

3

10.03.2013, 16:14

Vertex- sowie Pixel-Shadermodel 3.0.

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

4

10.03.2013, 19:29

In dem Fall: gar nicht. Wenn Du es nicht in die 10x 4float reinbekommst, die Du vom VertexShader zum PixelShader übergeben kannst, gibt es keinen Weg.

Du könntest das Ganze globaler angehen, indem Du in einem separaten Pass die Ergebnisse in eine Textur rausschreibst und deren Inhalt dann im nächsten Pass ausliest. Evtl. verrätst Du aber auch, was Du eigentlich vor hast, und wir finden evtl. eine bessere Lösung.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

5

16.03.2013, 14:17

Entschuldigt, dass ich nicht geantwortet habe. Schulisch ist im Moment sehr viel zu tun.
Ich will folgendes machen: Ich habe einen Blinn-Phong Shader. Ich möchte jetzt nicht mehr X Lichter mit Multipassverfahren rendern, sonder gleich alle Lichter mit in die Textur einberechnen. Ohne BumpMapping wäre das kein Problem. Da kann ich das Array von meinem Programm aus definieren. Doch mit BumpMapping muss ich das definierte Array, welches übrigens die Lichtrichtungen enthält, und die "ViewDir" noch in den Tangentenraum umrechnen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    // HLSL
    if(g_bBumpMapping)
    {
        float3 n = mul(IN.normal, (float3x3)g_WorldInverseTransposeMatrix);
        float3 t = mul(IN.tangent.xyz, (float3x3)g_WorldInverseTransposeMatrix);
        float3 b = cross(n, t) * IN.tangent.w;
        float3x3 tbnMatrix = float3x3(t.x, b.x, n.x,
                                      t.y, b.y, n.y,
                                      t.z, b.z, n.z);

        // Umrechnen
        OUT.lightDir = mul(lightDir, tbnMatrix);
        OUT.viewDir = mul(g_vCameraPos - worldPos, tbnMatrix);
    }

OUT.lightDir müsste ich mit meinem Array ersetzen. Doch ich kann nichts in das Array, da es const definiert wurde (global).
OUT.viewDir müsste ich eigentlich auch noch in ein Array schreiben, aber das kommt danach. Es ist ja das selbe Prinzip.
Im Pixelshader das Array umzurechnen, ist mir zu Performancelastig. Ich müsste dann mehrmals das selbe rechnen.

Im Pixelshader mit dem Array zu rechnen ist kein Problem. Da kann ich das Array lokal kopieren. Je nachdem welches Licht gerade berechnet werden soll.
Das ganze in eine Textur zu rendern, geht natürlich auch. Aber ich warte mal ab, ob es noch eine andere Möglichkeit gibt. Wenn nein dann mache ich das.

Grüße FSA.

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

6

16.03.2013, 15:48

Ok, das geht in die Richtung, die ich erwartet habe. Die Splitterwelten-Engine macht das genau so. Da wird per Skript ein Shader-Quelltext nach vorgegebener Lichtquellen-Liste generiert. Vom VertexShader in den PixelShader gehen Position, zumeist 1x Texturkoordinaten und 1x Vertexfarbe, evtl. noch der Vektor zur Kamera in Tangentenkoordinaten, und dann die Lichtquellen-Daten. Pro Lichtquelle brauche ich 1x Vektor zum Licht in Tangentenkoordinaten und (falls die Lichtquelle Schatten wirft) 1x ShadowMap-Texturkoordinaten. Shadermodell 3.0 bietet Position + 10 Allzweck-Interpolatoren, drei davon sind nach dieser Liste Grundverbrauch, also habe ich noch 7 für Lichtquellen. Reicht also bestenfalls für 7 Lichtquellen ohne Schatten, oder 3 mit Schatten und eine ohne.

Ab SM4.0 hast Du dann übrigens 32 davon, wenn ich die Spec richtig verstehe. Nach meinem Wissen kannst Du aber keine davon mit Arrayzugriff benutzen, der Compiler muss also *immer* zur Compile Time exakt auflösen können, welches Register Du mit welchem Zugriff meinst, sonst kompiliert Dein Shader nicht. Als Beispiel:

Quellcode

1
2
3
[unroll]
for( int a = 0; a < 5; ++a )
  output.light[a] = RechneMirDasAus();


Der Beispielcode funktioniert, weil die Schleife entrollt werden kann und damit für jeden Zugriff genau feststeht, welcher Interpolator gemeint ist. Ersetze die "5" durch eine Variable und die Schleife kann nicht entrollt werden, damit muss der Array-Zugriff tatsächlich als solcher kompiliert werden, wodurch das Ganze nicht mehr funktioniert.

Nach meinem Wissen willst Du auf DX9-Level bleiben. Damit ist bei 3 Lichtquellen Schicht im Schacht. Die Splitterwelten-Engine fängt dann einen neuen Pass an, das klappt alles schon ganz gut. Aber Dein eigentliches Problem werden dann die Massen an Shader-Varianten und das Kompilieren dieser Shader.

Alternativ-Vorschlag, falls Du noch mitliest :-) Gib in den PixelShader neben den notwendigen Daten keine Lichtvektoren, sondern die Tangentenmatrix rein. Natürlich invertiert bzw. transponiert dann, logisch, damit es eine "Tangentenkoordinaten zu Weltkoordinaten"-Transformation ist. Damit kannst Du dann im PixelShader Position, Normale und alles, was Du sonst noch so brauchst, in Weltkoordinaten transformieren und kannst die komplette Lichtmathematik in Weltkoordinaten machen. Die Lichtdaten kannst Du dann einfach in Konstanten-Registern ablegen, der Bedarf an Interpolator-Registern ist immer konstant. Die Splitterwelten-Engine braucht pro Licht maximal 7x float4 an Daten, ShaderModell 3.0 garantiert Dir im PixelShader 224 Konstantenregister, also kriegst Du damit bis zu 32 Lichter mit Schatten und allem hin.

Erkaufen tust Du Dir diese Freiheit mit einem höheren Mathe-Aufwand pro Lichtquelle und Pixel, was aber bei reiner Mathematik heutzutage nicht mehr so dramatisch ist - Texturzugriffe sind immernoch mit Abstand das Teuerste. Und Du brauchst flexible PixelShader - eine Shadercode-Erzeugung per Skript wie bei den Splitterwelten geht da definitiv nicht, weil Du bei 32 Lichtquellen eine absurde Menge an Permutationen kriegst. Evtl. würde hier sogar Dynamic Branching helfen, obwohl das selbst auf aktuellster Hardware eigentlich sonst ein Performance-Killer ist. Denk Dir was aus! Und halte mich auf dem Laufenden, wie Du es gelöst hast :D
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

7

17.03.2013, 19:32

Ich werde da mal etwas ausarbeiten. Doch im Moment habe ich keine Zeit. Ich melde mich nochmal.
Danke für deine Tipps ;)

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

8

30.03.2013, 16:22

So jetzt habe ich mal etwas ausgearbeitet. Das Problem ist: Ich habe nicht bedacht, dass ich für das Array noch die Vertexposition brauche.

C-/C++-Quelltext

1
2
3
float3 worldPos = mul(float4(IN.position, 1.0f), g_WorldMatrix).xyz;
float3 viewDir = g_vCameraPos - worldPos;
float3 lightDir = (g_Light[0].pos - worldPos) / g_Light[0].radius;

Wie man sieht, brauche ich für ViewDir und LightDir die Variable WorldPos. Wenn ich jetzt jedoch nach meine Vorhaben ViewDir und LightDir im Programm berechnen lassen möchte, komme ich ja nicht an die einzelnen Vertexpositionen heran. Es wäre wohl sehr ineffizient, wenn ich die Vertexpositionen einzeln auslese aus meinem VertexBuffer, oder? Hat jemand eine andere Idee?

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »FSA« (30.03.2013, 16:42)


Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

9

30.03.2013, 19:19

Ich verstehe die Frage nicht. Was willst Du in welches Array tun? Wo willst Du das berechnen, was da steht? Im VertexShader hast Du die Position. In den PixelShader kannst Du die einfach reinreichen. Schlauer wäre es aber, die TangentSpace-Matrix zu transponieren oder invertieren, die World Matrix mit dranzuketten und die Gesamttransformation dann in den PixelShader zu reichen. Das ist dann eine 4x3-Matrix, mit der Du im PixelShader die Normale in den World Space transformieren kannst, ein viertes Eingaberegister trägt die interpolierte Vertex-Position im World Space, und Du hast alle Daten da, die Du für eine komplette Beleuchtung im PixelShader brauchst. Die Kameraposition kannst Du ja als Konstante reinreichen, oder alternativ den ZurKamera-Vektor in Weltkoordinaten mit reinreichen.
Häuptling von Dreamworlds. Baut aktuell an nichts konkretem, weil das Vollzeitangestelltenverhältnis ihn fest im Griff hat. Baut daneben nur noch sehr selten an der Open Asset Import Library mit.

FSA

Community-Fossil

  • »FSA« ist der Autor dieses Themas
  • Private Nachricht senden

10

30.03.2013, 19:27

Ich meine, wie ich die Variable WorldPos in meinem Programm (nicht im Shader) berechnen kann. Im Shader geht es wie folgt:

C-/C++-Quelltext

1
float3 worldPos = mul(float4(IN.position, 1.0f), g_WorldMatrix).xyz;

Diesen Wert brauche ich, für weitere Berechnungen. Ich weiß jedoch gerade nicht, wie ich für jeden Vertex die Berechnung in meinem Programm durchführen kann. Oder besser gesagt am besten ausführen soll.

Zitat

Der RCCSWU (RandomCamelCaseSomtimesWithUndersquare) Stil bricht auch mal mit den veraltet strukturierten Denkmustern und erlaubt dem Entwickler seine Kreativität zu entfalten.

Werbeanzeige