[OpenGL] 桌子的平移、旋转和缩放

            


1绘制立方体


        考虑分别绘制六个面,先把每个正方形的坐标点存储在数组中,然后再利用循环完成绘制。(这样的绘制模式使一条边被绘制了两次,有一些优化的方法,为了逻辑更清晰没有进行优化)

        在三维笛卡尔坐标系中,一个立方体可由三个顶点坐标唯一确定,一共是9个值。考虑到这里的立方体每条边都是与坐标轴平行的,简化后只需传入6个值。

 

        由此,很容易计算出六个面的四点坐标值:


        { { x1,y1,z1 },{ x2,y1,z1 },{ x2,y2,z1 },{ x1,y2,z1 } },

        { { x1,y1,z1 },{ x2,y1,z1 },{ x2,y1,z2 },{ x1,y1,z2 } },

        { { x2,y1,z1 },{ x2,y2,z1 },{ x2,y2,z2 },{ x2,y1,z2 } },

        { { x1,y1,z1 },{ x1,y2,z1 },{ x1,y2,z2 },{ x1,y1,z2 } },

        { { x1,y2,z1 },{ x2,y2,z1 },{ x2,y2,z2 },{ x1,y2,z2 } },

        { { x1,y1,z2 },{ x2,y1,z2 },{ x2,y2,z2 },{ x1,y2,z2 } };

 

        绘制时,先设置多边形模式为正反面、线型,调用如下函数绘制多个四边形:

              

2绘制桌子

        调用已有立方体函数,通过传入具体位置来绘制桌子,由于会多次调用,将其封装成一个函数。

 

3平移,旋转,缩放

        完成基本的平移旋转缩放操作需要调glTranslatef,glRotatef,glScalef三个函数,更准确的来说,它们完成的不是平移旋转缩放操作,而是在当前操作矩阵上乘以一个平移,旋转或缩放矩阵。所以在绘制时,我们需要先设置当前矩阵的模式为模型矩阵,并且将矩阵初始化为单位矩阵。

        并且,在完成特定操作(如平移)时,我们将所有的操作矩阵放到堆栈时,完成后再抛出,这样可以保证不同操作之间相互不影响。

        同时需要注意到相乘顺序与实际情况是相反的:


  

        为了完成屏幕的时刻刷新,需要注册空闲时调用的回调函数,在这个回调函数中调用自己的绘图函数,每执行完一次绘图函数刷新一下平移/旋转/缩放因子,达到动画效果。

 

         平移矩阵:

           glTranslatef(GLfloat z, GLfloaty, GLfloat z);

         传入的参数是在x,y,z方向上平移的长度。


                       1 0  0  0

      [ x y z1 ]  [ 0 1  0  0 ]

                       0 0  1  0

                      dx dy dz  1

 

         旋转矩阵:

          glRotatef(GLfloat theta, GLfloatx, GLfloat y, GLfloat z);    

          传入参数是旋转角度,坐标轴。需要注意的是,旋转轴是过原点的,需要先把物体移到原点,旋转,再挪回来。

 

                       cosa 0  -sina  0

      [ x y z 1 ]  [   0   1    0      0 ]

                      sina   0  cosa  0

                          0    0    0     1          

 

      (绕y轴旋转

 

         缩放矩阵:

          glScalef(GLfloat x, GLfloat y, GLfloatz);

         传入参数是不同坐标轴方向缩放程度,同理,要先把物体移到原点,再缩放,最后移到原位。

 

                        Sx  0  0   0

      [ x y z 1 ]  [ 0  Sy  0   0 ]

                        0   0  Sz  0

                        0   0   0  1

/*
author:fish1996
date:2016/03/24
*/

#define GLUT_DISABLE_ATEXIT_HACK    
#include "gl/glut.h"

float fTranslate; //平移因子
float fRotate; //旋转因子
float fScale = 1.0f; //缩放因子

//绘制正方体,它是由直线x = x1, x = x2, y = y1, y = y2, z = z1, z = z2 划分出的空间
void drawCube(GLfloat x1, GLfloat x2, GLfloat y1, GLfloat y2, GLfloat z1, GLfloat z2)
{
	int i, j;
	//指定六个面的四个顶点,每个顶点用3个坐标值表示
	GLfloat point[6][4][3] = {
		{ { x1,y1,z1 },{ x2,y1,z1 },{ x2,y2,z1 },{ x1,y2,z1 } },
		{ { x1,y1,z1 },{ x2,y1,z1 },{ x2,y1,z2 },{ x1,y1,z2 } },
		{ { x2,y1,z1 },{ x2,y2,z1 },{ x2,y2,z2 },{ x2,y1,z2 } },
		{ { x1,y1,z1 },{ x1,y2,z1 },{ x1,y2,z2 },{ x1,y1,z2 } },
		{ { x1,y2,z1 },{ x2,y2,z1 },{ x2,y2,z2 },{ x1,y2,z2 } },
		{ { x1,y1,z2 },{ x2,y1,z2 },{ x2,y2,z2 },{ x1,y2,z2 } }
	};
	//设置正方形绘制模式
	glBegin(GL_QUADS);
	for (i = 0; i < 6; i++) {
		for (j = 0; j < 4; j++) {
			glVertex3fv(point[i][j]);
		}
	}
	glEnd();
}

//绘制桌子
void drawTable()
{
	drawCube(0.0, 1.0, 0.0, 0.8, 0.6, 0.8);	//桌面	
	drawCube(0.1, 0.3, 0.1, 0.3, 0.0, 0.6); //四条腿
	drawCube(0.7, 0.9, 0.1, 0.3, 0.0, 0.6);
	drawCube(0.1, 0.3, 0.5, 0.7, 0.0, 0.6);
	drawCube(0.7, 0.9, 0.5, 0.7, 0.0, 0.6);
}

void reshape(int width, int height)
{
	if (height == 0)	
	{
		height = 1;	 //高度为0时,让高度为1
	}

	glViewport(0, 0, width, height);	//设置视窗大小

	glMatrixMode(GL_PROJECTION);	//设置矩阵模式为投影
	glLoadIdentity();			//初始化矩阵为单位矩阵
								
	gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);//设置投影方位

	glMatrixMode(GL_MODELVIEW);	  //设置矩阵模式为模型
	glLoadIdentity();	//初始化矩阵为单位矩阵
}

void idle()
{
	glutPostRedisplay();//调用当前绘制函数
}

void redraw()
{
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);//设置多边形绘制模式:正反面,线型
	glClear(GL_COLOR_BUFFER_BIT);//清除颜色缓冲
	glLoadIdentity();	//初始化矩阵为单位矩阵

	glPushMatrix(); //压入矩阵堆栈
	glTranslatef(-2.0f, 0.0f, -6.0f); //图形向左平移,同时向里平移
	glTranslatef(0.0f, fTranslate, 0.0f);	//y轴方向上平移
	drawTable();//画桌子
	glPopMatrix();//抛出矩阵堆栈

	glPushMatrix();//压入矩阵堆栈
	glTranslatef(0.5f, 0.0f, -6.0f); //旋转前向右平移,改变坐标轴,同时向里平移	
	glRotatef(fRotate, 0, 1.0f, 0);     //以y轴为坐标轴旋转
	glTranslatef(-0.5f, 0.0f, 0.0f); //旋转后向左平移,恢复位置
	drawTable();//画桌子
	glPopMatrix();//抛出矩阵堆栈

	glPushMatrix();//压入矩阵堆栈
	glTranslatef(2.0f, 0.4f, -6.0f); //图形向右,向里平移 + 缩放前向右,向上平移,改变缩放点 
	glScalef(fScale, fScale, fScale); //等比例缩放
	glTranslatef(-0.5f, -0.4f, 0.0f); //缩放后向左,向下平移,恢复位置
	drawTable();//画桌子
	glPopMatrix();//抛出矩阵堆栈

	fTranslate += 0.002f; //更新平移因子
	fRotate += 0.4f; //更新旋转因子
	fScale -= 0.002f; //更新缩放因子

	if (fTranslate > 0.5f) fTranslate = 0.0f; //移到一定位置从头开始移
	if (fScale < 0.6f)fScale = 1.0f; //缩放到一定程度恢复原状

	glutSwapBuffers(); //交换缓冲区
}

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);//对glut的初始化
	glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);//初始化显示模式:RGB颜色模型,双缓冲 
	glutInitWindowSize(640, 480);//设置窗口大小  
	glutCreateWindow("Exercise2");//设置窗口标题 

	glutDisplayFunc(redraw);//注册绘制回调函数  
	glutReshapeFunc(reshape);//注册重绘回调函数  
	glutIdleFunc(idle);//注册全局回调函数:空闲时调用

	glutMainLoop();// glut事件处理循环  

	return 0;
}



  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值