实验七2D太阳系绘制

实验七2D太阳系绘制

一、实验目的

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 <windows.h>
#include <gl/glut.h>
#include <math.h>

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太阳系绘制

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值