您的位置:首页 > 运维架构

OpenGL-学习之路-简单二维几何变换及应用

2014-11-04 20:07 375 查看
简单二维几何变换

1. 回顾gluOrtho和glViewport

在OpenGL中,gluOtho和glViewport 为两个比较重要的投影变换函数。

-gluOrtho 是创建一个正交平行的视影体的矩阵,并把它与当前矩阵相乘,裁剪出要显示的部分。例如你画出了一个半径为1,中心点在圆点的二维图形圆形,gluOrtho2D作用在了 (0,1,0,1)。则最终显示了个1/4圆形。

-glViewport 则是定义了像素矩阵,最终图像将映射到该矩阵。例如,上面那个1/4圆形原本是显示在左下角,如果我们将glViewport  定义在(0,1,1,1),则该1/4圆形显示在了窗口的左上角。

简单来说: gluOrtho定义了显示的内容,glVieport则设置了显示的位置。

更详细内容:

http://www.cnblogs.com/yxnchinahlj/archive/2010/10/30/1865298.html

http://blog.csdn.net/lingedeng/article/details/7302204

2. 简单二维几何变换

简单二维几何的变换,可以通过 坐标变换 或 矩阵变换。两个方法各有长处,具体使用看实际情况。

下面是平移,旋转,缩放的简单二维图形变换。

#include <gl\glut.h>
#include <iostream>
using namespace std;

//transilate时,x,y上的增量
float i = 0,j=0;
//rotate时的角度增量
GLint angle=0;
//scale时,x,y上的增量
float s1 = 1, s2 = 1;

void init()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 600.0, 0.0, 600.0);
}

void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glTranslatef(300+i, 300+j, 0);
glRotatef(angle % 360, 0, 0, 1);
glScalef(s1, s2, 0);

glColor3f(0, 0.6, 0.5);
glRectf(-100, 100, 100, -100);

glFlush();
glutSwapBuffers();
}

void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 'w':
j++; break;
case 's':
j--; break;
case 'a':
i--; break;
case 'd':
i++; break;
case 'q':
angle += 10; break;
case 'e':
angle -= 10; break;
case 'z':
s1 += 0.1; break;
case 'x':
s2 += 0.1; break;
case 'c':
s1 -= 0.1; break;
case 'v':
s2 -= 0.1; break;
}
glutPostRedisplay();
}

void main(int argc, char ** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(400, 50);
glutInitWindowSize(600, 600);
glutCreateWindow("Computer Graphics: 二维几何变换");

init();

glutDisplayFunc(display);

cout << " w,s,a,d键 分别为上下左右平移" << endl;
cout << " q,e键 分别为放大,缩小" << endl;
cout << " z,x,c,v键 分别为长宽的放大缩小" << endl;
glutKeyboardFunc(keyboard);

glutMainLoop();
}

最后效果:



3. 应用——Sun,Earth,Moon

内容:画出三个圆分别代表,太阳,地球,月球,并且地球绕着太阳旋转,月亮绕着地球旋转。

#include <gl\glut.h>
#include <math.h>

//旋转角度
GLint angle = 30;
//地球旋转半径
GLdouble r1 = 100;
//月球旋转半径
GLdouble r2 = 40;

void init()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 600.0, 0.0, 600.0);
}

//画圆函数,传入中心点坐标(x,y),以及半径r
void drawCircle(double x, double y, double r)
{
double N = 30;
//把圆N等分,则每一等分为 360/N=2Pi/N , 则旋转角度为 i*360/N=2*Pi*i/N
double delta = 3.1415926*2.0 / N;
glBegin(GL_TRIANGLE_FAN);
for (int i = 0; i <= N; i++)
{
glVertex2f(x, y);
glVertex2f(x + r*cos(delta*i), y + r*sin(delta*i));
glVertex2f(x + r*cos(delta*(i + 1)), y + r*sin(delta*(i + 1)));
}
glEnd();
}

//坐标变换
void run()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//太阳
glColor3f(1.0f, 0.0f, 0.0f);
drawCircle(300, 300, 20);

//地球
int x0, y0;
x0 = 300 + r1*cos((3.1415926*2.0 / 360)*(angle % 360));
y0 = 300 + r1*sin((3.1415926*2.0 / 360)*(angle % 360));
glColor3f(0.0, 0.5, 1.0);
drawCircle(x0, y0, 15);

//月球
int x1, y1;
x1 = x0 + r2*cos((3.1415926*2.0 / 360)*(angle * 12 % 360));
y1 = y0 + r2*sin((3.1415926*2.0 / 360)*(angle * 12 % 360));
glColor3f(1.0, 1.0, 1.0);
drawCircle(x1, y1, 5);

glFlush();
glutSwapBuffers();
}

//矩阵变换
/*
void run()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//太阳
glTranslatef(300.0f, 300.0f, 0.0f);
glColor3f(1.0f, 0.0f, 0.0f);
drawCircle(0, 0, 20);

//地球
glRotatef(angle % 360, 0, 0, 1);
glTranslatef(r1, 0, 0);
glColor3f(0.0f, 0.5f, 1.0f);
drawCircle(0, 0, 15);

//月球
glRotatef(angle * 12 % 360, 0, 0, 1);
glTranslatef(r2, 0, 0);
glColor3f(1.0f, 1.0f, 1.0f);
drawCircle(0, 0, 5);

glFlush();
glutSwapBuffers();
}
*/

void idle()
{
angle++;
glutPostRedisplay();
}

void main(int argc, char ** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(400, 50);
glutInitWindowSize(600, 600);
glutCreateWindow("Computer Graphics: Sun,Earth,Moon");

init();

glutDisplayFunc(run);
glutIdleFunc(idle);

glutMainLoop();
}

最后效果:



4, 应用——简单自行车动画

内容: 实现自行车模型在一个方向上的运动(轮子的滚动速度与自行车前进距离合适)

#include <gl\glut.h>
#include <math.h>
#include <iostream>
using namespace std;

//自行车中心点坐标
double x = 100, y = 330;
//车轮半径
double r = 30;
//自行车旋转角,及旋转角速度
GLint angle = 0;
GLint angleSpeed = 10;

void init()
{
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, 600.0, 0.0, 600.0);
}

//画圆函数,传入中心点坐标(x,y),以及半径r
void drawCircle(double x, double y, double r)
{
double N = 8;
//把圆N等分,则每一等分为 360/N=2Pi/N
double delta = 3.1415926*2.0 / N;
//x0,y0,x1,y1分别代表该圆中第i和i+1个顶点的坐标,tmpx1,tmpy1,tmpx2,tmpy2则分别为对应顶点旋转后坐标.
double x0, y0, x1, y1, tmpx1, tmpy1, tmpx2, tmpy2;

glBegin(GL_LINE_LOOP);
for (int i = 0; i <= N; i++)
{
//第i个顶点坐标
x0 = x + r*cos(delta*i);
y0 = y + r*sin(delta*i);
//旋转计算
tmpx1 = x + (x0 - x)*cos(angle % 360) - (y0 - y)*sin(angle % 360);
tmpy1 = y + (x0 - x)*sin(angle % 360) + (y0 - y)*cos(angle % 360);
//第i+1个顶点坐标
x1 = x + r*cos(delta*(i + 1));
y1 = y + r*sin(delta*(i + 1));
//旋转计算
tmpx2 = x + (x1 - x)*cos(angle % 360) - (y1 - y)*sin(angle % 360);
tmpy2 = y + (x1 - x)*sin(angle % 360) + (y1 - y)*cos(angle % 360);

glVertex2f(x, y);
glVertex2f(tmpx1, tmpy1);
glVertex2f(tmpx2, tmpy2);
}
glEnd();
}

//坐标变换
void DisplayFunc()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//陆地横线
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINES);
glVertex2i(0, 300);
glVertex2i(600, 300);
glEnd();

//自行车前后轮
//x0,y0为后轮中心点的x,y坐标
double x0, y0;
x0 = x + 2 * 3.1415926*r*(double)angle / 360;
drawCircle(x0, y, r);
drawCircle(x0 + 90, y, r);

//自行车横杠把手部分
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINES);
glVertex2i(x0, y);
glVertex2i(x0 + 90, y);
glVertex2i(x0 + 90, y);
glVertex2i(x0 + 44, y + 120);
glVertex2i(x0 + 66, y + 144);
glVertex2i(x0 + 44, y + 120);
glVertex2i(x0 + 22, y + 96);
glVertex2i(x0 + 44, y + 120);
glEnd();

glFlush();
glutSwapBuffers();
}

void MouseFunc(GLint button, GLint action, GLint x, GLint y)
{
if (button == GLUT_LEFT_BUTTON && action == GLUT_DOWN)
{
angle += angleSpeed;
glutPostRedisplay();
}
if (button == GLUT_RIGHT_BUTTON && action == GLUT_DOWN)
{
angle -= angleSpeed;
glutPostRedisplay();
}
}

void main(int argc, char ** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(400, 50);
glutInitWindowSize(600, 600);
glutCreateWindow("Computer Graphics:Bike");

init();

glutDisplayFunc(DisplayFunc);
cout << "鼠标左键前进,右键后退" << endl;
glutMouseFunc(MouseFunc);

glutMainLoop();
}

最后效果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: