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

Phili

unregistriert

1

01.08.2006, 16:23

Shader in HLSL auch ohne D3DX

Ich bin jetzt hier zwar nicht unbedingt der Pro, aber wir wollten ja ne Tutorial-Sektion hier machen, da will ich als gutes Vorbild vorangehen .
Für alle Anfänger, die gerne Shader in ihren Programmen verwenden würden, ist dieses Tutorial. Es ist sehr einfach gehalten und sollte für jeden verständlich sein.
Dieses Tutorial ist keine Anleitung zum schreiben von Shadern-dafür gibts im web allemal genug!

Ok, nach diesem kleinen Vorwort wollen wir dann mal loslegen. Ich denk mal jeder, der sich mal bei google Informiert hat weiß, dass es tausende von Tutorials im Internet gibt, die beschreiben, wozu Shader sind, wie toll sie sind, wie man sie schreibt... Aber wenn es heißt: "Wie implentiere ich Shader", dann heißts nur "wir benutzen die Funktionen von D3DX". Ich persönlich finde, D3DX ist eine Ballast, auch wenn es in manchen bereichen, wie z.B. Texturen zugegebenermaßen recht nützlich ist. Aber bei Shadern braucht man nun wirklich kein D3DX.
Übrigens: Ich benutze ich diesem Tutorial jetzt einen VertexShader. Einen PixelShader benutzt man absolut genau so(nur halt mit „Pixel“ statt „Vertex“).

Also wollen wir erstmal den Shader selbst in das Programm laden.
Es kann eigentlich kaum einfacher sein:
Wir erstellen ne Klasse:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
class PH3DVertexShaderBuffer 
{ 
public: 
    IDirect3DVertexShader9 *HardBuffer; 
    char SoftBuffer[10000]; 
    void Laden(char *filename); 
    void Erstellen(IDirect3DDevice9 *D3DDev); 
    void Darstellen(IDirect3DDevice9 *D3DDev); 
};

Dann will ich die Klasse mal ein bisschen erklären:
-IDirect3DVertexShader *HardBuffer
Das wird unsere Schnittstelle zu dem Shader. Über die können wir ihn dann unter Direct3D ansprechen.
-char SoftBuffer[10000]
Da kommt der Shader rein, wenn wir ihn aus der Textur laden. Sozusagn ein Zwischenspeicher, bevor wir ihn in das Interface reinzwängen.
-void Laden(…)
Mit dieser Funktion werden wir dann die Daten des Shaders aus der Datei in unserer SoftBuffer reinschaufeln.
-void Erstellen (…)
Die Funktion wird benötigt um das VertexShader Interface zu erstellen und mit den Daten zu füllen. In dieser Funktion kommt zum ersten mal wirklich D3D ins Spiel.

C-/C++-Quelltext

1
2
3
4
5
6
void PH3DVertexShaderBuffer::Laden(char *filename) 
{ 
    ifstream ifs(filename); 
    ifs.read(SoftBuffer, 10000);
    ifs.close();
}

Es sollte klar ersichtlich sein, was passiert: das File wird geöffnet. Dann wird der Shader in den SoftBuffer geladen und am Ende wird die Datei wieder ordnungsgemäß geschlossen.

Dann kommt die "Erstellen"-Funktion:

C-/C++-Quelltext

1
2
3
4
void PH3DVertexShaderBuffer::Erstellen(IDirect3DDevice9 *D3DDev) 
{ 
    D3DDev->CreateVertexShader((DWORD*)SoftBuffer, &HardBuffer); 
}

Auch diese Funktion sollte soweit selbsterklärend sein. Es wird eben mit Hilfe der Device der HardBuffer erstellt und gefüllt.



C-/C++-Quelltext

1
2
3
4
void PH3DVertexShaderBuffer::Darstellen(IDirect3DDevice9 *D3DDev) 
{ 
    D3DDev->SetVertexShader(HardBuffer); 
}

Was soll ich da wieder erklären? Es wird halt der VertexShader gesetzt.

Ihr glaubt mir nicht, dass es so einfach ist? Doch, das ist es ! Allerdings kann man so natürlich keinen HLSL-Code einlesen. Aber keine Sorge, in den Vorzug der High Level Shader Language kommen wir trotzdem
Jetzt nehmen wir uns fxc, vsa und psa(genauere Benutzung siehe anderes Tutorial). und die daraus resultierende Datei können wir mit unserer Klasse einlesen.
Jetzt gibt es nurnoch ein Problem zu klären: Wie setzen wir z.B. Matrizen in unsere Shader ein?
Warscheinlich habt ihr ne Klasse ungefär wie diese:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
class PHMAMatrix 
{ 
public: 
    float _11; float _12; float _13; float _14; 
    float _21; float _22; float _23; float _24; 
    float _31; float _32; float _33; float _34; 
    float _41; float _42; float _43; float _44; 

    void operator=(PHMAMatrix A); 
    PHMAMatrix operator-(PHMAMatrix A); 
    PHMAMatrix operator+(PHMAMatrix A); 
    PHMAMatrix operator*(PHMAMatrix A); 
};

Und dann gibts da ne Funktion namens

C-/C++-Quelltext

1
IDirect3DDevice9::SetVertexShaderConstantF


Die erwartet 3 Parameter:
1)Die Registernummer in die das ganze reinsoll.
2)Das, was ins Register soll: ein Array von floats, im Grunde kann man einfach die Matrix in float umwandeln, wenn man schreibt (float*)&matrix, allerdings gibt es dann das Problem, dass man den Speicher nichtmehr freigeben kann, also lieber nicht direkt an die Funktion übergeben, sondern erst zwischenspeichern(gibt später nen Beispiel).
3) Das kann etwas verwirren, die Menge der zu setzenden float4. Das liegt daran, das die Speicherregister der Grafikkarte jeweils 4 float lang sind. Wenn man einzelne float-Werte setzen will, gibt man hier auch 1 an, drei floats bleiben dann(soweit ich weiß) ungenutzt.
Für ne matrix gibt man hier 4 an.
Die ganze Sache hat aber leinder nen Haken .
DX will die Matrix nämlich Spaltenweise-deswegen kann man nicht einfach die matrix übergeben, sondern muss erst ne Funktion wie

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
PHMAMatrix MatrixTranspose(PHMAMatrix A) 
{ 
    PHMAMatrix B; 
    B._11=A._11; B._12=A._21; B._13=A._31; B._14= A._41; 
    B._21=A._12; B._22=A._22; B._23=A._32; B._24= A._42; 
    B._31=A._13; B._32=A._23; B._33=A._33; B._34= A._43; 
    B._41=A._14; B._42=A._24; B._43=A._34; B._44= A._44; 
    return B; 
}

Aufrufen, um Zeilen und Spalten zu vertauschen.
Um z.B. ne Matrix in das Register c0 zu setzen schreiben wir also:

C-/C++-Quelltext

1
2
3
4
5
PHMAMatrix mat; 
mat = //was man halt will 

float *Zwischen; 
Zwischen=(float*)&MatrixTranspose(mat); 
D3DDev->SetVertexShaderConstantF(0, Zwischen, 4); 

So, und schon haben wir unseren Ersten VertexShader in Benutzung. Damit hätten wir glaub ich alles wichtige...

Wenn ihr Kritik habt schreibt sie bitte!
Kritik zu folgendem ist allerdings nicht erwünscht:
-Mangelde Fehlerabfragen hab ich absichtlich weggelassen- meiner Meinung nach haben die in Beispielcode nix zu suchen, die kann jeder selber einbauen und würden hier nur für Unübersicht sorgen.
-Sonstiger quatsch(ich schreib kein std:: vor ifstream und ähnliches)

.

Phili

unregistriert

2

01.08.2006, 18:33

gefällts euch?

BlackSnake

Community-Fossil

Beiträge: 1 549

Beruf: Student

  • Private Nachricht senden

3

01.08.2006, 18:42

es ist ganz cool, obwohl ich nur in hlsl progge.
sonst es ist gut gemacht

Phili

unregistriert

4

01.08.2006, 18:44

@Ghostrider
Du hasts dir wohl nicht richtig durchgelesen. Es ist ein Tutorial, wie man HLSL ohne D3DX verwenden kann.

BlackSnake

Community-Fossil

Beiträge: 1 549

Beruf: Student

  • Private Nachricht senden

5

01.08.2006, 19:39

ok^^,
das kommt wahrscheinlich daher weil das bei mir immer anders aussieht als bei dir.
ich verwende die effekt klasse der tribase engine. die nutzt d3dx

aber es ist trotzdem gutgelungen ;)

Anonymous

unregistriert

6

01.08.2006, 19:47

Exzellente Arbeit! Solltest aber noch dazu schreiben wie man den Shader-Compiler bedient :) und sagen das das bei PixelShadern das selbe ist :)

Phili

unregistriert

7

01.08.2006, 20:27

@nix da
Wow, da fühl ich mich jetzt echt geehrt! Ok, deine Kritik werd ich einarbeiten! :D
Ok, hab jetzt kurz die Benutzung von fxc erläutert...

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

8

01.08.2006, 21:06

C-/C++-Quelltext

1
char SoftBuffer[10000];

Das ist aber nicht sehr schön!

Anonymous

unregistriert

9

01.08.2006, 21:08

Es sollte auch

C-/C++-Quelltext

1
delete [] Zwischen;
lauten.

Phili

unregistriert

10

01.08.2006, 21:16

@David Sherfgen
Naja, die 10000 sind vieleicht nen bissl übertrieben, aber wie man das anders lösen kann wüsst ich nciht, weil ich nicht weiß, wie man die größe einer Datei mit fstream bestimmt.
@nix da
Ja hast recht... :oops:

Werbeanzeige