1.掌握2D太阳系绘制方法。
2.掌握矩阵堆栈流程。
3.进一步掌握复合2D图形变换。
1.已知太阳半径氏,地球半径月球半径Rm,每 个星球都会自转,地球绕太阳公转,月球绕地球公转。
2.基本框架程序2DSunSystem.cpp见“五、附基本 框架程序。”
3.设计世界坐标系,见实验图7-1,设计裁剪窗口 大小,编写2D太阳系代码。
4.效果截图见实验图7-2o
5.分别在太阳、地球、月球位置添加中文字体“太阳”、“地球”、“月球”。
6.在修改的代码上加上一些点缀修饰性图形。
三、参考函数
1.void glPushMatrix(void)
2.void glPopMatrix(void)
3.相关参数设置:
glPointSize(16);//设置点大小
glLineWidth(10);//设置线宽
4.中文字体绘制。
1)在程序头部声明所用到的字体函数:
void selectFont(int size, int charset, const char* face); //选择字体函数
void drawCNString(const char* str);//生成中文字体函数
2)程序尾部定义选择字体函数和生成中文字体函数:
/**************************************************************/
/*选择字体函数*/
/**************************************************************/
void selectFont(int size, int charset, const char* face) {
HFONT hFont = CreateFontA(size, 0, 0, 0, FW_MEDIUM, 0, 0, 0,
charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, face);
HFONT holdFont = (HFONT)SelectObject(wglGetCurrentDC(), hFont);
DeleteObject(holdFont);
}
/**************************************************************/
/*生成中文字体*/
/**************************************************************/
void drawCNString(const char* str) {
int len, i;
wchar_t* wstring;
HDC hDC = wglGetCurrentDC();
GLuint list = glGenLists(1);
// 计算字符的个数
// 如果是双字节字符的(比如中文字符),两个字节才算一个字符
// 否则一个字节算一个字符
len = 0;
for (i = 0; str[i] != '\0'; ++i) {
if (IsDBCSLeadByte(str[i]))
++i;
++len;
}
// 将混合字符转化为宽字符
wstring = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring, len);
wstring[len] = L'\0';
// 逐个输出字符
for (i = 0; i < len; ++i) {
wglUseFontBitmapsW(hDC, wstring[i], 1, list);
glCallList(list);
}
// 回收所有临时资源
free(wstring);
glDeleteLists(list, 1);
}
3)在绘制部分需要的地方调用字体函数,写中文字:
selectFont (48, GB2312_CHARSET, ” 楷体 _GB2312”); // 设置楷体 48 号字
glRasterPos2f (250, 550) ; //在世界坐标(250,250 )处定位首字位置
drawCNString ("Hello,大家好”); //写"Hello,大家好”
四、思考题
1.如果太阳在平面任意位置,程序应该如何修改?
程序中地球和月亮的坐标进行修改,加上太阳的横纵坐标。
2.OpenGL图形变换靠什么来完成?在OpenGL中完成矩阵操作需要注意哪些问题?
OpenGL图形变换靠矩阵操作。适当加载单位矩阵的压入弹出当前矩阵。
3.glPushMatrixO、gIPopMatrix()是如何工作的?试运用这两个函数设计其他复合(或动 画)图形。
对于矩阵的操作都是对于矩阵栈的栈顶来操作的。当前矩阵即为矩阵栈的栈顶元素,而对当前矩阵进行平移、旋转等的变换操作也同样是对栈顶矩阵的修改。所以我们在变换之前调用giPushMatrix()的话,就会把当前状态压入第二层,不过此时栈顶的矩阵也与第二层的相同。
当经过一系列的变换后,栈顶矩阵被修改,此时调用glPopMatrix()时,栈顶矩阵被弹出,且又会恢复为原来的状态。
#define GLUT_DISABLE_ATEXIT_HACK
//样本程序:简单太阳系
//2DSystem.cpp
#include
#include
#include
float rs = 50, re = 30, rm = 10; //太阳、地球和月球半径
float xs = 0, ys = 0, xe = 150, ye = 0, xm = 200, ym = 0; //太阳、地球和月球的球心坐标
float as, ae, am, aes, ame, ams; //太阳、地球、月球自转角度,地球绕太阳公转旋转角度等
void Display(void); //绘制函数
void Reshape(int w, int h); //窗口改变
void mytime(int value); //时间函数
void myinit(void); //初始化函数
void sun(); //太阳
void earth(); //地球
void moon(); //月球
void selectFont(int size, int charset, const char* face);// 选择字体
void drawCNString(const char* str); //生成中文字体函数
int main(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
char* argv[] = { (char*)"hello ",(char*)" " };
int argc = 2; //argv中的字符串数
glutInit(&argc, argv); //初始化GLUT库
int sheight = glutGet(GLUT_SCREEN_WIDTH);
int swidth = glutGet(GLUT_SCREEN_HEIGHT);
glutInitWindowSize(700, 700); //设置显示窗口大小
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //设置显示模式(注意双缓存 )
glutInitWindowPosition(sheight / 2 - 350, swidth / 2 - 350); //窗口左上角在屏幕的位置
glutCreateWindow("A Rotating Sun System"); //创建显示窗口
glutDisplayFunc(Display); //注册显示回调函数
glutReshapeFunc(Reshape); //注册窗口改变回调函数
myinit(); //初始化设置
glutTimerFunc(200, mytime, 100);
glutMainLoop(); //进入事件处理循环
return 0;
}
void myinit() {
glPointSize(16); //点大小
glLineWidth(8); //线宽
/*反走样代码*/
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glEnable(GL_POLYGON_SMOOTH);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
//glEnable(GL_DEPTH_TEST);
}
void Display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW); //设置矩阵模式为模型变换模式,表示在世界坐标系下
glLoadIdentity(); //将当前矩阵设置为单位矩阵
//gluLookAt(0, xm, 0, 0, 0, 0, 0, 0, 1); //设置观察点
sun(); //绘制太阳
earth(); //绘制地球
moon(); //绘制月球
glutSwapBuffers(); //双缓冲的刷新模式
}
void sun() {
glPushMatrix();
/*绕太阳中心点(坐标原点)自转*/
glRotatef(as, 0, 0, 1);
glPushMatrix();
/*绘制太阳*/
glColor3f(1, 0, 0);
glutWireSphere(rs, 40, 40); //半径为re的圆,圆心在原点
glPopMatrix();
/*在太阳圆弧上画点*/
glColor3f(1, 1, 0);
glBegin(GL_POINTS);
glVertex2f(xs + rs, ys);
glEnd();
/*在绘制部分调用字体函数,写中文字*/
glColor3f(1, 1, 0);
selectFont(24, GB2312_CHARSET, "楷体_GB2312"); //设置字体楷体号字
glRasterPos2f(xs, ys); //定位首字位置
drawCNString("太阳"); //写“太阳”
glPopMatrix();
}
void earth(){
glPushMatrix();
/*绕太阳中心点(坐标原点)公转*/
glRotatef(aes, 0, 0, 1);
/*绕地球中心点自转*/
glTranslatef(xe, ye, 0);
glRotatef(ae, 0, 0, 1);
glTranslatef(-xe, -ye, 0);
glPushMatrix();
/*绘制地球*/
glPushMatrix();
glColor3f(0, 0, 1);
glTranslatef(xe, ye, 0);
//glRotatef(45, 1, 0, 0);
glutWireSphere(re, 40, 40); //半径为re的圆,圆心在原点
glPopMatrix();
/*在地球圆弧上画点*/
glColor3f(1, 1, 0);
glBegin(GL_POINTS);
glVertex2f(xe + re, ye);
glEnd();
/*在绘制部分调用字体函数,写中文字*/
glColor3f(1, 1, 0);
selectFont(24, GB2312_CHARSET, "楷体_GB2312"); //设置字体楷体号字
glRasterPos2f(xe, ye); //定位首字位置
drawCNString("地球"); //写“地球”
glPopMatrix();
glPopMatrix();
}
void moon() {
glPushMatrix();
/*绕太阳中心点(坐标原点)公转*/
glRotatef(ams, 0, 0, 1);
/*绕地球中心点公转*/
glTranslatef(xe, ye, 0);
glRotatef(ame, 0, 0, 1);
glTranslatef(-xe, -ye, 0);
/*绕月球中心点自转*/
glTranslatef(xm, ym, 0);
glRotatef(am, 0, 0, 1);
glTranslatef(-xm, -ym, 0);
glPushMatrix();
/*绘制月球*/
glPushMatrix();
glColor3f(1, 1, 1);
glTranslatef(xm, ym, 0);
//glRotatef(45, 1, 0, 0);
glutWireSphere(rm, 40, 40); //半径为rm的圆,圆心在原点
glPopMatrix();
/*在月球圆弧上画点*/
glColor3f(1, 1, 0);
glBegin(GL_POINTS);
glVertex2f(xm + rm, ym);
glEnd();
/*在绘制部分调用字体函数,写中文字*/
glColor3f(1, 1, 0);
selectFont(24, GB2312_CHARSET, "楷体_GB2312"); //设置字体楷体号字
glRasterPos2f(xm+rm, ym); //定位首字位置
drawCNString("月球"); //写“月球”
glPopMatrix();
glPopMatrix();
}
void mytime(int value) {
as += 1; //太阳自转角度递增
ae += 1; //地球自转角度递增
am += 1; //月球自转角度递增
aes += 2; //地球绕太阳公转角度递增
ame += 2; //月球绕地球公转角度递增
ams += 2; //月球绕太阳公转角度递增
glutPostRedisplay(); //重画,相当于重新调用 Display(),改变后的变量得以传给绘制函数
glutTimerFunc(100, mytime, 10);//设置时间间隔
}
void Reshape(GLsizei w, GLsizei h) {
glMatrixMode(GL_PROJECTION); //投影矩阵模式
glLoadIdentity(); //矩阵堆栈清空
glViewport(0, 0, w, h); //设置视区大小
gluOrtho2D(-xm-rm-10, xm+rm+10, -xm-rm-10, xm+rm+10);//设置裁剪窗口大小
//gluPerspective(90, w / h, 20, 500);
glMatrixMode(GL_MODELVIEW); //模型矩阵模式
//glLoadIdentity(); //矩阵堆栈清空
}
/**************************************************************/
/*选择字体函数*/
/**************************************************************/
void selectFont(int size, int charset, const char* face) {
HFONT hFont = CreateFontA(size, 0, 0, 0, FW_MEDIUM, 0, 0, 0,
charset, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, face);
HFONT holdFont = (HFONT)SelectObject(wglGetCurrentDC(), hFont);
DeleteObject(holdFont);
}
/**************************************************************/
/*生成中文字体*/
/**************************************************************/
void drawCNString(const char* str) {
int len, i;
wchar_t* wstring;
HDC hDC = wglGetCurrentDC();
GLuint list = glGenLists(1);
// 计算字符的个数
// 如果是双字节字符的(比如中文字符),两个字节才算一个字符
// 否则一个字节算一个字符
len = 0;
for (i = 0; str[i] != '\0'; ++i) {
if (IsDBCSLeadByte(str[i]))
++i;
++len;
}
// 将混合字符转化为宽字符
wstring = (wchar_t*)malloc((len + 1) * sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstring, len);
wstring[len] = L'\0';
// 逐个输出字符
for (i = 0; i < len; ++i) {
wglUseFontBitmapsW(hDC, wstring[i], 1, list);
glCallList(list);
}
// 回收所有临时资源
free(wstring);
glDeleteLists(list, 1);
}
实验七2D太阳系绘制