一、代码部分
1、项目初始化
//1、 初始化API
//# (1)、设置工作目录
gltSetWorkingDirectory(argv[0]);
//# (2)、初始化API
glutInit(&argc, argv);
//# (3)、设置window的尺寸
glutInitWindowSize(800, 600);
//#(4)、创建Window的名称
glutCreateWindow("GL_POINTS");
//2、注册回调函数 (改变尺寸)
glutReshapeFunc(ChangSize);
//3、点击空格时,调用的函数
glutKeyboardFunc(KeyPressFunc);
//4、特殊键位函数 (上下左右)
glutSpecialFunc(SpecialKeys);
//5、显示函数
glutDisplayFunc(RenderScene);
//判断一下是否能初始化glew库,确保项目能正常使用OpenGL 框架
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error:%s\n",glewGetErrorString(err));
return 1;
}
// 6、绘制
SetupRC();
//runloop运行循环
glutMainLoop();
2、 回调函数 (改变尺寸)
// 窗口已更改大小,或刚刚创建 无论哪种情况,我们都需要
// 使用窗口维度设置视口和投影矩阵
void ChangSize(int w, int h)
{
/** glViewport是OpenGL中的一个函数。计算机图形学中,在屏幕上打开窗口的任务是由窗口系统,而不是OpenGL负责的。glViewport在默认情况下,[视口](http://baike.baidu.com/view/1522985.htm)被设置为占据打开窗口的整个像素矩形,窗口大小和设置视口大小相同,所以为了选择一个更小的绘图区域,就可以用glViewport函数来实现这一变换,在窗口中定义一个像素矩形,最终将[图像映射](http://baike.baidu.com/view/685692.htm)到这个矩形中。例如可以对窗口区域进行划分,在同一个窗口中显示分割屏幕的效果,以显示多个视图/
glViewport(GLint x,GLint y,GLsizei width,GLsizei height)为其函数原型。
X,Y————以像素为单位,指定了[视口](http://baike.baidu.com/view/1522985.htm)的左下角(在第一象限内,以(0,0)为原点的)位置。
width,height————表示这个视口矩形的宽度和高度,根据窗口的实时变化重绘窗口。
**/
glViewport(0, 0, w, h);
// 创建投影矩阵堆栈中
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
projectionMatix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//调用顶部载入单元矩阵
modelViewMatrix.LoadIdentity();
}
3、点击空格时,调用的函数
//根据空格次数.切换不同的“窗口名称”
void KeyPressFunc(unsigned char key,int x,int y)
{
if (key == 32) {
nStep++;
if (nStep > 6) {
nStep = 0;
}
}
switch (nStep) {
case 0:
glutSetWindowTitle("GL_POINTS");
break;
case 1:
glutSetWindowTitle("GL_LINES");
break;
case 2:
glutSetWindowTitle("GL_LINE_STRIP");
break;
case 3:
glutSetWindowTitle("GL_LINE_LOOP");
break;
case 4:
glutSetWindowTitle("GL_TRIANGLES");
break;
case 5:
glutSetWindowTitle("GL_TRIANGLE_STRIP");
break;
case 6:
glutSetWindowTitle("GL_TRIANGLE_FAN");
break;
default:
break;
}
// 从新绘制
glutPostRedisplay();
}
4、特殊键位函数 (上下左右)
// 特殊键位处理(上、下、左、右移动)
void SpecialKeys(int key,int x, int y){
if (key == GLUT_KEY_UP) {
// 围绕一个指定的X,Y,Z轴旋转
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
}
if (key == GLUT_KEY_DOWN) {
objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
}
if (key == GLUT_KEY_LEFT) {
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
}
if (key == GLUT_KEY_RIGHT) {
objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
}
glutPostRedisplay();
}
5、显示函数
// 召唤场景
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//压栈
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
//矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部
modelViewMatrix.MultMatrix(mCamera);
M3DMatrix44f mObjectFrame;
// 只要使用 GetMatrix 函数就可以获取矩阵堆栈顶部的值,这个函数可以进行 2次重载.用来使用GLShaderManger的使用.或者是获取顶部矩阵的顶部副本数据
objectFrame.GetMatrix(mObjectFrame);
//矩阵乘以矩阵堆栈的的顶部矩阵,相乘的结果随后简存储在堆栈的顶部
modelViewMatrix.MultMatrix(mObjectFrame);
/* GLShaderManager 中的Uniform 值——平面着色器
参数1:平面着色器
参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
--transformPipeline.GetModelViewProjectionMatrix() 获取的
GetMatrix函数就可以获得矩阵堆栈顶部的值
参数3:颜色值(黑色)
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vBlack);
switch (nStep) {
case 0:
// 设置点的大小
glPointSize(4.0f);
pointBatch.Draw();
glPointSize(1.0f);
break;
case 1:
// 设置线的宽度
glLineWidth(2.0f);
lineBatch.Draw();
glLineWidth(1.0f);
break;
case 2:
glLineWidth(2.0f);
lineStripBatch.Draw();
glLineWidth(1.0f);
break;
case 3:
glLineWidth(2.0f);
lineLoopBatch.Draw();
glLineWidth(1.0f);
break;
case 4:
DrawWireFramedBatch(&triangleBatch);
break;
case 5:
DrawWireFramedBatch(&triangleStripBatch);
break;
case 6:
DrawWireFramedBatch(&triangleFanBatch);
break;
default:
break;
}
// 还原到以前的模型视图矩阵 (单元矩阵)
modelViewMatrix.PopMatrix();
// 进行缓冲区交换
glutSwapBuffers();
}
6、绘制
// 此函数在呈现上下文中进行任何必要的初始化
// 这是第一次做任何与opengl相关的任务
void SetupRC()
{
// 灰色的背景
glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
shaderManager.InitializeStockShaders();
glEnable(GL_DEPTH_TEST);
// 设置变换管线以使用两个矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatix);
cameraFrame.MoveForward(-20.0f);
/*
常见函数:
void GLBatch::Begin(GLenum primitive,GLuint nVerts,GLuint nTextureUnits = 0);
参数1:表示使用的图元
参数2:顶点数
参数3:纹理坐标(可选)
//负责顶点坐标
void GLBatch::CopyVertexData3f(GLFloat *vNorms);
//结束,表示已经完成数据复制工作
void GLBatch::End(void);
*/
//定义一些点,类似佛罗里达州的形状
GLfloat vCoast[24][3] = {
{2.80, 1.20, 0.0 }, {2.0, 1.20, 0.0 },
{2.0, 1.08, 0.0 }, {2.0, 1.08, 0.0 },
{0.0, 0.80, 0.0 }, {-.32, 0.40, 0.0 },
{-.48, 0.2, 0.0 }, {-.40, 0.0, 0.0 },
{-.60, -.40, 0.0 }, {-.80, -.80, 0.0 },
{-.80, -1.4, 0.0 }, {-.40, -1.60, 0.0 },
{0.0, -1.20, 0.0 }, { .2, -.80, 0.0 },
{.48, -.40, 0.0 }, {.52, -.20, 0.0 },
{.48, .20, 0.0 }, {.80, .40, 0.0 },
{1.20, .80, 0.0 }, {1.60, .60, 0.0 },
{2.0, .60, 0.0 }, {2.2, .80, 0.0 },
{2.40, 1.0, 0.0 }, {2.80, 1.0, 0.0 }};
// 用点的形式表示佛罗里达州的形状
pointBatch.Begin(GL_POINTS, 24);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
//通过线的形式--表示佛罗里达州的形状
lineBatch.Begin(GL_LINES, 24);
lineBatch.CopyVertexData3f(vCoast);
lineBatch.End();
// 通过线段的形式--表示佛罗里达州的形状
lineStripBatch.Begin(GL_LINE_STRIP, 24);
lineStripBatch.CopyVertexData3f(vCoast);
lineStripBatch.End();
// 通过线换的形式--表达佛罗里达州的形状
lineLoopBatch.Begin(GL_LINE_LOOP, 24);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();
// 通过三角形创建金字塔
GLfloat vPyramid[12][3] = {
-2.0f, 0.0f, -2.0f,
2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, -2.0f,
2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
-2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f,
// 多画一个点 理解位置
// 2.0f, 0.0f, 2.0f,
// 2.0f, 4.0f,0.0f,
// 0.0f, 4.0f, 0.0f,
};
// GL_TRIANGLES 每三个顶点定义一个新的三角形
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
// 三角形扇形--六边形
GLfloat vPoints[100][3];
int nVerts = 0;
//半径
GLfloat r = 3.0f;
//原点(x,y,z) = (0,0,0);
vPoints[nVerts][0] = 0.0f;
vPoints[nVerts][1] = 0.0f;
vPoints[nVerts][2] = 0.0f;
//M3D_2PI 就是2Pi 的意思,就是一个圆的意思. 绘制圆形
for(GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f){
//数组下标自增 (每自增一次就表示一个点)
nVerts++;
/**
弧长=半径*角度,这里的角度是弧度制,不是平时的角度制
既然知道了cos值,那么角度=arccos,求一个反三角函数就行
**/
//X点坐标 cos(angle) * 半径
vPoints[nVerts][0] = float(cos(angle)) * r;
//y点坐标 sin(angle) * 半径
vPoints[nVerts][1] = float(sin(angle)) * r;
//z点的坐标
vPoints[nVerts][2] = -0.5f;
}
//结束扇形 前面一共绘制7个顶点 (包括圆心)
printf("三角形扇形顶点数:%d\n",nVerts);
//r添加闭合的终点
//课程添加演示:屏蔽177-180行代码并把绘制节点改为7.则三角形扇形是无法闭合的。
nVerts++;
vPoints[nVerts][0] = r;
vPoints[nVerts][1] = 0;
vPoints[nVerts][2] = 0.0f;
//加载!
triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
triangleFanBatch.CopyVertexData3f(vPoints);
triangleFanBatch.End();
// 三角形条带,一个小环或圆柱段
//顶点下标
int iCounter = 0;
//半径
GLfloat radius = 3.0f;
//从0度~360度,以0.3弧度为步长
for(GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle += 0.3f)
{
//或许圆形的顶点的X,Y
GLfloat x = radius * sin(angle);
GLfloat y = radius * cos(angle);
//绘制2个三角形 (他们的x,y顶点一样,只是z点不一样)
vPoints[iCounter][0] = x;
vPoints[iCounter][1] = y;
vPoints[iCounter][2] = -0.5;
iCounter++;
vPoints[iCounter][0] = x;
vPoints[iCounter][1] = y;
vPoints[iCounter][2] = 0.5;
iCounter++;
}
// 关闭循环
printf("三角形的顶点数:%d\n",iCounter);
// 结束循环,在循环位置生成2个三角形
vPoints[iCounter][0] = vPoints[0][0];
vPoints[iCounter][1] = vPoints[0][1];
vPoints[iCounter][2] = -0.5;
iCounter++;
vPoints[iCounter][0] = vPoints[1][0];
vPoints[iCounter][1] = vPoints[1][1];
vPoints[iCounter][2] = 0.5;
iCounter++;
// GL_TRIANGLE_STRIP 共用一个条带 (strip)上的顶点的一组三角形
triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
triangleStripBatch.CopyVertexData3f(vPoints);
triangleStripBatch.End();
}
二、逻辑解析
1、