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

BlackSnake

Community-Fossil

  • »BlackSnake« ist der Autor dieses Themas

Beiträge: 1 549

Beruf: Student

  • Private Nachricht senden

1

29.08.2007, 17:50

FragmentShader und Manager

Ich habe mich mal dazu entschlossen ein kleines Tutorial über Fragmentshader zu schreiben. Das Fragmentshader ansich ja recht leicht zu verstehen sind, werde ich noch einen kleinen Manager hinzufügen.

Einleitung
Also, als Erstes mal, was ist ein Fragmentshader überhaupt. Es steckt schon im wort drin -> Fragment. Es handelt sich hier nicht mehr um einen kompletten Vertex/Pixelshader, sondern um kleine Bruckstücke, Fragmente eben.
Diese Fragmente werden dann im Hauptprogramm zu einem richtigen und vollständigen Shader verlinkt.
Dies hat den Vorteil, dass man nicht für alles komplette Shader schreiben muss. Moderne Spiele haben heute weit über 1000 verschiedene Pixelshader. Vertexshader häufen sich ebenfalls. Wäre jetzt doch dumm, wenn man immer komplette Shader scheiben müsste. Hier kommen dann die Fragmente ins Spiel.

Der Manager ist nur ein Beispiel, wie man es machen kann. Den Code kann man mit Sicherheit auch noch verbessern, aber zum Vorführen reicht er vollkommen aus.
Ich habe zwar schon viel über D3DX gehört. Es soll langsam sein, nicht zuverlässig arbeiten etc... . Ich halte das für schwachsinn. Es arbeitet schnell und auch gut. Deswegen werde ich hier auch D3DX verwenden.

Außerdem verwende ich noch die TriBase. Sie ist einfach strukturiert, sodass man es schnell auf jede andere Engine umschreiben kann.

FSM -- FragmentShaderManager
Der Name der Klasse lautet "FSM". Dazu habe ich mich entschlossen, sie als Singleton anzulegen. Ist natürlich jedem selbst überlassen.
Wie man einen Singleton erstellt sollte eigentlich jedem bekannt sein. Falls das nicht der Fall sein sollte, schaut euch Anhang "A" an.
Alle Variablen die ich in dem Manager nutze sind als "private" deklariert.

Nun zur Klasse.
Ich habe als erstes drei "Sicherheitsvariablen" eingebaut:

C-/C++-Quelltext

1
2
3
bool    _isInit;
bool    _isVertexShader;
bool    _isPixelShader;

Die Variable "_isInit" wird auf true gesetzt, wenn man den Manager initialisiert. Bei jeder wichtigen Methode wird überprüft ob der Manager initialisiert ist, wenn nicht, passiert da gar nichts.
Die anderen beiden Variablen geben an, ob ein Vertex/Pixelshader gesetzt ist. Die werden später noch mal auftauchen.

Als nächtes kommen die Linker sachen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
ID3DXFragmentLinker*    _fragmentLinker;
LPD3DXCONSTANTTABLE _constantTable;
LPD3DXBUFFER        _vertexFragments;
LPD3DXBUFFER        _pixelFragments;
IDirect3DVertexShader9* _vertexshader;
IDirect3DPixelShader9*  _pixelshader;
D3DXHANDLE      _vertexFragmentHandles[10];
D3DXHANDLE      _pixelFragmentHandles[10];

Die Variable "_fragmentLinker" ist der eigentliche Linker, der später die einzelnen Fragmente linkt.
Die Variable "_constantTable" beinhaltet die ganzen globalen Variablen, die es gibt.
Die beiden Buffer "_vertexFragments" und "_pixelFragments" beinhalten die einzelnen Fragmente, die aus der Datei gelesen wurden.
Die beiden nächsten sind zu einem der Vertexshader und zum anderen der Pixelshader.
Die beiden letzten sind die Handles auf die einzelnen Fragmente.

Als letztes komme ein paar Hilfsvariablen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
unsigned int                _numberofSetVertexshader;
VertexFragments             _vertexFragmentList;
unsigned int                _numberofSetPixelshader;
PixelFragments              _pixelFragmentList;
unsigned int                _arrayPosition;
tbDirect3D*                 _d3d;
std::basic_string<wchar_t>  _vertexFragmentFile;
std::basic_string<wchar_t>  _pixelFragmentFile;

Die Variablen sollten sich von alleine klären, anderenfalls tauchen sie später nochmals auf.

Das waren die Variablen des Managers. Jetzt kommen noch die einzelnen Methoden der Klasse:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
    tbResult                    InitManager(tbDirect3D* _direct3D, std::basic_string<wchar_t> _vertexFragmentFile, std::basic_string<wchar_t> _pixelFragmentFile);
tbResult                    ExitManager();
tbResult                    SetVertexShader(std::basic_string<char> _shaderVersion, DWORD _flags);
tbResult                    SetPixelShader(std::basic_string<char> _shaderVersion, DWORD _flags);
LPD3DXCONSTANTTABLE         GetConstantTable()const;
tbResult                    Start();
tbResult                    Stop();
tbResult                    SetInteger(std::basic_string<char> _name, int _integer);
tbResult                    SetFloat(std::basic_string<char> _name, float _float);
tbResult                    SetVector(std::basic_string<char> _name, D3DXVECTOR4* _vector);
tbResult                    SetMatrix(std::basic_string<char> _name, D3DXMATRIX* _matrix);


Kommen wir jetzt zu den einzelnen Funktionen. Die werde ich nicht großartig erleutern. Man sollte das auch so erkennen was ich da mache.

InitManager
Die Init-Methode erwartet 3 Parameter. Der erste ist ein gültiger Zeiger auf eine D3D-Instance. Der 2 und 3 sind Pfadabgaben zu den einzelnen Files, die die Fragmente beinhalten. Dazu später.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
tbResult FSM::InitManager(tbDirect3D* _direct3D, std::basic_string<wchar_t> _vertexFragmentFile, std::basic_string<wchar_t> _pixelFragmentFile)
{
    TB_INFO("FragmentShaderManager wird initialisiert...");

    // Check parameters

    if(_vertexFragmentFile.empty() == true || _pixelFragmentFile.empty() == true || _direct3D == NULL)
        return TB_ERROR;

    // Copy parameter

    _d3d = _direct3D;
    _vertexFragmentFile = _vertexFragmentFile;
    _pixelFragmentFile  = _pixelFragmentFile;

    // Create fragment linker

    if(D3DXCreateFragmentLinker(_direct3D->GetDevice(), 0, &_fragmentLinker) != D3D_OK)
    {
        TB_ERROR("Fragmentlinker konnte nicht erstellt werden", TB_ERROR);
        return TB_ERROR;
    }

    // Gather all vertexfragments

    if(D3DXGatherFragmentsFromFile(_vertexFragmentFile.c_str(), NULL, NULL, NULL, &_vertexFragments, NULL) != D3D_OK)
    {
        TB_ERROR("Vertexfragmente konnten nicht gesammelt werden", TB_ERROR);
        return TB_ERROR;
    }

    // Gather all pixelfragments

    if(D3DXGatherFragmentsFromFile(_pixelFragmentFile.c_str(), NULL, NULL, NULL, &_pixelFragments, NULL) != D3D_OK)
    {
        TB_ERROR("Pixelfragmente konnten nicht gesammelt werden", TB_ERROR);
        return TB_ERROR;
    }

    // Add vertexfragments to buffer

    if(_fragmentLinker->AddFragments((DWORD*)_vertexFragments->GetBufferPointer()) != D3D_OK)
    {
        TB_ERROR("Vertexfragmente konnten nicht zum Buffer hinzugefügt werden", TB_ERROR);
        return TB_ERROR;
    }

    // Add pixelfragments to buffer

    if(_fragmentLinker->AddFragments((DWORD*)_pixelFragments->GetBufferPointer()) != D3D_OK)
    {
        TB_ERROR("Pixelfragmente konnten nicht zum Buffer hinzugefügt werden", TB_ERROR);
        return TB_ERROR;
    }

    _isInit = true;
    TB_INFO("FragmentShaderManager wurde initialisiert");
    return TB_OK;
}


ExitManager
Die Exit-Methode hat die Aufgabe alles wieder zu beenden.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
tbResult FSM::ExitManager()
{
    TB_INFO("FragmentShaderManager wird beendet...");

    // Release shader, vertex/pixel

    if(_vertexshader) _vertexshader->Release();
    if(_pixelshader) _pixelshader->Release();

    // Release fragmentbuffers, vertex/pixel

    if(_vertexFragments) _vertexFragments->Release();
    if(_pixelFragments) _pixelFragments->Release();

    // Release table

    if(_constantTable) _constantTable->Release();

    // Release linker

    if(_fragmentLinker) _fragmentLinker->Release();

    _isInit = false;
    TB_SAFE_DELETE(_manager);
    TB_INFO("FragmentShaderManager wurde beendet");
    return TB_OK;
}


SetVertexShader
Die Methode ist dafür verantwortlich alles zu linken, und anschließend den Vertexshader daraus zu basteln. Sie erwartet 2 Parameter. Der erste ist die Version des Shaders, vs_1_1 ... vs_4_1. Wer das neue SDK haben sollte kann nur noch den Bereich, vs_2_0 ... vs_4_1, verwenden.
Der zweite Parameter sind die Flags. Siehe für mehr Infos Anhang "B".

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
tbResult FSM::SetVertexShader(std::basic_string<char> _shaderVersion, DWORD _flags)
{
    // Variables

    ID3DXBuffer*    code;
    DWORD*          shaderCode = NULL;

    // Check parameters

    if(_shaderVersion.empty() == true)
        return TB_ERROR;

    _numberofSetVertexshader = NULL;
    _arrayPosition           = NULL;

    // Check flags

    if((_flags & VSF_NONE) == PSF_NONE)
        return TB_OK;
    if((_flags & VSF_PROJECTION) == VSF_PROJECTION)
    {
        _numberofSetVertexshader++;
        _vertexFragmentList.projection = true;
    }
    if((_flags & VSF_DIFFUSEAMBIENT) == VSF_DIFFUSEAMBIENT)
    {
        _numberofSetVertexshader++;
        _vertexFragmentList.diffuseAmbient = true;
    }

    // Get fragments

    if(_vertexFragmentList.projection == true)
    {
        _vertexFragmentHandles[_arrayPosition]  = _fragmentLinker->GetFragmentHandleByName("Fragment_Vertex_Projection");
        _arrayPosition++;
    }

    if(_vertexFragmentList.diffuseAmbient == true)
    {
        _vertexFragmentHandles[_arrayPosition]  = _fragmentLinker->GetFragmentHandleByName("Fragment_Vertex_DiffuseAmbient");
        _arrayPosition++;
    }

    if(_vertexshader) _vertexshader->Release();

    // Link...

    if(_fragmentLinker->LinkShader(_shaderVersion.c_str(), 0, _vertexFragmentHandles, _numberofSetVertexshader, &code, NULL) != D3D_OK)
    {
        TB_ERROR("Vertexshader konnten nicht gelinkt werden", TB_ERROR);
        return TB_ERROR;
    }
    shaderCode = (DWORD*)code->GetBufferPointer();
    code->Release();
    if(_d3d->GetDevice()->CreateVertexShader(shaderCode, &_vertexshader) != D3D_OK)
    {
        TB_ERROR("Vertexshader konnte nicht erstellt werden", TB_ERROR);
        return TB_ERROR;
    }
    if(_constantTable) _constantTable->Release();
    if(D3DXGetShaderConstantTable(shaderCode, &_constantTable) != D3D_OK)
    {
        TB_ERROR("Konstantenliste konnte nicht erstellt werden", TB_ERROR);
        return TB_ERROR;
    }

    _isVertexShader = true;
    return TB_OK;
}


SetPixelShader
Diese Funktion macht alles genaus wie der Vorgänger nur eben für die Pixelshader.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
tbResult FSM::SetPixelShader(std::basic_string<char> _shaderVersion, DWORD _flags)
{
    // Variables

    ID3DXBuffer*    code;
    DWORD*          shaderCode = NULL;

    // Check parameters

    if(_shaderVersion.empty() == true)
        return TB_ERROR;

    _numberofSetPixelshader  = NULL;
    _arrayPosition           = NULL;

    // Check flags

    if((_flags & PSF_NONE) == PSF_NONE)
        return TB_OK;
    if((_flags & PSF_TEXTURESURFACE) == PSF_TEXTURESURFACE)
    {
        _numberofSetPixelshader++;
        _pixelFragmentList.texturingSurface = true;
    }

    // Get fragments

    if(_pixelFragmentList.texturingSurface == true)
    {
        _pixelFragmentHandles[_arrayPosition]   = _fragmentLinker->GetFragmentHandleByName("Fragment_Pixel_TexturingSurface");
        _arrayPosition++;
    }

    if(_pixelshader) _pixelshader->Release();

    // Link...

    if(_fragmentLinker->LinkShader(_shaderVersion.c_str(), 0, _pixelFragmentHandles, _numberofSetPixelshader, &code, NULL) != D3D_OK)
    {
        TB_ERROR("Pixelshader konnten nicht gelinkt werden", TB_ERROR);
        return TB_ERROR;
    }
    shaderCode = (DWORD*)code->GetBufferPointer();
    code->Release();
    if(_d3d->GetDevice()->CreatePixelShader(shaderCode, &_pixelshader) != D3D_OK)
    {
        TB_ERROR("Pixelshader konnte nicht erstellt werden", TB_ERROR);
        return TB_ERROR;
    }

    _isPixelShader = true;
    return TB_OK;
}


Jetzt fehlern eigentlich nur noch die Funktionen für die Übergabe an Werten. Das kann man auf verschiedener Weise erledigen. Einmal direkt über die Variable "_constantTable". Allerdings, falls der ungültig werden sollte, schmiert das Programm mit einem Runtime-Error ab -> unschöne sache. Da habe ich mir einfach ein paar Methoden selbst erstellt, die vorher prüfen, ob die Variable gültig ist.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//.................................................

// FSM -> GetConstantTable()

//.................................................

LPD3DXCONSTANTTABLE FSM::GetConstantTable()const
{
    if(_constantTable)
        return _constantTable;

    return NULL;
}

//.................................................

// FSM -> SetInteger()

//.................................................

tbResult FSM::SetInteger(std::basic_string<char> _name, int _integer)
{
    if(_constantTable)
        _constantTable->SetInt(_d3d->GetDevice(), _name.c_str(), _integer);

    return TB_OK;
}

//.................................................

// FSM -> SetFloat()

//.................................................

tbResult FSM::SetFloat(std::basic_string<char> _name, float _float)
{
    if(_constantTable)
        _constantTable->SetFloat(_d3d->GetDevice(), _name.c_str(), _float);

    return TB_OK;
}

//.................................................

// FSM -> SetVector()

//.................................................

tbResult FSM::SetVector(std::basic_string<char> _name, D3DXVECTOR4* _vector)
{
    if(_constantTable)
        _constantTable->SetVector(_d3d->GetDevice(), _name.c_str(), _vector);

    return TB_OK;
}

//.................................................

// FSM -> SetMatrix()

//.................................................

tbResult FSM::SetMatrix(std::basic_string<char> _name, D3DXMATRIX* _matrix)
{
    if(_constantTable)
        _constantTable->SetMatrix(_d3d->GetDevice(), _name.c_str(), _matrix);

    return TB_OK;
}


Beinahe hätte ich das vergessen. Wie startet man den Shader nun? Das übernehmen die beiden nächsten Funktionen. Dort finden wir auch wieder unsere 2 Sicherheitsvariablen wieder.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//.................................................

// FSM -> Start()

//.................................................

tbResult FSM::Start()
{
    // Set pixel/vertex shader

    if(_isPixelShader)
    {
        if(_d3d->GetDevice()->SetPixelShader(_pixelshader) != D3D_OK)
        {
            TB_ERROR("Pixelshader konnte nicht gesetzt werden", TB_ERROR);
            return TB_ERROR;
        }
    }

    if(_isVertexShader)
    {
        if(_d3d->GetDevice()->SetVertexShader(_vertexshader) != D3D_OK)
        {
            TB_ERROR("Vertexshader konnte nicht gesetzt werden", TB_ERROR);
            return TB_ERROR;
        }
    }

    return TB_OK;
}

//.................................................

// FSM -> Stop()

//.................................................

tbResult FSM::Stop()
{
    // Set pixel/vertex shader

    _d3d->GetDevice()->SetPixelShader(NULL);
    _isPixelShader = false;
    _d3d->GetDevice()->SetVertexShader(NULL);
    _isVertexShader = false;
        
    return TB_OK;
}


Damit wäre die Klasse vollständig und einsatzbereit.

Fragmentshader-Files
Ich habe mir meine eigene Struktur für die Shader überlegt. Sie sieht ein wenig kompliziert aus, ist es aber eigentlich nicht.

Es gibt bei mir 5 unterschiedliche Datein. Die Namen sollten den Inhalt erklären:
1. Include_Sampler.fx
2. Include_Variables.fx
3. Include_Structs.fx
4. PixelShaderFragments.fx
5. PixelShaderFragments.fx
Ich werde nur auf die beiden letzten ein wenig intensiver eingehen.

Include_Sampler.fx
Das File beinhaltet die ganzen Sampler, die es gibt. Bei mir sind es ein paar mehr, aber hier brauchen wir erstmal nur einen.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//------------------------------------------------

// VARIABLES

//------------------------------------------------


texture texture_Surface;

//------------------------------------------------

// SAMPLER - SURFACE

//------------------------------------------------


sampler SamplerSurfaceLinear = sampler_state
{
    texture   = (texture_Surface);
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};

Die Texturevariablen lagern hier und nicht in dem eigentlichen Inlcudefile für die Variablen, aufgrund des sonst kommenden Fehlers der Mehrfachinkludierung.

Include_Variables.fx

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma once

//------------------------------------------------

// VARIABLES

//------------------------------------------------


shared float4x4 matrix_4x4_World;
shared float4x4 matrix_4x4_Rotation;
shared float4x4 matrix_4x4_View;
shared float4x4 matrix_4x4_Projection;
shared float4x4 matrix_4x4_ViewProjection;
shared float4x4 matrix_4x4_WorldViewProjection;

shared float4   vector_4_MaterialDiffuse;
shared float4   vector_4_MaterialAmbient;
shared float4   vector_4_LightDiffuse;
shared float4   vector_4_LightAmbient;

shared float3   vector_3_LightPosition;
shared float3   vector_3_DirToLight;


Include_Structs.fx
Hier lagern die ganzen Input-und Outputstrukturen für die Shader.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#pragma once

//------------------------------------------------

// STRUCTS - PROJECTION

//------------------------------------------------


// Input

struct input_Projection
{
    float4 ObjectPosition:POSITION;
    float3 ObjectNormal:NORMAL;
    float2 TextureSurface:TEXCOORD0;
};

// Output

struct output_Projection
{
    float4 ProjectionPosition:POSITION;
    float3 WorldNormal:r_WorldNormal;
    float2 TextureSurface:TEXCOORD0;
};

//------------------------------------------------

// STRUCTS - DIFFUSAMBIENTECOLOR

//------------------------------------------------


// Input

struct input_ColorDiffuseAmbient
{
    float3 WorldNormal:r_WorldNormal;
};

// Output

struct output_ColorDiffuseAmbient
{
    float4 ColorDiffuseAmbient:COLOR0;
};

//------------------------------------------------

// STRUCTS - TEXTURINGSURFACE

//------------------------------------------------


// Input

struct input_TexturingSurface
{
    float4 Color:COLOR0;
    float2 TextureSurface:TEXCOORD0;
};

// Output

struct output_TexturingSurface
{
    float4 Color:COLOR0;
};


PixelShaderFragments.fx
Kommen wir nun endlich zu den Hauptfiles, beginnend mit dem für die Pixelshaderfragmente.
Zuerst inkludieren wir alle drei Include-Files.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
#pragma once

//------------------------------------------------

// INCLUDES

//------------------------------------------------


#include "Include_Variables.fx"
#include "Include_Structs.fx"
#include "Include_Sampler.fx"


Jetzt folgt das erste Fragment. Es sieht einer Funktion sehr ähnlich. Sie erwartet 2 Parameter. Der erste ist die Inputstruktur, der zweite die Outputstruktur. Die Parameter füllt die Grafikkarte selbstständig.

C-/C++-Quelltext

1
2
3
4
5
6
7
//------------------------------------------------

// TexturingSurface

//------------------------------------------------

void TexturingSurface(in input_TexturingSurface IN, out output_TexturingSurface OUT)
{
    OUT.Color = IN.Color * tex2D(SamplerSurfaceAnisotropic, IN.TextureSurface);
};

Die Funktion addiert die Farbe des momentanen Texels mit der momentane Pixelfarbe des Models.

Jetzt kommt die eigentliche Fragmentdefinition.

C-/C++-Quelltext

1
2
3
4
//------------------------------------------------

// Fragments

//------------------------------------------------

pixelfragment Fragment_Pixel_TexturingSurface = compile_fragment ps_2_0 TexturingSurface();

Die Variable "pixelfragment" gibt an, dass es sich um ein Fragment für den Pixelshader handelt. Gefolgt von den Namen, des Fragments.
Als nächstes sagen wir ihm, das er unsere Funktion mit einem ps20 compilieren soll. Ansich recht simpel.
Damit hätten wir diese Datei auch besprochen.

VertexShaderFragments.fx
Diese Datei unterscheidet sich nicht groß zwischen der anderen. Hier inkludieren wir ebenfalls die Include-Files. Danach kommen 2 Funktionen. Die erste erledigt grundlegende Sachen, wie Projektion....

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
//------------------------------------------------

// Projection

//------------------------------------------------

void Projection(in input_Projection IN, out output_Projection OUT)
{    
    OUT.ProjectionPosition  = mul(IN.ObjectPosition, matrix_4x4_WorldViewProjection);
    OUT.WorldNormal         = mul(IN.ObjectNormal, (float3x3)matrix_4x4_World);
    OUT.TextureSurface      = IN.TextureSurface;
};


Die zweite berechnet anschließend die DifusseAmbiente-Beleuchtung.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
//------------------------------------------------

// CalculateDiffuseAmbientColor

//------------------------------------------------

void CalculateDiffuseAmbientColor(in input_ColorDiffuseAmbient IN, out output_ColorDiffuseAmbient OUT)
{
    OUT.ColorDiffuseAmbient = vector_4_LightDiffuse * vector_4_MaterialDiffuse * saturate(dot(IN.WorldNormal, normalize(vector_3_DirToLight)));
    OUT.ColorDiffuseAmbient += vector_4_LightAmbient * vector_4_MaterialAmbient;
};


Zu guter Letzt die beiden Fragmente.

C-/C++-Quelltext

1
2
3
4
5
//------------------------------------------------

// Fragments

//------------------------------------------------

vertexfragment Fragment_Vertex_Projection = compile_fragment vs_2_0 Projection();
vertexfragment Fragment_Vertex_DiffuseAmbient = compile_fragment vs_2_0 CalculateDiffuseAmbientColor();


Schlusswort
Ich hoffe mal ich konnte ich die Fragmentshader ein wenig näher bringen. Sicher, dieses Beispiel ist das leichteste was man hätte nehmen können. Aber so kommen auch Anfänger mit zu recht.
Das Geschriebene ist natürlich sehr lang. Falls einer da nicht mehr mit kommen sollte, kann sich den Coder im Anhang runterladen.

Ein paar Fragen kläre ich jetzt noch im Anhang.

Anhang A -> Singelton
http://www.oop-trainer.de/Themen/Singleton.html

Anhang B -> Flags
Die beiden Funktion SetVertexShader uns SetPixelShader erwarten Flags. Ich habe die folgenden genommen.

C-/C++-Quelltext

1
2
3
4
5
6
#define VSF_NONE                0x00
#define VSF_PROJECTION          0x01
#define VSF_DIFFUSEAMBIENT      0x02

#define PSF_NONE                0x00
#define PSF_TEXTURESURFACE      0x01


Anhang C -> Allgemeines
Die beiden Variablen des Managers, "_vertexFragmentList", "_pixelFragmentList" sind beides Strukturen, die Infos halten.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
struct VertexFragments
{
    // Variables

    bool                    projection;
    bool                    diffuseAmbient;

    // Constructor

    VertexFragments()
    {
        projection          = false;
        diffuseAmbient      = false;
    }

    // Destructor

    virtual ~VertexFragments()
    {}
};

struct PixelFragments
{
    // Variables

    bool                    texturingSurface;

    // Constructor

    PixelFragments()
    {
        texturingSurface    = false;
    }

    // Destructor

    virtual ~PixelFragments()
    {}
};


In den dem Strukturen-File der Shader taucht 2x sowas auf.

C-/C++-Quelltext

1
float3 WorldNormal:r_WorldNormal;

Das simbolisiert, dass die Variable ein und die selbe ist. Sie steckt zwar un unterschiedlichen Strukturen drin, aber wenn der Linker sie zusammenfummelt, macht er praktisch eine raus. das "r_" ist dabei Pflicht!

Anhang D -> Download
http://home.arcor.de/BlackSnake-Studios_…gmentShader.rar

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

2

29.08.2007, 18:32

Ganz nett, was mir aber beim ersten überfliegen auffällt:

Zitat


Also, als Erstes mal, was ist ein Fragmentshader überhaupt. Es steckt schon im wort drin -> Fragment. Es handelt sich hier nicht mehr um einen kompletten Vertex/Pixelshader, sondern um kleine Bruckstücke, Fragmente eben.
Diese Fragmente werden dann im Hauptprogramm zu einem richtigen und vollständigen Shader verlinkt.
Dies hat den Vorteil, dass man nicht für alles komplette Shader schreiben muss. Moderne Spiele haben heute weit über 1000 verschiedene Pixelshader. Vertexshader häufen sich ebenfalls. Wäre jetzt doch dumm, wenn man immer komplette Shader scheiben müsste. Hier kommen dann die Fragmente ins Spiel.


Mit Fragmenten werden hier Texel (Texturpixel) gemeint. Ein Fragmentshader kann auch einfach mit Pixelshader bezeichnet werden, wobei Fragmentshader die bessere Bezeichnung ist, wie ich finde.

C-/C++-Quelltext

1
std::basic_string<wchar_t>


Wird zu:

C-/C++-Quelltext

1
std::wstring


Und:

C-/C++-Quelltext

1
tbResult                    SetInteger(std::basic_string<char> _name, int _integer);


Wird zu:

C-/C++-Quelltext

1
tbResult                    SetInteger( const std::string& _name, int _integer);
@D13_Dreinig

ChrisJ

Alter Hase

Beiträge: 487

Wohnort: Schweich

Beruf: Schüler

  • Private Nachricht senden

3

29.08.2007, 21:10

ich finde 'fragment program' triffts am besten :)
"Don't trust your eyes: They are a hell of a lot smarter than you are"

BlackSnake

Community-Fossil

  • »BlackSnake« ist der Autor dieses Themas

Beiträge: 1 549

Beruf: Student

  • Private Nachricht senden

4

29.08.2007, 21:56

Zitat von »"David_pb"«

Ganz nett, was mir aber beim ersten überfliegen auffällt:

Zitat


Also, als Erstes mal, was ist ein Fragmentshader überhaupt. Es steckt schon im wort drin -> Fragment. Es handelt sich hier nicht mehr um einen kompletten Vertex/Pixelshader, sondern um kleine Bruckstücke, Fragmente eben.
Diese Fragmente werden dann im Hauptprogramm zu einem richtigen und vollständigen Shader verlinkt.
Dies hat den Vorteil, dass man nicht für alles komplette Shader schreiben muss. Moderne Spiele haben heute weit über 1000 verschiedene Pixelshader. Vertexshader häufen sich ebenfalls. Wäre jetzt doch dumm, wenn man immer komplette Shader scheiben müsste. Hier kommen dann die Fragmente ins Spiel.


Mit Fragmenten werden hier Texel (Texturpixel) gemeint. Ein Fragmentshader kann auch einfach mit Pixelshader bezeichnet werden, wobei Fragmentshader die bessere Bezeichnung ist, wie ich finde.


ich meine das ist nur bei opengl so, dass man dazu pixelshader sagt. aber das gabs ja schonmal hier in einem thread....
falls es total falsch ist, kann ich das ja noch ändern ;)

Zitat von »"ChrisJ"«


ich finde 'fragment program' triffts am besten ;)

naja, man kann es ja leicht werweitern mit schatten. das sollte ja nur das grundprinzip vorstellen und nicht gleich nen supershader zeigen ;).
ich arbeite im mom auch noch an der ganze sachen. das hier ist nur ei nauschnitt. das prinzip wird aber momentan auch in einem spiel verwendet und meine engine hat ein sehr erweitertes system davon, das effektsystem. man kann auf jedenfall gut mit arbeiten ;)

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

5

29.08.2007, 22:09

Grad bei OpenGL sagt man Fragment statt Pixel. :P Und ja, ich halte diese Erklärung für falsch! :)
@D13_Dreinig

BlackSnake

Community-Fossil

  • »BlackSnake« ist der Autor dieses Themas

Beiträge: 1 549

Beruf: Student

  • Private Nachricht senden

6

29.08.2007, 22:24

ah ich meinte natürlich fragment und nicht pixelshader, bei gl ;)
habe ich mich total verschrieben.

hat jemand das schon mal komplett durchgelesen? wäre cool wenn jemand nen statement abgibt ;)

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

7

30.08.2007, 09:10

Ich habs mir ganz durchgelesen, ich hab mein Statement abgegeben und gesagt was falsch ist und was ich verbessern würde. Auf die Verbesserungsvorschläge bist du nicht eingegangen und den Hinweis das deine Beschreibung falsch ist hast du tunlichst ignoriert (was du wohl meinst sind Shader Fragmente, nicht Fragmentshader. Das ist ein Unterschied). Es lohnt sich also garnicht dir ein Statement zu geben, da du ohnehin nur das positive Kritik anzunehmen scheinst... :roll:
@D13_Dreinig

CodingCat

1x Contest-Sieger

Beiträge: 420

Beruf: Student (KIT)

  • Private Nachricht senden

8

30.08.2007, 10:27

Zitat von »"David_pb"«

Ich habs mir ganz durchgelesen, ich hab mein Statement abgegeben und gesagt was falsch ist und was ich verbessern würde. Auf die Verbesserungsvorschläge bist du nicht eingegangen und den Hinweis das deine Beschreibung falsch ist hast du tunlichst ignoriert (was du wohl meinst sind Shader Fragmente, nicht Fragmentshader. Das ist ein Unterschied). Es lohnt sich also garnicht dir ein Statement zu geben, da du ohnehin nur das positive Kritik anzunehmen scheinst... :roll:


Vielleicht hättest Du dich ja auch gleich richtig ausdrücken können - dass mit Fragment Shader keine Pixel Shader gemeint sind, sollte ja wohl aus dem Tutorial hervorgehen - die Erklärung ist damit nicht falsch, lediglich die Bezeichnung - so wirkten deine Antworten bisher eher, als hättest du selbst nicht ganz verstanden, worum es in dem Tutorial eigentlich geht, was keine gute Grundlage für Verbesserungsvorschläge ist. :roll:

Mit deiner letzten Antwort hast du ja gezeigt, dass du weißt, um was es geht. Anstatt dich jetzt aufzuregen hättest du aber auch einfach von Anfang an sagen können: "'Fragment Shader' ist eine Ungeschickte Bezeichnung für 'Shader Fragments', da es in OpenGl den Ausdruck 'Fragment Program' gibt, der die OpenGl-Entsprechung zu 'Pixel Shader' in DirectX darstellt, was zu unglücklichen Verwirrungen führen könnte. Deshalb wäre es geschickter, im Tutorial den Begriff 'Fragment Shader' durch 'Shader Fragment' zu ersetzen." :)

koschka

Community-Fossil

Beiträge: 2 862

Wohnort: Dresden

Beruf: Student

  • Private Nachricht senden

9

30.08.2007, 10:41

Zitat von »"David_pb"«

Ganz nett, was mir aber beim ersten überfliegen auffällt:


Somit ist die Frage berechtigt:

Zitat von »"BlackSnake"«

hat jemand das schon mal komplett durchgelesen?


So und nun bitte zum Thema zurück.

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

10

30.08.2007, 11:02

Zitat von »"CodingCat"«


Vielleicht hättest Du dich ja auch gleich richtig ausdrücken können - dass mit Fragment Shader keine Pixel Shader gemeint sind, sollte ja wohl aus dem Tutorial hervorgehen - die Erklärung ist damit nicht falsch, lediglich die Bezeichnung - so wirkten deine Antworten bisher eher, als hättest du selbst nicht ganz verstanden, worum es in dem Tutorial eigentlich geht, was keine gute Grundlage für Verbesserungsvorschläge ist. :roll:


Nun... Die falsche Bezeichnung macht die komplette Erklährung falsch. Was die Ursache ist wurde ja bereits geklärt!

Zitat von »"CodingCat"«


Mit deiner letzten Antwort hast du ja gezeigt, dass du weißt, um was es geht. Anstatt dich jetzt aufzuregen hättest du aber auch einfach von Anfang an sagen können: "'Fragment Shader' ist eine Ungeschickte Bezeichnung für 'Shader Fragments', da es in OpenGl den Ausdruck 'Fragment Program' gibt, der die OpenGl-Entsprechung zu 'Pixel Shader' in DirectX darstellt, was zu unglücklichen Verwirrungen führen könnte. Deshalb wäre es geschickter, im Tutorial den Begriff 'Fragment Shader' durch 'Shader Fragment' zu ersetzen." :)


Warum wird immer davon ausgegangen man würde sich aufregen? Wer sich wegen so etwas aufregt ist selbst Schuld an den negativen Konsequenzen... Oo

Statement:
Wie auch immer, Fragent Shader ist keine ungeschickte Bezeichnung sondern in diesem Zusammenhang einfach eine falsche Bezeichnung. Der Begriff Fragment Shader ist ja nicht an OpenGL gebunden sondern allgemein geläufig. Und aus dem Wort geht ja schon hervor: Fragment Shader - 'Schattieren von Fragmenten' wohingegen Shader Fragments - 'Fragmente von Shadern' bedeutet. Unglücklicherweise ist das von 'Fragment' beschriebene Objekt jedesmal ein anderes.

Ansonsten find ich das Tutorial ja recht nett. Bis auf einige kleine Codeschwächen, die, wie ich hoffe, noch behoben werden.

Naja, mein Statement hab ich abgegeben. Jetzt zu den anderen! :-P
@D13_Dreinig

Werbeanzeige