OpenGL代码学习(7)--开始接触3D效果
注意:需要在配置好OpenGL的编程环境中运行下列代码,环境配置文章可参考:
OpenGL在Mac项目上的配置
下面的代码,直接放置在main.cpp文件中即可:
#include "GLTools.h" #include "GLMatrixStack.h" #include "GLFrame.h" #include "GLFrustum.h" #include "GLBatch.h" #include "GLGeometryTransform.h" #include <math.h> #include <glut/glut.h> GLShaderManager shaderManager; GLMatrixStack modelViewMatrix; GLMatrixStack projectionMatrix; GLFrame cameraFrame;// 摄像机的位置 GLFrame objectFrame;// 物体的位置 GLFrustum viewFrustum;// 投影矩阵 //三角形扇的批次 GLBatch triangleFanBatch; //变换管线 GLGeometryTransform transformPipeline; //颜色 GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f }; GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f }; //初始化三角形扇批次 void SetupTriangleFanBatch() { // 用代码生成三角形扇的顶点位置 // x,y,z 坐标的点 GLfloat vPoints[9][3];//?? int nVerts = 0; GLfloat r = 3.0f; vPoints[nVerts][0] = 0.0f; vPoints[nVerts][1] = 0.0f; vPoints[nVerts][2] = 0.0f; for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) { nVerts++; vPoints[nVerts][0] = float(cos(angle)) * r; vPoints[nVerts][1] = float(sin(angle)) * r; vPoints[nVerts][2] = -r; } //使三角形扇闭合 nVerts++; vPoints[nVerts][0] = r; vPoints[nVerts][1] = 0; vPoints[nVerts][2] = 0.0f; printf("顶点数据的个数:~%d\n", nVerts); /* 点 -> GL_POINTS:屏幕上单独的点 线段 -> GL_LINES:每对顶点定义一条线段 线条 -> GL_LINE_STRIP:从起始点依次经过所有后续点的线条 闭合线条 -> GL_LINE_LOOP:起始点和终点相连的线条 三角形 -> GL_TRIANGLES:每 3 个顶点定义一个三角形 三角形条带 -> GL_TRIANGLE_STRIP:共用一个条带上顶点的一组三角形 三角形扇 -> GL_TRIANGLE_FAN:以圆点为中心呈扇形的共用相邻顶点的一组三角形 */ //三角形扇批次初始化 triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8); triangleFanBatch.CopyVertexData3f(vPoints); triangleFanBatch.End(); glPointSize(5.f); } //为程序作一次性的设置 void SetupRC() { //设置窗口背景颜色 glClearColor(0.7f, 0.7f, 0.7f, 1.0f); //初始化着色器管理器 shaderManager.InitializeStockShaders(); //开启深度测试 glEnable(GL_DEPTH_TEST);// 如果去掉这行代码,依然能3D效果,点的颜色不再是绿色,而是黑色 //设置变换管线以使用两个矩阵堆栈 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);// 这行代码去掉的话,代码出错 /* 默认情况下,透视投影中的观察者位置处于原点(0,0,0),并沿着z轴负方向看向屏幕里面,一般通过moveForward方法来调整观察者位置,moveForward默认的朝向是-z轴,所有向屏幕里面移动传正数值,向屏幕外即+z轴,需要传负数值 */ //移动摄像机的位置 cameraFrame.MoveForward(-15.0f);//-25:看得更近 -10:看得更远 //准备画图要用的批次 SetupTriangleFanBatch(); } //画三角形 void DrawTriangleBatch(GLBatch* pBatch) { //画绿色面 shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen); pBatch->Draw(); //开启调节片段的深度值,使深度值产生偏移而不实际改变 3D 空间的物理位置 glPolygonOffset(-1.0f, -1.0f); 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); 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 RenderScene(void) { //清除一个或一组特定的缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //保存当前的模型视图矩阵 (单位矩阵) modelViewMatrix.PushMatrix(); //MultMatrix: 用一个矩阵乘以矩阵堆栈的顶部矩阵,相乘得到的结果随后将存储在堆栈的顶部 //处理模型相对于摄像机的位置 M3DMatrix44f mCamera; // GetCameraMatrix是GLFrame的一个函数,通常会用这个来进行设置,通过此函数来获取一个观察者变换后的矩阵 cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.MultMatrix(mCamera); //处理模型自身的旋转 M3DMatrix44f mObjectFrame; // GetCameraMatrix是GLFrame的一个函数,通常会用这个来进行设置,通过此函数来获取一个观察者变换后的矩阵 objectFrame.GetCameraMatrix(mObjectFrame); modelViewMatrix.MultMatrix(mObjectFrame); //画图 DrawTriangleBatch(&triangleFanBatch); // 还原以前的模型视图矩阵 (单位矩阵) modelViewMatrix.PopMatrix(); //将在后台缓冲区进行渲染,然后在结束时交换到前台 glutSwapBuffers(); } //特殊按键(功能键或者方向键)监听 void SpecialKeys(int key, int x, int y) { //上、下、左、右按键,3D 旋转 /* * RotateWorld(float fAngle, float x, float y, float z) * fAngle: 旋转弧度, x/y/z:以哪个坐标轴旋转 * m3dDegToRad:角度 -> 弧度 */ switch (key) { case GLUT_KEY_UP: objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f); break; case GLUT_KEY_DOWN: objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f); break; case GLUT_KEY_LEFT: objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f); break; case GLUT_KEY_RIGHT: objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f); break; default: break; } //触发渲染 glutPostRedisplay(); } //窗口大小改变时接受新的宽度和高度 void ChangeSize(int width, int height) { // 防止下面除法的除数为0导致的闪退 if(height == 0) height = 1; //设置视图窗口位置 glViewport(0, 0, width, height); // 创建投影矩阵,并将它载入到投影矩阵堆栈中 /* 显示3D图形,有远小近大的效果 参数1:垂直方向上的视场角度 参数2:窗口的纵横比 = w / h 参数3:近裁剪面距离 参数4:远裁剪面距离 */ viewFrustum.SetPerspective(35.0f, float(width) / float(height), 1.0f, 500.0f); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); // 在模型视图矩阵顶部载入单位矩阵 modelViewMatrix.LoadIdentity(); } //程序入口 int main(int argc, char* argv[]) { //设置当前工作目录,针对MAC OS X gltSetWorkingDirectory(argv[0]); //初始化GLUT库 glutInit(&argc, argv); /*初始化渲染模式,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指 双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL); //初始化窗口大小 glutInitWindowSize(800, 720); //创建窗口 glutCreateWindow("GL_POINTS"); //注册回调函数 glutReshapeFunc(ChangeSize); glutDisplayFunc(RenderScene); glutSpecialFunc(SpecialKeys); //确保驱动程序的初始化中没有出现任何问题 GLenum err = glewInit(); if(GLEW_OK != err) { fprintf(stderr, "glew error:%s\n", glewGetErrorString(err)); return 1; } //初始化设置 SetupRC(); //进入调用循环 glutMainLoop(); return 0; } #pragma mark - 代码逻辑整理 /* 1 UseStockShader函数肯定是关键,核心。所以先从该函数入手。 2 共有两处地方使用到了该函数 (1)shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen); (2)shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack); //变换管线 GLGeometryTransform transformPipeline; //设置变换管线以使用两个矩阵堆栈 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix); GLMatrixStack modelViewMatrix; modelViewMatrix.PushMatrix(); modelViewMatrix.MultMatrix(mCamera); (1)GLFrame cameraFrame; (2)//移动摄像机的位置 cameraFrame.MoveForward(-15.0f); (3)//处理模型相对于摄像机的位置 M3DMatrix44f mCamera; cameraFrame.GetCameraMatrix(mCamera); modelViewMatrix.MultMatrix(mCamera); modelViewMatrix.MultMatrix(mObjectFrame); (1)GLFrame objectFrame; (2)//处理模型自身的旋转 M3DMatrix44f mObjectFrame; objectFrame.GetCameraMatrix(mObjectFrame); modelViewMatrix.MultMatrix(mObjectFrame); (3)switch (key) { case GLUT_KEY_UP: objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f); break; case GLUT_KEY_DOWN: objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f); break; case GLUT_KEY_LEFT: objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f); break; case GLUT_KEY_RIGHT: objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f); break; default: break; } modelViewMatrix.PopMatrix(); modelViewMatrix.LoadIdentity(); GLMatrixStack projectionMatrix; projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); (1)GLFrustum viewFrustum; (2)// 创建投影矩阵,并将它载入到投影矩阵堆栈中 viewFrustum.SetPerspective(35.0f, float(width) / float(height), 1.0f, 500.0f); projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); */
运行上面的代码,得到的部分效果图示: