#include "GLTools.h" //OpenGL工具类:包含大部分GLTools中类似C语言的独立函数
#include "GLMatrixStack.h" //矩阵堆栈工具类:用于加载单元矩阵、矩阵相乘、压栈、出栈、缩放、平移、旋转等操作
#include "GLFrame.h" //矩阵工具类:表示位置,通过vOrigin、vForward、vUp定义
#include "GLFrustum.h" //矩阵工具类:用于快速设置正投影、透视投影矩阵,完成坐标从3D->2D的映射过程
#include "GLBatch.h" //三角形批次类:用于传输顶点、光照、纹理、颜色等数据到存储着色器
#include "GLGeometryTransform.h" //变换管道类:用于快速在代码中传输视图矩阵、投影矩阵、视图投影变换矩阵等
#include //数学库
GLShaderManagershaderManager; //存储着色器管理者
GLMatrixStackmodelViewMatrix; //模型视图矩阵
GLMatrixStackprojectionMatrix; //投影矩阵
GLFramecameraFrame; //角色帧:摄像机、观察者位置
GLFrame objectFrame; //角色帧;物体、世界坐标位置
GLFrustumviewFrustum; //视景体,用来构造投影矩阵
//三角形批次类
GLTriangleBatch sphereBatch; //球
GLTriangleBatch torusBatch; //环
GLTriangleBatch cylinderBatch; //圆柱
GLTriangleBatch coneBatch; //锥
GLTriangleBatch diskBatch; //磁盘
GLGeometryTransformtransformPipeline; //变换管道,存储模型视图、投影、模型视图投影矩阵
程序入口函数,OpenGL为面向过程编程,所以OpenGL及其封装的图形图像处理框架,处理过程都是以链式形式进行的。
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
//申请一个颜色缓存区、深度缓存区、双缓存区、模板缓存区
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//设置window大小
glutInitWindowSize(800, 600);
//设置window名称
glutCreateWindow("Sphere");
//注册函数:窗口大小变化
glutReshapeFunc(ChangeSize);
//注册函数:键盘”空格”键的回调函数
glutKeyboardFunc(KeyPressFunc);
//注册函数:键盘“上、下、左、右”键的回调函数
glutSpecialFunc(SpecialKeys);
//注册函数:鼠标右键菜单栏
glutCreateMenu(ProcessMenu);
glutAddMenuEntry("Menu1", 1);
glutAddMenuEntry("Menu2", 2);
glutAddMenuEntry("Menu3", 3);
//注册函数:渲染函数
glutDisplayFunc(RenderScene);
//判断glew库是否初始化成功,确保OpenGL框架的正常运行
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
//自定义函数:设置需要渲染图形的顶点数据、颜色数据等
SetupRC();
//runloop执行循环
glutMainLoop();
return 0;
}
当屏幕大小发生变化,或者第一次创建窗口时调用该函数。通过glutReshapFunc(函数名)注册。(需在main函数中通过注册调用)
void ChangeSize(int w, int h)
{
//1.防止h变为0
if(h == 0)
h = 1;
//2.设置视口窗口尺寸
glViewport(0, 0, w, h);
//3.设置透视模式,初始化其透视矩阵
//setPerspective函数的参数是一个从顶点方向看去的视场角度(用角度值表示)
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
//4.把透视矩阵viewFrustum加载到投影矩阵堆栈projectionMatrix中
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//5.modelViewMatrix矩阵堆栈加载单元矩阵。(该方法可不写,系统已默认加载)
//modelViewMatrix.LoadIdentity();
//6.初始化渲染管线:使用transformPipeline管理模型视图矩阵堆栈modelViewMatix和投影矩阵堆栈projectionMatrix
//也可在SetupRC()方法中进行初始化
//transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}
用于切换渲染图形。(需在main函数中通过注册调用)
void KeyPressFunc(unsigned char key, int x, int y)
{
if(key == 32)
{
nStep++;
if(nStep > 4)
nStep = 0;
}
switch(nStep)
{
case 0:
glutSetWindowTitle("Sphere");
break;
case 1:
glutSetWindowTitle("Torus");
break;
case 2:
glutSetWindowTitle("Cylinder");
break;
case 3:
glutSetWindowTitle("Cone");
break;
case 4:
glutSetWindowTitle("Disk");
break;
}
glutPostRedisplay();
}
用于处理键盘上、下、左、右键的响应操作。通过键位控制,移动objectFrame的视界坐标系RotateWorld,而非物体本身,来改变视口。(需在main函数中通过注册调用)
void SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
//移动世界坐标系,而不是去移动物体。
//将世界坐标系在X方向移动-5.0
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();
}
用于处理鼠标右击显示选项功能。(需在main函数中通过注册调用)
void ProcessMenu(int value)
{
switch (value) {
case 1:
//处理操作
break;
case 2:
//处理操作
break;
case 3:
//处理操作
break;
default:
break;
}
}
当屏幕大小发生变化、或者开发者主动渲染(调用glutPostRedisplay()函数)时,会调用此函数。通过glutDisplayFunc(函数名)来注册。实现从数据->渲染的过程。(需在main函数中通过注册调用)
void RenderScene(void)
{
//1.清除颜色缓冲区、深度缓冲区、清除窗口背景
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//2.模型视图矩阵栈堆,压栈
modelViewMatrix.PushMatrix();
//3.压栈 方法一:将objectFrame压入模型视图矩阵
//modelViewMatrix.PushMatrix(objectFrame);
//3.压栈 方法二:objectFrame + cameraFrame (要求先压入cameraFrame,后压入objectFrame)
//使用cameraFrame时,就需要在SetupRC方法中设置cameraFrame.MoveForward(-15.0f);否则设置objectFrame.MoveForward(-15.0f);
//a.压栈cameraFrame对应矩阵
M3DMatrix44f mCamera;
//GetCameraMatrix获取摄像机矩阵,获取camereaFrame矩阵堆栈的顶部矩阵到mCamera
cameraFrame.GetCameraMatrix(mCamera);
//MultMatrix矩阵相乘:将矩阵modelViewMatrix与mCamera矩阵相乘,然后将相乘的结果存储到modelViewMatrix矩阵堆栈顶部
modelViewMatrix.MultMatrix(mCamera);
//b.压栈objectFrame对应矩阵
M3DMatrix44f mObjectFrame;
//GetCameraMatrix:获取objectFrame矩阵堆栈顶部矩阵到mOjectFrame
objectFrame.GetMatrix(mObjectFrame);
//MultMatrix矩阵相乘:将矩阵modelViewMatrix与mOjbectFramek矩阵相乘,然后相乘的结果存储到modelViewMatrix矩阵堆栈顶部
modelViewMatrix.MultMatrix(mObjectFrame);
//5.判断你目前是绘制第几个图形
switch(nStep) {
case 0:
DrawWireFramedBatch(&sphereBatch);
break;
case 1:
DrawWireFramedBatch(&torusBatch);
break;
case 2:
DrawWireFramedBatch(&cylinderBatch);
break;
case 3:
DrawWireFramedBatch(&coneBatch);
break;
case 4:
DrawWireFramedBatch(&diskBatch);
break;
}
//6.还原到以前的模型视图矩阵(单位矩阵)
modelViewMatrix.PopMatrix();
//7.缓冲区交换
glutSwapBuffers();
}
用于封装图形填充及三角形线条的绘制。(RenderScene函数中调用)
void DrawWireFramedBatch(GLTriangleBatch* pBatch)
{
//----绘制图形----
//1.平面着色器,绘制三角形
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
//传过来的参数,对应不同的图形Batch
pBatch->Draw();
//---画出黑色轮廓---
//2.开启多边形偏移
glEnable(GL_POLYGON_OFFSET_LINE);
//多边形模型(背面、线) 将多边形背面设为线框模式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//开启多边形偏移(设置偏移数量)
glPolygonOffset(-1.0f, -1.0f);
//线条宽度
glLineWidth(2.5f);
//3.开启混合功能(颜色混合&抗锯齿功能)
glEnable(GL_BLEND);
//开启处理线段抗锯齿功能
glEnable(GL_LINE_SMOOTH);
//设置颜色混合因子
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//4.平面着色器绘制线条
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
pBatch->Draw();
//5.恢复多边形模式和深度测试
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
用于设置需要渲染图形的初始化顶点数据、颜色数据等。(main函数中直接调用,无需通过注册调用)
void SetupRC()
{
//1.
glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
shaderManager.InitializeStockShaders();
//2.开启深度测试
glEnable(GL_DEPTH_TEST);
//3.初始化渲染管线:使用transformPipeline管理模型视图矩阵堆栈modelViewMatix和投影矩阵堆栈projectionMatrix
//也可在ChangeSize()方法中进行初始化
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//4.将物体向屏幕外移动15.0(注:如果不设置MoveForward,图形将在屏幕z值为0的位置绘制,实际绘制效果会大于整个屏幕)
//objectFrame.MoveForward(-15.0f);
//5.将摄像机坐标Z往屏幕外移动15个单位距离 等效于 将物体坐标Z值往屏幕里边移动15个单位距离。
//MoveForward:表示离屏幕之间的距离,负数:往屏幕后面移动;正数:往屏幕前面移动。
//注:如果不设置MoveForward,图形将在屏幕z值为0的位置绘制,实际绘制效果会大于整个屏幕。
cameraFrame.MoveForward(-15.0f);
//6.利用三角形批次类构造图形对象
// 球
/*
gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks);
参数1:sphereBatch,三角形批次类对象
参数2:fRadius,球体半径
参数3:iSlices,从球体底部堆叠到顶部的三角形带的数量;其实球体是一圈一圈三角形带组成
参数4:iStacks,围绕球体一圈排列的三角形对数
建议:一个对称性较好的球体的片段数量是堆叠数量的2倍,就是iStacks = 2 * iSlices;
绘制球体都是围绕Z轴,这样+z就是球体的顶点,-z就是球体的底部。
*/
gltMakeSphere(sphereBatch, 3.0, 10, 20);
// 环面
/*
gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
参数1:torusBatch,三角形批次类对象
参数2:majorRadius,甜甜圈中心到外边缘的半径
参数3:minorRadius,甜甜圈中心到内边缘的半径
参数4:numMajor,沿着主半径的三角形数量
参数5:numMinor,沿着内部较小半径的三角形数量
*/
gltMakeTorus(torusBatch, 3.0f, 0.75f, 15, 15);
// 圆柱
/*
void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks);
参数1:cylinderBatch,三角形批次类对象
参数2:baseRadius,底部半径
参数3:topRadius,头部半径
参数4:fLength,圆形长度
参数5:numSlices,围绕Z轴的三角形对的数量
参数6:numStacks,圆柱底部堆叠到顶部圆环的三角形数量
*/
gltMakeCylinder(cylinderBatch, 2.0f, 2.0f, 3.0f, 15, 2);
//锥
/*
void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks);
参数1:cylinderBatch,三角形批次类对象
参数2:baseRadius,底部半径
参数3:topRadius,头部半径
参数4:fLength,圆形长度
参数5:numSlices,围绕Z轴的三角形对的数量
参数6:numStacks,圆柱底部堆叠到顶部圆环的三角形数量
*/
//圆柱体,从0开始向Z轴正方向延伸。
//圆锥体,是一端的半径为0,另一端半径可指定。
gltMakeCylinder(coneBatch, 2.0f, 0.0f, 3.0f, 13, 2);
// 磁盘
/*
void gltMakeDisk(GLTriangleBatch& diskBatch, GLfloat innerRadius, GLfloat outerRadius, GLint nSlices, GLint nStacks);
参数1:diskBatch,三角形批次类对象
参数2:innerRadius,内圆半径
参数3:outerRadius,外圆半径
参数4:nSlices,圆盘围绕Z轴的三角形对的数量
参数5:nStacks,圆盘外网到内围的三角形数量
*/
gltMakeDisk(diskBatch, 1.5f, 3.0f, 13, 3);
}