Grafikprogrammierung
 Texturen
      
      
        Thorsten Thormählen 
 29. November 2021
 Teil 7, Kapitel 1
      
        Thorsten Thormählen 
 29. November 2021
 Teil 7, Kapitel 1
      
            Dies ist die Druck-Ansicht. 
            
             
          
            Weiterschalten der Folien durch die → Taste oder 
 durch das Klicken auf den rechten Folienrand. 
 
             
          
Das Weiterschalten der Folien kann ebenfalls durch das Klicken auf den rechten bzw. linken Folienrand erfolgen.
| Typ | Schriftart | Beispiele | 
|---|---|---|
| Variablen (Skalare) | kursiv | $a, b, x, y$ | 
| Funktionen | aufrecht | $\mathrm{f}, \mathrm{g}(x), \mathrm{max}(x)$ | 
| Vektoren | fett, Elemente zeilenweise | $\mathbf{a}, \mathbf{b}= \begin{pmatrix}x\\y\end{pmatrix} = (x, y)^\top,$ $\mathbf{B}=(x, y, z)^\top$ | 
| Matrizen | Schreibmaschine | $\mathtt{A}, \mathtt{B}= \begin{bmatrix}a & b\\c & d\end{bmatrix}$ | 
| Mengen | kalligrafisch | $\mathcal{A}, B=\{a, b\}, b \in \mathcal{B}$ | 
| Zahlenbereiche, Koordinatenräume | doppelt gestrichen | $\mathbb{N}, \mathbb{Z}, \mathbb{R}^2, \mathbb{R}^3$ | 
          
        
          $(s, t)^\top \quad \longmapsto \quad (x,y,z)^\top$
        glTexCoord2f
          ... glBegin(GL_POLYGON); glTexCoord2f(0.25f,0.50f); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0.25f,0.25f); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(0.50f,0.25f); glVertex3f( 1.0f,-1.0f, 1.0f); glTexCoord2f(0.50f,0.50f); glVertex3f( 1.0f, 1.0f, 1.0f); glEnd(); ...
init()
            glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(GL_TEXTURE_2D, texLevel, texFormat, inWidth, inHeight, 
             inBorder, inFormat, inType, inData);
              texID ein Integer-Wert, der als eindeutiger Kennzeichner ("ID") für die erzeugte Textur dient. Mit Hilfe der Funktion glGenTextures(1, &texID) kann ein solcher eindeutiger Kennzeichner generiert werden
              glEnable(GL_TEXTURE_2D);
          glBindTexture(GL_TEXTURE_2D, texID);GL_TEXTURE_2D
          glBindTexture hat mehrere Funktion: Beim erstmaligen Aufruf mit einer neuen ID wird eine neue Textur erzeugt und ansonsten eine existierende Textur aktiviert
          
          
        class Renderer {
public:
  float t;
private:
  GLuint texID;
public:
  // constructor
  Renderer() : t(0.0), texID(0) {}
  
  // destructor
  ~Renderer() {
    if(texID !=0) glDeleteTextures( 1, &texID);
  }
public:
  void init() {
    glEnable(GL_DEPTH_TEST);
    std::string fileName("dice_texture_flip.ppm");
    texID = loadTexture(fileName);
  }
  void resize(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0);
  }
  void display() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    // set camera
    gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
    // draw scene
    glRotatef(t, 0.0f, 0.0f, 1.0f);
    drawTexturedCube();
  }
private:
  // returns a valid textureID on success, otherwise 0
  GLuint loadTexture(std::string &filename) {
    unsigned width;
    unsigned height;
    int level = 0;
    int border = 0;
    std::vector<unsigned char> imgData;
    // load image data
    if(!loadPPMImageFlipped(filename, width, height, imgData)) return 0;
    // data is aligned in byte order
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    //request textureID
    GLuint textureID;
    glGenTextures( 1, &textureID);
    // bind texture
    glBindTexture( GL_TEXTURE_2D, textureID);
    //define how to filter the texture (important but ignore for now)
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    //texture colors should replace the original color values
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //GL_MODULATE
    // specify the 2D texture map
    glTexImage2D(GL_TEXTURE_2D, level, GL_RGB, width, height, border, GL_RGB, 
                 GL_UNSIGNED_BYTE, &imgData[0]);
    // return unique texture identifier
    return textureID;
  }
  void drawTexturedCube() {
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texID);
    glColor3f(1.0f,0.0f,0.0f);
    glBegin(GL_POLYGON); // three
    glTexCoord2f(0.25f,0.50f); glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.25f,0.25f); glVertex3f(-1.0f,-1.0f, 1.0f);
    glTexCoord2f(0.50f,0.25f); glVertex3f( 1.0f,-1.0f, 1.0f);
    glTexCoord2f(0.50f,0.50f); glVertex3f( 1.0f, 1.0f, 1.0f);
    glEnd();
    glColor3f(1.0f,1.0f,0.0f);
    glBegin(GL_POLYGON); // five
    glTexCoord2f(0.00f,0.50f); glVertex3f(-1.0f, 1.0f,-1.0f);
    glTexCoord2f(0.00f,0.25f); glVertex3f(-1.0f,-1.0f,-1.0f);
    glTexCoord2f(0.25f,0.25f); glVertex3f(-1.0f,-1.0f, 1.0f);
    glTexCoord2f(0.25f,0.50f); glVertex3f(-1.0f, 1.0f, 1.0f);
    glEnd();
    glColor3f(0.0f,0.0f,1.0f);
    glBegin(GL_POLYGON); // two
    glTexCoord2f(0.50f,0.50f); glVertex3f( 1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.50f,0.25f); glVertex3f( 1.0f,-1.0f, 1.0f);
    glTexCoord2f(0.75f,0.25f); glVertex3f( 1.0f,-1.0f,-1.0f);
    glTexCoord2f(0.75f,0.50f); glVertex3f( 1.0f, 1.0f,-1.0f);
    glEnd();
    glColor3f(1.0f,1.0f,1.0f);
    glBegin(GL_POLYGON); // six
    glTexCoord2f(0.25f,0.75f); glVertex3f(-1.0f, 1.0f,-1.0f);
    glTexCoord2f(0.25f,0.50f); glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.50f,0.50f); glVertex3f( 1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.50f,0.75f); glVertex3f( 1.0f, 1.0f,-1.0f);
    glEnd();
    glColor3f(0.0f,1.0f,1.0f);
    glBegin(GL_POLYGON); // one
    glTexCoord2f(0.25f,0.25f); glVertex3f(-1.0f, -1.0f, 1.0f);
    glTexCoord2f(0.25f,0.00f); glVertex3f(-1.0f, -1.0f,-1.0f);
    glTexCoord2f(0.50f,0.00f); glVertex3f( 1.0f, -1.0f,-1.0f);
    glTexCoord2f(0.50f,0.25f); glVertex3f( 1.0f, -1.0f, 1.0f);
    glEnd();
    glColor3f(0.0f,1.0f,0.0f);
    glBegin(GL_POLYGON); //four
    glTexCoord2f(0.75f,0.50f); glVertex3f( 1.0f, 1.0f,-1.0f);
    glTexCoord2f(0.75f,0.25f); glVertex3f( 1.0f,-1.0f,-1.0f);
    glTexCoord2f(1.00f,0.25f); glVertex3f(-1.0f,-1.0f,-1.0f);
    glTexCoord2f(1.00f,0.50f); glVertex3f(-1.0f, 1.0f,-1.0f);
    glEnd();
    glDisable(GL_TEXTURE_2D);
  }
  ...
};
        GL_TEXTURE_WRAP-Parameter bestimmt, wie sich das Texture-Mapping verhalten soll, wenn die Texturkoordinate $s$ oder $t$ den Zahlenbereich $[0;1]$ verlässt
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
GL_CLAMP, GL_REPEAT, GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE,
            oder GL_MIRRORED_REPEAT
        
        GL_TEXTURE_MIN_FILTER setzt den Filter bei Verkleinerungen und GL_TEXTURE_MAG_FILTER für Vergrößerungen: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
GL_NEAREST oder GL_LINEARGL_NEAREST wird der Farbwert des Pixels verwendet, das den kleinsten Abstand zur Texturkoordinate hat $\begin{align} x_{\small \mathrm{nearest}} &= \mathrm{int}(s * \mathrm{width} + 0.5)\\ y_{\small \mathrm{nearest}} &= \mathrm{int}(t * \mathrm{height} + 0.5)\\ f_{\small \mathrm{nearest}} &= f(x_{\small \mathrm{nearest}}, y_{\small \mathrm{nearest}} ) \end{align}$
GL_LINEAR wird der Farbwert bilinear interpoliert
          
          $\begin{align} f(\mathbf{p}) = \Big((x_2-x_1)(y_2-y_1)\Big)^{-1} \Big( &(x_2-x)(y_2-y)\, f(x_1,y_1) +\\\ & (x-x_1)(y_2-y) \,f(x_2,y_1) +\\ & (x_2-x)(y-y_1) \,f(x_1,y_2) +\\ & (x-x_1)(y-y_1) \,f(x_2,y_2) \Big) \end{align}$
        
        glTexParameteri(GL_TEXTURE_2D, 
                GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, 
                GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D (...);GL_TEXTURE_MIN_FILTER sind: GL_NEAREST_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_NEAREST,
            GL_NEAREST_MIPMAP_LINEAR, und GL_LINEAR_MIPMAP_LINEAR
          GL_TEXTURE_MAG_FILTER ist die Verwendung von Mipmaps nicht sinnvoll und wird auch nicht unterstützt
          
        class Renderer {
public:
  float t;
  int wrapS;
  int wrapT;
  int magFilter;
  int minFilter;
  int selectedTexID;
private:
  GLuint texID0;
  GLuint texID1;
public:
  // constructor
  Renderer() : t(-90.0f),
               wrapS(GL_REPEAT), wrapT(GL_REPEAT),
               magFilter(GL_LINEAR), 
               minFilter(GL_LINEAR_MIPMAP_LINEAR),
               selectedTexID(0),
               texID0(0), texID1(0)
  {}
  // destructor
  ~Renderer() {
    if(texID0 !=0) glDeleteTextures( 1, &texID0);
    if(texID1 !=0) glDeleteTextures( 1, &texID1);
  }
public:
  void init() {
    glEnable(GL_DEPTH_TEST);
    std::string fileName0("checker_texture_512.ppm");
    texID0 = loadTexture(fileName0);
    std::string fileName1("checker_texture_32.ppm");
    texID1 = loadTexture(fileName1);
  }
  void resize(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0);
  }
  void display() {
    glClearColor(0.7f, 0.7f, 0.7f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    // set camera
    gluLookAt(8.0, -2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
    // draw scene
    glRotatef(t, 0.0f, 0.0f, 1.0f);
    drawTexturedPlane();
  }
  // returns a valid textureID on success, otherwise 0
  GLuint loadTexture(std::string &filename) {
    unsigned width;
    unsigned height;
    int level = 0;
    int border = 0;
    std::vector <unsigned char> imgData;
    // load image data
    if(!loadPPMImageFlipped(filename, width, height, imgData)) return 0;
    // data is aligned in byte order
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    //request textureID
    GLuint textureID;
    glGenTextures(1, &textureID);
    // bind texture
    glBindTexture(GL_TEXTURE_2D, textureID);
    // parameters that define how to warp the texture
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    GLfloat borderColor[4] = {1.0f, 1.0f, 0.0f, 1.0f};
    glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
    // parameters that define how to filter the texture
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
                    GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
    // texture colors should replace the original color values
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //GL_MODULATE
    // specify the 2D texture map
    glTexImage2D (GL_TEXTURE_2D, level, GL_RGB, width, height, border, 
                  GL_RGB, GL_UNSIGNED_BYTE, &imgData[0]);
    // return unique texture identifier
    return textureID;
  }
  void setTextureParameters() { 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
    glTexParameteri(GL_TEXTURE_2D, 
                    GL_TEXTURE_MAG_FILTER, magFilter);
    glTexParameteri(GL_TEXTURE_2D, 
                    GL_TEXTURE_MIN_FILTER, minFilter);
  }
  void drawTexturedPlane() {
    glEnable(GL_TEXTURE_2D);
    if(selectedTexID == 0) {
      glBindTexture(GL_TEXTURE_2D, texID0);
    }else{
      glBindTexture(GL_TEXTURE_2D, texID1);
    }
    setTextureParameters();
    glColor3f(1.0,0.0,0.0);
    glBegin(GL_POLYGON);
    glTexCoord2f(5 .00f,  5.00f); 
    glVertex3f(-10.0f, 10.0f, 0.0f);
    glTexCoord2f( 5.00f, -4.00f); 
    glVertex3f(-10.0f,-10.0f, 0.0f);
    glTexCoord2f(-4.00f, -4.00f); 
    glVertex3f( 10.0f,-10.0f, 0.0f);
    glTexCoord2f(-4.00f,  5.00f); 
    glVertex3f( 10.0f, 10.0f, 0.0f);
    glEnd();
    glDisable(GL_TEXTURE_2D);
  }
  ...
};
        glTexEnv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);kann beeinflusst werden, wie die Texturfarbe $C_s$ und der Texturalphakanal $A_s$ mit dem aktuellen Fragment (Farbwert $C_f$ und Alphakanal $A_f$) kombiniert wird
GL_REPLACE, GL_MODULATE, GL_DECAL, GL_BLEND,
            oder GL_ADD| GL_RGB | GL_RGBA | |
|---|---|---|
| GL_REPLACE | $C=C_s$ $A=A_f$  | $C=C_s$ $A=A_s$  | 
| GL_MODULATE | $C=C_fC_s$  $A=A_f$  | $C=C_f C_s$  $A=A_f A_s$  | 
| GL_DECAL | $C=C_s$  $A=A_f$  | $C=C_f (1-A_s) + C_s A_s$  $A=A_f$  | 
| GL_BLEND | $C=C_f(1-C_s)+C_c C_s$  $A=A_f$  | $C=C_f(1-C_s)+C_c C_s$  $A=A_f A_s$  | 
| GL_ADD | $C=C_f+ C_s$  $A=A_f$  | $C=C_f+ C_s$  $A=A_f A_s$  | 
        
              $\begin{align} s &= \frac{x-x_{\small \mathrm{min}} }{ x_{\small \mathrm{max}} - x_{\small \mathrm{min}} }\\ t &= \frac{y-y_{\small \mathrm{min}} }{ y_{\small \mathrm{max}} - y_{\small \mathrm{min}} } \end{align}$
          $\begin{align} s &= h = \frac{z-z_{\small \mathrm{min}} }{ z_{\small \mathrm{max}} - z_{\small \mathrm{min}} }\\ t &= \frac{1}{2\pi} \phi = \frac{1}{2\pi} \arctan\left(\frac{y}{x}\right) \end{align}$
Hinweise: Da in der Praxis $x=0$ sein kann, ist es sinnvoll, den $\arctan$ durch den $\mathrm{atan2}$ zu ersetzen
          $\begin{align} s &= \frac{1}{2\pi} \phi = \frac{1}{2\pi} \arctan\left(\frac{y}{x}\right)\\ t &= 1.0 - \frac{1}{\pi} \theta \\ &= 1.0 - \frac{1}{\pi} \arccos(z) \\ &= \frac{1}{\pi} \arccos(-z)\\ \end{align}$
              GL_TEXTURE_2D wird GL_TEXTURE_3D, aus glTexImage2D wird glTexImage3D, usw.
          glTexImage3D kann als eine Aneinanderreihung von 2D-Texturen-Daten
            interpretiert werden
          width
            Texel-Werten, und in $r$-Richtung erst nach width*height Texel-Werten
          
        class Renderer {
public:
  float t;
private:
  GLuint texID;
  std::vector <float> terrain;
public:
  // constructor
  Renderer() : t(0.0), texID(0) {}
  //destructor
  ~Renderer() {
    if(texID !=0) glDeleteTextures( 1, &texID);
  }
public:
  void init() {
    glEnable(GL_DEPTH_TEST);
    glTexImage3D = (PFNGLTEXIMAGE3DPROC) 
                   wglGetProcAddress("glTexImage3D");
    if(glTexImage3D == NULL) {
      QMessageBox msgBox;
      msgBox.setText("Can not load the glTexImage3D function");
      msgBox.exec();
    }
    std::vector< std::string > filenames;
    filenames.push_back("deep_water.ppm");
    filenames.push_back("shallow_water.ppm");
    filenames.push_back("shore.ppm");
    filenames.push_back("fields.ppm");
    filenames.push_back("rocks.ppm");
    filenames.push_back("snow.ppm");
    texID = loadTexture3D(filenames);
    rebuildTerrain();
  }
  void resize(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0);
  }
  
  void display() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    // set camera
    gluLookAt(1.5, -1.0, 1.5, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
    // draw scene
    glRotatef(t, 0.0f, 0.0f, 1.0f);
    drawTerrain();
  }
  
  void rebuildTerrain() {
    //create random values
    int dim = 40;
    terrain.resize(dim*dim);
    for(int r=0; r < dim*dim; r++) {
      int rval = rand();
      terrain[r] = (fabs(float(rval))/float(RAND_MAX));
    }
    if(true) { // generate smooth terrain values
      std::vector<float≷ smoothTerrain(dim*dim);
      for(unsigned k=0; k < 5; k++){
        float maxVal = 0.0f;
        float minVal = 1.0f;
        for(int x = 0; x < dim; x++) {
          for(int y = 0; y < dim; y++) {
            if(x == 0 || x == dim-1) terrain[x*dim+y] = 0.0f;
            else if (y == 0 || y == dim-1) {
              terrain[x*dim+y] = 0.0f;
            }else {
              float a = 0.0f;
              int counter = 0;
              for(int s=-1; s <= 1; s++) {
                for(int r=-1; r <= 1; r++) {
                  a += terrain[(x+s)*dim+(y+r)];
                  counter++;
                }
              }
              float val = a / float(counter);
              smoothTerrain[x*dim+y] = val;
              if(val > maxVal) maxVal = val;
              if(val < minVal) minVal = val;
            }
          }
        }
        for(int r=0; r < dim*dim; r++) {
          terrain[r] = (smoothTerrain[r] - minVal) / 
                       (maxVal-minVal);
        }
      }
    }
  }
private:
  // returns a valid textureID on success, otherwise 0
  GLuint loadTexture3D(std::vector< std::string > &filenames) {
    unsigned width = 0;
    unsigned height = 0;
    unsigned depth = unsigned(filenames.size());
    int level = 0;
    int border = 0;
    std::vector<unsigned char> imgData;
    std::vector<unsigned char> data3d;
    unsigned prevWidth = 0;
    unsigned prevHeight = 0;
    for(unsigned i=0; i < depth; i++) {
      // load image data
      if(!loadPPMImageFlipped(filenames[i], width, height, imgData)) return 0;
      if(i != 0 && (prevWidth != width || prevHeight != height)) return 0;
      // pack 2D images subsequently into a large 3D buffer
      data3d.insert(data3d.end(), imgData.begin(), imgData.end());
      prevWidth = width;
      prevHeight = height;
    }
    // data is aligned in byte order
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    //request textureID
    GLuint textureID;
    glGenTextures( 1, &textureID);
    // bind texture
    glBindTexture(GL_TEXTURE_3D, textureID);
    //parameters the define how to warp the texture
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
    GLfloat borderColor[4] = {0.0f,0.0f,0.0f,1.0f};
    glTexParameterfv(GL_TEXTURE_3D, GL_TEXTURE_BORDER_COLOR, borderColor);
    //define how to filter the texture
    glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    //texture colors should replace the original color values
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //GL_MODULATE
    // specify the 2D texture map
    glTexImage3D(GL_TEXTURE_3D, level, GL_RGB, width, height, depth, border, 
                 GL_RGB, GL_UNSIGNED_BYTE, &data3d[0]);
    // return unique texture identifier
    return textureID;
  }
  void drawTerrain() {
    glEnable(GL_TEXTURE_3D);
    glBindTexture(GL_TEXTURE_3D, texID);
    glColor3f(1.0f,0.0f,0.0f);
    unsigned dim = unsigned(sqrt(terrain.size()));
    float maxHeight = 0.2f;
    float texHeight = 0.9f;
    for(unsigned x = 1; x < dim; x++) {
      for(unsigned y = 1; y < dim; y++) {
        glBegin(GL_POLYGON);
        glTexCoord3f(float(x-1)/float(dim),
                     float(y-1)/float(dim),
                     terrain[(x-1)*dim+(y-1)]*texHeight);
        glVertex3f(float(x-1)/float(dim)-0.5f,
                   float(y-1)/float(dim)-0.5f,
                   terrain[(x-1)*dim+(y-1)]*maxHeight);
        glTexCoord3f(float(x)/float(dim),
                     float(y-1)/float(dim),
                     terrain[x*dim+(y-1)]*texHeight);
        glVertex3f(float(x)/float(dim)-0.5f,
                   float(y-1)/float(dim)-0.5f,
                    terrain[x*dim+(y-1)]*maxHeight);
        glTexCoord3f(float(x)/float(dim),
                   float(y)/float(dim),
                   terrain[x*dim+y]*texHeight);
        glVertex3f(float(x)/float(dim)-0.5f,
                   float(y)/float(dim)-0.5f,
                   terrain[x*dim+y]*maxHeight);
        glTexCoord3f(float(x-1)/float(dim),
                   float(y)/float(dim),
                   terrain[(x-1)*dim+y]*texHeight);
        glVertex3f(float(x-1)/float(dim)-0.5f,
                   float(y)/float(dim)-0.5f,
                   terrain[(x-1)*dim+y]*maxHeight);
        glEnd();
      }
    }
    glDisable(GL_TEXTURE_3D);
  }
  ...
};
        glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &noOfTextureUnits);
glActiveTexture schaltet die aktuell modifizierte Textureinheit um:
            glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texA); ... glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texB); ...
glMatrixMode(GL_TEXTURE)glGenFramebuffers(1, &fboID); glBindFramebuffer(GL_FRAMEBUFFER, fboID);
glFramebufferTexture2D(...) an das FBO übergeben werden 
glGenTextures (1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(GL_TEXTURE_2D, texLevel, texFormat, 
             inWidth, inHeight, inBorder, inFormat, inType, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
                       GL_TEXTURE_2D, texID, texLevel);
          GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, ..., GL_DEPTH_ATTACHMENT
          oder GL_STENCIL_ATTACHMENT
          glFramebufferRenderbuffer(..) an das FBO übergeben werden 
glGenRenderbuffers(1, &depthID);
glBindRenderbuffer(GL_RENDERBUFFER, depthID);
glRenderbufferStorage(GL_RENDERBUFFER, format, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
                          GL_RENDERBUFFER, depthID);
format so gewählt werden, dass es zum Verwendungszweck passt,
also z.B. GL_RGBA für GL_COLOR_ATTACHMENT0 oder GL_DEPTH_COMPONENT für GL_DEPTH_ATTACHMENT, usw.
class Renderer {
public:
  float t;
  int mode;
private:
  GLuint fboID;
  GLuint texID;
  GLuint depthID;
  int fboTexSize;
  int width;
  int height;
public:
  // constructor
  Renderer() : t(0.0), mode(1),
               fboID(0), texID(0), depthID(0),
               fboTexSize(512), width(0), height(0) {}
  // destructor
  ~Renderer() {
    if(texID !=0) glDeleteTextures( 1, &texID);
    if(fboID !=0) glDeleteFramebuffers(1, &fboID);
    if(depthID != 0) glDeleteRenderbuffers(1, &depthID);
  }
public:
  void init() {
    glEnable(GL_DEPTH_TEST);
    // create a frame buffer object
    glGenFramebuffers(1, &fboID);
    // bind the frame buffer
    glBindFramebuffer(GL_FRAMEBUFFER, fboID);
    // Generate render texture
    glGenTextures (1, &texID);
    glBindTexture(GL_TEXTURE_2D, texID);
    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);
    glTexParameteri(GL_TEXTURE_2D, 
                    GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    int level = 0;
    glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, 
                 fboTexSize, fboTexSize, 
                 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    // Attach the texture to the fbo
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 
                           GL_TEXTURE_2D, texID, level);
    if(!checkFramebufferStatus()) exit(1);
    // generate a renderbuffer for the depth buffer
    glGenRenderbuffers(1, &depthID);
    glBindRenderbuffer(GL_RENDERBUFFER, depthID);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 
                          fboTexSize, fboTexSize);
    // Attach the depth buffer to the fbo
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, 
                              GL_DEPTH_ATTACHMENT, 
                              GL_RENDERBUFFER, depthID);
    if(!checkFramebufferStatus()) exit(1);
    // unbind texture
    glBindTexture(GL_TEXTURE_2D, 0);
    //unbind fbo
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
  }
  void resize(int w, int h) {
    width = w;
    height = h;
    changeViewport(w, h);
  }
  void display() {
    if(mode == 1) {
      // bind the fbo
      glBindFramebuffer(GL_FRAMEBUFFER, fboID);
      changeViewport(fboTexSize,fboTexSize);
    }
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    // render to attached fbo
    drawScene();
    if(mode == 1) {
      // unbind frame buffer
      glBindFramebuffer(GL_FRAMEBUFFER, 0);
      changeViewport(width, height);
      glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      // using first render pass result as texture
      glEnable(GL_TEXTURE_2D);
      glBindTexture(GL_TEXTURE_2D, texID);
      // second render pass
      drawScene();
      glDisable(GL_TEXTURE_2D);
    }
  }
  
private:
  void changeViewport(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (30.0, (float)w/(float)h, 0.1, 50.0);
  }
  void drawScene() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    // set camera
    gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
    // draw scene
    glRotatef(t, 0.0f, 0.0f, 1.0f);
    drawTexturedCube();
  }
  bool checkFramebufferStatus() {
    GLenum status;
    status = (GLenum) glCheckFramebufferStatus(GL_FRAMEBUFFER);
    switch(status) {
    case GL_FRAMEBUFFER_COMPLETE:
      return true;
    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
      printf("Framebuffer incomplete, incomplete attachment\n");
      return false;
    case GL_FRAMEBUFFER_UNSUPPORTED:
      printf("Unsupported framebuffer format\n");
      return false;
    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
      printf("Framebuffer incomplete, missing attachment\n");
      return false;
    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
      printf("Framebuffer incomplete, missing draw buffer\n");
      return false;
    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
      printf("Framebuffer incomplete, missing read buffer\n");
      return false;
    }
    return false;
  }
  void drawTexturedCube() {
    glColor3f(1.0f,0.0f,0.0f);
    glBegin(GL_POLYGON);
    glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f,-1.0f, 1.0f);
    glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f,-1.0f, 1.0f);
    glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, 1.0f, 1.0f);
    glEnd();
    glColor3f(1.0f,1.0f,0.0f);
    glBegin(GL_POLYGON);
    glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, 1.0f,-1.0f);
    glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f,-1.0f,-1.0f);
    glTexCoord2f(1.00f,1.00f); glVertex3f(-1.0f,-1.0f, 1.0f);
    glTexCoord2f(0.00f,1.00f); glVertex3f(-1.0f, 1.0f, 1.0f);
    glEnd();
    glColor3f(0.0f,0.0f,1.0f);
    glBegin(GL_POLYGON);
    glTexCoord2f(0.00f,0.00f); glVertex3f( 1.0f, 1.0f, 1.0f);
    glTexCoord2f(1.00f,0.00f); glVertex3f( 1.0f,-1.0f, 1.0f);
    glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f,-1.0f,-1.0f);
    glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, 1.0f,-1.0f);
    glEnd();
    glColor3f(1.0f,1.0f,1.0f);
    glBegin(GL_POLYGON);
    glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, 1.0f,-1.0f);
    glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, 1.0f,-1.0f);
    glEnd();
    glColor3f(0.0f,1.0f,1.0f);
    glBegin(GL_POLYGON);
    glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f, -1.0f, 1.0f);
    glTexCoord2f(1.00f,0.00f); glVertex3f(-1.0f, -1.0f,-1.0f);
    glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f, -1.0f,-1.0f);
    glTexCoord2f(0.00f,1.00f); glVertex3f( 1.0f, -1.0f, 1.0f);
    glEnd();
    glColor3f(0.0f,1.0f,0.0f);
    glBegin(GL_POLYGON);
    glTexCoord2f(0.00f,0.00f); glVertex3f( 1.0f, 1.0f,-1.0f);
    glTexCoord2f(1.00f,0.00f); glVertex3f( 1.0f,-1.0f,-1.0f);
    glTexCoord2f(1.00f,1.00f); glVertex3f(-1.0f,-1.0f,-1.0f);
    glTexCoord2f(0.00f,1.00f); glVertex3f(-1.0f, 1.0f,-1.0f);
    glEnd();
  }
};
        
        class Renderer {
public:
  float t;
  int mode;
private:
  GLuint fboID;
  GLuint depthID;
  int fboTexSize;
  int width;
  int height;
public:
  // constructor
  Renderer() : t(0.0), mode(1),
               fboID(0), depthID(0),
               fboTexSize(512), width(0), height(0) {}
  // destructor
  ~Renderer() {
    if(fboID !=0) glDeleteFramebuffers(1, &fboID);
    if(depthID != 0) glDeleteTextures(1, &depthID);
  }
public:
 void init() {
    glEnable(GL_DEPTH_TEST);
    // create a frame buffer object
    glGenFramebuffers(1, &fboID);
    // bind the frame buffer
    glBindFramebuffer(GL_FRAMEBUFFER, fboID);
     // Generate depth render texture
    glGenTextures (1, &depthID);
    glBindTexture(GL_TEXTURE_2D, depthID);
    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);
    glTexParameteri(GL_TEXTURE_2D, 
                    GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    int level = 0;
    glTexImage2D(GL_TEXTURE_2D, level, GL_DEPTH_COMPONENT, 
                 fboTexSize, fboTexSize, 0, GL_DEPTH_COMPONENT, 
                 GL_FLOAT, NULL);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    // Attach the texture to the fbo
    glFramebufferTexture2D(GL_FRAMEBUFFER, 
                           GL_DEPTH_ATTACHMENT, 
                           GL_TEXTURE_2D, depthID, level);
    if(!checkFramebufferStatus()) exit(1);
    // unbind texture
    glBindTexture(GL_TEXTURE_2D, 0);
    //unbind fbo
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
  }
  void resize(int w, int h) {
    width = w;
    height = h;
    changeViewport(w, h);
  }
  void display() {
    if(mode > 0) {
      // bind the fbo
      glBindFramebuffer(GL_FRAMEBUFFER, fboID);
      changeViewport(fboTexSize,fboTexSize);
    }else{
      changeViewport(width, height);
    }
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    // render to attached fbo
    drawScene();
    if(mode == 1) {
      // unbind frame buffer
      glBindFramebuffer(GL_FRAMEBUFFER, 0);
      changeViewportOrtho(width, height);
      // using first render pass result as texture
      glEnable(GL_TEXTURE_2D);
      glBindTexture(GL_TEXTURE_2D, depthID);
      //draw quad with depth texture
      glColor3f(1.0f,0.0f,0.0f);
      glBegin(GL_POLYGON);
      glTexCoord2f(0.00f,0.00f); glVertex3f(-1.0f,-1.0f, 0.0f);
      glTexCoord2f(1.00f,0.00f); glVertex3f( 1.0f,-1.0f, 0.0f);
      glTexCoord2f(1.00f,1.00f); glVertex3f( 1.0f, 1.0f, 0.0f);
      glTexCoord2f(0.00f,1.00f); glVertex3f(-1.0f, 1.0f, 0.0f);
      glEnd();
      glDisable(GL_TEXTURE_2D);
    }  
  }
private:
  void changeViewport(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective (30.0, (float)w/(float)h, 7.0, 12.0);
  }
  void changeViewportOrtho(int w, int h) {
    float aspect = (float)w/(float)h;
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0*aspect, 1.0*aspect, -1.0, 1.0, -1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
  }
  void drawScene() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    // set camera
    gluLookAt(8.0, -2.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
    // draw scene
    glRotatef(t, 0.0f, 0.0f, 1.0f);
    drawTexturedCube();
  }
...
};
        
        Anregungen oder Verbesserungsvorschläge können auch gerne per E-mail an mich gesendet werden: Kontakt