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