1. 程式人生 > >為OpenGL考試而準備的程式碼——滑鼠控制視角變換+簡單紋理對映+鍵盤的光照控制+Bezier曲線

為OpenGL考試而準備的程式碼——滑鼠控制視角變換+簡單紋理對映+鍵盤的光照控制+Bezier曲線

使用背景:

使用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;
}
執行結果如下: