四、OpenGL案例分析
2020-07-10 本文已影响0人
随意昵称你能懂得
本文将以金字塔为例,对使用OpenGL绘制图形的代码做一些简单分析。
金字塔.png
金字塔实现
必要属性
//着色管理器
GLShaderManager shaderManager;
//模型矩阵
GLMatrixStack modelViewMatrix;
//投影矩阵
GLMatrixStack projectionMatrix;
//相机位置
GLFrame cameraFrame;
//模型位置
GLFrame objectFrame;
//投影矩阵
GLFrustum viewFrustum;
//金色塔容器
GLBatch triangleBatch;
//几何变换的管道
GLGeometryTransform transformPipeline;
//红色表面
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
//黑色比酷昂
GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
main函数
需要初始化一些功能,再绑定一些按键和方法,然后初始化显示数据,最后开启循环。
int main(int argc, char* argv[])
{
//设置当前目录
gltSetWorkingDirectory(argv[0]);
//初始化glut
glutInit(&argc, argv);
//申请一个颜色缓存区、深度缓存区、双缓存区、模板缓存区
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//设置视图窗口的尺寸
glutInitWindowSize(800, 600);
//创建视图窗口的名称
glutCreateWindow("GL_TRIANGLES");
//监听视图窗口改变大小
glutReshapeFunc(ChangeSize);
//监听按键,例如空格
glutKeyboardFunc(KeyPressFunc);
//监听特殊键位,例如上下左右
glutSpecialFunc(SpecialKeys);
//监听屏幕刷新,处理屏幕刷新
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;
}
自定义绘制方法
设置改场景下的部分设置,并且初始化金字塔数据
void SetupRC()
{
//设置背景色
glClearColor(1.0f, 1.0f, 1.0f, 1.0f );
//初始化着色管理器
shaderManager.InitializeStockShaders();
//打开深度测试
glEnable(GL_DEPTH_TEST);
//设置变换管线以使用两个矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//设置相机位置
cameraFrame.MoveForward(-15.0f);
//通过三角形创建金字塔
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
};
//GL_TRIANGLES 每3个顶点定义一个新的三角形
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
}
显示函数
进行矩阵变换,中间留出正在渲染金字塔的方法
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次重载。用来使用GLShaderManager 的使用。或者是获取顶部矩阵的顶点副本数据
objectFrame.GetMatrix(mObjectFrame);
//矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部
modelViewMatrix.MultMatrix(mObjectFrame);
//渲染金字塔方法
DrawWireFramedBatch(&triangleBatch);
//还原到以前的模型视图矩阵(单位矩阵)
modelViewMatrix.PopMatrix();
// 进行缓冲区交换
glutSwapBuffers();
}
渲染金字塔
先画表面,然后画边框,设置一些优化属性,需要还原回来。
void DrawWireFramedBatch(GLBatch* pBatch)
{
//金字塔表面
//提供着色器的Uniform值-平面着色器
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
pBatch->Draw();
//黑色边框
glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
glEnable(GL_POLYGON_OFFSET_LINE);
//反锯齿
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//设置为线框模式
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//设置线条宽度
glLineWidth(2.5f);
//提供着色器的Uniform值-平面着色器
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
pBatch->Draw();
// 复原原本的设置
//这个必须设置回来,不然可能会导致移动后表面颜色消失
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
上下左右按键
在屏幕中做旋转
void SpecialKeys(int key, int x, int y) {
if(key == GLUT_KEY_UP)
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();
}
窗口大小改变
该方法必须设置绑定,不然会导致显示不出东西
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
//创建投影矩阵,并将它载入投影矩阵堆栈中
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//调用顶部载入单元矩阵
modelViewMatrix.LoadIdentity();
}