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

Schwarzefee

Treue Seele

  • »Schwarzefee« ist der Autor dieses Themas

Beiträge: 155

Wohnort: Ost-Sachsen

Beruf: Programmierer

  • Private Nachricht senden

12

15.09.2014, 21:11

Hi,

ich bin im Moment soweit, dass der Texture-Atlas erstellt wird.
Zum Test wollte ich mal den Texture Atlas ausgeben, sieht aber irgendwie komisch aus.


(Link)


Hier mal der Code vom Erstellen des Atlas:

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
66
bool Font::CreateTextureAtlas()
{
    FT_Error error;
    FT_GlyphSlot g = this->FTFontFace->glyph;
    int width = 0;
    int height = 0;

    //Fertige Breite+Höhe des Font-Atlas ermitteln
    for(int i = this->StartChar; i < this->EndChar; i++) 
    {
        error = FT_Load_Char(this->FTFontFace, i, FT_LOAD_RENDER);
        if (error)
        {
            THROW_FontException("error_loadchar", "Error loading char " + i, error);
            continue;
        }
 
        width += g->bitmap.width;
        if (g->bitmap.rows > height)
        {
            height = g->bitmap.rows;
        }
    }

    //Jetzt Texture-Atlas erstellen
    this->FontAtlas.reset();
    this->FontAtlas = std::unique_ptr<STEngine::Graphics::Resources::Texture2D>(new STEngine::Graphics::Resources::Texture2D());
    this->FontAtlas->CreateNewTexture(width, height);
    
    //Texture-Atlas befüllen
    int x = 0;

    for(int i = this->StartChar; i < this->EndChar; i++) 
    {
        error = FT_Load_Char(this->FTFontFace, i, FT_LOAD_RENDER);
        if (error)
        {
            continue;
        }

        this->FontAtlas->SetSubImage(x, 0, g->bitmap.width, g->bitmap.rows, g->bitmap.buffer);

        //Char-Cache erstellen
        CharInfo charinfo;
        charinfo.advancex = g->advance.x >> 6;
        charinfo.advanceay = g->advance.y >> 6;
        charinfo.charwidth = g->bitmap.width;
        charinfo.charheight = g->bitmap.rows;
        charinfo.bitmapleft = g->bitmap_left;
        charinfo.bitmaptop = g->bitmap_top;
        charinfo.texoffsetx = (float)x / width;
            
        //Char-Cache speichern
        if (this->CharInfos.find(i) != this->CharInfos.end())
        {
            this->CharInfos.erase(i);
        }
        this->CharInfos.insert(std::pair<int, CharInfo>(i, charinfo));
            
        x += g->bitmap.width;
    }

    this->IsLoaded = true;

    return true;
}


und meine Shader sehn so aus:

HLSL-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
//VertexShader
uniform mat4 pm;

in vec2 vertex0;
in vec2 texCoord0;

varying vec2 texCoords;

void main()
{
    texCoords = texCoord0;
    gl_Position = pm * vec4(vertex0, 0.0, 1.0);
}


HLSL-Quelltext

1
2
3
4
5
6
7
8
9
//FragmentShader
uniform sampler2D texture0;
uniform vec4 textcolor;

in vec2 texCoords;

void main(){
    gl_FragColor = vec4(1, 1, 1, texture2D(texture0, texCoords).a) * textcolor;
}


Hat jemand ne schlaue Idee, warum das so komisch aussieht?


Gruß


EDIT: Was mir grad eingefallen ist:
Eigentlich sind diese roten Striche unter den Zeichen kein Problem, da sie eh nicht angezeigt werden.
Ist dann mein Code soweit richtig, oder mach ich doch noch etwas falsch?

Schrompf

Alter Hase

Beiträge: 1 470

Wohnort: Dresden

Beruf: Softwareentwickler

  • Private Nachricht senden

13

15.09.2014, 21:41

Code kann ich auf die Schnelle nicht bewerten. Aber das Bild sieht aus, als hättest Du ganz banal einen Font geladen, der eine Menge Zeichen gar nicht enthält.
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.

Schwarzefee

Treue Seele

  • »Schwarzefee« ist der Autor dieses Themas

Beiträge: 155

Wohnort: Ost-Sachsen

Beruf: Programmierer

  • Private Nachricht senden

14

30.10.2014, 14:13

Hi,

die Grundlagen meiner Font-Engine funktionieren erstmal.

Jetzt wollte ich ein bisschen weiter gehn und ein paar Features einbauen.

Ich hab gelesen, Freetype unterstützt Outline. Leider habe ich nichts aufschlussreiches gefunden, wie das funktioniert.

Hat vielleicht jemand ein Beispiel? Ist das eine reine Shader-Sache, oder muss man beim Laden der Glyphen was beachten?


Gruß

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

15

01.11.2014, 14:18

Hi

eine kurze OT Anmerkung zum Thema dynamische vs statische Puffer.

Generell sind die Angaben eher ein Hinweis um dem Treiber mitzuteilen wie ein Puffer von der Anwendung genutzt wird. Basierend darauf kann der Treiber dann entscheiden wie die Ressource am besten angelegt/verwaltet werden sollte um möglichst viel Effizienz zu gewährleisten. Im DirectX Kontext wäre z.B. IMMUTABLE ein Hint dafür, die Resource möglichst direkt im lokalen Videospeicher zu hinterlegen, weil generell kein Schreibzugriff gewünscht ist und die GPU so am schnellsten lesend zugreifen kann. DYNAMIC hingegen erlaubt (erzwingt) einen Schreibzugriff von der CPU. D.h. der Treiber wird die Ressource irgendwo hinterlegen wo die CPU möglichst effizienten Schreibzugriff hat, z.B. im AGP/PCI Speicher o.Ä. Das wiederum hat zur Folge des der Lesezugriff der GPU nicht mehr ganz so effizient ist, weil die Daten über einen Bus gehen müssen.

Außerdem unterscheidet sich das Management von Ressourcen deutlich. Beispiel: wie bereits angedeutet wurde muss für dynamische Ressourcen davon ausgegangen werden, das diese sich jederzeit ändern können. Da GPU und CPU ihre Daten asynchron abarbeiten führt das in der Praxis zu Problemen, wenn ein Puffer geändert wird bevor die GPU die Daten konsumiert hat. Um solche Fälle zu vermeiden wird die Ressource "renamed", d.h. ein neuer Speicherbereich alloziert und (transparent) hinter den Handle geschoben. Die GPU kann dann problemlos ihre(n) Kommandpuffer abarbeiten, ohne das Daten überschrieben werden. Wenn eine Ressource gemapped wird aber keine Referenz auf irgendeinen Commandbuffer existiert dann ist der Zugriff wieder günstig (kein renaming).

So ein Management ist natürlich nicht umsonst und deshalb möglichst zu vermeiden. Falls eine Ressource kein update benötigt sollte sie also am besten "Immutable" sein. Falls eine Ressource häufig verändert wird (z.B. einmal pro Frame) sollte die Ressource dynamisch sein. Um Bufferrenaming zu vermeiden kann man folgendes Pattern verwenden:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// allocate
ID3D11Buffer* foo = createVertexBuffer(size * multiplier);

// map
uint32 numberOfMaps = 0; // member etc...

ubyte* ptr = 0;

if (numerOfMaps == 0)
{
  ptr = (ubyte*)map(DISCARD);
}
else
{
  ptr = (ubyte*)map(NO_OVERWRITE);
  ptr = ptr + numberOfMaps * size;
}

numerOfMaps = (numberOfMaps + 1) % multiplier;


Damit wird der Puffer theoretisch nur alle 'n' Frames umbenannt (DISCARD). Praktisch kann das renaming damit effektiv vermindert werden, weil die 'gefahr' das die Ressource noch von der GPU verwendet wird minimert wird (angenommen die GPU ist 2-3 Frames zurück). Zum Teil werden solche Optimierungen auch intern schon vorgenommen, einige GCN Treiber allozieren für das renaming 8 MB Puffer und führen das o.g. Zugriffspattern intern durch.

D3D11_USAGE Enumeration gibt eine super Übersicht über die Zugriffsmodi (ganz unten). Und ist eigentlich eine ganz gute Hilfestellung.
@D13_Dreinig

Werbeanzeige