OpenGL04 - 使用固定着色器实现甜甜圈

636 阅读3分钟

一. 最终效果

照葫芦画瓢,简单实现了下甜甜圈的效果,最终效果如下图所示:

二. 代码实现

  1. 入口main函数如下所示:
int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);
    
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    glutInitWindowSize(800, 600); // 设置展示的窗口的大小
    glutCreateWindow("Geometry Test Program"); // 设窗口名称
    glutReshapeFunc(ChangeSize); // ChanegSize为自定义函数,当窗口大小发生变化的时候,就会调用
    glutSpecialFunc(SpecialKeys); // Specialkeys为自定义函数,键盘点击时候调用
    glutDisplayFunc(RenderScene); // RenderScene为自定义函数,当触发渲染的时候,就会调用这个函数。
    
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
        return 1;
    }
    
    SetupRC();  // 设置你需要渲染的图形相关顶点数据/颜色数据等数据的准备工作
    
    glutMainLoop();
    return 0;
}
  1. changeSize函数:
 //窗口改变
void ChangeSize(int w, int h)
{
    glViewport(0, 0, w, h);
    viewFrustum.SetPerspective(20.0f, float(w)/float(h), 1.0f, 100.0f); 
    
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix()); // 加载投影矩阵
    modelViewMatix.LoadIdentity(); // 加载模型视图矩阵
    
    transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix); // 把两个矩阵放入传送管道中
}

viewFrustum是GLFrustum类型,用于定义投影类型,因为我们需要显示的为3D图像,所以这里需要用到透视投影(区别于正投影,正投影主要用在显示2D图像上)。

GLFrustum类通过setPerspective 方法为我们构建⼀一个平截头体, 如下图所示:

函数说明如下:

CLFrustum::SetPerspective(float fFov , float fAspect ,float fNear ,float fFar);
参数:
fFov:垂直⽅方向上的视场⻆角度 
fAspect:窗⼝口的宽度与⾼高度的纵横⽐比 
fNear:近裁剪⾯面距离 
fFar:远裁剪⾯面距离
纵横⽐比 = 宽(w)/⾼高(h)

3. SetupRC函数

   void SetupRC() {
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);   // 设置背景颜色
    glEnable(GL_CULL_FACE); // 开启正背面剔除,下一篇文章会讲到正背面剔除的原理
    shaderManager.InitializeStockShaders(); // 初始化固定着色器管理类
    
    cameraFrame.MoveForward(-10.0f); // 可以理解为视角离开屏幕的距离加10,这里也可以设置viewFrame达到相同的效果。
    
    gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26); // 生成甜甜圈顶点数据放入到torusBatch中
    
    glPointSize(4.0f); // 设置点的大小
}
  1. RenderScene函数

这个函数是最为关键的部分,当屏幕发生变化,或者开发者主动渲染的时候,比如手动调用glutPostRedisplay(),会调用此函数进行渲染操作,把数据渲染生成图像。实现如下: ```C++ void RenderScene(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除颜色和深度缓存

modelViewMatix.PushMatrix(); // 压入一个单元矩阵
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera); // 获取视角矩阵,表示视角的旋转移动等变化
modelViewMatix.MultMatrix(mCamera); // 和栈顶的单元矩阵相乘

M3DMatrix44f mObjectFrame;
viewFrame.GetMatrix(mObjectFrame); // 获取物体矩阵,表示物体的旋转移动等变化
modelViewMatix.MultMatrix(mObjectFrame); // 和栈顶的矩阵相乘

GLfloat vRed[] = { 0.0f, 1.0f, 0.0f, 1.0f };

// 使用默认光源着色器
shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vRed);
// 开始绘画
torusBatch.Draw();

modelViewMatix.PopMatrix();

glutSwapBuffers();
}
```

默认光源着色器函数说明:

	GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);
	参数1: 存储着⾊色器器种类-默认光源着⾊色器器 参数2: 模型4*4矩阵
	参数3: 投影4*4矩阵
	参数4: 颜⾊色值
	使⽤用场景: 在绘制图形时, 可以应⽤用变换(模型/投影变化) 这种着⾊色器器会使绘制的图形产⽣生 阴影和光照的效果.

三. 总结

实现甜甜圈的效果其实是非常简单的,主要是要了解渲染的整个流程,以及顶点数据的获取。

上文中出现了3种矩阵:视角矩阵、模型矩阵、投影矩阵。用一个简单的图就可以说明三者之间的关系: 我们就是上图中的小人,在我们的眼中呈现这个物体时,我们从左看,或者从右看,物体展现的样子是不一样的,所以需要一个矩阵去描述我们自己的位置,即视角矩阵。物体如果旋转了,在我们眼中展现出来的图像也是不一样的,所以也需要一个矩阵去描述物体的位置,即模型矩阵。投影矩阵则决定了,图像展现在我们眼中是2D还是3D,大小等。

Demo地址