用OpenGL实现跳跃的立体小球
一、目的
掌握OpenGL中显示列表对象的使用方法。
二、示例代码
#include "stdafx.h" #include <GL/glut.h> #include <cmath> #include <stdlib.h> #include <GL/glut.h> #include <math.h> //色彩全局常量 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 x, double z) : radius(r), color(c), maximumHeight(h), direction(-1), y(h), x(x), z(z) { } //更新和绘制方法 void update() { //正反运动 y += direction * 0.05; if (y > maximumHeight) { y = maximumHeight; direction = -1; } else if (y < radius) { y = radius; 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(1, GREEN, 7, 6, 1), Ball(1.5, MAGENTA, 6, 3, 4), Ball(0.4, WHITE, 5, 1, 7) }; //自定义初始化方法 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(); //绘制小球 for (int i = 0; i < sizeof balls / sizeof(Ball); i++) { //更新位置并绘图 balls[i].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(); } 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); //设置按键处理函数 glutTimerFunc(100, timer, 0); //设置计时器函数--每100ms被调用1次 init();//自定义初始化函数 glutMainLoop();//进入opengl主循环 return 0; }
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子里和园子外的大大们指正错误,共同进步。或者直接私信我 (^∀^)
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
您的资助是我最大的动力!
金额随意,欢迎来赏!
如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的
本博客的所有打赏均将用于博主女朋友的化妆品购买以及养肥计划O(∩_∩)O。我是【~不会飞的章鱼~】!