一、实验目的:
- 1) 熟悉并掌握包括平移、比例、对称、旋转、错切在内的五种基本二维几何变换的原理和实现过程;
- 2)熟悉并掌握二维符合变换的原理和实现过程;
- 3) 掌握 OpenGL 程序关于平移、旋转、缩放、错切变换的方法;
- 4)能够根据学习教程自行设计几何变换程序,实现特定的几何变换。
二、实验内容
共有六道题目,其中第六题是加分题。请根据给定的实验结果样例,结合参考程序设计程序,实现样例的显
示效果,把程序代码和实验截图拷贝到实验报告中。
题目 1:
设计程序实现平移变换。
- 在窗口中心处绘制第一个正方形(2*2 大小);
- 将正方形向右平移 2 个单位,向上平移 3 个单位,绘制第二个正方形;
- 将第一个正方形向右平移 2 个单位,绘制第三个正方形;
效果:
代码:
#include <GL/glut.h>
void init (void)
{
glClearColor (1.0, 1.0, 1.0, 0.0);
glMatrixMode (GL_PROJECTION);
gluOrtho2D (-5.0, 5.0, -5.0, 5.0); //设置显示的范围是 X:-5.0~5.0, Y:-5.0~5.0
glMatrixMode (GL_MODELVIEW);
}
void drawSquare(void) //绘制中心在原点,边长为 2 的正方形
{
glBegin (GL_POLYGON); //顶点指定需要按逆时针方向
glVertex2f (-1.0f,-1.0f);//左下点
glVertex2f (1.0f,-1.0f);//右下点
glVertex2f (1.0f, 1.0f);//右上点
glVertex2f (-1.0f,1.0f);//左上点
glEnd ( );
}
void myDraw (void)
{
glClear (GL_COLOR_BUFFER_BIT); //清空
glLoadIdentity(); //将当前矩阵设为单位矩阵
glPushMatrix();
glColor3f (1.0, 0.0, 0.0);
drawSquare();//中间红色矩形
glPopMatrix();
glPushMatrix();
glTranslatef(2.0f,3.0f,0.0f);
glColor3f (0.0, 1.0, 0.0);
drawSquare(); //上面绿色矩形
glPopMatrix();
glPushMatrix();
glTranslatef(2.0,0.0,0.0);
glColor3f (0.0, 0.0, 1.0);
drawSquare();//右边蓝色矩形
glFlush ( );
}
void main (int argc, char** argv){
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition (0, 0);
glutInitWindowSize (600, 600);
glutCreateWindow ("几何变换函数综合示例");
init();
glutDisplayFunc (myDraw);
glutMainLoop ( );
}
题目 2:
设计程序实现旋转变换。
- 在窗口中心处绘制第一个正方形(2*2 大小);
- 将正方形向右平移 2 个单位,向上平移 3 个单位,顺时针旋转 30
度,绘制第二个正方形; - 将第一个正方形向左平移 2 个单位,向下平移 3 个单位,逆时针旋转 30 度,绘制第三个正方形;
效果:
代码:
#include <GL/glut.h>
void init (void){
glClearColor (1.0, 1.0, 1.0, 0.0);
glMatrixMode (GL_PROJECTION);
gluOrtho2D (-5.0, 5.0, -5.0, 5.0); //设置显示的范围是 X:-5.0~5.0, Y:-5.0~5.0
glMatrixMode (GL_MODELVIEW);
}
void drawSquare(void) //绘制中心在原点,边长为 2 的正方形
{
glBegin (GL_POLYGON); //顶点指定需要按逆时针方向
glVertex2f (-1.0f,-1.0f);//左下点
glVertex2f (1.0f,-1.0f);//右下点
glVertex2f (1.0f, 1.0f);//右上点
glVertex2f (-1.0f,1.0f);//左上点
glEnd ( );
}
void myDraw (void){
glClear (GL_COLOR_BUFFER_BIT); //清空
glLoadIdentity(); //将当前矩阵设为单位矩阵
glPushMatrix();
glColor3f (1.0, 0.0, 0.0);
drawSquare();//中间红色矩形
glPopMatrix();
glPushMatrix();
glTranslatef(2.0f,3.0f,0.0f);
glRotatef(-30.0,0.0,0.0,1.0);
glColor3f (0.0, 1.0, 0.0);
drawSquare(); //上面绿色矩形
glPopMatrix();
glPushMatrix();
glTranslatef(-2.0,-3.0,0.0);
glRotatef(30.0,0.0,0.0,1.0);
glColor3f (0.0, 0.0, 1.0);
drawSquare();//右边蓝色矩形
glFlush ( );
}
void main (int argc, char** argv){
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition (0, 0);
glutInitWindowSize (600, 600);
glutCreateWindow ("几何变换函数综合示例");
init();
glutDisplayFunc (myDraw);
glutMainLoop ( );
}
题目 3:
设计程序实现比例变换。
-
在窗口中心处绘制第一个正方形(2*2 大小);
-
将正方形向右平移 2 个单位,向上平移 3 个单位,X 和 Z 方向保持不变,Y方向放大为原来的 1.5 倍,绘制 第二个正方形;
-
将第一个正方形向左平移 2 个单位,向下平移 3 个单位,Z 方向保持不变,X方向缩小为原来的 0.5 倍,Y 方向放大为原来的 1.5 倍,绘制第三个正方形;
效果:
代码:
#include <GL/glut.h>
void init (void){
glClearColor (1.0, 1.0, 1.0, 0.0);
glMatrixMode (GL_PROJECTION);
gluOrtho2D (-5.0, 5.0, -5.0, 5.0); //设置显示的范围是 X:-5.0~5.0, Y:-5.0~5.0
glMatrixMode (GL_MODELVIEW);
}
void drawSquare(void) //绘制中心在原点,边长为 2 的正方形
{
glBegin (GL_POLYGON); //顶点指定需要按逆时针方向
glVertex2f (-1.0f,-1.0f);//左下点
glVertex2f (1.0f,-1.0f);//右下点
glVertex2f (1.0f, 1.0f);//右上点
glVertex2f (-1.0f,1.0f);//左上点
glEnd ( );
}
void myDraw (void){
glClear (GL_COLOR_BUFFER_BIT); //清空
glLoadIdentity(); //将当前矩阵设为单位矩阵
glPushMatrix();
glColor3f (1.0, 0.0, 0.0);
drawSquare();//中间红色矩形
glPopMatrix();
glPushMatrix();
glTranslatef(2.0f,3.0f,0.0f);
glScalef(1.0,1.5,1.0);
glColor3f (0.0, 1.0, 0.0);
drawSquare(); //上面绿色矩形
glPopMatrix();
glPushMatrix();
glTranslatef(-2.0,-3.0,0.0);
glScalef(0.5,1.5,1.0);
glColor3f (0.0, 0.0, 1.0);
drawSquare();//右边蓝色矩形
glFlush ( );
}
void main (int argc, char** argv){
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition (0, 0);
glutInitWindowSize (600, 600);
glutCreateWindow ("几何变换函数综合示例");
init();
glutDisplayFunc (myDraw);
glutMainLoop ( );
}
题目 4:
利用旋转变换,设计程序实现三个菱形显示。菱形短轴半径设为 1,长轴半径设为 2。(注意:变换顺序不同,会得出不同的变换式样)
效果:
代码:
#include <GL/glut.h>
void init (void){
glClearColor (1.0, 1.0, 1.0, 0.0);
glMatrixMode (GL_PROJECTION);
gluOrtho2D (-5.0, 5.0, -5.0, 5.0); //设置显示的范围是 X:-5.0~5.0, Y:-5.0~5.0
glMatrixMode (GL_MODELVIEW);
}
void drawSquare(void) //绘制中心在原点,边长为 2 的正方形
{
glBegin (GL_POLYGON); //顶点指定需要按逆时针方向
glVertex2f (0.0f,2.0f);
glVertex2f (0.5f,1.0f);
glVertex2f (0.0f,0.0f);//长轴半径设为 2
glVertex2f (-0.5f,1.0f);//短轴半径设为 1
glVertex2f (0.0f,2.0f);
glEnd ( );
}
void myDraw (void){
glClear (GL_COLOR_BUFFER_BIT); //清空
glLoadIdentity(); //将当前矩阵设为单位矩阵
glPushMatrix();
glColor3f (1.0, 0.0, 0.0);
drawSquare();//中间红色矩形
glPopMatrix();
glPushMatrix();
glRotatef(120.0,0.0,0.0,1.0);
glPushMatrix();
glColor3f (0.0, 1.0, 0.0);
drawSquare(); //左边绿色矩形
glPopMatrix();
glRotatef(120.0,0.0,0.0,1.0);
glColor3f (0.0, 0.0, 1.0);
drawSquare();//右边蓝色矩形
glFlush ( );
}
void main (int argc, char** argv){
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition (0, 0);
glutInitWindowSize (600, 600);
glutCreateWindow ("菱形复合变换");
init();
glutDisplayFunc (myDraw);
glutMainLoop ( );
}
题目 5:
画人头怪(每一个矩形大小为 2*2)
注意:
- 尖嘴的部分是通过对矩形做比例变换和平移获得的,不是画了一个菱形。
- 坠饰可以加一点逐步放大的效果。
效果:
代码:
#include <GL/glut.h>
#include <math.h>
float R1 = 1;
float R2 = 0.65;
float R3 = 0.5;
int i;
int j;
void init (void)
{
glClearColor (1.0, 1.0, 1.0, 0.0);
glMatrixMode (GL_PROJECTION);
gluOrtho2D (-18.0, 18.0, -18.0, 18.0); //设置显示的范围是 X:-5.0~5.0, Y:-5.0~5.0
glMatrixMode (GL_MODELVIEW);
}
void drawSquare(void) //绘制中心在原点,边长为 2 的正方形
{
glBegin (GL_POLYGON); //顶点指定需要按逆时针方向
glVertex2f (-1.0f,-1.0f);//左下点
glVertex2f (1.0f,-1.0f);//右下点
glVertex2f (1.0f, 1.0f);//右上点
glVertex2f (-1.0f,1.0f);//左上点
glEnd ( );
}
void drawCicle1(float R1 ){
int n=3600;
float PI=3.1415926f; //定义 π
glBegin(GL_POLYGON);//定义绘制模式
for (i=1;i<n;i++){
glVertex2f(R1*cos(2*PI*i/n)+2.5,R1*sin(2*PI*i/n)-2.5); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
glBegin(GL_POLYGON);
for (i = 1; i < n; i++){
glVertex2f(R1*cos(2*PI*i/n)-4.5,R1*sin(2*PI*i/n)-2.5); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
}
void drawCicle2(float R2 ){
int n=3600;
float PI=3.1415926f; //定义 π
for(j = 0;j<7;j++){
glBegin(GL_POLYGON);//定义绘制模式
for (i = 1; i < n; i++){
glVertex2f(R2*cos(2*PI*i/n)-7,R2*sin(2*PI*i/n)-3.65-j*1.3); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
}
for(j = 0;j<7;j++){
glBegin(GL_POLYGON);//定义绘制模式
for (i = 1; i < n; i++){
glVertex2f(R2*cos(2*PI*i/n)+5,R2*sin(2*PI*i/n)-3.65-j*1.3); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
}
for(j = 0;j<7;j++){
glBegin(GL_POLYGON);//定义绘制模式
for (i = 1; i < n; i++){
glVertex2f(R2*cos(2*PI*i/n)-9.7,R2*sin(2*PI*i/n)-1.65-j*1.3); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
}
for(j = 0;j<7;j++){
glBegin(GL_POLYGON);//定义绘制模式
for (i = 1; i < n; i++){
glVertex2f(R2*cos(2*PI*i/n)+7.7,R2*sin(2*PI*i/n)-1.65-j*1.3); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
}
for(j = 0;j<7;j++){
glBegin(GL_POLYGON);//定义绘制模式
for (i = 1; i < n; i++){
glVertex2f(R2*cos(2*PI*i/n)-13.7,R2*sin(2*PI*i/n)+0.35-j*1.3); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
}
for(j = 0;j<7;j++){
glBegin(GL_POLYGON);//定义绘制模式
for (i = 1; i < n; i++){
glVertex2f(R2*cos(2*PI*i/n)+11.7,R2*sin(2*PI*i/n)+0.35-j*1.3); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
}
}
void drawCicle3(float R3 ){
int n=3600;
float PI=3.1415926f; //定义 π
glBegin(GL_POLYGON);//定义绘制模式
for (i = 1; i < n; i++){
glVertex2f(R3*cos(2*PI*i/n)-2.5,R3*sin(2*PI*i/n)-7.5); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
glBegin(GL_POLYGON);
for (i = 1; i < n; i++){
glVertex2f(R3*cos(2*PI*i/n)+0.5,R3*sin(2*PI*i/n)-7.5); //设定点坐标,共有 3600 个点,用来绘制凸多边形
}
glEnd();
}
void myDraw (void)//先画矩形再画圆形
{
int i, j;
float r = 0.05;
float g = 0.27;
float b = 0.34;
int x = -1, y = -7;
glClear(GL_COLOR_BUFFER_BIT); //清空
glLoadIdentity(); //将当前矩阵设为单位矩阵
//中间矩形
glPushMatrix();
glColor3f(1.0, 1.0, 0.0);
drawSquare(); //黄色矩形
glPopMatrix();
//三角形嘴巴
for (i = 1; i < 10; i++) {
glPushMatrix();
glTranslatef(-1 + i * 0.0025, -7 - i * 0.2, 0.0);
glColor3f(r, g, b);
glScalef(1 - 0.1 * i, 1 - 0.1 * i, 1);
drawSquare();
glPopMatrix();
}
//脸
for (i = 0; i < 10; i++) {
for (j = -i; j <= i; j += 2) {
glPushMatrix();
glTranslatef(x + j + 0.05 * j, y + i, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
}
if(i==7){
glPushMatrix();
glTranslatef(-10 - 0.3-0.15, y + i, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
glPushMatrix();
glTranslatef(8 + 0.3+0.15, y + i, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
}
if(i == 8){
glPushMatrix();
glTranslatef(-11-0.5, y + i, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
glPushMatrix();
glTranslatef(9 +0.5, y + i, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
}
if (i == 9) {
glPushMatrix();
glTranslatef(-12-0.5, y + i, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
glPushMatrix();
glTranslatef(10 +0.5, y + i, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
glPushMatrix();
glTranslatef(-14 - 0.3, y + i, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
glPushMatrix();
glTranslatef(12 + 0.3, y + i, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
}
r += 0.1;
g += 0.2;
b += 0.3;
if (r > 1.0)
r -= 0.23f;
if (g > 1.0)
g -= 0.45f;
if (b > 1.0)
b -= 0.67f;
}
//眼睛
glColor4f(0, 0, 0, 0); //定义颜色
glBegin(GL_POLYGON);//定义绘制模式
drawCicle1(R1);
//胡子
glColor4f(1, 0, 0, 0); //定义颜色
glBegin(GL_POLYGON);//定义绘制模式
drawCicle2(R2);
glFlush ( );
//鼻子
glColor4f(0, 0, 1, 0); //定义颜色
glBegin(GL_POLYGON);//定义绘制模式
drawCicle3(R3);
glFlush ( );
}
void main (int argc, char** argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition (0, 0);
glutInitWindowSize (600, 600);
glutCreateWindow ("人头怪");
init();
glutDisplayFunc (myDraw);
glutMainLoop ( );
}
题目 6:加分题
包含但不限于以下图片,通过复合变换,实现其形状
博主实现的效果:
代码:
#include <GL/glut.h>
#include <math.h>
float R1 = 1;
float R2 = 0.65;
float R3 = 0.5;
int i;
int j;
void init (void)
{
glClearColor (1.0, 1.0, 1.0, 0.0);
glMatrixMode (GL_PROJECTION);
gluOrtho2D (-18.0, 18.0, -18.0, 18.0); //设置显示的范围是 X:-5.0~5.0, Y:-5.0~5.0
glMatrixMode (GL_MODELVIEW);
}
void drawSquare(void) //绘制中心在原点,边长为 2 的正方形
{
glBegin (GL_POLYGON); //顶点指定需要按逆时针方向
glVertex2f (-1.0f,-1.0f);//左下点
glVertex2f (1.0f,-1.0f);//右下点
glVertex2f (1.0f, 1.0f);//右上点
glVertex2f (-1.0f,1.0f);//左上点
glEnd ( );
}
void myDraw (void)
{
int i, j;
float r = 0.05;
float g = 0.27;
float b = 0.34;
int x = -1, y = -7;
glClear(GL_COLOR_BUFFER_BIT); //清空
glLoadIdentity(); //将当前矩阵设为单位矩阵
//中间矩形
glPushMatrix();
glColor3f(1.0, 1.0, 0.0);
drawSquare();
glPopMatrix();
for (i = 0; i < 10; i++) {
for (j = -i; j <= i; j += 2) {
glPushMatrix();
glTranslatef(x + j + 1 * j, y + i +j*2, 0.0);
glColor3f(r, g, b);
drawSquare();
glPopMatrix();
}
r += 0.1;
g += 0.2;
b += 0.3;
if (r > 1.0)
r -= 0.23f;
if (g > 1.0)
g -= 0.45f;
if (b > 1.0)
b -= 0.67f;
}
glFlush ( );
}
void main (int argc, char** argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition (0, 0);
glutInitWindowSize (600, 600);
glutCreateWindow ("跑酷楼梯");
init();
glutDisplayFunc (myDraw);
glutMainLoop ( );
}
三、主要函数说明:
1、glMatrixMode():
-
这个函数其实就是对接下来要做什么进行一下声明,也就是在要做下一步之前告诉计算机我要对“什么”进行操作了,这个“什么”在
glMatrixMode 的“()”里的参数:GL_PROJECTION,GL_MODELVIEW 和 GL_TEXTURE。 -
GL_PROJECTION
:投影,就是要对投影相关进行操作,也就是把物体投影到一个平面上,就像我们照相 一样,把 3 维物体投到 2
维的平面上。这样,接下来的语句可以是跟透视相关的函数,比如 glFrustum()或 gluPerspective(); -
GL_MODELVIEW
:对模型视景的操作,接下来的语句描绘一个以模型为基础的适应,这样来设置参数, 接下来用到的就是像
gluLookAt()这样的函数; -
GL_TEXTURE
:就是对纹理相关进行操作;
顺便说下,OpenGL 里面的操作,很多是基于对矩阵的操作的,比如位移,旋转,缩放,所以,这里其实说的规范一点就是glMatrixMode是用来指定哪一个矩阵是当前矩阵,而它的参数代表要操作的目标,
GL_PROJECTION
是对投影矩阵操作,GL_MODELVIEW
是对模型视景矩阵操作,GL_TEXTURE
是对纹理矩阵进行随后的操作。
2、glLoadIdentity():
在进行变换前把当前矩阵设置为单位矩阵。
进行模型和视图变换,主要涉及到三个函数:
glTranslate()
:平移变换函数。glTranslatef(GLfloat x,GLfloat y,GLfloat z)
; 函数功能:- 沿 X 轴正方向平移 x 个单位(x 是有符号数) 沿 Y 轴正方向平移 y 个单位(y 是有符号数) 沿 Z 轴正方向平移 z个单位(z 是有符号数)
- 这里的 x,y,z 是相对于 glOrtho2D()函数给出的视窗显示范围对应设定的。
例如,这里给出 x的范围是 [-5, 5],那么 x 的值就不能大于 5 或者小于-5,否则物体就会移出视窗口,进入不可见区域。
glRotate()
:旋转变换函数。glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLfloat z);
- 先解释一下旋转方向,做(0,0,0)到(x,y,z)的向量,用右手握住这条向量,大拇指指向向量的正方向,四指环绕的方向就是旋转的方向;
- 例如:
glRotatef (xrot , 1.0f, 0.0f, 0.0f); // 绕 X 轴旋转 glRotatef (yrot ,
0.0f, 1.0f, 0.0f); // 绕 Y 轴旋转
-
函数功能:以点(0,0,0)到点(x,y,z)的直线为轴,逆时针旋转 angle 角度;
-
glScale()
:缩放函数。 -
glScalef(GLfloat sx, GLfloat sy, GLfloat sz);
-
函数功能:模型沿着 x,y,z 轴方向进行比例缩放,缩放比分别为 sx,sy,sz。sx,sy,sz 都是大于 0 的 数字。
-
如果在某个方向是保持大小不变,则需把对应的缩放系数设置为 1,不能设置为 0。
3、glPushMatrix()和 glPopMatrix(): 矩阵堆栈操作函数。
- 就是数据结构中的堆栈操作问题,先进后出。
glPushMatrix
函数把当前状态复制一份,放入堆栈中,glPopMatrix
函数从堆栈中取出放在里面的状态。
我们在进行矩阵操作时,有可能需要先复制保存某个矩阵,过一段时间再恢复它。
- 当我们需要保存时,调 用 glPushMatrix 函数,它相当于把矩阵(相当于盘子)放到堆栈上。
- 当需要恢复最近一次的保存时,调用 glPopMatrix 函数,它相当于把矩阵从堆栈上取下。
- 先堆起来的盘子后取出。
- 当你做了一些移动或旋转等变换后,使用 glPushMatrix();
OpenGL 会把这个变换后的位置和角度保存起来。 - 然后你再随便做第二次移动或旋转变换,再用 glPopMatrix();
OpenGL 就把刚刚保存的那个位置和角度恢复。 - 比如:
glLoadIdentity();
glTranslatef(1,0,0);//向右移动(1,0,0)
glPushMatrix();//保存当前位置 glTranslatef(0,1,0);//现在是(1,1,0)了
glPopMatrix();//这样,现在又回到(1,0,0)了
glPushMatrix();//复制保存的就是它之前的矩阵状态,可以包括平移、旋转、比例、颜色在内的所有变换状态。
1、glPushMatrix()函数需要放在画图函数之前(这里是 drawSqure()),放在之后就没有用了,因为之前设置的矩阵状态都丢失了。
2、 OpenGL 规定堆栈的容量至少可以容纳 32 个矩阵,某些 OpenGL 实现中,堆栈的容量实际上超过了 32 个。
因此不必担心矩阵的容量问题。
4、glOrtho2D(): 负责使用什么样的视景体来截取图像,设置显示窗口坐标范围。
“ 我深怕自己本非美玉,故而不敢加以辛苦琢磨。却又半信自己是块美玉,固又不肯庸庸碌碌与瓦砾为伍。于是我渐渐的脱离凡尘,疏远世人。结果便是任愤懑与羞恨,日益助长内心怯懦的自尊心。——《山月记》 ”