代碼實現功能如下:
繪製一個小球,並且在小球下方添加有材質的地面。w,s,a,d分別實現控制小球上,下,左,右的移動。鍵盤上,下,左,右的箭頭分別控制視角的旋轉變化。
#include <GL/glut.h>
#include <cmath>
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
static int s = 0;
//色彩全局常量
GLfloat WHITE[] = { 1, 1, 1 }; //白色
GLfloat RED[] = { 1, 0, 0 }; //紅色
GLfloat GREEN[] = { 0, 1, 0 }; //綠色
GLfloat MAGENTA[] = { 1, 0, 1 }; //洋紅
//攝像機類:水平移動半徑爲10,按上下鍵則垂直移動
class Camera {
public:
double theta; //確定x和z的位置
double y; //y位置
double dTheta; //角度增量
double dy; //上下y增量
public:
//類構造函數—默認初始化用法
Camera() : theta(0), y(3), dTheta(0.04), dy(0.2) {}
//類方法
double getX() { return 10 * cos(theta); }
double getY() { return y; }
double getZ() { return 10 * sin(theta); }
void moveRight() { theta += dTheta; }
void moveLeft() { theta -= dTheta; }
void moveUp() { y += dy; }
void moveDown() { if (y > dy) y -= dy; }
};
//球類定義
//半徑、顏色、最大高度
//x和z固定
//用lame bouncing algorithm
//每幀上下移動0.05單位
class Ball {
//類的屬性
double radius;
GLfloat* color;
double maximumHeight;
double x;
double y;
double z;
int direction; //方向
public:
//構造函數
Ball(double r, GLfloat* c, double h, double y, double z) :
radius(r), color(c), maximumHeight(h), direction(-1),
y(h), x(x), z(z) {
}
//更新和繪製方法
void update() {
if(s==0){
z+=0.05;
}
else if(s==1){
z-=0.05;
}
else if(s==2){
x+=0.05;
}
else if(s==3){
x-=0.05;
}
if (x > 7) {
x = 7;
direction = -1;
}
else if (x < 0) {
x =0;
direction = 1;
}
glPushMatrix();
//單獨設置每個球的材質參數
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
glTranslated(x, y, z);
//創建球
glutSolidSphere(radius, 30, 30);
glPopMatrix();
}
};
//棋盤格:沿x和z平面分佈
//點光源位置設置爲(4, 3, 7).
class Checkerboard {
int displayListId;
int width;
int depth;
public:
//構造函數
Checkerboard(int width, int depth) : width(width), depth(depth) {}
//中心X
double centerx() { return width / 2; }
//中心Y
double centerz() { return depth / 2; }
//創建方法
void create() {
displayListId = glGenLists(1); //每個顯示列表對應1個編號——關聯起來
//新建操作表
glNewList(displayListId, GL_COMPILE); //把下述命令裝入顯示列表但不顯示
//光源位置參數
GLfloat lightPosition[] = { 4, 3, 7, 1 };
//設置光源位置
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
//開始繪製四邊形
glBegin(GL_QUADS);
//法向量方向
glNormal3d(0, 1, 0);
for (int x = 0; x < width - 1; x++) {
for (int z = 0; z < depth - 1; z++) {
//設置每個格子的材質屬性
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
(x + z) % 2 == 0 ? RED : WHITE);
//四邊形的4個點座標
glVertex3d(x, 0, z);
glVertex3d(x + 1, 0, z);
glVertex3d(x + 1, 0, z + 1);
glVertex3d(x, 0, z + 1);
}
}
glEnd();
glEndList();
}
//按列表編號繪製棋盤格
void draw() {
glCallList(displayListId);
}
};
//全局變量:棋盤格、相機和3個球的數組
Checkerboard checkerboard(8, 8);
Camera camera;
//創建3個小球的數組
Ball balls[] = {
Ball(0.2, GREEN, 0.2, 2, 3)
};
//自定義初始化方法
void init() {
//允許深度測試
glEnable(GL_DEPTH_TEST);
//設置散射和鏡像反射爲白光
glLightfv(GL_LIGHT0, GL_DIFFUSE, WHITE);
glLightfv(GL_LIGHT0, GL_SPECULAR, WHITE);
//設置前表面的高光鏡像反射爲白光
glMaterialfv(GL_FRONT, GL_SPECULAR, WHITE);
//設置前表面散射光反光係數
glMaterialf(GL_FRONT, GL_SHININESS, 30);
//允許燈光
glEnable(GL_LIGHTING);
//打開0#燈
glEnable(GL_LIGHT0);
//創建棋盤格
checkerboard.create();
}
//自定義繪製函數
//通過類繪製各對象,display函數代碼得以簡化
void display() {
//清除前一幀繪圖結果
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//裝入單位陣
glLoadIdentity();
//設置視角——攝像機參數
gluLookAt(camera.getX(), camera.getY(), camera.getZ(), //攝像機位置
checkerboard.centerx(), 0.0, checkerboard.centerz(), //焦點座標
0.0, 1.0, 0.0); //攝像機機頂方向矢量
//繪製棋盤
checkerboard.draw();
//繪製小球
//更新位置並繪圖
balls[0].update();
//glFlush();
glutSwapBuffers();
}
//窗口調整大小時調用的函數
void reshape(GLint w, GLint h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0, GLfloat(w) / GLfloat(h), 1.0, 150.0);
glMatrixMode(GL_MODELVIEW);
}
//自定義計時器函數
void timer(int v) {
//當計時器喚醒時所調用的函數
glutPostRedisplay();
//設置下一次計時器的參數
glutTimerFunc(1000 / 60, timer/*函數名*/, v);
}
//鍵盤處理函數
void onKey(int key, int, int) {
//按鍵:上下左右
switch (key) {
case GLUT_KEY_LEFT: camera.moveLeft(); break;
case GLUT_KEY_RIGHT: camera.moveRight(); break;
case GLUT_KEY_UP: camera.moveUp(); break;
case GLUT_KEY_DOWN: camera.moveDown(); break;
}
glutPostRedisplay();
}
void keyboard (unsigned char key, int x, int y)
{
switch (key) {
case 'w':
s=0;
balls[0].update();
glutPostRedisplay();
break;
case 's':
s=1;
balls[0].update();
glutPostRedisplay();
break;
case 'a':
s=2;
balls[0].update();
glutPostRedisplay();
break;
case 'd':
s=3;
balls[0].update();
glutPostRedisplay();
break;
}
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowPosition(80, 80);
glutInitWindowSize(800, 600);
glutCreateWindow("小球遊戲");
glutDisplayFunc(display); //設置顯示函數
glutReshapeFunc(reshape); //設置窗口調整大小的函數
glutSpecialFunc(onKey); //設置按鍵處理函數
glutKeyboardFunc(keyboard);
init();//自定義初始化函數
glutMainLoop();//進入opengl主循環
return 0;
}