10.10节书中给出了一个程序示例,有一个填充正方形,从侧面的角度观察并画到屏幕上。
图0
这里进一步画出一个立方体,将相机放入立方体中心,旋转相机,达到在立方体中旋转看到不同画面的效果。
步骤:
1 使用的是4.9节中的OpenGL顶点数组方法。创建一个立方体100*100*100,坐标范围(0, 0, 0)到(100, 100, 100)。
2 立方体各面使用不同的颜色,调整顶点顺序以确保相机看到的都是填充面而不是线框图。
3 将投影观察点(即观察系原点)设置在矩形中心P0 = (50, 50, 50)。
4 视点Pref为相机朝向的点(注意,这个不是观察点),初始设置为Pref =(0, 50, 0)。
5 修改Pref的坐标,使其绕x=z=50进行逆时针旋转(与y轴平行的旋转公式(9.9)),最终实现相机在立方体中逆时针旋转,看到不同面的效果。
备注:
1 与y轴平行的旋转公式,先将旋转轴平移到与y轴重合,再进行旋转:z' = z * cosθ - x * sinθ, x' = z * sinθ + x * cosθ, y'=y;
2 近平面距离投影观察点不能为0,近平面和远平面的坐标会影响画面的效果,调整范围以确保画面不太离谱(并不真实)
3 之前直接在displayFcn中调用cube,修改使用display list后可以提高cpu的效率,从2%降到1%。
问题:
1 调整dnear和dfar时,会影响投影效果。dnear离P0越近,投影效果强度更大,离得远的点看着更小。见图2。不真实。
2 当调整近裁剪面大小且当立方体旋转时,投影画面会改变宽度,看起来会更奇怪。见图3。不真实。
3 在idleFcn中使用glutPostRedisplay替换直接调用displayFcn,效率有降低,不懂为什么。
1 #include <GLUT/GLUT.h> 2 #include <math.h> 3 4 GLint winWidth = 600, winHeight = 600; 5 GLfloat x0 = 50.0, y00 = 50.0, z0 = 50.0; // 这是观察参考点,与观察系原点重合 6 GLfloat xref = 0.0, yref = 50.0, zref = 0.0; // camera要瞄准的点,不是观察参考点 7 GLfloat Vx = 0.0, Vy = 1.0, Vz = 0.0; 8 GLfloat xwMin = -40.0, ywMin = -40.0, xwMax = 40.0, ywMax = 40.0; 9 GLfloat dnear = 25, dfar = 75; 10 GLdouble radianAngle = 1.0/360.0 * 3.14159; 11 GLfloat cos1 = cos(radianAngle); 12 GLfloat sin1 = sin(radianAngle); 13 14 typedef GLint vertex3 [3]; 15 vertex3 pt [8] = {{0, 0, 0}, {0, 100, 0}, {100, 0, 0}, {100, 100, 0}, 16 {0, 0, 100}, {0, 100, 100}, {100, 0, 100}, {100, 100, 100}}; 17 18 void init (void) 19 { 20 glClearColor(1.0, 1.0, 1.0, 0.0); 21 22 glMatrixMode(GL_MODELVIEW); 23 gluLookAt(x0, y00, z0, xref, yref, zref, Vx, Vy, Vz); 24 25 glMatrixMode(GL_PROJECTION); 26 glFrustum(xwMin, xwMax, ywMin, ywMax, dnear, dfar); 27 28 void cube(); 29 cube(); 30 } 31 32 void quad (GLint n1, GLint n2, GLint n3, GLint n4) 33 { 34 glBegin(GL_QUADS); 35 glVertex3iv(pt[n1]); 36 glVertex3iv(pt[n2]); 37 glVertex3iv(pt[n3]); 38 glVertex3iv(pt[n4]); 39 glEnd(); 40 } 41 42 GLuint regHex; 43 44 void cube () 45 { 46 regHex = glGenLists(1); 47 glNewList(regHex, GL_COMPILE); 48 49 glColor3f(0.0, 1.0, 0.0); // back 50 quad(0, 2, 3, 1); 51 glColor3f(1.0, 0.0, 0.0); // left 52 quad(0, 1, 5, 4); 53 glColor3f(0.0, 0.0, 1.0); // top 54 quad(1, 3, 7, 5); 55 glColor3f(1.0, 1.0, 0.0); // front 56 quad(4, 5, 7, 6); 57 glColor3f(0.0, 1.0, 1.0); // right 58 quad(2, 6, 7, 3); 59 glColor3f(1.0, 0.0, 1.0); // bottom 60 quad(0, 4, 6, 2); 61 62 glEndList(); 63 } 64 65 void displayFcn (void) 66 { 67 glClear(GL_COLOR_BUFFER_BIT); 68 69 glColor3f(0.0, 1.0, 0.0); 70 glPolygonMode(GL_FRONT, GL_FILL); 71 glPolygonMode(GL_BACK, GL_LINE); 72 // glFrontFace(GL_CW); // show the back 73 74 glCallList(regHex); 75 76 glutSwapBuffers(); 77 } 78 79 void reshapeFcn (GLint newWidth, GLint newHeight) 80 { 81 glViewport(0, 0, newWidth, newHeight); 82 83 winWidth = newWidth; 84 winHeight = newHeight; 85 } 86 87 void idleFcn (void) 88 { 89 GLfloat xref1, zref1; 90 xref = xref - x0; 91 zref = zref - z0; 92 zref1 = zref * cos1 - xref * sin1 + z0; 93 xref1 = zref * sin1 + xref * cos1 + x0; 94 xref = xref1; 95 zref = zref1; 96 97 glMatrixMode(GL_MODELVIEW); 98 glLoadIdentity(); 99 gluLookAt(x0, y00, z0, xref, yref, zref, Vx, Vy, Vz); 100 101 glutPostRedisplay(); 102 } 103 104 int main(int argc, char * argv[]) 105 { 106 glutInit(&argc, argv); 107 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 108 glutInitWindowSize(winWidth, winHeight); 109 glutInitWindowPosition(50, 50); 110 glutCreateWindow("Perspective View of A Square"); 111 112 init(); 113 glutDisplayFunc(displayFcn); 114 glutReshapeFunc(reshapeFcn); 115 glutIdleFunc(idleFcn); 116 glutMainLoop(); 117 118 return 0; 119 }