当前位置: 首页 > news >正文

OpenGL的学习之路 -5

1.视景体 正交投影 

人眼看世界,有一个可见范围。范围内可见,范围外不可见。视景体就是这么一个概念。

(上图仅学习记录用)

在OGL中,有两种投影方式,对应两种视景体。第一种,正交投影;第二种,透视投影(更符合人眼)。

正交投影 

 

透视投影(可见,从视觉效果上,透视投影更符合人眼)

正交投影(代码)

 

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



// Rotation amounts
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;


void ChangeSize(GLsizei w, GLsizei h) {
   GLfloat nRange = 100.0f;

   if (h == 0)  h = 1;

   glViewport(0, 0, w, h);  //视口是一个矩形区域,它定义了OpenGL窗口中可以显示图形的区域
   glMatrixMode(GL_PROJECTION);  //下面对堆栈的操作是对 投影堆栈
   glLoadIdentity();

   //保持视景体的 纵横比 为w/h
   if (w <= h)
      glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange*2.0f, nRange*2.0f);
   else
      glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange*2.0f, nRange*2.0f);

   glMatrixMode(GL_MODELVIEW);  //再把堆栈由 投影栈 转换为 变换栈
   glLoadIdentity();
}


//先不看这个(灯光什么的,初始化)
void SetupRC() {
   // Light values and coordinates
   GLfloat  whiteLight[]  = { 0.45f, 0.45f, 0.45f, 1.0f };
   GLfloat  sourceLight[] = { 0.25f, 0.25f, 0.25f, 1.0f };
   GLfloat  lightPos[]    = { -50.f, 25.0f, 250.0f, 0.0f };

   glEnable(GL_DEPTH_TEST);	// Hidden surface removal <<============
   glFrontFace(GL_CCW);		// Counter clock-wise polygons face out
   glEnable(GL_CULL_FACE);		// Do not calculate inside of jet

   // Enable lighting
   glEnable(GL_LIGHTING);

   // Setup and enable light 0
   glLightModelfv(GL_LIGHT_MODEL_AMBIENT,whiteLight);
   glLightfv(GL_LIGHT0,GL_AMBIENT,sourceLight);
   glLightfv(GL_LIGHT0,GL_DIFFUSE,sourceLight);
   glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
   glEnable(GL_LIGHT0);

   // Enable color tracking
   glEnable(GL_COLOR_MATERIAL);

   // Set Material properties to follow glColor values
   glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

   // Black blue background
   glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
}


void SpecialKeys(int key, int x, int y) {
	if (key == GLUT_KEY_UP)    xRot -= 5.0f;
	if (key == GLUT_KEY_DOWN)  xRot += 5.0f;
	if (key == GLUT_KEY_LEFT)  yRot -= 5.0f;
	if (key == GLUT_KEY_RIGHT) yRot += 5.0f;

   xRot = (GLfloat)((const int)xRot % 360);
   yRot = (GLfloat)((const int)yRot % 360);

	// Refresh the Window
	glutPostRedisplay();
}



void RenderScene(void) {
   float fZ,bZ;

   // Clear the window with current clearing color
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

   fZ = 100.0f;
   bZ = -100.0f;

   // Save the matrix state and do the rotations
   glPushMatrix();
   glRotatef(xRot, 1.0f, 0.0f, 0.0f);
   glRotatef(yRot, 0.0f, 1.0f, 0.0f);

   // Set material color, Red
   glColor3f(1.0f, 0.0f, 0.0f);

   // Front Face
   glBegin(GL_QUADS);
      // Pointing straight out Z
      glNormal3f(0.0f, 0.0f, 1.0f);

      // Left Panel
      glVertex3f(-50.0f, 50.0f, fZ);
      glVertex3f(-50.0f, -50.0f, fZ);
      glVertex3f(-35.0f, -50.0f, fZ);
      glVertex3f(-35.0f,50.0f,fZ);

      // Right Panel
      glVertex3f(50.0f, 50.0f, fZ);
      glVertex3f(35.0f, 50.0f, fZ);
      glVertex3f(35.0f, -50.0f, fZ);
      glVertex3f(50.0f,-50.0f,fZ);

      // Top Panel
      glVertex3f(-35.0f, 50.0f, fZ);
      glVertex3f(-35.0f, 35.0f, fZ);
      glVertex3f(35.0f, 35.0f, fZ);
      glVertex3f(35.0f, 50.0f,fZ);

      // Bottom Panel
      glVertex3f(-35.0f, -35.0f, fZ);
      glVertex3f(-35.0f, -50.0f, fZ);
      glVertex3f(35.0f, -50.0f, fZ);
      glVertex3f(35.0f, -35.0f,fZ);

      // Top length section
      // Normal points up Y axis
      glNormal3f(0.0f, 1.0f, 0.0f);
      glVertex3f(-50.0f, 50.0f, fZ);
      glVertex3f(50.0f, 50.0f, fZ);
      glVertex3f(50.0f, 50.0f, bZ);
      glVertex3f(-50.0f,50.0f,bZ);

      // Bottom section
      glNormal3f(0.0f, -1.0f, 0.0f);
      glVertex3f(-50.0f, -50.0f, fZ);
      glVertex3f(-50.0f, -50.0f, bZ);
      glVertex3f(50.0f, -50.0f, bZ);
      glVertex3f(50.0f, -50.0f, fZ);

      // Left section
      glNormal3f(1.0f, 0.0f, 0.0f);
      glVertex3f(50.0f, 50.0f, fZ);
      glVertex3f(50.0f, -50.0f, fZ);
      glVertex3f(50.0f, -50.0f, bZ);
      glVertex3f(50.0f, 50.0f, bZ);

      // Right Section
      glNormal3f(-1.0f, 0.0f, 0.0f);
      glVertex3f(-50.0f, 50.0f, fZ);
      glVertex3f(-50.0f, 50.0f, bZ);
      glVertex3f(-50.0f, -50.0f, bZ);
      glVertex3f(-50.0f, -50.0f, fZ);
   glEnd();

   glFrontFace(GL_CW);		// clock-wise polygons face out

   glBegin(GL_QUADS);
      // Back section
      // Pointing straight out Z
      glNormal3f(0.0f, 0.0f, -1.0f);

      // Left Panel
      glVertex3f(-50.0f, 50.0f, bZ);
      glVertex3f(-50.0f, -50.0f, bZ);
      glVertex3f(-35.0f, -50.0f, bZ);
      glVertex3f(-35.0f,50.0f,bZ);

      // Right Panel
      glVertex3f(50.0f, 50.0f, bZ);
      glVertex3f(35.0f, 50.0f, bZ);
      glVertex3f(35.0f, -50.0f, bZ);
      glVertex3f(50.0f,-50.0f,bZ);

      // Top Panel
      glVertex3f(-35.0f, 50.0f, bZ);
      glVertex3f(-35.0f, 35.0f, bZ);
      glVertex3f(35.0f, 35.0f, bZ);
      glVertex3f(35.0f, 50.0f,bZ);

      // Bottom Panel
      glVertex3f(-35.0f, -35.0f, bZ);
      glVertex3f(-35.0f, -50.0f, bZ);
      glVertex3f(35.0f, -50.0f, bZ);
      glVertex3f(35.0f, -35.0f,bZ);

      // Insides /
   	glColor3f(0.75f, 0.75f, 0.75f);

      // Normal points up Y axis
      glNormal3f(0.0f, 1.0f, 0.0f);
      glVertex3f(-35.0f, 35.0f, fZ);
      glVertex3f(35.0f, 35.0f, fZ);
      glVertex3f(35.0f, 35.0f, bZ);
      glVertex3f(-35.0f,35.0f,bZ);

      // Bottom section
      glNormal3f(0.0f, 1.0f, 0.0f);
      glVertex3f(-35.0f, -35.0f, fZ);
      glVertex3f(-35.0f, -35.0f, bZ);
      glVertex3f(35.0f, -35.0f, bZ);
      glVertex3f(35.0f, -35.0f, fZ);

      // Left section
      glNormal3f(1.0f, 0.0f, 0.0f);
      glVertex3f(-35.0f, 35.0f, fZ);
      glVertex3f(-35.0f, 35.0f, bZ);
      glVertex3f(-35.0f, -35.0f, bZ);
      glVertex3f(-35.0f, -35.0f, fZ);

      // Right Section
      glNormal3f(-1.0f, 0.0f, 0.0f);
      glVertex3f(35.0f, 35.0f, fZ);
      glVertex3f(35.0f, -35.0f, fZ);
      glVertex3f(35.0f, -35.0f, bZ);
      glVertex3f(35.0f, 35.0f, bZ);
   glEnd();

   glFrontFace(GL_CCW);		// Counter clock-wise polygons face out

   // Restore the matrix state
   glPopMatrix();

   // Buffer swap
   glutSwapBuffers();
}



int main(int argc, char *argv[]) {
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);   //需要动画,使用的是双缓冲
    glutInitWindowSize(800, 600);
    glutCreateWindow("Orthographic Projection");

    //回调函数
    glutReshapeFunc(ChangeSize);    //改变窗口大小
    glutSpecialFunc(SpecialKeys);   //敲击特殊键
    glutDisplayFunc(RenderScene);   //显示
    //初始化函数
	SetupRC();

    glutMainLoop();
    return 0;
}

透视投影(替换代码)

2.几个代码示例(主要目的:弄明白 变换栈)

(1)三个球绕红球转

效果:

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


// Rotation amounts
static float xRot = 0.0f;


void RenderScene(void) {
	// Angle of revolution around the nucleus
	static float fElect1 = 0.0f;

	// Clear the window with current clearing color
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Reset the modelview matrix
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glTranslatef(0.0f, 0.0f, -100.0f); //A
	glColor3ub(255, 0, 0);
	glutSolidSphere(10.0f, 15, 15);  // 红色实心球(A)

	glColor3ub(255,255,0);
	glPushMatrix();
	glRotatef(fElect1, 0.0f, 1.0f, 0.0f);  //B
	glTranslatef(90.0f, 0.0f, 0.0f);       //C
	glutSolidSphere(6.0f, 15, 15);         //黄色实心球1(ABC)
	glPopMatrix();

	//xRot由特殊键控制
	glPushMatrix();
	glRotatef(45.0f, 0.0f, 0.0f, 1.0f);  //D
	glRotatef(xRot, 0.0f, 1.0f, 0.0f);   //E
	glTranslatef(-70.0f, 0.0f, 0.0f);    //F
	glutSolidSphere(6.0f, 15, 15);       //黄色实心球2(ADEF)
	glPopMatrix();

	glPushMatrix();
	glRotatef(300.0f,0.0f, 0.0f, 1.0f);    //G
	glRotatef(fElect1, 0.0f, 1.0f, 0.0f);  //H
	glTranslatef(0.0f, 0.0f, 60.0f);       //I
	glutSolidSphere(6.0f, 15, 15);         //黄色实心球3(AGHI)
	glPopMatrix();

	// Increment the angle of revolution
	fElect1 += 1.0f;
	if (fElect1 > 360.0f)
		fElect1 = 0.0f;

	// Show the image
	glutSwapBuffers();
}


void SetupRC() //初始化函数
{
	glEnable(GL_DEPTH_TEST);	// Hidden surface removal
	glFrontFace(GL_CCW);		// Counter clock-wise polygons face out
	glEnable(GL_CULL_FACE);		// Do not calculate inside of jet
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
}


void SpecialKeys(int key, int x, int y) {
	if (key == GLUT_KEY_UP)    xRot -= 5.0f;
	if (key == GLUT_KEY_DOWN)  xRot += 5.0f;
	//if (key == GLUT_KEY_LEFT)  yRot -= 5.0f;
	//if (key == GLUT_KEY_RIGHT) yRot += 5.0f;
	if (key > 356.0f) xRot = 0.0f;
	if (key < -1.0f)  xRot = 355.0f;
	//if (key > 356.0f) yRot = 0.0f;
	//if (key < -1.0f)  yRot = 355.0f;

	glutPostRedisplay();    // Refresh the Window
}


void TimerFunc(int value) {
    glutPostRedisplay();     // Refresh the Window
    /*
    millis:指定的时间间隔,以毫秒为单位。
    callback:指向回调函数的指针,该回调函数在指定时间间隔过后被调用。
    data:传递给回调函数的整型数值参数
    */
    glutTimerFunc(10, TimerFunc, 1); //seconds, func, para(注册了一个定时器)
}


void ChangeSize(int w, int h) {
   float nRange = 100.0f;

   if (h == 0) h = 1;

   glViewport(0, 0, w, h);

   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();

   //正交投影(left, right, bottom, top, near, far)
   if (w <= h)
      glOrtho (-nRange, nRange, nRange*h/w, -nRange*h/w, -nRange*2.0f, nRange*2.0f);
   else
      glOrtho (-nRange*w/h, nRange*w/h, nRange, -nRange, -nRange*2.0f, nRange*2.0f);
}


int main(int argc, char* argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
	glutCreateWindow("OpenGL Atom");

	glutReshapeFunc(ChangeSize);    //改变窗口大小时的回调函数
	glutSpecialFunc(SpecialKeys);   //敲击特殊键的回调函数
	glutDisplayFunc(RenderScene);   //显示的回调函数
    glutTimerFunc(500, TimerFunc, 1);   ///new!!(保持连续变化)
	SetupRC();

	glutMainLoop();
	return 0;
}

(2)键盘控制的自转和公转

效果:

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

///
static int year = 0, day = 0;

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

///
void display(void) {
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1.0, 1.0, 1.0);

    glPushMatrix();
    glRotatef((GLfloat)year, 0.0, 1.0, 0.0);   //A(实现自传效果)
    glutWireSphere(1.0, 20, 16);               //画线框太阳(A)
    ///思考:加上这两句的效果会怎样?
    //glPopMatrix();
    //glPushMatrix();
    
    glTranslatef(2.0, 0.0, 0.0);                //B
    glRotatef((GLfloat) day, 0.0, 1.0, 0.0);    //C
    glutWireSphere(0.2, 10, 8);                 //画线框地球(ABC)
	glPopMatrix();

    glutSwapBuffers();
}


///
void reshape(int w, int h) {
   glViewport(0, 0,(GLsizei) w,(GLsizei) h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(60.0,(float) w/(float) h, 1.0, 20.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}


///
void keyboard(unsigned char key, int x, int y) {
   switch(key) {
      case 'd':  day =(day + 10) % 360;   break;
      case 'D':  day =(day - 10) % 360;   break;
      case 'y':  year =(year + 5) % 360;  break;
      case 'Y':  year =(year - 5) % 360;  break;
      case 27:   exit(0);
      default:   break;
   }
	glutPostRedisplay();
}

///
int main(int argc, char** argv) {
    
	std::cout<<"D/d: 行星转动\nY/y: 太阳转动\n";

   glutInit(&argc, argv);
   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize(500, 500);
   glutInitWindowPosition(500, 100);
   glutCreateWindow("earthmoon");

   init();   //初始化函数
   glutDisplayFunc(display);    //显示的回调函数
   glutReshapeFunc(reshape);    //改变窗口大小的回调函数
   glutKeyboardFunc(keyboard);  //点击键盘的回调函数

   glutMainLoop();
   return 0;
}

如果点击‘D’或者‘d’,矩阵C变化,地球实现自转的效果;如果点击‘Y’或者‘y’,矩阵A变化,太阳自转,地球跟着太阳转;如果同时按下‘D’或者‘d’以及‘Y’或者‘y’,地球自转的同时绕着太阳公转,同时,太阳也在自转。

(3)星系

效果:

#include <math.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#define N  6

///
// Lighting values
float whiteLight[]  = { 0.2f, 0.2f, 0.2f, 1.0f };
float sourceLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };
float	lightPos[]  = { 0.0f, 0.0f, 0.0f, 1.0f };

float para[N][3] = { {2.0f,  30.0f, 99.f},
                     {3.0f,  50.0f, 44.f},
                     {6.0f,  70.0f, 20.f},
                     {5.0f,  90.0f, 80.f},
                     {9.0f, 110.0f, 10.f},
                     {2.0f, 120.0f, 15.f}
						 };
float fEarthRot = 0;

///
void RenderScene(void) {
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);

	glPushMatrix();
	glLoadIdentity();
	glTranslatef(0.0f, 0.0f, -300.0f);  //A
    glRotatef(15, 1.0f, 0.0f, 0.0f);    //B

    glDisable(GL_LIGHTING);
	glColor3ub(255, 255, 0);
	glutSolidSphere(10.0f, 18, 17);  // 太阳(AB)

    glEnable(GL_LIGHTING);
	glLightfv(GL_LIGHT0, GL_POSITION, lightPos); // Move the light after we draw the sun!

	for (int i=0; i<N; ++i)   //画几大行星
    {
	   glPushMatrix();  //AB再复制一份放到栈顶
	   glRotatef(fEarthRot*para[i][2], 0.0f, 1.0f, 0.0f);   //C
	   glColor3ub(0,0,255);
	   glTranslatef(para[i][1],0.0f,0.0f);                  //D
	   glutSolidSphere(para[i][0], 30, 17);                 //画行星(ABCD)

	   glPushMatrix();      //ABCD再复制一份放到栈顶
	   glLoadIdentity();    //转化为单位阵(I)
       glTranslatef(0.0f, 0.0f, -300.0f);   //E
       glRotatef(15, 1.0f, 0.0f, 0.0f);     //F
       glDisable(GL_LIGHTING);
       glColor3f(1,0,0);

       glBegin(GL_LINE_LOOP);  //画轨迹
       for (float j=0; j<2*3.14149265; j+=0.1f) {
	   	  glVertex3f(para[i][1]*sin(j), 0.0f, para[i][1]*cos(j));  //轨迹(EF)
		  }
       glEnd();

       glPopMatrix(); //将当前栈顶矩阵 EF 弹出

       glPopMatrix(); //将当前栈顶矩阵 ABCD 弹出,弹出后,栈顶元素变为AB
       glEnable(GL_LIGHTING);
	}

	glPopMatrix();	//将当前栈顶矩阵 AB 弹出

	fEarthRot += 0.1f;
	if (fEarthRot > 360.0f)	fEarthRot = 0.0f; //转起来

	glutSwapBuffers();
}

//初始化函数,关于灯光的一些操作
///
void SetupRC() {
	glEnable(GL_DEPTH_TEST);
	glFrontFace(GL_CCW);
	glEnable(GL_CULL_FACE);
	glEnable(GL_LIGHTING);

	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,whiteLight);
	glLightfv(GL_LIGHT0,GL_DIFFUSE,sourceLight);
	glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
	glEnable(GL_LIGHT0);
	glEnable(GL_COLOR_MATERIAL);
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
	glClearColor(0.3f, 0.3f, 0.3f, 1.0f );
}

///
void TimerFunc(int value) {
   glutPostRedisplay();               //重新绘制
   glutTimerFunc(100, TimerFunc, 1);  //设置定时器
}

///
void ChangeSize(int w, int h) {
    float fAspect;

    if (h == 0)  h = 1;
    glViewport(0, 0, w, h);
    fAspect = (float)w/(float)h;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(40.0f, fAspect, 1.0, 600.0);  //透视投影

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

///
int main(int argc, char* argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
	glutCreateWindow("Earth/Moon/Sun System");

	glutReshapeFunc(ChangeSize);        //改变窗口大小的回调函数
	glutDisplayFunc(RenderScene);       //显示的回调函数
    glutTimerFunc(250, TimerFunc, 1);   ///new!!

	SetupRC();  //初始化
	glutMainLoop();
	return 0;
}

程序分析:

(4)月亮绕着地球转、地球绕着太阳转

效果:

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

///
// Lighting values
float  whiteLight[]  = { 0.2f, 0.2f, 0.2f, 1.0f };
float  sourceLight[] = { 1.0f, 1.0f, 1.0f, 1.0f };
float	lightPos[]    = { 0.0f, 0.0f, 0.0f, 1.0f };

///
void RenderScene(void) {
	static float fMoonRot  = 0.0f;
	static float fEarthRot = 0.0f;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Save the matrix state and do the rotations
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();

	glTranslatef(0.0f, 0.0f, -300.0f);  //A
    glDisable(GL_LIGHTING);
	glColor3ub(255, 255, 0);
	glutSolidSphere(18.0f, 18, 17);  /// 太阳(A)
    glEnable(GL_LIGHTING);

	// Move the light after we draw the sun!
	glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

	glRotatef(fEarthRot, 0.0f, 1.0f, 0.0f); //B
	glColor3ub(0,0,255);
	glTranslatef(105.0f,0.0f,0.0f);   //C
	glutSolidSphere(6.0f, 30, 17);    ///地球(ABC)

	glColor3ub(200,200,200);
	glRotatef(fMoonRot,0.0f, 0.0f, 1.0f); //D
	glTranslatef(15.0f, 0.0f, 0.0f);      //E
	glutSolidSphere(3.0f, 30, 17);        ///月亮(ABCDE)

	// Restore the matrix state
	glPopMatrix();	// Modelview matrix

    fMoonRot += 10.0f;
	if (fMoonRot > 360.0f)
		fMoonRot = 0.0f;

	fEarthRot += 2.0f;
	if (fEarthRot > 360.0f)
		fEarthRot = 0.0f;

	// Show the image
	glutSwapBuffers();
}

///
// This function does any needed initialization on the rendering context.
void SetupRC() {
	glEnable(GL_DEPTH_TEST);	// Hidden surface removal
	glFrontFace(GL_CCW);	   	// Counter clock-wise polygons face out
	glEnable(GL_CULL_FACE);		// Do not calculate inside of jet

	glEnable(GL_LIGHTING);

	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,whiteLight);
	glLightfv(GL_LIGHT0,GL_DIFFUSE,sourceLight);
	glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
	glEnable(GL_LIGHT0);

	glEnable(GL_COLOR_MATERIAL);

	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

	glClearColor(0.3f, 0.3f, 0.3f, 1.0f );
}

///
void TimerFunc(int value) {
   glutPostRedisplay();
   glutTimerFunc(100, TimerFunc, 1);
}

///
void ChangeSize(int w, int h) {
    float fAspect;

    if (h == 0)  h = 1;
    glViewport(0, 0, w, h);

    fAspect = (float)w/(float)h;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, fAspect, 1.0, 425.0); //透视投影

    // Modelview matrix reset
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

}

///
int main(int argc, char* argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800, 600);
	glutCreateWindow("Earth/Moon/Sun System");

	glutReshapeFunc(ChangeSize);    //改变窗口大小的回调函数
	glutDisplayFunc(RenderScene);   //显示的回调函数
    glutTimerFunc(250, TimerFunc, 1);   ///new!!

	SetupRC();  //初始化函数

	glutMainLoop();

	return 0;
}

 推广:

(5)机器人的手臂

效果:

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

///
static int shoulder = 0, elbow = 0;

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

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

    glPushMatrix();         //将当前栈顶矩阵A复制一份,放在栈顶
    glTranslatef (-1.0f, 0.0, 0.0);   //B
    glRotatef ((GLfloat) shoulder, 0.0, 0.0, 1.0f);   //C
    glTranslatef (1.0, 0.0, 0.0);     //D

    glPushMatrix();         //将当前栈顶矩阵ABCD复制一份,放在栈顶
    glScalef (2.0f, 0.4f, 1.0f);       //E
    glutWireCube (1.0);     ///机器人 上手臂(ABCDE)
    glPopMatrix();          //将当前栈顶矩阵ABCDE弹出

    glTranslatef (1.0f, 0.0, 0.0);     //F
    glRotatef ((GLfloat) elbow, 0.0, 0.0, 1.0f);   //G
    glTranslatef (1.0f, 0.0, 0.0);     //H
    glScalef (2.0f, 0.4f, 1.0f);  //I
    glutWireCube (1.0f);    ///机器人 下手臂(ABCDFGHI)
    glPopMatrix();          //将当前栈顶矩阵ABCDFGHI弹出
    glPopMatrix();          //将当前栈顶矩阵ABCD弹出
    glPopMatrix();          //将当前栈顶矩阵A弹出
    glutSwapBuffers();
}

///
void reshape (int w, int h) {
   glViewport (0, 0, (GLsizei) w, (GLsizei) h);
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
   gluPerspective(65.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);  //透视投影
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glTranslatef (0.0, 0.0, -5.0);   // A
}

///
void keyboard (unsigned char key, int x, int y) {
   switch (key) {
      case 's':  shoulder = (shoulder + 5) % 360;  break;
      case 'S':  shoulder = (shoulder - 5) % 360;  break;
      case 'e':  elbow = (elbow + 5) % 360;  break;
      case 'E':  elbow = (elbow - 5) % 360;  break;
      case 27:   exit(0);
      default:   break;
   }
   glutPostRedisplay();
}

///
int main(int argc, char** argv) {
   printf("S, Or E\n");
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize (500, 500);
   glutInitWindowPosition (100, 100);
   glutCreateWindow ("robot");

   init ();     //初始化函数
   glutDisplayFunc(display);    //显示的回调函数
   glutReshapeFunc(reshape);    //改变窗口大小时的回调函数
   glutKeyboardFunc(keyboard);  //敲击键盘的回调函数

   glutMainLoop();
   return 0;
}

简单分析:

显示函数中,旋转之前都有一个平移。也就是物体进行缩放后(长度变为2),先向右平移一个单位,之后再进行旋转,这样物体的最左侧位于原点位置,相当于物体以其最右侧为旋转固定中心进行旋转。完成这一效果之后,再进行平移也不影响这一效果(物体以其最右侧为旋转固定中心进行旋转)。

相关文章:

  • 基于SpringBoot房产销售系统
  • 指数退避和抖动
  • 网工内推 | 云计算运维,云相关认证优先,最高30K,带薪年假
  • 视频号小店需要多少资金?都需要准备什么东西?一篇详解!
  • Python与设计模式--门面模式
  • 03_MySQL基本SQL语句讲解
  • ClickHouse:真正的OLAP列式DBMS
  • 【迅搜04】索引配置(一)加载配置文件以及服务端配置
  • 【开源】基于Vue和SpringBoot的个人健康管理系统
  • sql24(Leetcode1141查询近30天活跃用户数)
  • 市场调研:2023年SLG游戏行业需求及发展前景预测
  • uniapp IOS从打包到上架流程(详细简单)
  • linux下Qt使用LinuxDeployqt打包
  • rocky8.9配置K8S集群kubernetes,centos同理
  • 汽车功能安全ISO26262
  • python监控显卡显存
  • Go 从编译到执行
  • 目标检测开源数据
  • 选择合适的企业邮箱供应商的策略与技巧
  • 基于javaweb的宠物服务商城系统设计与开发
  • 文学花边|对话《借命而生》原著作者石一枫:我给剧打90分
  • IPO周报|本周A股暂无新股网上申购,年内最低价股周二上市
  • 射箭世界杯上海站摘得两银,中国队新周期冲击韩国缩小差距
  • 著名学者黄修己去世,享年90岁
  • 韩国总统大选候选人登记结束,共7人参选
  • 家电维修担心遇“李鬼”?上海推动“物业+专业服务”进社区