[OpenGL] Problem mit Texturen



  • Hallo

    Nach langer Zeit wollte ich nochmal etwas mit OpenGL machen... und bin beim Laden von Texturen auf ein Problem gestoßen. Zum Verwalten von Texturen habe ich die folgende Klasse geschrieben:

    class Texture
    {
    
        private:
    
            Texture (const GLuint nTextureID) : m_nTextureID (nTextureID) { }
    
        public:
    
            ~Texture () { glDeleteTextures (1, &m_nTextureID); }
    
        public:
    
            static Texture* loadFromBMP (const std::string& sFile);
    
            GLuint getID () const
            {
                return m_nTextureID;
            }
    
            void setActive () const
            {
                glBindTexture (GL_TEXTURE_2D, m_nTextureID);
            }
    
        private:
    
            const GLuint m_nTextureID;
    
    };
    

    Die Funktion zum Laden der Textur ist wie folgt definiert:

    Texture* Texture::loadFromBMP (const std::string& sFile)
    {
        std::ifstream fIn (sFile.c_str (), std::ios::in | std::ios::binary);
        if (fIn.good ())
        {
            try
            {
                // read header
                unsigned short nFormat;
                fIn.read (reinterpret_cast <char*> (&nFormat), 2);
                if (nFormat != 19778)
                {
                    std::cerr << "(EE) Failed to read: " << sFile << std::endl;
                    std::cerr << "(EE)   Not a Windows Bitmap." << std::endl;
                    std::cerr << std::endl;
                    fIn.close ();
                    return NULL;
                }
    
                fIn.seekg (18);
                signed int nWidth, nHeight;
                fIn.read (reinterpret_cast <char*> (&nWidth), 4);
                fIn.read (reinterpret_cast <char*> (&nHeight), 4);
    
                // compute body size
                const unsigned int nBodySize = 3 * nWidth * nHeight;
    
                // read planes
                unsigned short nPlanes;
                fIn.read (reinterpret_cast <char*> (&nPlanes), 2);
    
                // read bits per pixel
                unsigned short nBPP;
                fIn.read (reinterpret_cast <char*> (&nBPP), 2);
    
                // ensure format is supported
                if (nPlanes != 1 || nBPP != 24)
                {
                    std::cerr << "(EE) Failed to read: " << sFile << std::endl;
                    std::cerr << "(EE)   Unsupported format: " << nBPP << " bpp, " << nPlanes << " plane(s)" << std::endl;
                    std::cerr << "(EE)   Only bitmaps with 24 color depth and 1 plane are supported." << std::endl;
                    std::cerr << std::endl;
                    fIn.close ();
                    return NULL;
                }
    
                // seek past the rest of the header
                fIn.seekg (54);
    
                // read body data
                char* const pcData = new char [nBodySize];
                fIn.read (pcData, nBodySize);
    
                // we are done reading the file
                fIn.close ();
    
                // reverse byte order (convert 'BGR' to 'RGB')
                for (unsigned int j = 0; j < nBodySize ; j += 3)
                {
                    pcData [j] ^= pcData [j + 2];
                    pcData [j + 2] ^= pcData [j];
                }
    
                // now we need to create the texture
                GLuint nTextureID;
                glGenTextures (1, &nTextureID);
                glBindTexture (GL_TEXTURE_2D, nTextureID);
                glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    
                // 2D texture, level of detail 0 (normal), 3 components (red, green, blue), x size, y size,
                // border 0 (normal), rgb color data, unsigned byte data, and finally the data itself
                glTexImage2D (GL_TEXTURE_2D, 0, 3, nWidth, nHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, pcData);
                delete [] pcData;
    
                // finish
                return new Texture (nTextureID);
            }
            catch (...)
            {
                fIn.close ();
                std::cerr << "(EE) Failed to read: " << sFile << std::endl;
                std::cerr << "(EE)   Unknown error." << std::endl;
                std::cerr << std::endl;
                return NULL;
            }
        }
        else
        {
            fIn.close ();
            std::cerr << "(EE) Failed to read: " << sFile << std::endl;
            std::cerr << "(EE)   Either file not found or not allowed to open for reading." << std::endl;
            std::cerr << std::endl;
            return NULL;
        }
    }
    

    Nun rufe ich bei der Initialisierung des Programms auf:

    static Texture* s_aTextures []; // Member einer Klasse C
    
    // [...]
    
    Texture* C::s_aTextures [] = { NULL, NULL, NULL, NULL, NULL, NULL };
    
    // [...]
    
    s_aTextures [0] = Texture::loadFromBMP ("test1.bmp");
    s_aTextures [1] = Texture::loadFromBMP ("test2.bmp");
    s_aTextures [2] = Texture::loadFromBMP ("test3.bmp");
    s_aTextures [3] = Texture::loadFromBMP ("test4.bmp");
    s_aTextures [4] = Texture::loadFromBMP ("test5.bmp");
    s_aTextures [5] = Texture::loadFromBMP ("test6.bmp");
    

    Beim Vor-Rendern der Szene in eine Display-List rufe ich dann auf unterschiedlichen Elementen des Arrays auf:

    s_aTextures [2] -> setActive ();
    

    Nun das Problem: Alles, was ich rendere, wird mit derselben Textur belegt, obwohl ich unterschiedliche Texturen einstelle. Um genau zu sein, wird alles mit der Textur überzogen, die ich als letztes erstelle (lade) - Nicht missverstehen, es wird nicht immer die Textur benutzt, auf der ich zuletzt setActive aufrufe. Aber ich finde den Fehler einfach nich. Die lokale Variable nTextureID in Texture::loadFromBMP hat auch einen korrekten Wert, nämlich bei jedem Aufruf einen anderen. Jemand eine Idee?

    Danke im Voraus



  • Hast Du schonmal mit glGetError() gearbeitet? Könnte ja zum Beispiel beim binden der Textur was schief gehen.

    Mr Train



  • Wie alt is deine GraKa/dein Treiber? Sind alle Texturen von der Weite/Höhe 2^n?
    Du könntest auch nach dem Nutzen der Textur immer erstmal wieder auf die 0 binden, sodass keine Textur gewählt ist, einfach um evtl der Fehlerquelle näher zu kommen



  • Machst du das binden ausserhalb von glBegin(GL_...)?



  • Hi,

    meiner Meinung nach liegt es hier dran:
    (Irgendwie habe ich das Gefühl das da was mit den Zeigern nicht stimmt.
    Weil du zwar mit Zeigern hantierst aber nirgends ein new für ein Objekt der Klasse zu sehen ist)

    static Texture* s_aTextures []; // Member einer Klasse C 
    
    // [...] 
    
    Texture* C::s_aTextures [] = { NULL, NULL, NULL, NULL, NULL, NULL }; 
    
    // [...] 
    
    s_aTextures [0] = Texture::loadFromBMP ("test1.bmp"); 
    s_aTextures [1] = Texture::loadFromBMP ("test2.bmp"); 
    s_aTextures [2] = Texture::loadFromBMP ("test3.bmp"); 
    s_aTextures [3] = Texture::loadFromBMP ("test4.bmp"); 
    s_aTextures [4] = Texture::loadFromBMP ("test5.bmp"); 
    s_aTextures [5] = Texture::loadFromBMP ("test6.bmp");
    

    Schmeiß mal alles was mit Zeigern ist raus:

    Überall

    class Texture 
    { 
    
        private: 
    
           GLuint textur;
    
        public: 
    
            ~Texture () { } 
    
        public: 
    
           ladenTest(const std::string& sFile); 
           {
               textur=loadFromBMP ( sFile); 
           }  
    
           GluInt loadFromBMP (const std::string& sFile); 
    
            GLuint getID () const 
            { 
                return textur;        } 
    
            void setActive () const 
            { 
                glBindTexture (GL_TEXTURE_2D,textur); 
            } 
    
    };
    
    Texture test[6];
    test[0].ladenTest ("test1.bmp");
    test[1].ladenTest ("test2.bmp");
    test[2].ladenTest ("test3.bmp");
    test[3].ladenTest ("test4.bmp");
    test[4].ladenTest("test5.bmp");
    test[5].ladenTest("test6.bmp");
    

    Dann beim Rendern:

    test[0].setActive;                  //je nachdem welche du brauchst
    

    Hinweis: Gegebenenfalls "Texture::" hinzufügen wo es der Compiler vermißt.

    Fall es doch am OpenGL Teil liegt: Hier eine schnell zusammenkopierte funktionierende Klasse:
    Textur.h

    #include <windows.h>													// Header File For Windows
    #include <gl\glu.h>														// Header File For The GLu32 Library
    #include <TCHAR.h> 
    #include <math.h>														// Header File For The Math Library			(Used In BuildTexture)
    
    #include <fstream>
    using namespace std;
    
    #define GL_CLAMP_TO_EDGE 0x812F 
    
    #pragma once
    
    class Textur {
    
    private:
    	GLuint textur;
    	bool geladen;
    	int glTexParameterfv_param;
    
    	bool LoadBitmap(wchar_t *filename);	
    	bool LoadTGA(wchar_t *filename);
    
    public:
    	Textur ();
    	Textur (GLuint glTexParameterfv_param_);
    	bool LoadGLTextures(wchar_t *filename);
    
    	bool get_geladen();
    	int get_texture();
    
    };
    

    Textur.cpp:

    #include "Textur.h"
    
    Textur::Textur ():geladen(false),glTexParameterfv_param(GL_CLAMP_TO_EDGE){}
    Textur::Textur (GLuint glTexParameterfv_param_):geladen(false),glTexParameterfv_param(glTexParameterfv_param_) {}
    
    bool Textur::LoadGLTextures(wchar_t *filename)									// Load Bitmaps And Convert To Textures
    {
    	if (LoadBitmap(filename))					// versucht das Bild im angegeben Pfad als *.bmp zu laden
    	{
    		geladen=true;
    		return true;
    	}
    	if (LoadTGA(filename))						// versucht as Bild im angegeben Pfad als *.tga zu laden
    	{
    		geladen=true;
    		return true;
    	}
    
    	return false;	
    }
    
    bool Textur::LoadBitmap(wchar_t *filename)									// Load Bitmaps And Convert To Textures
    {
    	HBITMAP hBMP;														// Handle Of The Bitmap
    	BITMAP	BMP;														// Bitmap Structure
    
    	glGenTextures(1, &textur);											// Create The Texture
    	hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL), filename, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE );
    
    	if (!hBMP)															// Does The Bitmap Exist?
    	{
    		return false;													// If Not Return False
    	}
    	GetObject(hBMP, sizeof(BMP), &BMP);									// Get The Object
    	// hBMP:        Handle To Graphics Object
    	// sizeof(BMP): Size Of Buffer For Object Information
    	// &BMP:        Buffer For Object Information
    
    	glPixelStorei(GL_UNPACK_ALIGNMENT, 4);								// Pixel Storage Mode (Word Alignment / 4 Bytes)
    
    	glBindTexture(GL_TEXTURE_2D, textur);
    	glTexImage2D(GL_TEXTURE_2D, 0, 3, BMP.bmWidth,  BMP.bmHeight, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
    
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glTexParameterfv_param ); 
    	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glTexParameterfv_param  ); 
    
    	//Mipmapping verhindert ein Rauschen bei entfernten Texturen
    	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR );
    	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    	gluBuild2DMipmaps( GL_TEXTURE_2D, 3,  BMP.bmWidth, BMP.bmHeight ,GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
    
    	DeleteObject(hBMP);													// Delete The Object
    
    	return true;	
    }
    
    bool Textur::LoadTGA(wchar_t *filename)						// Loads A TGA File Into Memory
    {     
    	GLubyte	*imageData;											// Image Data (Up To 32 Bits)
    	GLuint	bpp;												// Image Color Depth In Bits Per Pixel.
    	GLuint	width;												// Image Width
    	GLuint	height;												// Image Height
    
    	GLubyte		TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};		// Uncompressed TGA Header
    	GLubyte		TGAcompare[12];									// Used To Compare TGA Header
    	GLubyte		header[6];										// First 6 Useful Bytes From The Header
    	GLuint		bytesPerPixel;									// Holds Number Of Bytes Per Pixel Used In The TGA File
    	GLuint		imageSize;										// Used To Store The Image Size When Setting Aside Ram
    	GLuint		temp;											// Temporary Variable
    	GLuint		type=GL_RGBA;									// Set The Default GL Mode To RBGA (32 BPP)
    
    	FILE *file; 
    	_wfopen_s(&file,filename, L"rb");							// Open The TGA File
    
    	if(	file==NULL ||											// Does File Even Exist?
    		fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare) ||	// Are There 12 Bytes To Read?
    		memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0				||	// Does The Header Match What We Want?
    		fread(header,1,sizeof(header),file)!=sizeof(header))				// If So Read Next 6 Header Bytes
    	{
    		if (file == NULL)										// Did The File Even Exist? *Added Jim Strong*
    			return false;										// Return False
    		else													// Otherwise
    		{
    			fclose(file);										// If Anything Failed, Close The File
    			return false;										// Return False
    		}
    	}
    
    	width  = header[1] * 256 + header[0];				// Determine The TGA Width	(highbyte*256+lowbyte)
    	height = header[3] * 256 + header[2];				// Determine The TGA Height	(highbyte*256+lowbyte)
    
    	if(	width	<=0	||									// Is The Width Less Than Or Equal To Zero
    		height	<=0	||									// Is The Height Less Than Or Equal To Zero
    		(header[4]!=24 && header[4]!=32))						// Is The TGA 24 or 32 Bit?
    	{
    		fclose(file);											// If Anything Failed, Close The File
    		return false;											// Return False
    	}
    
    	bpp	= header[4];								// Grab The TGA's Bits Per Pixel (24 or 32)
    	bytesPerPixel	= bpp/8;							// Divide By 8 To Get The Bytes Per Pixel
    	imageSize		= width*height*bytesPerPixel;	// Calculate The Memory Required For The TGA Data
    
    	imageData=(GLubyte *)malloc(imageSize);			// Reserve Memory To Hold The TGA Data
    
    	if(	imageData==NULL ||								// Does The Storage Memory Exist?
    		fread(imageData, 1, imageSize, file)!=imageSize)	// Does The Image Size Match The Memory Reserved?
    	{
    		if(imageData!=NULL)							// Was Image Data Loaded
    			free(imageData);							// If So, Release The Image Data
    
    		fclose(file);											// Close The File
    		return false;											// Return False
    	}
    
    	for(GLuint i=0; i<int(imageSize); i+=bytesPerPixel)			// Loop Through The Image Data
    	{															// Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
    		temp=imageData[i];								// Temporarily Store The Value At Image Data 'i'
    		imageData[i] = imageData[i + 2];		// Set The 1st Byte To The Value Of The 3rd Byte
    		imageData[i + 2] = temp;						// Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
    	}
    
    	fclose (file);												// Close The File
    
    	// Build A Texture From The Data
    	glGenTextures(1, &textur);						// Generate OpenGL texture IDs
    
    	glBindTexture(GL_TEXTURE_2D, textur);				// Bind Our Texture
    	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	// Linear Filtered
    	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);	// Linear Filtered
    
    	if (bpp==24)										// Was The TGA 24 Bits
    	{
    		type=GL_RGB;											// If So Set The 'type' To GL_RGB
    	}
    
    	glTexImage2D(GL_TEXTURE_2D, 0, type, width, height, 0, type, GL_UNSIGNED_BYTE,imageData );
    
    	return true;												// Texture Building Went Ok, Return True
    }
    
    bool Textur::get_geladen()
    {
    	return geladen;
    }
    
    int Textur::get_texture()
    {
    	if (geladen)
    	{
    		return textur;
    	}
    	return NULL;
    }
    

    Quellen von LoadBitmap(...) und LoadTGA(...)
    http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=06
    http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=24



  • Sein new steht so da:

    return new Texture (nTextureID);
    

    in Zeile 77.


Anmelden zum Antworten