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

在图形学中通常使用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) );

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

 代码再开一篇附吧好像太长了..

转载于:https://www.cnblogs.com/BirdCage/p/9974089.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值