Farbfehler in OpenGL 2D-Textur
-
Sodele Leute,
ich bin inzwischen von DrawPixel auf Texturen umgestiegen, da nun einige Sachen geändert/angepasst wurden.
Bei der Verwendung von einer Textur ist jetzt allerdings ein Problem aufgetaucht.
Ich hab mit Gimp eine 750x750 BMP erstellt, lese diese ein und packe dies dann in eine Textur, welche ich dann zur Darstellung nutze.
Das Problem besteht jetzt darin, dass die farbige Schrift in der Textur ein Streifenmuster ausbildet, welches auch noch von der Skalierung des Quads auf dem Bildschirm abhängt
Ich hab wirklich keine Ahnung, woran das liegen könnte...
Dazu habe ich an 2 Seiten noch einen Farbsaum von einem Pixel breite...
Sieht man alles auf dem Bild. Ich wäre über Tips sehr dankbar!
http://image-upload.de/thumb/6yo234/caaeb2196c.png
http://image-upload.de/thumb/SSictX/37e4bb789f.png
-
Ich denk mal GL_CLAMP_TO_EDGE wird dir bei den Rändern helfen.
Was die Probleme mitten im Bild angeht, so sind das wohl Artefakte die durch das bilineare Filtering bedingt sind. Möglicherweise hilft dir da Mip-Mapping.
-
Was mich wundert ist halt, dass das Problem mit anderen BMP-Files nicht auftaucht...
Vor allem, die Schrift ist ja entweder Rot (255,0,0) oder Blau(0,0,255). Ich versteh nicht, wo da die ganzen Mischfarben herkommen.
Irgendwas läuft da mit dem Mapping habe ich den Eindruck schief.
Wenn ich die größe der Textur ändere hab ich aber immer das gleiche Problem.. -.-
Btw. übergebe folgende Struktur für die Textur:
GLfloat pixels[HOEHE][BREITE][3];
Zu den Mipmaps:
Wie war die Vorgehensweise hierzu nochmals?EDIT:
GL_CLAMP_TO_EDGE hat nichts gebracht. Sehe keinen Unterschied.
-
Eventuell nen Fehler beim einlesen?
Wie liest du die Datei denn? Hast selber was gebacken?
Ich würde mal FreeImage verwenden und schauen obs dann auch auftritt, falls deine Funktion selber gemacht ist. Und eventuell auch nen PNG mit Alpha Channel.Und zeig mal den Code wo du die Textur mit OpenGL erstellst.
-
Nimm mal eine Texturgröße von "Power of 2"
-
dgdgdgd schrieb:
Nimm mal eine Texturgröße von "Power of 2"
Mit 2^x tritt das selbe Problem auf. Das war gleich eine der ersten Sachen, die ich geprüft habe.
Sodel, dann hier der Code fürs lesen der BMPs (ja ich weiß, nur für 24Bit BMPs brauchbar).
#ifndef BMP_READER_H #define BMP_READER_H #if defined(_WIN32) #include "stdafx.h" #include <Windows.h> #endif #include <iostream> #include <fstream> //word == unsigned short //dword == unsigned long //http://www.datasource.de/programmierung/tab33_cppdatentypen.html typedef struct BMPFILEHEADER{ unsigned short bfType; //ASCII-Zeichenkette "BM" (Dezimalwert 19778) unsigned long bfSize; //Größe der BMP-Datei in Byte (unzuverlässig) unsigned long bfReserved; //0 unsigned long bfOffBits; //Offset der Bilddaten in Byte vom Beginn der Datei an } BMPFILEHEADER; typedef struct BMPINFOHEADER{ unsigned long biSize; //40 (Größe der BITMAPINFOHEADER-Struktur in Byte) long biWidth; //Breite der Bitmap in Pixel. long biHeight; //Der Betrag gibt die Höhe der Bitmap in Pixel an. // Ist der Wert positiv, so ist die Bitmap eine sogenannte "bottom-up"-Bitmap (die Bilddaten beginnen mit der untersten und enden mit der obersten Bildzeile). Dies ist die gebräuchlichste Variante. // Ist der Wert negativ, so ist die Bitmap eine "top-down"-Bitmap (die Bilddaten beginnen mit der obersten und enden mit der untersten Bildzeile). unsigned short biPlanes; //1 (Stand in einigen älteren Formaten wie PCX für die Anzahl der Farbebenen, wird aber für BMP nicht verwendet) unsigned short biBitCount; //Gibt die Farbtiefe der Bitmap in bpp an; muss einer der folgenden Werte sein: 1, 4, 8, 16, 24 oder 32. Bei 1, 4 und 8 bpp sind die Farben indiziert. 16 und 32 bpp sind ungebräuchlich. unsigned long biCompression; //Einer der folgenden Werte: // 0 (BI_RGB): Bilddaten sind unkomprimiert. // 1 (BI_RLE8): Bilddaten sind lauflängenkodiert für 8 bpp. Nur erlaubt wenn biBitCount=8 und biHeight positiv. // 2 (BI_RLE4): Bilddaten sind lauflängenkodiert für 4 bpp. Nur erlaubt wenn biBitCount=4 und biHeight positiv. // 3 (BI_BITFIELDS): Bilddaten sind unkomprimiert und benutzerdefiniert (mittels Farbmasken) kodiert. Nur erlaubt wenn biBitCount=16 oder 32; ungebräuchlich. unsigned long biSizeImage; //Wenn biCompression=BI_RGB: Entweder 0 oder die Größe der Bilddaten in Byte. //Ansonsten: Größe der Bilddaten in Byte. long biXPelsPerMeter; //Horizontale Auflösung des Zielausgabegerätes in Pixel pro Meter; wird aber für BMP-Dateien meistens auf 0 gesetzt. long biYPelsPerMeter; //Vertikale Auflösung des Zielausgabegerätes in Pixel pro Meter; wird aber für BMP-Dateien meistens auf 0 gesetzt. unsigned long biClrUsed; // Wenn biBitCount=1: 0. // Wenn biBitCount=4 oder 8: die Anzahl der Einträge der Farbtabelle; 0 bedeutet die maximale Anzahl (16 bzw. 256). // Ansonsten: Die Anzahl der Einträge der Farbtabelle (0=keine Farbtabelle). Auch wenn sie in diesem Fall nicht notwendig ist, kann dennoch eine für die Farbquantisierung empfohlene Farbtabelle angegeben werden. unsigned long biClrImportant; // Wenn biBitCount=1, 4 oder 8: Die Anzahl sämtlicher im Bild verwendeten Farben; 0 bedeutet alle Farben der Farbtabelle. // Ansonsten: // Wenn eine Farbtabelle vorhanden ist und diese sämtliche im Bild verwendeten Farben enthält: deren Anzahl. // Ansonsten: 0. }BMPINFOHEADER; unsigned char* loadBMPFile(char *filename); BMPINFOHEADER loadBMPInfoHeader(char *filename); void initBild(unsigned char* bild, char* filename); //NOTE: The arangement of the data have to be BGR (NOT! RGB) int writeBMPfile(char* filename, long biWidth, long biHeight, unsigned char* data); #endif
#include "stdafx.h" #include "bmp-reader.h" using namespace std; void initBild(unsigned char* bild, char* filename){ BMPINFOHEADER info; info=loadBMPInfoHeader(filename); if(info.biSizeImage!=0){ bild=new unsigned char [info.biSizeImage]; } else{ int size; size=info.biWidth*3; if(size%4==0){ size*=info.biHeight; } else{ size+=4-(info.biWidth%4); size*=info.biHeight; } cout<<"size of the image:"<<size<<endl; bild=new unsigned char[size]; } } unsigned char *loadBMPFile(char *filename){ fstream bmpfile; BMPFILEHEADER bmpFileHeader; BMPINFOHEADER info; unsigned char *bmpImage; int imageIdx=0; unsigned char tempRGB; cout<<"filename:"<<filename<<endl; bmpfile.open(filename, ios::in|ios::binary); if(bmpfile.good()){ cout<<"lese aus Datei: "<<filename<<endl; bmpfile.read(reinterpret_cast<char*>(&bmpFileHeader.bfType), sizeof(unsigned short)); bmpfile.read(reinterpret_cast<char*>(&bmpFileHeader.bfSize), sizeof(unsigned long)); bmpfile.read(reinterpret_cast<char*>(&bmpFileHeader.bfReserved), sizeof(unsigned long)); bmpfile.read(reinterpret_cast<char*>(&bmpFileHeader.bfOffBits), sizeof(unsigned long)); bmpfile.read((char*)&info,sizeof(BMPINFOHEADER)); //Move the Data-Pointer to the next read position bmpfile.seekg(bmpFileHeader.bfOffBits, ios::beg); //allocate memory for the bmp image data int size; if(info.biSizeImage!=0){ size=info.biSizeImage; } else{ size=info.biWidth*3; if(size%4==0){ size*=info.biHeight; } else{ size+=4-(info.biWidth%4); size*=info.biHeight; } } bmpImage = new unsigned char [size]; bmpfile.read(reinterpret_cast<char*>(bmpImage), size); //swap the r and b values, because BMP is BGR, but we want RGB for(imageIdx=0; imageIdx<size; imageIdx+=3){ tempRGB=bmpImage[imageIdx]; bmpImage[imageIdx]=bmpImage[imageIdx+2]; bmpImage[imageIdx+2]=tempRGB; } bmpfile.close(); cout<<"Auslesen beendet. Datei wurde geschlossen"<<endl; } else{ cout<<"FEHLER! Kann nicht aus Datei lesen"<<endl; } /* for(int i=0; i<info.biSizeImage; i+=3){ if(float(bmpImage[i])!=205 || float(bmpImage[i+1])!=205 || float(bmpImage[i+2])!=205){ cout<<float(bmpImage[i])<<endl; cout<<float(bmpImage[i+1])<<endl; cout<<float(bmpImage[i+2])<<endl; } } */ return bmpImage; } BMPINFOHEADER loadBMPInfoHeader(char *filename){ fstream bmpfile; BMPFILEHEADER bmpFileHeader; BMPINFOHEADER info; bmpfile.open(filename, ios::in|ios::binary); if(bmpfile.good()){ cout<<"lese aus Datei"<<endl; bmpfile.read(reinterpret_cast<char*>(&bmpFileHeader.bfType), sizeof(unsigned short)); bmpfile.read(reinterpret_cast<char*>(&bmpFileHeader.bfSize), sizeof(unsigned long)); bmpfile.read(reinterpret_cast<char*>(&bmpFileHeader.bfReserved), sizeof(unsigned long)); bmpfile.read(reinterpret_cast<char*>(&bmpFileHeader.bfOffBits), sizeof(unsigned long)); cout<<"Der File-Header enthält folgende Daten:"<<endl; cout<<"bfType:" <<bmpFileHeader.bfType<<endl; cout<<"bfSize:" <<bmpFileHeader.bfSize<<endl; cout<<"bfReserved:" <<bmpFileHeader.bfReserved<<endl; cout<<"bfOffBits:" <<bmpFileHeader.bfOffBits<<endl; bmpfile.read(reinterpret_cast<char*>(&info),sizeof(BMPINFOHEADER)); cout<<"Der Info-Header enthält folgende Daten:"<<endl; cout<<"biSize:"<<info.biSize<<endl; cout<<"biWidth:"<<info.biWidth<<endl; cout<<"biHeight:"<<info.biHeight<<endl; cout<<"biPlanes:"<<info.biPlanes<<endl; cout<<"biBitCount:"<<info.biBitCount<<endl; cout<<"biCompression:"<<info.biCompression<<endl; cout<<"biSizeImage:"<<info.biSizeImage<<endl; cout<<"biXPelsPerMeter:"<<info.biXPelsPerMeter<<endl; cout<<"biYPelsPerMeter:"<<info.biYPelsPerMeter<<endl; cout<<"biClrUsed:"<<info.biClrUsed<<endl; cout<<"biClrImportant:"<<info.biClrImportant<<endl; return info; } else{ cout<<"FEHLER: BMP:"<<filename<<" kann nicht geöffnet werden"<<endl; } } int writeBMPfile(char* filename, long biWidth, long biHeight, unsigned char* data){ fstream bmpfile; BMPFILEHEADER fileheader; BMPINFOHEADER infoheader; //calculate if a line is a multiple of 4 bytes int alignbytes; alignbytes=(biWidth*3)%4; //vorbereiten der Header fileheader.bfType=19778; fileheader.bfSize=54+biHeight*(biWidth*3+alignbytes); fileheader.bfReserved=0; fileheader.bfOffBits=54; //this is a static value because, we don´t use colour table infoheader.biSize=40; infoheader.biWidth=biWidth; infoheader.biHeight=biHeight; infoheader.biPlanes=1; infoheader.biBitCount=24; infoheader.biCompression=0; infoheader.biSizeImage=0;//0 because this value is not save infoheader.biXPelsPerMeter=0; infoheader.biYPelsPerMeter=0; infoheader.biClrUsed=0; infoheader.biClrImportant=0; bmpfile.open(filename, ios::out|ios::binary); if(bmpfile.good()){ //write fileheader bmpfile.write(reinterpret_cast<char*>(&fileheader.bfType), sizeof(unsigned short)); bmpfile.write(reinterpret_cast<char*>(&fileheader.bfSize), sizeof(unsigned long)); bmpfile.write(reinterpret_cast<char*>(&fileheader.bfReserved), sizeof(unsigned long)); bmpfile.write(reinterpret_cast<char*>(&fileheader.bfOffBits), sizeof(unsigned long)); //write infoheader bmpfile.write(reinterpret_cast<char*>(&infoheader.biSize), sizeof(unsigned long)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biWidth), sizeof(long)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biHeight), sizeof(long)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biPlanes), sizeof(unsigned short)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biBitCount), sizeof(unsigned short)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biCompression), sizeof(unsigned long)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biSizeImage), sizeof(unsigned long)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biXPelsPerMeter), sizeof(long)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biYPelsPerMeter), sizeof(long)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biClrUsed), sizeof(unsigned long)); bmpfile.write(reinterpret_cast<char*>(&infoheader.biClrImportant), sizeof(unsigned long)); //write image data //remember, that the data in one line allways have to be a multiple of 4 bytes unsigned char tempRGB; unsigned char* writebuffer=new unsigned char[biHeight*(biWidth*3+alignbytes)]; int wpos;//writepos for(int i=0; i<infoheader.biHeight; i++){ for(int j=0; j<infoheader.biWidth*3; j+=3){ //we have to reorder, because BMP file need BGE instead of RGB wpos=i*infoheader.biWidth*3+j; writebuffer[wpos+0]=data[wpos+2];//B writebuffer[wpos+1]=data[wpos+1];//G writebuffer[wpos+2]=data[wpos+0];//R } for(int i=0; i<alignbytes; i++){ writebuffer[wpos+3+i]='0'; } } //write the bufferd data into the file on disk. Buffer the write improve the performance by a factor 5! bmpfile.write(reinterpret_cast<char*>(writebuffer), sizeof(char)*biHeight*(biWidth*3+alignbytes));//B bmpfile.close(); if(!bmpfile.good()){ cout<<"FEHLER:"<<filename<<" konnte nicht geschlossen werden"<<endl; return -2; } } else{ cout<<"FEHLER:"<<filename<<" konnte nicht geöffnet werden"<<endl; return -1; } return 1; }
Und hier noch, wie ich das ganze verwende:
BMPInit(){ //erstellen des bmp-arrays pictures = new bmp_file[10]; //Einlesen der BMP char** filename= new char* [num_pics]; char temp[80]; for(int i=0; i<num_pics; i++){ filename[i]= new char[256]; sprintf(temp, "BMP_%i.bmp", i); strcpy(filename[i], temp); } //sprintf(temp, " %f", temp_f); //strcat(w_FPS, temp); for(int i=0; i<num_pics; i++){ pictures[i].info=loadBMPInfoHeader(filename[i]); initBild(pictures[i].bild, filename[i]); pictures[i].bild=loadBMPFile(filename[i]); } }
GLfloat pixels[HOEHE][BREITE][3]; if(change==0){ //check if there is alignment or not if((pictures[pic].info.biWidth*3)%4==0){ wrap_size=pictures[pic].info.biWidth*3; } else{ wrap_size=pictures[pic].info.biWidth*3 + 4-(pictures[pic].info.biWidth*3)%4; } int h, b; for (h = 0; h < HOEHE; h ++) for (b = 0; b < BREITE; b ++) { if(h<pictures[pic].info.biHeight && b<pictures[pic].info.biWidth){ if(channels[0]==true){ pixels [h] [b] [0] = float(pictures[pic].bild[h*wrap_size+b*3 ])/255; /*R*/ } else{ pixels [h] [b] [0] = 1; /*R*/ } if(channels[1]==true){ pixels [h] [b] [1] = float(pictures[pic].bild[h*wrap_size+b*3+1])/255; /*G*/ } else{ pixels [h] [b] [1] = 1; /*G*/ } if(channels[2]==true){ pixels [h] [b] [2] = float(pictures[pic].bild[h*wrap_size+b*3+2])/255; /*B*/ } else{ pixels [h] [b] [2] = 1; /*B*/ } } else{ pixels [h] [b] [0] = float(rand())/RAND_MAX; /* kein rot */ pixels [h] [b] [1] = float(rand())/RAND_MAX; /* grün = Zufall */ pixels [h] [b] [2] = float(rand())/RAND_MAX; /* kein blau */ } } glClearColor (1, 1, 1, 0); glClear (GL_COLOR_BUFFER_BIT); glPointSize (10); glColor3f (0, 0, 0); //glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glPixelZoom(zoom, zoom); // glRasterPos2f(bmp_coord[0],bmp_coord[1]); // glDrawPixels (BREITE, HOEHE, GL_RGB, GL_FLOAT, pixels); // glBegin(GL_POINTS); // glVertex2f(bmp_coord[0],bmp_coord[1]); // glEnd(); ///////// //TEST TEXTURE ///////// glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, BREITE, HOEHE, 0, GL_RGB, GL_FLOAT, pixels); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glMatrixMode(GL_MODELVIEW); glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glNormal3f(0.0,1.0,0.0); glTexCoord2f(0.0,1.0); glVertex3f(1.0,1.0,0.0); glTexCoord2f(0.0,0.0); glVertex3f(1.0,-1.0,0.0); glTexCoord2f(1.0,0.0); glVertex3f(-1.0,-1.0,0.0); glTexCoord2f(1.0,1.0); glVertex3f(-1.0,1.0,0.0); glEnd(); glDisable(GL_TEXTURE_2D); glLoadIdentity(); glColor4f(1, 0, 0, 0); // glTranslated(0.58,-0.15,0.0); glRotated(rot,0.0,0.0,1.0); glBegin(GL_LINES); glVertex3f(0.00,0.0,0.1); glVertex3f(0.00,0.40,0.1); glEnd(); glLoadIdentity(); glColor4f(0, 0, 1, 0); // glTranslated(0.58,-0.15,0.0); glRotated(-rot,0.0,0.0,1.0); glBegin(GL_LINES); glVertex3f(0.00,0.0,0.1); glVertex3f(0.00,0.40,0.1); glEnd(); if(rot<360){ rot+=1; } else{ rot=0; } ////////// glFlush(); glutSwapBuffers();
das sollte eigentlich so ziemlich der gesamte relevante Code sein. Ja ich weiß, man kann noch einiges raus werfen, aber das Ding ist noch in Arbeit.
-
niemand eine Idee, woran es liegen könnte?
-
Problem besteht trotz größter Bemühungen meiner seits weiterhin.
Hat keiner eine Idee, woran das liegen könnte, bzw eine Lösung dafür?
-
kommt er je in zeile 42 der letzten datei an? das wuerde die bunten farben erklaeren.
-
Ja klar kommt er dort an, aber nur für die Bereiche, wo es keine Bildinformation gibt.
Das sieht völlig anders aus.
Wie ich schon gesagt habe, stimmen die Farben ja auch bei einer gewissen Skalierung
Der Effekt ist größenabhängig! Siehe Bilder im Startpost.
Wenn man noch kleiner wird, dann sind die Farben auch irgendwann fast perfekt richtig.
-
du schreibst also bunte pixel in eine textur, zeichnest diese komplett und siehst bunte pixel und fragst dann woher die kommen?
und bist auch ganz verwundert, dass man weniger von den textur pixeln sieht, wenn man weniger bildschrimpixel zeichnet als die textur pixel hat sodass nicht alle zu sehen sind?
du bist gut
-
eieiei...
Ok, nochmals langsam...
Der Teil mit rand wird nur aufgerufen, wenn der Buffer größer ist, als das BMP, welches geladen wird.
Inzwischen lad ich die Textur direkt in der richtigen größe, und lasse diese einfach skalieren. Daher ist der Teil mit dem Rand sogar eigentlich völlig überflüssig, und im aktuellen Code auch gar nicht mehr enthalten. Der Farbfehler ist aber weiterhin vorhanden.
Der Farbfehler taucht wie gesagt auch nur bei dieser BMP-Datei auf. andere BMP-Datein mit beliebigen Inhalt werden korrekt dargestellt. Nur eben diese hier nicht.
Der Farbfehler kommt wirklich einzig und allein aus der Skalierung der Größe des Quads entsprechend der Fenstergröße.
Siehe hier: http://image-upload.de/thumb/ADkQMi/047d2c0ae4.png
Das sind mehrere Aufnahmen, bei denen ich einfach nur die Fenstergröße verändert habe.
Zum Vergleich mal hier das Selbe mit einem Bild und ohne Farbfehler...
http://image-upload.de/thumb/cERSsS/0a85906efd.pngWie man sieht, tritt dieses Problem nicht immer auf, sondern nur mit dieser BMP-Datei. Die Ursache ist mir aber völlig schleierhaft, da ich die Header-Infos ausgelesen habe, und hier kein Unterschied besteht. Vor allem passt es ja bei einer gewissen Größe -.-
Ich hab daher auch keine Idee, wie ich das beseitigen kann, was sehr natürlich wichtig ist. So kanns nämlich nicht bleiben.
-
Rapso kommt noch was von dir?
Wenn nein, das Problem ist weiterhin offen, und mir fällt auch weiterhin kein Grund dafür ein, warum es diesen Effekt gibt.