OpenGL 的学习之路-4(变换)

三大变换:平移、缩放、旋转(通过这三种变换,可以将图像移动到任意位置)

其实,这背后对应的数学在 闫令琪 图形学课程 中有过一些了解,所以,理解起来也不觉得很困难。看程序吧。

1.画三角形(运用三种变化效果)

cpp 复制代码
///
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <stdlib.h>


///
void init(void) {
   glClearColor (0.0, 0.0, 0.0, 0.0);
   //glShadeModel (GL_FLAT);
}


///
void draw_triangle(void) {
   glBegin (GL_LINE_LOOP);
   glVertex2f(0.0, 25.0);
   glVertex2f(25.0, -25.0);
   glVertex2f(-25.0, -25.0);
   glEnd();
}


///
void display(void) {
   glClear (GL_COLOR_BUFFER_BIT);

   glLoadIdentity (); ///!!!!
   glColor3f (1.0, 1.0, 1.0);
   draw_triangle ();

   glEnable (GL_LINE_STIPPLE); ///!!!!打开画线型的开关

   glLineStipple (1, 0xF0F0);
   glLoadIdentity ();
   glTranslatef (-20.0, 0.0, 0.0);  ///平移
   draw_triangle ();

   glLineStipple (1, 0xF00F);
   glLoadIdentity ();
   glScalef (1.5, 0.5, 1.0);   ///缩放
   draw_triangle ();

   glLineStipple (1, 0x8888);
   glLoadIdentity ();
   glRotatef (90.0, 0.0, 0.0, 1.0);   ///旋转,第一个参数是角度,后面三个是旋转的轴
   draw_triangle ();

   glDisable (GL_LINE_STIPPLE); //*/

   glFlush ();
}

//先不看这个
///
void reshape (int w, int h) {
   glViewport (0, 0, (GLsizei) w, (GLsizei) h);
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
   if (w <= h)
      glOrtho (-50.0, 50.0, -50.0*(GLfloat)h/(GLfloat)w,
         50.0*(GLfloat)h/(GLfloat)w, -1.0, 1.0);
   else
      glOrtho (-50.0*(GLfloat)w/(GLfloat)h,
         50.0*(GLfloat)w/(GLfloat)h, -50.0, 50.0, -1.0, 1.0);
   glMatrixMode(GL_MODELVIEW);
}



///
int main(int argc, char** argv) { //int argc, char** argv) {
   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
   glutInitWindowSize(500, 500);
   glutInitWindowPosition(100, 100);
   glutCreateWindow(""); //argv[0]);

   init();

   glutDisplayFunc(display);
   glutReshapeFunc(reshape);

   glutMainLoop();

   return 0;
}

运行结果:

程序分析:

知识点:

1.**glLoadIdentity ()**所有的变换操作是放在一个栈中的,在施加一个新变化上,该语句的作用是向栈中压入一个I(单位阵),也就是现在还无变换。方便后续操作。

2.**glTranslatef (-20.0, 0.0, 0.0)**平移操作,向x轴的负半轴平移20个单位。该语句施加在前面I之上,相当于该平移变换起作用。

3.glScalef (1.5, 0.5, 1.0) 缩放操作,x轴坐标变为原来的1.5倍,y轴坐标变为原来的0.5倍。该语句施加在前面I之上,相当于该缩放变换起作用。

4.glRotatef (90.0, 0.0, 0.0, 1.0) 旋转操作,以(0,0,1)也就是z轴为旋转轴,旋转度数为90度。该语句施加在前面I之上,相当于该旋转变换起作用。

2.变换的顺序 以及 新的语句使用

cpp 复制代码
///
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <iostream>


///
void myMainWinDraw(void);
void myMainWinReshape(int _width, int _height);


///
int winWidth, winHeight;
int control(0);


///
int main(int argc,char** argv) {
    glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
	glutInitWindowSize(400, 400);
	glutInitWindowPosition(0, 0);

	glutCreateWindow("Hello");

	glutDisplayFunc(myMainWinDraw);
	glutReshapeFunc(myMainWinReshape);

	glutMainLoop();

   return 0;
}

//先不看这个(的作用)
///
void myMainWinReshape(int _width, int _height) {
	winWidth  = _width;
	winHeight = _height;
	glViewport(0, 0, _width, _height);
}


///
void myMainWinDraw() {
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	glPushMatrix();  //!!!

	glLoadIdentity();
    //attention: order is very important !!
    glRotatef(90, 0.0f, 0.0f, 1.0f); //<<===new!!
    glTranslatef(0.75f, 0.0, 0.0f);   //<<===new!!
    glutWireTeapot(0.25f);

    glPopMatrix();   //!!!

	glFlush();
}

///

运行结果:

如果改变R和T的顺序:

运行结果:

示意图:

知识点:

1.**glPushMatrix()**将存着变换的栈中的栈顶矩阵复制一份再放到栈顶。

2.**glLoadIdentity ()**将那个栈顶的矩阵变换为单位阵 I。

3.如果有多个变换的函数,先施行的是最下面的,然后往上进行。

4.glPopMatrix() 将栈顶的矩阵弹出,这样比较安全。变换前后,保持了栈中的状态没有变化。

(以上三种变换属于模型变换)

3.设置相机的位置

拍摄受相机的影响,影响相机的三个因素:相机的位置、相机的指向、相机的top方向。如果把相机比作人的眼睛的话,眼睛的位置、眼睛看向哪里、头的歪头。

cpp 复制代码
///
///

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#define STEP  0.01f


///
double eyex, eyez, upx;

///
void myDrawing(void);
void myKeyboard(unsigned char _key, int _x, int _y);
void reshape(GLsizei _wid, GLsizei _hei);


///
int main(int argc,char** argv) {
    glutInit(&argc,argv);
	eyex = eyez = 0;
	upx  = 0;

	glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
	glutInitWindowSize(300, 300);
	glutInitWindowPosition(400, 0);
	glutCreateWindow("Hello");

	glutDisplayFunc(myDrawing);
	glutKeyboardFunc(myKeyboard);
	glutReshapeFunc(reshape);

	glutMainLoop();

   return 0;
}


///
void reshape(GLsizei _wid, GLsizei _hei) {
	glViewport(0, 0, _wid, _hei);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

#if 1
	if (_wid<=_hei) {
		glOrtho(-3.0, 3.0, -3.0*_hei/_wid, 3.0*_hei/_wid, -3.0, 13.0);
	} else {
		glOrtho(-3.0*_wid/_hei, 3.0*_wid/_hei, -3.0, 3.0, -3.0, 13.0);
	}
#else
	gluPerspective(90.0, 1.0, 0, 10.0);
#endif

	glMatrixMode(GL_MODELVIEW);
}

///
// 图形绘制函数
void myDrawing(void) {
	glClearColor(0.0, 0.0, 1.0f, 0.0);  //设置背景清除蓝色
	glClear(GL_COLOR_BUFFER_BIT);       //执行清除

	glPushMatrix();
	  glLoadIdentity();
	  gluLookAt(eyex, 0, eyez, 0, 0, -1, upx, 1, 0);  //会在modelview矩阵上叠加
	  glTranslatef(0.0f, 0.0f, -3.0f);
	  glutWireTeapot(0.5f);
	  //gluLookAt(eyex, 0, eyez, 0, 0, -1, upx, 1, 0);  //会在modelview矩阵上叠加----顺序
	glPopMatrix();

	glFlush();
}



///
// 键盘事件处理函数               <==========NEW!!!
void myKeyboard(unsigned char _key, int _x, int _y) {
	switch (_key) {
	case 'w': eyex += STEP; break;
	case 's': eyex -= STEP; break;

	case 'r': eyez += STEP; break;
	case 'f': eyez -= STEP; break;

	case 'e': upx += STEP; break;
	case 'd': upx -= STEP; break;
	}

	glutPostRedisplay();
}

知识点:

1.**gluLookAtt(eyex, 0, eyez, 0, 0, -1, upx, 1, 0)**9个参数,三个一组,前三个是相机的位置,中间三个是相机看向的方向,后三个是相机的top方向。这里,一开始,相机位于原点位置,相机看向z轴负半轴(也就是屏幕里),相机的top方向是y轴的正方向。

2.这里使用了键盘事件处理的回调函数 来实现 漫游(相机的移动)。

相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习