对于初学者来说,做小项目用的glut已经很足够了,它的定义是用于简单程序和初学者学习使用的简单的、容易的、小的。
vs2015创建空项目:
然后在项目中添加glut中include路径:
先创建一个调用glut.h的大框架:
#include
// 创建图形窗口的基本宏
#define WINDOW_X_POS 50
#define WINDOW_Y_POS 50
#define WIDTH 700
#define HEIGHT 700
// 用于注册 GLUT 的回调
void onDisplay(void);
void onUpdate(void);
void onKeyboard(unsigned char key, int x, int y);
int main(int argc, char* argv[]) {
// 对 GLUT 进行初始化,并处理所有的命令行参数
glutInit(&argc, argv);
// 这个函数指定了使用 RGBA 模式还是颜色索引模式。另外还可以
// 指定是使用单缓冲还是双缓冲窗口。这里我们使用 RGBA 和 双缓冲窗口
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
// 设置窗口被创建时左上角位于屏幕上的位置
glutInitWindowPosition(WINDOW_X_POS, WINDOW_Y_POS);
// 设置窗口被创建时的宽高, 为了简便起见
glutInitWindowSize(WIDTH, HEIGHT);
// 创建一个窗口,输入的字符串为窗口的标题
glutCreateWindow("SolarSystem at Shiyanlou");
// glutDisplayFunc 的函数原型为 glutDisplayFunc(void (*func)(void))
// 这是一个回调函数,每当 GLUT 确定一个窗口的内容需要更新显示的时候,
// glutDisplayFunc 注册的回调函数就会被执行.
//
// glutIdleFunc(void (*func)(void)) 将指定一个函数,用于处理当事件循环
// 处于空闲的时候,就执行这个函数。这个回调函数接受一个函数指针作为它的唯一参数
//
// glutKeyboardFunc(void (*func)(unsigned char key, int x, int y))
// 会将键盘上的键与一个函数关联,当这个键被按下或者释放时,函数就会调用
//
// 因此下面的三行实际上是在向 GLUT 注册关键的三个回调函数
glutDisplayFunc(onDisplay);
glutIdleFunc(onUpdate);
glutKeyboardFunc(onKeyboard);
glutMainLoop();
return 0;
}
进行我们需要的更改:
//
// main.cpp
// solarsystem
//
#include //glut基本头文件
#include "solarsystem.h"
//创建图形窗口的基本宏
#define WINDOW_X_POS 50
#define WINDOW_Y_POS 50
#define WIDTH 700
#define HEIGHT 700
SolarSystem solarsystem;
//用于注册glut的回调
void onDisplay(void) {
solarsystem.onDisplay();
}
void onUpdate(void) {
solarsystem.onUpdate();
}
void onKeyboard(unsigned char key, int x, int y) {
solarsystem.onKeyboard(key, x, y);
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);//对GLUT初始化,并处理所有命令行参数
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
//指定使用RGBA模式
//另外指定了双缓冲窗口
glutInitWindowPosition(WINDOW_X_POS, WINDOW_Y_POS);
//指定窗口创建时左上角位于屏幕的位置
glutCreateWindow("SolarSystem");
//指定创建的窗口标题为SolarSystem
glutDisplayFunc(onDisplay);
//回调函数,当GLUT确定窗口内容需要更新时
//指定函数onDisplay就会被执行
glutIdleFunc(onUpdate);
//指定函数onUpdate
//当事件循环处于空闲,执行此函数
glutKeyboardFunc(onKeyboard);
//将键盘上的键与函数相关联,按键被按下或者释放,函数调用
glutMainLoop();
return 0;
}
基础知识:
单缓冲:将所有指令在窗口上直接执行,即就图绘画,但效率低下,且受限于电脑性能。如果电脑性能很差,就会出现闪烁。
双缓冲:绘图指令在缓冲区完成,并在完成后通过交换指令输出完成后的图形,视觉效果好,效率较单缓冲要高。
双缓冲又可分为前台缓冲和后台缓冲,前台缓冲就我们肉眼所见的屏幕,后台缓冲则在内存中。后者的操作会将完成了图片复制到屏幕上面。由于绘制操作是与显卡实时进行,任务复杂,IO操作复杂,显示效果就会很差,而在交换缓冲区进行绘制,后面就可直接发效果给显卡渲染即可。
既然是c++,那当然得有面向对象的操作,来,大家看到我的项目名字吗?哦,我没放出来,哈哈哈。我这里是在进行了实验楼的太阳系描绘后,根据我做的记录来在自己电脑上面的实操,对的,我这里要重绘太阳系:
如下初始化:
初始化 OpenGL 引擎, 实现 onDraw 和 onUpdate;
星球有自己的属性、绕行关系、变换相关绘制,因此在设计星球的类时应该提供一个绘制 draw() 方法;对于星球的自转公转应有一个控制更新的方法update();
在 onDraw() 中应调用各星球的 draw() 方法;
在 onUpdate() 中调用各星球的 update() 方法;
在 onKeyboard() 键盘调整整个太阳系的显示。
具体属性:
颜色 color
公转半径 radius
自转速度 rotationSp
公转速度 revolutionSp
距离太阳中心的距离 distance
围绕公转的星球 parentStar
当前的自转的角度 rotation_angle
当前的公转角度 revolution_angle
好的,基本格调如此
class Star {
public:
// 星球的运行半径
GLfloat radius;
// 星球的公转、自传速度
GLfloat rotationSp, revolutionSp;
// 星球的中心与父节点星球中心的距离
GLfloat distance;
// 星球的颜色
GLfloat rgbaColor[4];
// 父节点星球
Star* parentStar;
// 构造函数,构造一颗星球时必须提供
// 旋转半径、旋转速度、自转速度、绕行(父节点)星球
Star(GLfloat radius, GLfloat distance,
GLfloat revolutionSp, GLfloat rotationSp,
Star* parentStar);
// 对一般的星球的移动、旋转等活动进行绘制
void drawStar();
// 提供默认实现,负责调用 drawStar()
virtual void draw() { drawStar(); }
// 参数为每次刷新画面时的时间跨度
virtual void update(long timeSpan);
protected:
GLfloat rotationang, revolution_angle;
};
class Planet : public Star {
public:
// 构造函数
Planet(GLfloat radius, GLfloat distance,
GLfloat revolutionSp, GLfloat rotationSp,
Star* parentStar, GLfloat rgbColor[3]);
// 增加对具备自身材质的行星绘制材质
void drawPlanet();
// 继续向其子类开放重写功能
virtual void draw() { drawPlanet(); drawStar(); }
};
class Fixed_star : public Planet {
public:
Fixed_star(GLfloat Radius, GLfloat Distance,
GLfloat revolutionSp, GLfloat rotationSp,
Star* ParentStar, GLfloat rgbColor[]);
// 增加对提供光源的恒星绘制光照
void drawsun();
virtual void draw() { drawsun(); drawPlanet(); drawStar(); }
};
接着是我们太阳系的设计
#include"stars.h"
#include
#define STARS_NUM 10
class SolarSystem {
public:
SolarSystem();
~SolarSystem();
void onDisplay();
void onUpdate();
void onKeyboard(unsigned char key, int x, int y);
private:
Star *stars[STARS_NUM];
// 定义观察视角的参数
GLdouble viewX, viewY, viewZ;
GLdouble centerX, centerY, centerZ;
GLdouble upX, upY, upZ;
};
太阳系内部成员九个(不包含冥王星)
以star为基本对象:
#define STARS_NUM 10
enum STARS {
Sun, // 太阳
Mercury, // 水星
Venus, // 金星
Earth, // 地球
Moon, // 月球
Mars, // 火星
Jupiter, // 木星
Saturn, // 土星
Uranus, // 天王星
Neptune // 海王星
};
Star * stars[STARS_NUM];
//相同自转速度
#define TIMEPAST 1
#define SELFROTATE 3
//
// stars.cpp
// solarsystem
//
#include "stars.h"
#define PI 3.1415926535
Star::Star(GLfloat radius, GLfloat distance,
GLfloat revolutionSp, GLfloat rotationSp,
Star* parentStar) {
// TODO:
}
void Star::drawStar() {
// TODO:
}
void Star::update(long timeSpan) {
// TODO:
}
Planet::Planet(GLfloat radius, GLfloat distance,
GLfloat revolutionSp, GLfloat rotationSp,
Star* parentStar, GLfloat rgbColor[3]):Star(radius,distance,revolutionSp,rotationSp,parentStar){
// TODO:
}
void Planet::drawPlanet() {
// TODO:
}
Fixed_star::Fixed_star(GLfloat Radius, GLfloat Distance,
GLfloat revolutionSp, GLfloat rotationSp,
Star* ParentStar, GLfloat rgbColor[]):
Planet(radius, distance, revolutionSp,rotationSp, parentStar, rgbColor) {
// TODO:
}
void Fixed_star::drawsun() {
// TODO:
}
//
//
// solarsystem
//
#include "solarsystem.h"
#define TIMEPAST 1
#define SELFROTATE 3
enum STARS {
Sun, Mercury, Venus, Earth, Moon,
Mars, Jupiter, Saturn, Uranus, Neptune
};
void SolarSystem::onDisplay() {
// TODO:
}
void SolarSystem::onUpdate() {
// TODO:
}
void SolarSystem::onKeyboard(unsigned char key, int x, int y) {
// TODO:
}
SolarSystem::SolarSystem() {
// TODO:
}
SolarSystem::~SolarSystem() {
// TODO:
}
错误 LNK1104 无法打开文件“glut32.lib” solarsystem
这是连接错误,因为当初我下载glut的时候就没发现glut32.lib等文件,所以在创建项目的时候就没有在动态库中包含进去,现在要解决这个问题了。
sudo apt-get update && sudo apt-get install freeglut3 freeglut3-dev
因为sudo命令在centos7上面运行会出现无法找到,centos7用的还是yum来安装
# yum list mesa*
# yum install -y mesa*
# yum install -y freeglut*
# yum install -y *glew*
安装好后就是对之前的程序进行测试,那么问题来了,由于先前在vs2015上面进行编辑,留下了太多格式问题,所以有好的方法解决请告诉我,谢谢(就是说我用了老办法!对应删空格!)哦对了,还有个法子,就是你vim建立了文档,直接保存退出,不编辑。。。。。。搞了两三个才想起这方法。
接下来就是编写makefile
CXX = g++
EXEC = solarsystem
SOURCES = main.cpp stars.cpp solarsystem.cpp
OBJECTS = main.o stars.o solarsystem.o
LDFLAGS = -lglut -lGL -lGLU
all :
$(CXX) $(SOURCES) $(LDFLAGS) -o $(EXEC)
clean:
rm -f $(EXEC) *.gdb *.o
我在这里make编译时出现以下错误:
make: *** makefile: 是一个目录。 停止。
百度到的结果是:
特殊变量VPATH的编写错误导致,VPATH是makefile中的特殊变量,用于标示目标文件和依赖文件的,没定义的话就会在所在目录进行寻找。进行到这里也挺累的了,先留一下吧,明天继续。
哦,忘记了,还可以直接编译运行的,我上去就是一个g++
g++ solarsystem.cpp stars.cpp main.cpp -o solarsystem
然后报错了。。。。。。
问题显示如下:
/tmp/ccn3DYud.o:在函数‘main’中:
main.cpp:(.text+0x69):对‘glutInit’未定义的引用
main.cpp:(.text+0x73):对‘glutInitDisplayMode’未定义的引用
main.cpp:(.text+0x82):对‘glutInitWindowPosition’未定义的引用
main.cpp:(.text+0x8c):对‘glutCreateWindow’未定义的引用
main.cpp:(.text+0x96):对‘glutDisplayFunc’未定义的引用
main.cpp:(.text+0xa0):对‘glutIdleFunc’未定义的引用
main.cpp:(.text+0xaa):对‘glutKeyboardFunc’未定义的引用
main.cpp:(.text+0xaf):对‘glutMainLoop’未定义的引用
collect2: 错误:ld 返回 1
原来是还没链接编译,然后我学废了,再来!
g++ main.cpp stars.cpp solarsystem.cpp -lglut -lGL -lGLU -o solarsystem
然后,生成了!
我美滋滋的运行,一片黑如我的脸色。。。。。。毕竟还没完善上面的成员函数,害,知足吧。makefile都写不好呢(悻悻)。
后续如下:
openGL学习之太阳系天体系统绘制