// // Computergraphik II // Prof. Dr. Juergen Doellner // Wintersemester 2001/02 // // Rahmenprogramm zu Aufgabenzettel 9 // #include "cgtexture.h" #include "vector.h" #include "noise.h" #include #include #include "glext.h" #ifndef APIENTRY #define WIN32_LEAN_AND_MEAN 1 #include #endif /*APIENTRY*/ #ifdef _WIN32 /* This has already been done by glext.h */ /*typedef void (APIENTRY* PFNGLTEXIMAGE3DEXTPROC)(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *image);*/ PFNGLTEXIMAGE3DPROC glTexImage3D; #endif _WIN32*/ int isExtensionSupported(const char *extension) { const GLubyte *extensions = NULL; const GLubyte *start; GLubyte *where, *terminator; /* Extension names should not have spaces. */ where = (GLubyte*) strchr(extension, ' '); if (where || *extension == '\0') return 0; extensions = glGetString(GL_EXTENSIONS); /* It takes a bit of care to bew fol-proof about parsing the OpenGL extensions string. Donn't be fooled by sub-strings, etc. */ start = extensions; for(;;) { where = (GLubyte*) strstr((const char*) start, extension); if (!where) break; terminator = where + strlen(extension); if (where == start ||*(where-1)==' ') if (*terminator == ' ' || *terminator == '\0') return 1; start = terminator; } return 0; } void buildAvailableExtensions() { // Beispiel zum Abfragen des Extensionstrings ing OpenGL: // int hasImaging = isExtensionSupported("GL_ARB_imaging"); #ifdef _WIN32 glTexImage3D = (PFNGLTEXIMAGE3DPROC) wglGetProcAddress("glTexImage3D"); #endif }; #ifndef PI const double PI = 3.14159265358979323846; #endif CGTexture::CGTexture() { run_ = false; zoom_ = 1.0; usetorus_ = true; texWidth_ = texHeight_ = texDepth_ = 64; } CGTexture::~CGTexture() { } void CGTexture::drawScene() { glPushMatrix(); glRotatef(200, 0.0, 1.0, 0.0); glRotatef(55,1,0,0); glScaled(zoom_, zoom_, zoom_); glEnable(GL_TEXTURE_3D); if (usetorus_) { // our oopy-doopy torus drawObject(); } else { // a simple quad to test the 3D texture static float depth = 0; static float increment = 0.01; glDisable(GL_LIGHTING); glBegin(GL_QUADS); glTexCoord3f(0,0,depth); glVertex3f(-1,-1,0); glTexCoord3f(1,0,depth); glVertex3f(+1,-1,0); glTexCoord3f(1,1,depth); glVertex3f(+1,+1,0); glTexCoord3f(0,1,depth); glVertex3f(-1,+1,0); glEnd(); glEnable(GL_LIGHTING); depth += increment; if (depth < 0 || depth > 1) { increment = -increment; depth += increment; } } glDisable(GL_TEXTURE_3D); glPopMatrix(); } void CGTexture::drawObject() { // draw torus glCallList(torus_); } void CGTexture::buildPatch(int detail) { if (glIsList(torus_)) glDeleteLists(torus_, 1); GLint i, j; float theta1, phi1, theta2, phi2, rings, sides; float v0[03], v1[3], v2[3], v3[3]; float t0[03], t1[3], t2[3], t3[3]; float n0[3], n1[3], n2[3], n3[3]; float innerRadius=0.4; float outerRadius=0.8; float scalFac; rings = detail; sides = 10; scalFac=1/((outerRadius+innerRadius)*2); glNewList(torus_, GL_COMPILE); glBegin(GL_QUADS); for (i = 0; i < rings; i++) { theta1 = (float)i * 2.0 * PI / rings; theta2 = (float)(i + 1) * 2.0 * PI / rings; for (j = 0; j < sides; j++) { phi1 = (float)j * 2.0 * PI / sides; phi2 = (float)(j + 1) * 2.0 * PI / sides; v0[0] = cos(theta1) * (outerRadius + innerRadius * cos(phi1)); v0[1] = -sin(theta1) * (outerRadius + innerRadius * cos(phi1)); v0[2] = innerRadius * sin(phi1); v1[0] = cos(theta2) * (outerRadius + innerRadius * cos(phi1)); v1[1] = -sin(theta2) * (outerRadius + innerRadius * cos(phi1)); v1[2] = innerRadius * sin(phi1); v2[0] = cos(theta2) * (outerRadius + innerRadius * cos(phi2)); v2[1] = -sin(theta2) * (outerRadius + innerRadius * cos(phi2)); v2[2] = innerRadius * sin(phi2); v3[0] = cos(theta1) * (outerRadius + innerRadius * cos(phi2)); v3[1] = -sin(theta1) * (outerRadius + innerRadius * cos(phi2)); v3[2] = innerRadius * sin(phi2); n0[0] = cos(theta1) * (cos(phi1)); n0[1] = -sin(theta1) * (cos(phi1)); n0[2] = sin(phi1); n1[0] = cos(theta2) * (cos(phi1)); n1[1] = -sin(theta2) * (cos(phi1)); n1[2] = sin(phi1); n2[0] = cos(theta2) * (cos(phi2)); n2[1] = -sin(theta2) * (cos(phi2)); n2[2] = sin(phi2); n3[0] = cos(theta1) * (cos(phi2)); n3[1] = -sin(theta1) * (cos(phi2)); n3[2] = sin(phi2); t0[0] = v0[0]*scalFac + 0.5; t0[1] = v0[1]*scalFac + 0.5; t0[2] = v0[2]*scalFac + 0.5; t1[0] = v1[0]*scalFac + 0.5; t1[1] = v1[1]*scalFac + 0.5; t1[2] = v1[2]*scalFac + 0.5; t2[0] = v2[0]*scalFac + 0.5; t2[1] = v2[1]*scalFac + 0.5; t2[2] = v2[2]*scalFac + 0.5; t3[0] = v3[0]*scalFac + 0.5; t3[1] = v3[1]*scalFac + 0.5; t3[2] = v3[2]*scalFac + 0.5; glNormal3fv(n3); glTexCoord3fv(t3); glVertex3fv(v3); glNormal3fv(n2); glTexCoord3fv(t2); glVertex3fv(v2); glNormal3fv(n1); glTexCoord3fv(t1); glVertex3fv(v1); glNormal3fv(n0); glTexCoord3fv(t0); glVertex3fv(v0); } } glEnd(); glEndList(); } // // Einige nützliche Funktionen: // // distance from a point inline float distance(float x, float y, float z, float cx, float cy, float cz) { float dx = x-cx; float dy = y-cy; float dz = y-cz; return sqrt(dx*dx + dy*dy + dz*dz); } // clamp x to be between a and b inline float clamp(float x, float a, float b) { return (x < a ? a : (x > b ? b : x)); } inline float smoothstep(float a, float b, float x) { if(x<=a) return 0.0; if(x>=b) return 1.0; x = (x-a)/(b-a); // normalized interval [0,1] return x*x*(3-2*x); } // Spline Interpolation Vector spline(float x, int nknots, Vector* knot) { int span; int nspans = nknots-3; Vector c0,c1,c2,c3; if(nspans<1) { cout << "Error in spline function" << endl; return NULL; } x=clamp(x,0,1)*nspans; span = (int) x; if(span >= nknots-3) span = nknots-3; x-=span; // Horner c3 = -0.5 * knot[span] + 1.5 * knot[1+span] - 1.5 * knot[2+span] + 0.5 * knot[3+span]; c2 = 1.0 * knot[span] - 2.5 * knot[1+span] + 2.0 * knot[2+span] - 0.5 * knot[3+span]; c1 = -0.5 * knot[span] + 0.0 * knot[1+span] + 0.5 * knot[2+span] + 0.0 * knot[3+span]; c0 = 0.0 * knot[span] + 1.0 * knot[1+span] + 0.0 * knot[2+span] + 0.0 * knot[3+span]; return ((c3*x + c2)*x + c1)*x + c0; } Vector mix(const Vector& color1, const Vector& color2, const float alpha) { return (1-alpha)*color1 + alpha*color2; } static Vector dark = Vector(0.10, 0.10, 0.15); static Vector bright = Vector(0.95, 0.95, 0.95); static Vector brown = Vector(0.80, 0.65, 0.35); void CGTexture::createNoiseTexture3D() { int w = texWidth_; int h = texHeight_; int d = texDepth_; // Notwendiger Aufruf zur Initialisierung der Hashtable-Struktur: Noise::init(); GLubyte *img1 = new GLubyte[w * h * d * 3]; // 3D Textur I GLubyte *img2 = new GLubyte[w * h * d * 3]; // 3D Textur II GLubyte *img3 = new GLubyte[w * h * d * 3]; // 3D Textur III // // Generieren Sie eine 3D-Textur, die Marmor oder eine Steinstruktur simuliert // // Benutzen Sie die Perlin-Noise-Funktion: Noise::noise3(point) (!) // ... // // Lassen Sie Ihrer Kreativitaet freien Lauf! // cout << endl <<"3x 3D Textures ("< 1) noise1 = 1; if (noise2 < 0) noise2 = 0; if (noise2 > 1) noise2 = 1; // color Vector color(0,0,0); // brown marble color = mix(bright, brown, smoothstep(0.55, 0.60, noise1)); color = mix(color, bright, smoothstep(0.65, 0.68, noise1)); // texture III: brown marble img3[baseoffset+0] = color[0]*255; img3[baseoffset+1] = color[1]*255; img3[baseoffset+2] = color[2]*255; // dark marble if (noise2 <= 0.55) color = mix(color, dark, smoothstep(0.50, 0.52, noise2)); if (noise2 >= 0.52) color = mix(dark, color, smoothstep(0.52, 0.55, noise2)); // texture I: combined img1[baseoffset+0] = color[0]*255; img1[baseoffset+1] = color[1]*255; img1[baseoffset+2] = color[2]*255; // dark marble (for texture II) color = mix(bright, dark, smoothstep(0.50, 0.52, noise2)); color = mix(color, bright, smoothstep(0.52, 0.55, noise2)); // texture II: dark marble img2[baseoffset+0] = color[0]*255; img2[baseoffset+1] = color[1]*255; img2[baseoffset+2] = color[2]*255; } // show progress (1 point = ca. 10%) if (x % 7 == 0) { cout << "."; cout.flush(); } } // Textur parameter glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glGenTextures(1, &texName1_); glGenTextures(2, &texName2_); glGenTextures(3, &texName3_); // texture I glBindTexture(GL_TEXTURE_3D, texName1_); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, w, h, d, 0, GL_RGB, GL_UNSIGNED_BYTE, img1); // texture II glBindTexture(GL_TEXTURE_3D, texName2_); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, w, h, d, 0, GL_RGB, GL_UNSIGNED_BYTE, img2); // texture III glBindTexture(GL_TEXTURE_3D, texName3_); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, w, h, d, 0, GL_RGB, GL_UNSIGNED_BYTE, img3); // activate texture I glBindTexture(GL_TEXTURE_3D, texName1_); delete[] img1; delete[] img2; delete[] img3; } void CGTexture::onInit() { buildAvailableExtensions(); torus_ = glGenLists(1); buildPatch(32); // Prozedurale 3D Textur createNoiseTexture3D(); /* init light */ GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 25.0 }; GLfloat gray[] = { 0.6, 0.6, 0.6, 0.0 }; GLfloat white[] = { 1.0, 1.0, 1.0, 0.0 }; GLfloat light_position[] = { 0.0, 3.0, 3.0, 0.0 }; glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightfv(GL_LIGHT0, GL_AMBIENT, gray); glLightfv(GL_LIGHT0, GL_DIFFUSE, white); glLightfv(GL_LIGHT0, GL_SPECULAR, white); glColorMaterial(GL_FRONT, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // Tiefen Test aktivieren glEnable(GL_DEPTH_TEST); // Smooth Schattierung aktivieren glShadeModel(GL_SMOOTH); // Projection glMatrixMode(GL_PROJECTION); gluPerspective(60.0, 1.0, 2.0, 50.0); // LookAt glMatrixMode(GL_MODELVIEW); gluLookAt( 0.0, 0.0, 4.0, // from (0,0,4) 0.0, 0.0, 0.0, // to (0,0,0) 0.0, 1.0, 0.); // up glClearColor(1, 1, 1, 1); } void CGTexture::onSize(unsigned int newWidth,unsigned int newHeight) { width_ = newWidth; height_ = newHeight; glMatrixMode(GL_PROJECTION); glViewport(0, 0, width_ - 1, height_ - 1); glLoadIdentity(); gluPerspective(40.0,float(width_)/float(height_),2.0, 100.0); glMatrixMode(GL_MODELVIEW); } void CGTexture::onKey(unsigned char key) { switch (key) { case 27: { exit(0); break; } case '+': { zoom_*= 1.1; break; } case '-': { zoom_*= 0.9; break; } case ' ': { run_ = !run_; break; } case '1': { buildPatch(4); break; } case '2': { buildPatch(8); break; } case '3': { buildPatch(16); break; } case '4': { buildPatch(32); break; } case '5': { buildPatch(64); break; } case '6': { buildPatch(128); break; } case 't': { usetorus_ = !usetorus_; break; } case 'q': { glBindTexture(GL_TEXTURE_3D, texName1_); break; } case 'w': { glBindTexture(GL_TEXTURE_3D, texName2_); break; } case 'e': { glBindTexture(GL_TEXTURE_3D, texName3_); break; } } onDraw(); } void CGTexture::onIdle() { if (run_) { glRotatef(.5, 0.0, 1.0, 0.0); } onDraw(); } void CGTexture::onDraw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawScene(); swapBuffers(); } // Hauptprogramm int main(int argc, char* argv[]) { // Erzeuge eine Instanz der Beispiel-Anwendung: CGTexture sample; cout << "Tastenbelegung:" << endl << "ESC Programm beenden" << endl << "Leertaste Objekt drehen" << endl << "+ Hineinzoomen" << endl << "- Herauszoomen" << endl << "t Torus oder Quadrat zeichnen" << endl << "q gemischter Marmor" << endl << "w schwarzer Marmor" << endl << "e brauner Marmor" << endl << "1-6 Tessellationsgrad des Torus (max=6)" << endl; // Starte die Beispiel-Anwendung: sample.start("Stephan Brumme, 702544", true, 256, 256); return(0); }