openGL学习之glut库的使用

对于初学者来说,做小项目用的glut已经很足够了,它的定义是用于简单程序和初学者学习使用的简单的、容易的、小的。
vs2015创建空项目:
然后在项目中添加glut中include路径:
openGL学习之glut库的使用_第1张图片
先创建一个调用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++,那当然得有面向对象的操作,来,大家看到我的项目名字吗?哦,我没放出来,哈哈哈。我这里是在进行了实验楼的太阳系描绘后,根据我做的记录来在自己电脑上面的实操,对的,我这里要重绘太阳系:

  1. 类设计
    进行基本设定,首先太阳系是天体系统,所以先抽取概念天体系统。对于天体系统里面,最基本的对象就是天体(star),在此之上,不同天体有着各种不同属性:发光发热的恒星(fixed_star)、被各种恒星所捕抓的有特定轨道的行星(planet),另外就是这两个普遍元素以外的天体,这里姑且称为(sstar,special star)再来点正常设定:
    行星运行轨道为圆形;
    保持相同自转速度;
    定下刷新间隔为一天,一天结束,开始刷新

如下初始化:
初始化 OpenGL 引擎, 实现 onDraw 和 onUpdate;
星球有自己的属性、绕行关系、变换相关绘制,因此在设计星球的类时应该提供一个绘制 draw() 方法;对于星球的自转公转应有一个控制更新的方法update();
在 onDraw() 中应调用各星球的 draw() 方法;
在 onUpdate() 中调用各星球的 update() 方法;
在 onKeyboard() 键盘调整整个太阳系的显示。

具体属性:
颜色 color
公转半径 radius
自转速度 rotationSp
公转速度 revolutionSp
距离太阳中心的距离 distance
围绕公转的星球 parentStar
当前的自转的角度 rotation_angle
当前的公转角度 revolution_angle
好的,基本格调如此

  1. 编写对应头文件
    stars头文件
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
  1. 类方法的实现
//
//  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:
}
  1. 方法声明并没有给完全,是因为我现在想先检验这个框架的可行性,所以编译一下先。结果显示

错误 LNK1104 无法打开文件“glut32.lib” solarsystem
这是连接错误,因为当初我下载glut的时候就没发现glut32.lib等文件,所以在创建项目的时候就没有在动态库中包含进去,现在要解决这个问题了。

  1. 链接glut32.lib
    百度得来的结果呢,是当初的glut太老了,已经被舍弃,并且有了个替代版的freeglut
    这里推荐一个很多好用开发库的下载
    source
    下载好了,不过对应最新版和旧版,都是没有lib目录,哦豁,继续找解决办法
    最后实在没办法了,资源要么被别人作为生财之道,要么就是我网络无法连接过去,只好找找看有没有特定包了(深切体会到人们赚钱的渴望和资源的珍贵)。
  2. 转换思路
    在windows上面接连受挫,让我不由得想效仿实验楼的系统,在unix系统上面进行试验,反正是学习它的使用,linux虚拟机也没差。
    我用的是centos7所以无法像实验楼那样直接使用命令
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学习之glut库的使用_第2张图片
后续如下:
openGL学习之太阳系天体系统绘制

你可能感兴趣的:(c++)