三大变换:平移、缩放、旋转(通过这三种变换,可以将图像移动到任意位置)
其实,这背后对应的数学在 闫令琪 图形学课程 中有过一些了解,所以,理解起来也不觉得很困难。看程序吧。
1.画三角形(运用三种变化效果)
///
#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.变换的顺序 以及 新的语句使用
///
#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方向。如果把相机比作人的眼睛的话,眼睛的位置、眼睛看向哪里、头的歪头。
///
///
#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.这里使用了键盘事件处理的回调函数 来实现 漫游(相机的移动)。