OpenGL实验(二)桌子的坐标系变换 矩阵 视图

来源:互联网 发布:自学人工智能 编辑:程序博客网 时间:2024/04/27 20:43

在图形学中通常使用4X4矩阵来表示三维物体的空间几何变换


要求

最左边的桌子循环上移(即匀速上移到一定位置后回到原点继续匀速上移),中间的桌子不断旋转(即绕自身中间轴旋转),最右边的桌子循环缩小(即不断缩小到一定大小后回归原来大小继续缩小)。

尺寸要求:
ZJUCG

参考:
ZJUCG


绘制桌子

其实也不太清楚怎么画算比较好……因为是 一个矩形一个矩形画的 所以这一步感觉还是蛮机械的

void Draw_Leg() // This function draws a triangle with RGB colors{    //四面    glBegin(GL_QUADS);    glVertex3f(-0.5f, 0.5f, 3.0f);    glVertex3f(0.5f, 0.5f, 3.0f);    glVertex3f(0.5f, 0.5f, 0.0f);    glVertex3f(-0.5f, 0.5f, 0.0f);    //...    //底边    glVertex3f(0.5f, 0.5f, 0.0f);    glVertex3f(0.5f, -0.5f, 0.0f);    glVertex3f(-0.5f, -0.5f, 0.0f);    glVertex3f(-0.5f, 0.5f, 0.0f);    glEnd();}void Draw_Table() // This function draws a triangle with RGB colors{    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);          //空心    //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);        //实心    glColor3f(1.0f, 1.0f, 1.0f);                        //选择颜色    //上下    glBegin(GL_QUADS);    glVertex3f(2.5f, 2.0f, 4.0f);    glVertex3f(2.5f, -2.0f, 4.0f);    glVertex3f(-2.5f, -2.0f, 4.0f);    glVertex3f(-2.5f, 2.0f, 4.0f);    glVertex3f(2.5f, 2.0f, 3.0f);    glVertex3f(2.5f, -2.0f, 3.0f);    glVertex3f(-2.5f, -2.0f, 3.0f);    glVertex3f(-2.5f, 2.0f, 3.0f);    //四面        glVertex3f(2.5f, 2.0f, 4.0f);    glVertex3f(2.5f, -2.0f, 4.0f);    glVertex3f(2.5f, -2.0f, 3.0f);    glVertex3f(2.5f, 2.0f, 3.0f);    glEnd();    //...    //画桌子腿    glPushMatrix();    glTranslatef(1.5f, 1.0f, 0.0f);    Draw_Leg();    //.....}

table


子窗口-视点

http://www.cnblogs.com/live41/p/3395902.html

很大一部分是按着上面那个链接改的(所以这次的作业干的事情就是拼拼凑凑)还有很多要学的哇

在双缓存的情况下,对一个窗口的颜色进行初始化时,glClear一定要调用后SwapBuffers()

感觉子窗口是相对独立的概念。如果我们希望的话,可以对某个单独的子窗口进行操作。然后建立在子窗口上的一些操作就需要多次的初始化。这里的Init操作包括各种键盘鼠标事件。

    //创建的代码    //sub windows    subWindow1 = glutCreateSubWindow(mainWindow, border, border, w - 2 * border, h / 2 - border * 3 / 2);    glutDisplayFunc(renderScenesw1);    init();    subWindow2 = glutCreateSubWindow(mainWindow, border, (h + border) / 2, w / 2 - border * 3 / 2, h / 2 - border * 3 / 2);    glutDisplayFunc(renderScenesw2);    init();    subWindow3 = glutCreateSubWindow(mainWindow, (w + border) / 2, (h + border) / 2, w / 2 - border * 3 / 2, h / 2 - border * 3 / 2);    glutDisplayFunc(renderScenesw3);    init();

对窗口的操作默认是对当前选中的窗口进行的。所以在有子窗口的情况下,需要通过比如glutSetWindow(subWindow1)来确定当前选中的窗口。这里我的subWindow1等变量都设置为全局变量(居然是int类型233)

对于每一个窗口都要进行glutPostRedisplay()标记它需要进行重绘(如果对mainWindow不进行的话在缩放的时候可能会出现问题)
glutSwapBuffers()用于显示,如果设置的是单缓存则没作用

绘制的过程中(至少在这个例子里)相当于对于每一个子窗口对图形进行重复绘制,通过设置不同的视点使得显示有所区别。(但是总感觉大概可以对于同一个图形设置,比如说三个不同的视点?这样感觉起来应该会节省存储的空间,毕竟每点的位置都是需要存放的)

还有例子用到的函数

glEnable(GL_DEPTH_TEST);    glEnable(GL_CULL_FACE);

虽然我不是很清楚它是怎么工作的但在这里这两行没啥必要,感觉更接近于模仿真实场景(比如这个GL_FOG:雾化效果 例如距离越远越模糊)(看起来蛮好玩的)

有子窗口的情况下reshape更加繁琐(计算复杂),不过应该没什么需要调整的

Birdy


键盘事件-平移

这一块以及下两块主要参考的是:http://blog.csdn.net/bill_ming/article/details/7662809
传说中的茶壶= =

键盘事件主要函数是

void glutKeyboardFunc(void (*func)(unsigned char key, int x, int y));void glutSpecialFunc(void (*func)(int key, int x, int y));

前者是有ASCII码的键盘输入,后者处理没有ASCII的特殊输入,比如上下左右、F1等,格式为GLUT_KEY_*,具体可以参考https://www.opengl.org/resources/libraries/glut/spec3/node54.html
接收到对应的事件调整全局变量的值。
和参考相似并且比较容易理解,在这里不赘述了。

键盘


鼠标事件-旋转

鼠标主要用到的两个函数:

void glutMouseFunc(void (*func)(int button, int state,                            int x, int y));

button :

  • GLUT_LEFT_BUTTON
  • GLUT_MIDDLE_BUTTON
  • GLUT_RIGHT_BUTTON

    state:

  • GLUT_UP
  • GLUT_DOWN

    所以说这个函数不会记录鼠标是不是处于被按下状态。
    如果我们需要设置(针对某个特定的键,比如左键)拖动,则需要另外设置变量来记录(左键)是否处于按下状态,经历GLUT_DOWN则改为TRUE,经历GLUT_UP则改为FALSE

    结合下面一个函数就可以对拖动进行处理:

    void glutMotionFunc(void (*func)(int x, int y));void glutPassiveMotionFunc(void (*func)(int x, int y));

前者当有一或多个按钮按下,并且在窗口内移动的时候被调用。后者在没有按钮按下,并且进行移动的时候被调用。

基本思路是,设置全局量记录鼠标的位置,当左键按下时记录(按下)以及更新鼠标的xy坐标记录。
在鼠标进行拖动的时候,记录xy坐标的该变量,以此作为旋转角度的参考。
(代码包含下面一块延时的内容:右键的时候开启循环)
调用:
glutMouseFunc(mouse);
glutMotionFunc(motion);

void mouse(int button, int state, int x, int y){    if (button == GLUT_LEFT_BUTTON)    {        if (state == GLUT_DOWN)        {            mouseisdown = true;             loopr = false;            tx = x;            ty = y;        }        else        {            mouseisdown = false;        }    }    if (button == GLUT_RIGHT_BUTTON)        if (state == GLUT_DOWN)        {            loopr = true;            glutTimerFunc(200, timer, 0);        }}void motion(int x, int y){    if (mouseisdown == true)    {    rz += x - tx;    rx += y - ty;    //rx rz 为传给坐标变换的转角度    tx = x;    ty = y;    glutPostRedisplay();    }}

鼠标

并看不到鼠标QwQ


自发事件-延时

这一块最主要用到的函数是

void glutTimerFunc(unsigned int msecs, void (*func)(int value), value);

它的性质类似于定时器,在多少时间后改变一个量。
然后比如茶壶的不断旋转的操作是通过定时器自身的调用。此外有一个全局bool量来控制这个循环是否终止。

void timer(int p){    //具体操作    if (loopr)    {        glutTimerFunc(200, timer, 0);    }}

这个性质还是蛮神奇的,这意味着,要是有多个这种定时器,那个操作的执行次数会越来越快。
比如下图 我在这个过程中多次的单击右键

自动

接下来说说这一块的实现

这里的变换是简单的在前两块已经有的基础上增加了缩放。就是说在绘制前,对坐标系进行调整。
其中time是一个由(定时器)调整的值,在这里我设置它的范围是0~29变化
这里通过接受键盘1 2 3来设置变换方式(旋转/平移/缩放)

void drawMain(){    glPushMatrix();    if (loopr)    {        switch (state)        {        case 1:            mz = 0.1 * time;            state = 1;            break;        case 2:            rx = 12 * time;            break;        case 3:            glScalef(1 + 0.01*time, 1 + 0.01*time, 1 + 0.01*time);            break;        }    }    glTranslatef(mx, 0.0f, mz);     // 平移    //旋转    glRotatef(rx, 1, 0, 0);     glRotatef(ry, 0, 1, 0);    glRotatef(rz, 0, 0, 1);    Draw_Table();                       // Draw table       glPopMatrix();}

其他

初始化的时候有一个函数是

   glutIgnoreKeyRepeat( c_int(ignore) );

意思//确认是否忽略自动的连续击键,也就是一直按着一个键的时候,比如向上,会处理成一次事件还是连续事件。

 代码再开一篇附吧好像太长了..
0 0
原创粉丝点击