PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Der tägliche "Wahnsinn" mit OpenGL


Asmodeus
2006-01-22, 12:03:20
Ich habe folgende Beobachtung gemacht, die ich mir noch nicht erklären kann:
Man lege sich ein Unsigned Byte Array mit 12 Einträgen an. Die ersten 6 Einträge fülle man jeweils mit dem Wert 0 die letzten 6 Einträge fülle man jeweils mit dem Wert 255. Somt hat man im Grunde eine 2x2 Pixel RGB-Textur, wobei die ersten beiden Pixel schwarz und die letzten beiden Pixel weiß sind. Dieses Array übergibt man nun an OpenGL als 2D-RGB-Textur mit GL_NEAREST als Filterparameter. Im Hinterkopf behalten wir, intern werden RGB Texturen ja immer als RGBA abgespeichert. Nun zeichnen wir auf den Bildschirm ein simples Quad mit Texturkoordinaten in X- und Y-Richtung von 0.0 bis 1.0. und legen die 2x2 RGB-Textur darüber.

Und nun die Frage, wie viele weiße und wie viele schwarze "Bereiche" sehe ich auf meinem Quad. Ich habe immer angenommen, ich sehe dann 2 schwarze "Bereiche" und 2 weiße "Bereiche". Aber stattdessen sehe ich 2 schwarze "Bereiche", nur einen weißen "Bereich" und dafür, welch Wunder, noch einen roten "Bereich". Hmm, liege ich nun völlig falsch, wenn ich einfach mal behaupte, das ist so nicht ganz korrekt?

Gruss, Carsten.

zeckensack
2006-01-22, 12:41:35
1)Wrap-Modi? (wg border)
2)Ganz sicher dass du den Speicher nicht aus Versehen selbst kaputtmachst, bevor du die Textur erzeugst?
Es kann bei solch obskuren Fehlern sicher nicht schaden direkt vor dem TexImage2D folgende Zeilen einzufügen:assert(wuzzah[6]==255);
assert(wuzzah[7]==255);
assert(wuzzah[8]==255);
assert(wuzzah[9]==0);
assert(wuzzah[10]==0);
assert(wuzzah[11]==0);=)
3)Dein TexImage2D-Aufruf sollte so enden:...,GL_RGB,GL_UNSIGNED_BYTE,wuzzah);

Mehr fällt mir dazu jetzt nicht ein. Oder Moment ... doch: "Normal ist das nicht" :D

Asmodeus
2006-01-22, 13:01:22
Ja, habe ich alles auch schon mehrmals überprüft, man sucht aus Erfahrung die Fehler ja erst mal bei sich selbst ;). Ich hab mir im Debugmodus den Speicherbereich des Arrays angesehen, damit da auch ja nichts falsch läuft. Dann übergebe ich das Array mit glTexImage2D(GL_TEXTURE_2D,0,GL_RGB8,2,2,0,GL_RGB,GL_UNSIGNED_BYTE,Buffer) , dann setzte ich den Inhalt meines gesamtes Arrays auf 0 zurück und dann lese ich sofort mit glGetTexImage(GL_TEXTURE_2D,0,GL_RGB,GL_RGB,GL_UNSIGNED_BYTE,Buffer) die Werte wieder in das Array zurück und siehe da, das 3. Pixel ist nicht mehr weiß sondern rot.

Erweitere ich mein Array von RGB auf RGBA und übergebe es dann als RGBA-Textur, dann stimmt alles. Oder wenn die Texturauflösung größer als 2x2 ist und ich mit RGB arbeite, dann stimmt auch alles wieder. Nur bei der Auflösung 2x2 und RGB tritt dieser Fehler auf.

Gruss, Carsten.

Expandable
2006-01-22, 13:08:29
glTexImage2D(GL_TEXTURE_2D,0,GL_RGB8,2,2,0,GL_RGB,GL_UNSIGNED_BYTE,Buffer)


Wieso verwendest Du GL_RGB8 anstatt GL_RGB? :confused: Oder ist das das gleiche?

Asmodeus
2006-01-22, 13:20:09
Wieso verwendest Du GL_RGB8 anstatt GL_RGB? :confused: Oder ist das das gleiche?

Wenn ich mich richtig erinnere, dann ist GL_RGB8 ein sogenanntes "internal texture format" und GL_RGB das dazügehörige "base internal format". Und mit GL_RGB8 spezifiziert man eben, dass genau 8 Bit für den R-,G- und B-Kanal verwendet werden sollen. Mit GL_RGB wird meines Wissens nach standardmäßig aber auch 8 Bit pro Farbkanal verwendet, somit ist eigentlich beides richtig.

Gruss, Carsten.

Expandable
2006-01-22, 13:24:29
Also bei mir funktioniert's so absolut korrekt (d.h., das Quad hat ist halbiert in eine weiße und eine schwarze Fläche):


glGenTextures(1, &m_id);
glBindTexture(GL_TEXTURE_2D, m_id);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

unsigned char *arr = new unsigned char[12];
arr[0] = 0;
arr[1] = 0;
arr[2] = 0;

arr[3] = 0;
arr[4] = 0;
arr[5] = 0;

arr[6] = 255;
arr[7] = 255;
arr[8] = 255;

arr[9] = 255;
arr[10] = 255;
arr[11] = 255;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, arr);

Asmodeus
2006-01-22, 13:28:37
Und mein Programmcode ist absolut identisch zu Deinem und bei mir funktioniert es nicht. :confused:
Welche Grafikkarte und welchen Treiber verwendest Du, wenn ich mal fragen darf?

Gruss, Carsten.

Expandable
2006-01-22, 13:32:00
GeForce 6800GT 256 MByte, Treiber 77.72

Wobei ich das gerade nicht verstehe... wenn ich das Array so definiere:

unsigned char *arr = new unsigned char[12];
arr[0] = 0;
arr[1] = 0;
arr[2] = 0;

arr[3] = 255;
arr[4] = 255;
arr[5] = 255;

arr[6] = 0;
arr[7] = 0;
arr[8] = 0;

arr[9] = 255;
arr[10] = 255;
arr[11] = 255;


Dann müsste ich doch einen schwarzen, einen weißen, wieder einen schwarzen und wieder einen weißen Pixel haben, oder? Komischerweise hab ich dann aber keine Schachbrettstruktur, sondern eine weiße, eine schwarze, eine fast weiße (leichter Rotstich) und eine HELLBLAUE Fläche!!! Hää?

Nachtrag: Das wird wohl ein Treiberbug sein - denn wenn ich obige "Textur" im RGBA-Format erstelle, habe ich ein korrektes Schachbrettmuster...

Asmodeus
2006-01-22, 13:44:41
Bingo, das ist genau das gleiche Fehlverhalten. Also liegts wohl nicht an mir :D. Nur woran liegt es dann, sowas kann doch eigentlich kein Treiberbug sein, oder?

Gruss, Carsten.

ScottManDeath
2006-01-22, 14:48:05
Das Alignment beim Textransfer ist Standard 4 Bytes ...... klappt also, wenn man RGBA hat.

glPixelstore solltet ihr aufrufen, und es aus 1 Byte setzen, wenn man alle 3 Bytes einen neuen Pixel anfangen lässt.

Asmodeus
2006-01-22, 15:27:03
Das Alignment beim Textransfer ist Standard 4 Bytes ...... klappt also, wenn man RGBA hat.

glPixelstore solltet ihr aufrufen, und es aus 1 Byte setzen, wenn man alle 3 Bytes einen neuen Pixel anfangen lässt.

Boing, mit diesem dezenten Hinweis hast Du natürlich absolut recht. ;)

Gruss, Carsten.

Expandable
2006-01-22, 17:20:44
Versteh ich jetzt nicht. Was hat das Alignment damit zu tun? Das Array wird im Speicher wahrscheinlich auf 16 Bytes "aufgerundet", aber das sollte doch egal sein, wenn OpenGL nur die ersten 12 liest?

Xmas
2006-01-22, 17:40:32
Versteh ich jetzt nicht. Was hat das Alignment damit zu tun? Das Array wird im Speicher wahrscheinlich auf 16 Bytes "aufgerundet", aber das sollte doch egal sein, wenn OpenGL nur die ersten 12 liest?
GL_PACK_ALIGNMENT
Specifies the alignment requirements for the start of each pixel row in memory. The allowable values are 1 (byte-alignment), 2 (rows aligned to even-numbered bytes), 4 (word alignment), and 8 (rows start on double-word boundaries).
Der Treiber liest eben nicht nur 12 Bytes, sondern liest die ersten 6 für die erste Zeile, überspringt dann 2 (damit die zweite Zeile mit Word Alignment beginnt), und liest wieder 6 Bytes. Insgesamt also 14. Darum auch die seltsamen Farben:
(0 0 0 [schwarz]) (255 255 255 [weiß]) 0 0
(0 255 255 [türkis]) (255 x x [irgendwas mit rot])

Expandable
2006-01-22, 18:15:55
Hmm... merkwürdiges Verhalten. Aber danke für die Erklärung.

zeckensack
2006-01-23, 03:10:33
Oh phuq ja! Wie konnte ich das nur vergessen.

Ich hab's mir zur Gewohnheit gemacht, auf einen frischen GL-Kontext mit als erstes bei der Initialisierung immer dies zu machen: glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glPixelStorei(GL_PACK_ALIGNMENT,1);Die Gewohnheit ist so tief verwurzelt, dass ich schon garnicht mehr darüber nachdenke :crazy:

muhkuh_rs
2006-01-24, 10:53:18
Eigentlich sind die Zeilen von Bildern, die man mit diversen Bibliotheken lädt oder an eine rendering-API (z.B. GDI), standardmäßig immer 4byte aligned. Bei Texturen fällt das normalerweise kaum auf, da sie RGBA, irgendeine Zweierpotenz oder durch 4 teilbare Bildschirmauflösung sind und damit ist jede Zeile i.d.R. durch 4 teilbar.

micki
2006-01-24, 13:00:41
für ogl sind die kleinsten erlaubte texturen 64x64 oder nicht?

muhkuh_rs
2006-01-24, 14:17:39
für ogl sind die kleinsten erlaubte texturen 64x64 oder nicht?

Letzteres.

micki
2006-01-24, 16:22:44
Letzteres.
schön dass es abgeschsft wurde, fand es selstam!!1

Coda
2006-01-24, 17:01:54
Ich glaube du hast da was falsch verstanden. Evtl. müssen die Grafikkarten minimal 64x64 können, das heißt aber nicht dass man keine 2x2 Texturen verwenden darf.

Expandable
2006-03-01, 17:46:49
Ich muss den Thread jetzt mal schnell entführen. Ich habe nämlich ein Problem, dass mich langsam in den Wahnsinn treibt.

Ich habe eine 256*256 24 bit TGA-Textur. Diese Lade ich mit folgendem Code:


#include "TextureHandler.h"
#include <fstream>

void TextureHandler::LoadTextures()
{
for (std::map<std::string, GLuint>::const_iterator i = m_texTable.begin(); i != m_texTable.end(); ++i)
{
if (LoadTexture(i->first, i->second) == false)
MessageBox(NULL, std::string("Unable to load texture \"" + i->first + "\"").c_str(), "Texture not found", NULL);
}
}

bool TextureHandler::LoadTexture(std::string textureName, GLuint texID)
{
GLshort width;
GLshort height;
GLubyte *texData = 0;

std::ifstream textureFile(std::string(textureName + ".tga").c_str(), std::ios::binary | std::ios::in);
if (!textureFile) return false;

// We don't need the first two bytes
textureFile.ignore(2);

// Read the image type
GLubyte imageType;
textureFile.read(reinterpret_cast<char *>(&imageType), 1);

// If imageTypeCode is not 2 (= uncompressed RGB image) or 3 (=uncompressed black and white image), abort
if (imageType != 2 && imageType != 3)
{
textureFile.close();
return false;
}

// We don't need the next 9 bytes
textureFile.ignore(9);

// Read width, height, bitdepth
textureFile.read(reinterpret_cast<char *>(&width), sizeof(width));
textureFile.read(reinterpret_cast<char *>(&height), sizeof(height));
GLubyte bitsPerPixel;
textureFile.read(reinterpret_cast<char *>(&bitsPerPixel), sizeof(bitsPerPixel));

// We don't need the next byte
textureFile.ignore(1);

// Only 24- and 32-bits TGAs are supported right now
if (bitsPerPixel == 32 || bitsPerPixel == 24)
{
GLint numOfChannels = bitsPerPixel / 8;
GLint imgSize = numOfChannels * width * height;

texData = new GLubyte[imgSize];
textureFile.get(reinterpret_cast<char *>(texData), imgSize);

for (int i = 0; i < imgSize - 1; i += numOfChannels)
std::swap(texData[i], texData[i + 1]);
}
else
{
textureFile.close();
return false;
}

glBindTexture(GL_TEXTURE_2D, texID);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

GLenum texFormat = bitsPerPixel == 32 ? GL_RGBA : GL_RGB;

gluBuild2DMipmaps(GL_TEXTURE_2D, texFormat, width, height, texFormat, GL_UNSIGNED_BYTE, texData);

delete[] texData;
textureFile.close();

return true;
}


Die Textur wird richtig angezeigt, alles wunderbar. Texturkoordinaten stimmen. Ein Aufruf von

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);

hilft auch nicht.

Das Problem ist nun: Bei manchen (!) Texturen, z.B. oben genannte 24 bit 256*256 tga-Textur, gibt es Farbprobleme. Diese Textur hat (im Paint Shop Pro betrachtet) oben rechts plötzlich ein paar merkwürdig bunte Pixel in meinem Programm, die sie in PSP nicht hat. Interessanterweise sind die immer da. Also wenn ich die Textur auf 32x32 verkleinere, sind die farbigen Pixel an der gleichen Stelle, nur größer. Wenn ich die Textur auf 2048x2048 vergrößere, sind die Pixel an der gleichen Stelle, nur viel kleiner.

Manche Texturen haben keine Falschfarben. Andere hingegen sind komplett merkwürdig bunt. Hä? Was übersehe ich da?

Danke schonmal ;)

Asmodeus
2006-03-01, 18:03:05
Mir ist im Zusammenhang mit TGA-Dateien bisher mal folgende Unregelmäßigkeit aufgefallen: Es gibt Grafikprogramme, die TGA-Dateien mit einem 1 Byte größeren Header erzeugen als andere Grafikprogramme. Darauf muss man dann achten, sonst können eben die Farben komplett falsch aussehen. Ob diese Beobachtung nun bei Deinem Problem eine Rolle spielen könnte, kann ich natürlich leider nicht sagen.

Gruss, Carsten.

Expandable
2006-03-01, 18:27:48
Wo fügen die das Byte denn ein? Ich hab das letzte ignore mal auf 2 gesetzt, geändert hat sich aber nix (und nachdem ja alle Informationen korrekt aus dem Header ausgelesen werden, muss es vorher ja eigentlich auch stimmen)...

Asmodeus
2006-03-01, 22:37:54
Wo fügen die das Byte denn ein? Ich hab das letzte ignore mal auf 2 gesetzt, geändert hat sich aber nix (und nachdem ja alle Informationen korrekt aus dem Header ausgelesen werden, muss es vorher ja eigentlich auch stimmen)...

Hmm, da kann ich mich beim besten Willen nicht mehr daran erinnern, wo im Header das zusätzliche Byte vorkam. Hast Du mal Test-TGA-Dateien erzeugt, mit markanten Farbmustern/-übergängen, so dass Du genau weißt, was drinstehen müsste. Dann einfach mal den Inhalt als Textur binden, und wieder mit glGetTexImage() in einen Buffer lesen und vergleichen, ob noch der erwartete Inhalt drin steht. Denn irgendwie kann ich mir nur vorstellen, dass eine Verschiebung der Bytes vorliegt, und dadurch die Farbinformationen etwas falsch sind.

Gruss, Carsten.

Coda
2006-03-01, 22:42:15
Hast du die RLE-Kompression bedacht?

Expandable
2006-03-01, 23:17:13
Es wird keine Kompression verwendet. Die meisten Texturen werden ja auch richtig angezeigt, nur manche gar nicht und die eine eben teilweise falsch (vielleicht 5 oder 6 Pixel von 256x256 Pixel, die eine falsche Farbe haben)...

Expandable
2006-03-02, 14:16:20
Okay, ich habe jetzt herausgefunden, warum manche Texturen nicht richtig funktioniert haben - und zwar haben manche noch ein "ID Feld" vor den Bildinformationen, das natürlich auch übersprungen werden muss. Jetzt habe ich aber ein anderes Problem. Und zwar ist bei ALLEN Texturen der letzte Pixel (d.h. der ganz unten, rechts) in einer ganz bestimmten Farbe - die Farbe ist bei allen Texturen gleich... irgendeine Idee, woran das liegen könnte? Hier nochmal der verbesserte Textur-Lade-Code:


bool TextureHandler::LoadTexture(std::string textureName, GLuint texID)
{
GLshort width;
GLshort height;
GLubyte *texData = 0;

std::ifstream textureFile(std::string(textureName + ".tga").c_str(), std::ios::binary | std::ios::in);
if (!textureFile) return false;

// Get the size of the ID field
GLubyte idSize;
textureFile.read(reinterpret_cast<char *>(&idSize), sizeof(idSize));

textureFile.ignore(1);

// Read the image type
GLubyte imageType;
textureFile.read(reinterpret_cast<char *>(&imageType), sizeof(imageType));

// If imageTypeCode is not 2 (= uncompressed BGR image) or 3 (= uncompressed grey scale image), abort
if (imageType != 2 && imageType != 3)
{
textureFile.close();
return false;
}

textureFile.ignore(9);

// Read width, height, bitdepth
textureFile.read(reinterpret_cast<char *>(&width), sizeof(width));
textureFile.read(reinterpret_cast<char *>(&height), sizeof(height));
GLubyte bitsPerPixel;
textureFile.read(reinterpret_cast<char *>(&bitsPerPixel), sizeof(bitsPerPixel));

// Skip the next (idSize + 1) bytes
textureFile.ignore(idSize + 1);

// Only 24- and 32-bits TGAs are supported
if (bitsPerPixel == 32 || bitsPerPixel == 24)
{
GLint numOfChannels = bitsPerPixel / 8;
GLint imgSize = numOfChannels * width * height;

texData = new GLubyte[imgSize];
textureFile.get(reinterpret_cast<char *>(texData), imgSize);

for (int i = 0; i < imgSize - 2; i += numOfChannels)
std::swap(texData[i], texData[i + 2]);
}
else
{
textureFile.close();
return false;
}

glBindTexture(GL_TEXTURE_2D, texID);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

GLenum texFormat = bitsPerPixel == 32 ? GL_RGBA : GL_RGB;

gluBuild2DMipmaps(GL_TEXTURE_2D, texFormat, width, height, texFormat, GL_UNSIGNED_BYTE, texData);

delete[] texData;
textureFile.close();

return true;
}

Coda
2006-03-02, 16:44:03
Uhm mal ne anderer Vorschlag: Warum nimmst du nicht einfach z.B. DevIL (http://openil.sourceforge.net/)?

Expandable
2006-03-02, 17:48:50
NEEEEINNN! Ich könnt mich Ohrfeigen! Nach stundenlanger Fehlersuche habe ich bemerkt, dass ich die Textur mit textureFile.GET() anstatt textureFile.READ() ausgelesen habe :wall:

Jetzt geht's einwandfrei... so ein Mist... überall hab ich read, nur DA NICHT... ich glaub's ja nicht...

Dennoch danke für Eure Hilfen ;)