OpenGL-旋转平移与缩放

OpenGL里面的旋转缩放与平移其实就是坐标系的相关变换,不过由于初学者(像我)很容易被OpenGL里面各种坐标系搞晕而难以理解,现在将我的理解记录如下。PS: 由于学校课程要求,使用的是过时的固定管线。

为了清楚地理解这三种变换,我们只关心两个坐标系:建模坐标系世界坐标系。眼坐标之类的使用默认值。文末有一段程序代码,绘制了一个正方体,并实现了这三种变换。

世界坐标系(WC):你现在正对绘图窗口,右方是世界坐标系的x轴,上方是y轴,从屏幕指向你的是z轴。

模型坐标系(MC):使用glVertex() 之类的函数定义图元时用的坐标系,初始时MC和WC是重合的。

下文中的图,用蓝色表示MC,黑色表示WC

coordinate

旋转

旋转时世界坐标系不变,但是建模坐标系会旋转,所以旋转之后MC和WC是不重合的。

旋转需要选定一个向量以及一个角度,相应的函数为glRotatef()注意:这个向量指的是建模坐标系下的一个向量,建模坐标系绕着这个向量旋转。

例如:绕y轴旋转30度,向量为(0, 1, 0),角度为30。角度可正可负,opengl里面的是右手坐标系,所以旋转的正方向就是右手大拇指朝向旋转向量所指方向时,四个手指所指方向。下图为绕(0, 1, 0)旋转30度。

绕y旋转30度之后

这样其实也不难理解,但是当时被自己写的代码坑到了。

文末的代码中,旋转是在一对glPushMatrix()glPopMatrix() 中的,所以你在屏幕上看到的图形是由最开始的MC旋转得到的,而不是由上次旋转后的MC再次旋转得到的。

在我写的程序中显示的图形是由绕x, y, z轴依次旋转而得到的(当然也可以不绕着坐标轴),按下xyz键会改变绕xyz轴旋转的角度r_x, r_y, r_z,然后依次地绕xyz轴旋转而得到最终显示的图形。

现在有一种情形,绕xyz轴旋转的角度为r_x, r_y, r_z且均不为0,图形已经绘制好了,我现在按着y键,使r_y一直增加,我看到的是图形绕着y轴转动了一定角度吗?

不是。由于是依次绕着xyz轴旋转,r_y增加,所以受影响的只是基于最开始的MC绘制时,绕y轴旋转的角度,但是绕y轴之后还有绕z轴转动啊,最终的到的图形与之前旋转了r_x,r_y,r_z时相比,并不是绕y轴旋转。如果想直观观察到,可以编译运行下面的代码,先胡乱按xyz,然后按着y键不放。

平移

平移时MC相对与WC的位置不变,但是MC里面所有的坐标都将在原来的基础上加上偏移量(dx, dy, dz)。使用的函数为glTranslatef() ,平移相对来说比较容易理解,不详细叙述了。

缩放

先说说现实中的缩放,如果你想要一个物体变小,有两个方法:

  • 增加你和物体之间的距离
  • 对物体施加魔法,改变它的实际尺寸

同理,OpenGL里面你如果想要对一个图形进行缩放,可以用glOrtho() 之类的函数调整投影区域,也可以使用glScalef() 等将图形的各个坐标缩小或放大。

#include <iostream>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <math.h>
#include <unistd.h>

/*---------------全局变量---------------------*/
//--------------------------------------------
const double PI = 3.14159;
//旋转角度
GLfloat r_xyz[3] = {0.0f};

//平移偏移量
GLfloat dx=0, dy=0, dz=0;

//缩放比例
double radio = 1.0d;

int cx = 200, cy = 200; //中心坐标窗口
//窗口大小
int w = 400;
int h = 400;

//标记是否着色,默认着色
int mode = 1;

/*------------------函数声明--------------------*/
//---------------------------------------------
void onDisplay();
void onReshape(int , int);
void Drawing();
void myRotate();
void rgb(int r, int g, int b);
void specialKeys(int key, int x, int y);


void rgb(int r, int g, int b)
{
    glColor3f(r/255.0f, g/255.0f, b/255.0f);
}


void onDisplay()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    Drawing();
    glutSwapBuffers();
}

void onReshape(int width, int height)
{
    GLfloat aspect = (GLfloat) w/(GLfloat)h;
    GLfloat nRange = 400;
    w = width;
    h = height;
    int min = w > h ? h : w;
    glViewport(0, 0, min, min);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-nRange, nRange, -nRange , nRange, -nRange, nRange);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glutSwapBuffers();
    glutPostRedisplay();
}

void myRotate()
{
    int vec[3][3] = {
        {1, 0, 0},
        {0, 1, 0},
        {0, 0, 1}
    };
    for (int i = 0 ; i <= 2 ; i ++)
    {
        glRotatef(r_xyz[i], vec[i][0], vec[i][1], vec[i][2]);
    }
}
void Drawing()
{
    glPushMatrix();
    glLoadIdentity();
    //旋转
    myRotate();
    glScalef(radio, radio, radio);
    glTranslatef(dx, dy, dz);

    if (mode == 2)
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        glLineWidth(3);
    }
    else
    {
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    }

    //顶点向量
    //下面表示一个正方体
    int A[] = {-100, -100, 100};
    int a[] = {-100, -100, -100};
    int B[] = {100, -100, 100};
    int b[] = {100, -100, -100};
    int C[] = {100, 100, 100};
    int c[] = {100, 100, -100};
    int D[] = {-100, 100, 100};
    int d[] = {-100, 100, -100};


    glBegin(GL_QUADS);
        //front  tomato
        rgb(234, 67, 53);
        glVertex3iv(A);
        glVertex3iv(B);
        glVertex3iv(C);
        glVertex3iv(D);

        //fruit salad
        rgb(52, 168, 83);
        glVertex3iv(D);
        glVertex3iv(C);
        glVertex3iv(c);
        glVertex3iv(d);

        //gray
        rgb(120, 120, 120);
        glVertex3iv(d);
        glVertex3iv(c);
        glVertex3iv(b);
        glVertex3iv(a);

        //white
        rgb(255, 255, 255);
        glVertex3iv(a);
        glVertex3iv(b);
        glVertex3iv(B);
        glVertex3iv(A);

        //yellow
        rgb(251, 188, 5);
        glVertex3iv(a);
        glVertex3iv(A);
        glVertex3iv(D);
        glVertex3iv(d);

        //blue
        rgb(66, 132, 243);
        glVertex3iv(B);
        glVertex3iv(C);
        glVertex3iv(c);
        glVertex3iv(b);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glEnd();
    glPopMatrix();
    glutSwapBuffers();
}

void keyFunc(unsigned char key, int x, int y)
{
    switch(key)
    {
        case 'z': r_xyz[2] += 2; break;
        case 'Z': r_xyz[2] -= 2; break;
        case 'y': r_xyz[1] += 2; break;
        case 'Y': r_xyz[1] -= 2; break;
        case 'x': r_xyz[0] += 2; break;
        case 'X': r_xyz[0] -= 2; break;

        case '-': if (radio > 0)radio -= 0.01; break;
        case '+': radio += 0.01; break;
        case 'q': exit(0);

        case '1': mode = 1;break;
        case '2': mode = 2; break;
    }
    glutPostRedisplay();
}

void specialKeys(int key, int x, int y)
{
    switch(key)
    {
        case GLUT_KEY_UP: dy += 4;break;
        case GLUT_KEY_DOWN: dy -= 4; break;
        case GLUT_KEY_LEFT: dx -= 4; break;
        case GLUT_KEY_RIGHT: dx += 4; break;
    }
    glutPostRedisplay();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowPosition(10, 10);
    glutInitWindowSize(400, 400);
    glutCreateWindow("this is not what I wanted");

    glutDisplayFunc(onDisplay);
    glutReshapeFunc(onReshape);
    glutKeyboardFunc(keyFunc);
    glutSpecialFunc(specialKeys);

    glutMainLoop();
}
  • 11
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值