Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Fr Jul 18, 2025 00:05

Foren-Übersicht » Programmierung » Einsteiger-Fragen
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 16 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Autor Nachricht
 Betreff des Beitrags: Texturen mit unerwünschtem Rahmen
BeitragVerfasst: Do Mai 20, 2010 12:31 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mär 21, 2006 20:03
Beiträge: 21
Programmiersprache: Delphi, C++
Hi,

ich arbeite derzeit mit Freunden an einem kleinen Jump 'n Run a lá Mario etc.
Da wir das Spiel derzeit mit 1280x720 laufen lassen und das im Software modus doch recht langsam wird, dachte ich mir, versuche ich mich an OpenGL.
Das ist auch kein allzu großes Problem, da sowohl das 2D Tutorial als auch das Forum mir einige Fragen beantworten.
Nun gibt es aber das Problem, dass die Texturen einen unschönen schwarzen Rahmen bekommen.

Zum Vergleich zeige ich einmal wie das aussieht und auch wie es aussehen sollte ...

So sieht es aus:
Bild

Uploaded with ImageShack.us

Und so sollte es aussehen:
Bild

Uploaded with ImageShack.us

Um Fragen nach Source Code vorzubeugen (bin zwar ein noob in OpenGL, aber nicht unbedingt in Foren :lol: ), poste ich hier mal die Function, die ein SDL_Surface in eine OpenGL Textur umwandelt.

Code:
GLuint SDL2GL(SDL_Surface *Image)
{
   GLint NumberOfColors;
   GLenum TextureFormat = GL_RGB;

   NumberOfColors = Image->format->BytesPerPixel;
   switch (NumberOfColors) {
      case 4:
         if (Image->format->Rmask == 0x000000ff) {
            TextureFormat = GL_RGBA;
         } else {
            TextureFormat = GL_BGRA;
         };
         break;
      case 3:
         if (Image->format->Rmask == 0x000000ff) {
            TextureFormat = GL_RGB;
         } else {
            TextureFormat = GL_BGR;
         };
         break;
   };

   GLuint texnr;
   glGenTextures(1, &texnr);
   glBindTexture(GL_TEXTURE_2D, texnr);

   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   gluBuild2DMipmaps(GL_TEXTURE_2D, NumberOfColors, Image->w, Image->h, TextureFormat, GL_UNSIGNED_BYTE, Image->pixels);

   return texnr;
}


Ich denke, dass der Fehler in dieser Funktion liegt. Denn sowohl die TTF Funktion als auch der normale Loader greifen auf diese Funktion zu.

Ich bin für jede Hilfe dankbar. =)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Mai 20, 2010 13:02 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Das Problem liegt viel wahrscheinlicher im Rendering. Du musst OpenGL sagen, dass es den Alphakanal nutzen soll, um eine Transparenz hübsch darzustellen.
Code:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Die Funktion glBlendFunc ist auch im Wiki dokumentiert.

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Mai 20, 2010 14:11 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Zitat:
Das Problem liegt viel wahrscheinlicher im Rendering.

Jein, ich vermute es liegt auch an der Textur. Ich vermute du verwendest da eine Textur mit roter Schrift auf schwarzem Grund. Dein Alphakanal beschreibt die Schrift einfach mit 0 bzw. 1, also einem hartem Übergang. Da du GL_LINEAR als Min/Mag-Filter gewählt hast wird zwischen den Pixeln (*) interpoliert: Diese Pixel sind dann halt irgendwie dunkel rot mit einem Alpha von 0.5 oder so.

Mögliche Lösungen:
1. Textur enthält einfach nur eine rote Fläche, die Schrift wird einzig durch den Alphakanal realisiert. Das dürfte für dich die beste Lösung sein.
2. Textur bekommt dieses Gelb als Hintergrundfarbe....dann ist der unschöne Rand eben Gelb => sieht keiner ;)
3. Textur mit GL_NEAREST Filter rendern. Könnte möglicherweise pixelig werden.
4. Textur ohne Skalierung (also 1:1) mit GL_NEAREST Filter rendern. Da hier nicht skaliert wird kann auch nichts pixelig werden.

(*) in diesem Zusammenhang eigentlich "Texel", aber lassen wir das im Einsteigerforum ;)

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Mai 21, 2010 14:11 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mär 21, 2006 20:03
Beiträge: 21
Programmiersprache: Delphi, C++
Lord Horazont hat geschrieben:
Das Problem liegt viel wahrscheinlicher im Rendering. Du musst OpenGL sagen, dass es den Alphakanal nutzen soll, um eine Transparenz hübsch darzustellen.
Code:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Die Funktion glBlendFunc ist auch im Wiki dokumentiert.

greetings

Ich fürchte, ich muss dich enttäuschen. Das nutze ich nämlich bereits. Aber danke für den Tipp. =)

Coolcat hat geschrieben:
1. Textur enthält einfach nur eine rote Fläche, die Schrift wird einzig durch den Alphakanal realisiert. Das dürfte für dich die beste Lösung sein.
2. Textur bekommt dieses Gelb als Hintergrundfarbe....dann ist der unschöne Rand eben Gelb => sieht keiner ;)
3. Textur mit GL_NEAREST Filter rendern. Könnte möglicherweise pixelig werden.
4. Textur ohne Skalierung (also 1:1) mit GL_NEAREST Filter rendern. Da hier nicht skaliert wird kann auch nichts pixelig werden.

1.) Es ist egal welche Schriftfrarbe ich nehme. Es geht ja auch nicht nur um die Schrift. Auch der Charakter wird mit diesem Rahmen "verschönert"
2.) Da dieses Problem nicht nur die Schrift betrifft, sondern alle Texturen, ist das leider ein No-Go.
3.) Danke für den Hinweis. Hab ich gleich ausprobiert. Das Ergebniss ist dennoch noch nicht so ganz wie gewünscht:
Bild

Uploaded with ImageShack.us
4.) Also eigentlich strecke ich nichts ...
Code:
bool RendererGL::RenderImage(Uint32 X, Uint32 Y, Uint8 Z, TImage &Image)
{
   if (&Image == NULL) {
      return false;
   };
   glBindTexture(GL_TEXTURE_2D, Image.GL);

   glBegin(GL_QUADS);
      glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
      glTexCoord2f(0,0);
      glVertex3i(X,Y,Z);

      glTexCoord2f(0,1);
      glVertex3i(X,Y+Image.h,Z);

      glTexCoord2f(1,1);
      glVertex3i(X+Image.w,Y+Image.h,Z);

      glTexCoord2f(1,0);
      glVertex3i(X+Image.w,Y,Z);
   glEnd();

   return true;
}
Ich strecke sie auch nicht im SDL-Modus. Von der Texturqualität einmal abgesehen sind beide Renderer in der Ausgabe identisch. (Okay, OpenGL ist meistens schneller. :D )

Ach, bevor ich es vergesse ...
Ich habe die Graphiken im 8-Bit Modus abgespeichert, damit SDL im Software Modus nicht ins schwitzen kommt. (8 Bit : ~400 FPS; 32 Bit : ~40 FPS)
Die Laderoutine wandelt es aber im Vorraus in ein 32 Bit Surface um und stellt sicher, dass das Bild den Alpha Kanal hat.

Könnte es vielleich daran liegen? Also an der Umwandlung?
Der Source des RenderText sieht so aus:
Code:
bool RendererGL::RenderText(Uint32 X, Uint32 Y, Uint8 Z, string Text, SDL_Color TextColor, TTF_Font *Font)
{
   if (Font == NULL)
   {
      Log.Log(0, LOG_FATAL_ERROR, "Failed to render text.");
      return false;
   }

   TImage Image;
   SDL_Surface *RenderedText;

   RenderedText = TTF_RenderText_Solid(Font, Text.c_str(), TextColor);

   SDL_Surface *conv = SDL_CreateRGBSurface(SDL_SWSURFACE, RenderedText->w, RenderedText->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
   SDL_BlitSurface(RenderedText, 0, conv, 0);

   Image.GL = SDL2GL(conv);
   Image.w = RenderedText->w;
   Image.h = RenderedText->h;

   SDL_FreeSurface(conv);
   SDL_FreeSurface(RenderedText);

   RenderImage(X, Y, Z, Image);

   UnloadImage(Image);

   return true;
}


Zuletzt geändert von aniheX am So Mai 23, 2010 12:42, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Mai 21, 2010 17:36 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Eh ja. Ohne 32Bit Surface hast du keine Chance, einen passenden Alphakanal für OpenGL zu haben. Zumindest keinen, der schöne Ergebnisse erzielt.

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Fr Mai 21, 2010 17:42 
Offline
DGL Member
Benutzeravatar

Registriert: Do Dez 29, 2005 12:28
Beiträge: 2249
Wohnort: Düsseldorf
Programmiersprache: C++, C#, Java
Wird bei dir eigentlich jedes Frame die Textur / das Surface neu erzeugt? Ich würde sagen dann musst du dich nicht über 40 fps wundern.

_________________
Yeah! :mrgreen:


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mai 23, 2010 12:40 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mär 21, 2006 20:03
Beiträge: 21
Programmiersprache: Delphi, C++
Lord Horazont hat geschrieben:
Eh ja. Ohne 32Bit Surface hast du keine Chance, einen passenden Alphakanal für OpenGL zu haben. Zumindest keinen, der schöne Ergebnisse erzielt.

Das bezweifel ich schon fast. Die Textur wird zwar als 8 Bit abgespeichert, aber sie wird intern in eine 32 Bit SDL_Surface umgewandelt.
Code:
TImage RendererGL::LoadImage(string FileName) {
   TImage Result;
   Result.Error = true;

   SDL_Surface *LoadedImage;

   LoadedImage = IMG_Load(FileName.c_str());
   if (LoadedImage == NULL) {
      Log.Log(0, LOG_ERROR, "Failed to load Image: "+FileName);
      Result.ErrorMessage = IMG_GetError();
      return Result;
   }

   // Umwandlung in ein 32 Bit Surface
   SDL_Surface *conv = SDL_CreateRGBSurface(SDL_SWSURFACE, LoadedImage->w, LoadedImage->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
   SDL_BlitSurface(LoadedImage, 0, conv, 0);

   Result.Error = false;

   Result.w = LoadedImage->w;
   Result.h = LoadedImage->h;
   Result.GL = SDL2GL(conv);

   SDL_FreeSurface(LoadedImage);
   SDL_FreeSurface(conv);

   return Result;
}
Zudem habe ich bereits ein Programm, welches im groben auf die Techniken dieser Dateien Zugreift und blendend funktioniert.

Coolcat hat geschrieben:
Wird bei dir eigentlich jedes Frame die Textur / das Surface neu erzeugt? Ich würde sagen dann musst du dich nicht über 40 fps wundern.

1.) Ja, das Font wird derzti bei jedem Rendering Vorgang neu erstellt. Darunter leidet aber vor allem OpenGL und nicht der SDL Modus.
2.) Selbst wenn ich NUR einen komplett LEEREN Hintergrund anzeige und dieser Hintergrund eine 32 Bit Graphik gewesen ist, krachen die FPS im SDL Modus auf die 40 runter. Das hat nichts mit der Schrift zu tun.

Und ja, ich optimiere das noch auf Geschwindigkeit. Also das die Texte nicht bei jedem Rendering neu erstellt werden müssen. ;)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mai 23, 2010 13:21 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Naja, aber wo nur 8 bit sind kann nicht plötzlich mehr herkommen. Informationen aus dem Nichts geht nur in unrealistischen, meist kriminalistisch angehauchten, Fernsehsendungen.

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mai 23, 2010 14:10 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mär 21, 2006 20:03
Beiträge: 21
Programmiersprache: Delphi, C++
Warum denn "Informationen aus dem Nichts"?
Die Farbpalette hat ja auch einen RGB Farbwert.
Und es gibt ja nur eine Transparentz von 0 oder 1 (Im 8 bit Modus).

Durch die Umandlung wird auf dem 32 Bit Surface nun nicht mehr der Farbindex, sondern die RGB Farben dahinter gespeichert. Und der Alpha-Kanal erhält nun einen Wert von 0 oder 255.

Es ist also kein "Aus dem Nichts", sondern "Umwandeln von Vorhandenem".


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mai 23, 2010 15:12 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Schon, aber um einen sanften Übergang von voller Abdeckung zu Hintergrund zu bekommen, reicht 0 oder 1 respektive 0 oder 255 nicht. Du brauchst auch die Zwischenwerte, und damit die stimmen müssten "Informationen aus dem Nichts" kommen.

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mai 23, 2010 16:55 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mär 21, 2006 20:03
Beiträge: 21
Programmiersprache: Delphi, C++
Ich möchte ja aber gar keine weichen Übergänge haben. Weder im SDL noch im OpenGL Modus. Ich möchte einfach nur, dass die Darstellung im OpenGL Modus exakt dem SDL Modus entspricht.
Und sowohl SDL, als auch OpenGL bekommen die gleichen Graphiken. Beide sind 8-Bit. Der einzige Unterschied ist: OpenGL sieht unschön aus, während SDL absolut perfekt läuft.

Hierbei ist es egal, ob ich 8-Bit Bilder lade und sie dann in 32 Bit umwandel, oder ob ich ein Bild dynamisch erstelle. Und ich bezweifel sehr stark, dass es am Bildformat liegt. Der Grund ist einfach, dass ich die gleiche Optik auch mit 32 Bit Graphiken habe. Es ändert sich nichts.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mai 23, 2010 16:57 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ist der Text auf den Screenshots gerendert mit SDL oder ein geladenes Bild? Wenn letzteres, vergiss diesen Post. Zeichnest du mit den Textzeichenfunktionen von SDL direkt auf deine Surface und wenn ja, welche verwendest du dafür?

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mai 23, 2010 17:34 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mär 21, 2006 20:03
Beiträge: 21
Programmiersprache: Delphi, C++
Ich verwende die SDL_TTF Erweiterung zum erstellen der Bilder.
Der Quelltext der Funktion für OpenGL sieht so aus:
Code:
bool RendererGL::RenderText(Uint32 X, Uint32 Y, Uint8 Z, string Text, SDL_Color TextColor, TTF_Font *Font, TAlign Align)
{
   if (Font == NULL)
   {
      Log.Log(0, LOG_FATAL_ERROR, "Failed to render text.");
      return false;
   }

   TImage Image;
   SDL_Surface *RenderedText;

   RenderedText = TTF_RenderText_Solid(Font, Text.c_str(), TextColor);

   SDL_Surface *conv = SDL_CreateRGBSurface(SDL_SWSURFACE, RenderedText->w, RenderedText->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
   SDL_BlitSurface(RenderedText, 0, conv, 0);

   Image.GL = SDL2GL(conv);
   Image.w = RenderedText->w;
   Image.h = RenderedText->h;

   SDL_FreeSurface(conv);
   SDL_FreeSurface(RenderedText);

   switch ( Align )
   {
      case ALIGN_None:
         RenderImage(X, Y, Z, Image);
         break;
      case ALIGN_Left:
         RenderImage(0, Y, Z, Image);
         break;
      case ALIGN_Right:
         RenderImage(rWidth-Image.w, Y, Z, Image);
         break;
      case ALIGN_Center:
         RenderImage( (rWidth-Image.w) / 2, Y, Z, Image);
         break;
      case ALIGN_ScreenCenter:
         RenderImage( (rWidth-Image.w) / 2, (rHeight-Image.h) / 2, Z, Image);
         break;
   }

   UnloadImage(Image);

   return true;
}


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mai 23, 2010 18:25 
Offline
DGL Member

Registriert: Fr Okt 03, 2008 13:32
Beiträge: 367
Ich kenn' mich mit SDL nicht so aus, aber mit OpenGL einigermaßen.

Erstmal (wie bereits gesagt) Textur in jedem Frame neu erzeugen ist sehr schlecht.

Dann hab' ich auch noch eine Frage: Hat "Image" vom Typ "TImage", was an verschiedenen Stellen verwendet wird, Zweierpotenzen als Abmessung? Bzw. hat "RenderedText" in der Funktion "RenderText" ebensolche?
Wenn nein, könnte das den schwarzen Rand erklären. Nur wenige Grafikkarten unterstützen npot-Texturen, weshalb man immer solche mit Höhe und Breite entsprechend den Zweierpotenzen benutzen sollte. Wenn SDL nun deshalb automatisch deine Textur streckt um die Abmessungen auf die nächste Potenz zu bringen, wird logischerweise interpoliert. Dann entstehen wieder solche Probleme mit halbtransparenten Teilen wie sie bereits beschrieben wurden. Da hilft dann auch kein GL_NEAREST weil der Fehler quasi schon in der Textur vorhanden ist.
Eine mögliche Lösung ist die überschüssigen Texel mit Transparenz zu füllen und die Texturkoordinaten anzupassen. Falls dann noch die Ränder kommen nochmal GL_NEAREST probieren (was sowieso schneller als GL_LINEAR sein sollte). Und falls dann noch die Ränder kommen, hab' ich mich geirrt und es liegt an etwas gänzlich anderem.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: So Mai 23, 2010 19:26 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mär 21, 2006 20:03
Beiträge: 21
Programmiersprache: Delphi, C++
Ich habe es ausprobiert und du hast recht. Nachdem ich die Maße des Characters auf eine Potenz von zwei vergörßert hatte, funktionierte alles einwandfrei.
Ich ändere noch die Text-Funktion damit es auf eine Potenz von zwei erweitert. Danke nochmal. =)


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 16 Beiträge ]  Gehe zu Seite 1, 2  Nächste
Foren-Übersicht » Programmierung » Einsteiger-Fragen


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 6 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.010s | 16 Queries | GZIP : On ]