為OpenGL考試而準備的程式碼——滑鼠控制視角變換+簡單紋理對映+鍵盤的光照控制+Bezier曲線
阿新 • • 發佈:2019-02-19
使用背景:
使用codeblocks13.12編譯,呼叫了imageloader.cpp和imageloader.h
程式碼如下:
執行結果如下:#include <windows.h> #include <iostream> #include <stdlib.h> #include <math.h> #ifdef __APPLE__ #include <OpenGL/OpenGL.h> #include <GLUT/glut.h> #else #include <GL/glut.h> #endif #include "imageloader.h" #define G_PI 3.14159265358979323846f using namespace std; const float BOX_SIZE = 7.0f; //立方體長度 static double _angle = 0; //立方體自動旋轉角度 static double SX=1,SY=1,SZ=1,theta=0,phi=0; static int du=90,oldmy=-1,oldmx=-1; //du是視點繞y軸的角度,opengl裡預設y軸是上方向 static double r=1.5f,h=0.0f; //r是視點繞y軸的半徑,h是視點高度即在y軸上的座標 static double c=G_PI/180.0f; //弧度和角度轉換引數 static double ctrlPoints[4][3]; GLuint _textureId; //紋理的OpenGL的ID GLuint _textureId1; //紋理的OpenGL的ID GLuint _textureId2; //紋理的OpenGL的ID //光照控制 void prepare_lighting() { theta = fmodf( theta, 2*G_PI ); phi = fmodf( phi, 2*G_PI ); int dis=1; float light_diffuse[4] = {1.0, 1.0, 1.0, 1.0}; float mat_diffuse[4] = {1.0, 1.0, 1.0, 1.0}; float light_position[4] = { dis*sinf(theta) * cosf(phi), dis*cosf(theta), dis*(-sinf(theta) * sinf(phi)), 0 }; glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable( GL_LIGHT0 ); } //鍵盤操作 void keyboard(unsigned char key, int x, int y) { switch( key ) { case 'w': theta -= .05; prepare_lighting(); glutPostRedisplay(); break; case 's': theta += .05; prepare_lighting(); glutPostRedisplay(); break; case 'a': phi -= .05; prepare_lighting(); glutPostRedisplay(); break; case 'd': phi += .05; prepare_lighting(); glutPostRedisplay(); break; case '+': SX+=0.1; SY+=0.1; SZ+=0.1; prepare_lighting(); glutPostRedisplay(); break; case '-': SX-=0.1; SY-=0.1; SZ-=0.1; // prepare_lighting(); glutPostRedisplay(); break; case 27: exit(0); }; } //滑鼠點選 void Mouse(int button, int state, int x, int y) { if(state==GLUT_DOWN) //第一次滑鼠按下時,記錄滑鼠在視窗中的初始座標 oldmx=x,oldmy=y; } void onMouseMove(int x,int y) //滑鼠拖動 { du+=x-oldmx; //滑鼠在視窗x軸方向上的增量加到視點繞y軸的角度上,這樣就左右轉了 h +=0.03f*(y-oldmy); //滑鼠在視窗y軸方向上的改變加到視點的y座標上,就上下轉了 if(h>1.0f) h=1.0f; //視點y座標作一些限制,不會使視點太奇怪 else if(h<-1.0f) h=-1.0f; oldmx=x,oldmy=y; //把此時的滑鼠座標作為舊值,為下一次計算增量做準備 prepare_lighting(); glutPostRedisplay(); } //使影象轉換成紋理,並返回紋理的ID GLuint loadTexture(Image* image) { GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image->width, image->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->pixels); return textureId; } //紋理對映控制 void initRendering() { glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); glEnable(GL_COLOR_MATERIAL); Image* image = loadBMP("C:\\Program Files (x86)\\CodeBlocks\\MinGW\\Example\\cube(wen li ying she)\\111.bmp"); _textureId = loadTexture(image); Image* image1 = loadBMP("C:\\Program Files (x86)\\CodeBlocks\\MinGW\\Example\\cube(wen li ying she)\\222.bmp"); _textureId1 = loadTexture(image1); Image* image2 = loadBMP("C:\\Program Files (x86)\\CodeBlocks\\MinGW\\Example\\cube(wen li ying she)\\333.bmp"); _textureId2 = loadTexture(image2); delete image,image1,image2; } //Bezier曲線 void BezierCurve(int n) { ctrlPoints[0][0]=5.0;//初始點 ctrlPoints[0][1]=5.0; ctrlPoints[0][2]=5.0; ctrlPoints[1][0]=15.5; ctrlPoints[1][1]=15.1; ctrlPoints[1][2]=15.2; ctrlPoints[2][0]=15.0; ctrlPoints[2][1]=-15.2; ctrlPoints[2][2]=-15.2; ctrlPoints[3][0]=5.5;//結束點 ctrlPoints[3][1]=-5.3; ctrlPoints[3][2]=-5.3; double t, dt, t2, t3,t4, f1, f2, f3, f4; dt = 1.0/n; // t從0到1 glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_STRIP); for (t = 0.0; t <= 1.0; t += dt) { //三次Bezier曲線 t2 = t * t; t3 = t2 * t; // t3 = t * t * t t4 = (1-t); f1 = t4*t4*t4; f2 = 3*t*t4*t4; f3 = 3*t2*t4; f4 = t3; glNormal3f( f1*ctrlPoints[0][0] + f2*ctrlPoints[1][0] + f3*ctrlPoints[2][0] + f4*ctrlPoints[3][0], f1*ctrlPoints[0][1] + f2*ctrlPoints[1][1] + f3*ctrlPoints[2][1] + f4*ctrlPoints[3][1], f1*ctrlPoints[0][2] + f2*ctrlPoints[1][2] + f3*ctrlPoints[2][2] + f4*ctrlPoints[3][2] ); glVertex3f( f1*ctrlPoints[0][0] + f2*ctrlPoints[1][0] + f3*ctrlPoints[2][0] + f4*ctrlPoints[3][0], f1*ctrlPoints[0][1] + f2*ctrlPoints[1][1] + f3*ctrlPoints[2][1] + f4*ctrlPoints[3][1], f1*ctrlPoints[0][2] + f2*ctrlPoints[1][2] + f3*ctrlPoints[2][2] + f4*ctrlPoints[3][2] ); } glEnd(); } void init() { initRendering();//呼叫紋理對映 prepare_lighting();//先改光照,再改觀察點 glTranslatef(0.0f, 0.0f, -20.0f);//平移函式,要在gluLookAt之前,否則將出現觀察點固定,拖動滑鼠只能環視的情況 gluLookAt(r*cos(c*du), h, r*sin(c*du), 0, 0, 0, 0, 1, 0);//設定觀察點 BezierCurve(10);//Bezier曲線 glRotatef(-_angle, 1.0f, 1.0f, 0.0f);//自動旋轉 glBegin(GL_QUADS); //Top face glColor3f(1.0f, 1.0f, 0.0f); glNormal3f(0.0, 1.0f, 0.0f); glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2); glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2); glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2); glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2); //Bottom face glColor3f(1.0f, 0.0f, 1.0f); glNormal3f(0.0, -1.0f, 0.0f); glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2); glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2); glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2); glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2); //Left face glNormal3f(-1.0, 0.0f, 0.0f); glColor3f(0.0f, 1.0f, 1.0f); glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2); glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2); glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2); glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2); //Right face glNormal3f(1.0, 0.0f, 0.0f); glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2); glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2); glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2); glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2); glEnd(); //Front face glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, _textureId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_QUADS); glNormal3f(0.0, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2); glTexCoord2f(1.0f, 0.0f); glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, BOX_SIZE / 2); glTexCoord2f(1.0f, 1.0f); glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2); glTexCoord2f(0.0f, 1.0f); glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, BOX_SIZE / 2); glEnd(); glDisable(GL_TEXTURE_2D); //Back face glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, _textureId2); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_QUADS); glNormal3f(0.0, 0.0f, -1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2); glTexCoord2f(1.0f, 0.0f); glVertex3f(-BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2); glTexCoord2f(1.0f, 1.0f); glVertex3f(BOX_SIZE / 2, BOX_SIZE / 2, -BOX_SIZE / 2); glTexCoord2f(0.0f, 1.0f); glVertex3f(BOX_SIZE / 2, -BOX_SIZE / 2, -BOX_SIZE / 2); glEnd(); glDisable(GL_TEXTURE_2D); } void drawScene() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除螢幕 glMatrixMode(GL_PROJECTION);//設定觀察點 glLoadIdentity(); gluPerspective(75.0f, 1, 1.0f, 1000.0f); glMatrixMode(GL_MODELVIEW);//設定觀察點 glLoadIdentity(); // glutSolidTeapot( .1 ); init(); glutSwapBuffers(); } //旋轉速度 每30ms重新整理一次 void update(int value) { _angle += 1.0f; if (_angle > 360) { _angle -= 360; } glutPostRedisplay(); glutTimerFunc(30, update, 0); } int main(int argc, char** argv) { cout<<"wasd控制光照,滑鼠拖動控制視點旋轉"; theta = G_PI/2; phi = -G_PI/2; glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(400, 400); glutCreateWindow("滑鼠控制視角變換+簡單紋理對映+鍵盤的光照控制"); glutDisplayFunc(drawScene); glutKeyboardFunc( keyboard ); glutMouseFunc(Mouse); glutMotionFunc(onMouseMove); glutTimerFunc(30, update, 0); glutMainLoop(); return 0; }