开场白
这篇文章主要聊聊使用MVP模式的图元绘制,先来看看效果
![](https://img.haomeiwen.com/i20196568/91c79b60c60ee530.gif)
1.空格切换绘制模式:
main函数中增加键盘的回调函数,用来响应‘空格’按键:
int main(int argc, char* argv[]){
...
glutKeyboardFunc(KeyPressFunc);
...
}
然后我们来看看KeyPressFunc实现
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;
}
glutPostRedisplay();
}
- key == 32是判断是否为空格键,32是ascll码
- 当点击空格键后,修改全局变量nStep
- switch判断当前的nStep,显示不同的窗口title
- 调用glut的重绘函数
2.SetupRC实现
void SetupRC()
{
//设置背景色
glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
//初始化着色管理器
shaderManager.InitializeStockShaders();
//开启深度测试
glEnable(GL_DEPTH_TEST);
//设置变化管线的矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//设置camera位置
cameraFrame.MoveForward(-15.0f);
//后续代码是设置一些顶点信息,不是本文章的重点。
...
}
本段代码主要设置了管线transformPipeline,并且设置了矩阵堆栈,目的是使用MVP模式进行绘图。MVP模式就是model-view-projection的三个矩阵变换,来渲染图片。
设置了camera的位置,cameraFrame.MoveForward为-15的位置,这个可以理解为在屏幕前,距离屏幕15的位置。
3.ChangeSize实现
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();
}
- 设置视口,
-
视图椎体viewFrustum,设置观察者的位置。视图椎体:以camera(观察者)在的位置为顶点,以Far clip plane(远端平截面)为底的几何椎体。请参考下图:
视图椎体示意[图片上传中...(image.png-c04e57-1594315058378-0)]
-
设置视图矩阵projectionMatrix和模型视图矩阵modelViewMatrix,视图矩阵初始值是单元矩阵,该单元矩阵乘以从视图椎体中取出视图矩阵,将值赋值给视图矩阵projectionMatrix。模型视图矩阵设置为单元矩阵(默认值就是单元矩阵,所以此行代码可以不写。),因为当前还没有模型视图,所以设置为初始值。
坐标系转换
4.RenderScene
本文的重点部分
void RenderScene(void) {
//1.清除一个或一组特定的缓冲区
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
//2.记录当前模型视图矩阵,当前的值是单元矩阵,所以入栈的是单元矩阵。目的是本次改变后,调用出栈方法,将模型视图矩阵重新复制成单元矩阵,下面有对应PopMatrix函数调用
modelViewMatrix.PushMatrix();
//3.将camera frame转换成矩阵
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
//modelViewMatrix矩阵乘以camera矩阵栈,相乘的结果存放到modelViewMatrix
modelViewMatrix.MultMatrix(mCamera);
//4.将object frame转换成矩阵,objectFrame在键盘上下左右时设置的值
M3DMatrix44f mObjectFrame;
objectFrame.GetMatrix(mObjectFrame);
//modelViewMatrix矩阵乘以object矩阵栈,相乘的结果存放到modelViewMatrix
modelViewMatrix.MultMatrix(mObjectFrame);
//5.使用平面着色器,参数2是从变换管线transformPipeline中获取MVP(ModelViewProjectionMatrix)矩阵
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
//6.
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;
}
//7.出栈,将modelViewMatrix还原成单元矩阵
modelViewMatrix.PopMatrix();
//8.将在后台缓冲区进行渲染,然后在结束时交换到前台
glutSwapBuffers();
}
- 清除缓冲区
- modelViewMatrix.PushMatrix();入栈处理。此时modelViewMatrix还是单元矩阵(矩阵的初始值,任何矩阵✖️单元矩阵,还是等于本身),目的是本次修改后还可以恢复到原来的初始值。
- 获取camera的矩阵,并将camera矩阵与modelView矩阵,也就是将camera的位置信息混入modelView矩阵中。
- 将objectFrame也转换成矩阵,并和第三步一样,混入到modelView矩阵中。objectFrame的变化是在‘空格键’响应函数中进行修改的(KeyPressFunc)。
- 调用平面着色器,参数2是从变换管线transformPipeline中获取MVP(ModelViewProjectionMatrix)矩阵
- 根据当前nStep,获取不同的容器批次类进行绘制。
- 出栈。对应第2步
- 交换缓冲区。
5. DrawWireFramedBatch
在RenderScene的实现中的switch case 4-6中调用了DrawWireFramedBatch函数,该函数作用是为了渲染复杂3d几何图形时需要进行的一些处理,我们先来看看实现
void DrawWireFramedBatch(GLBatch* pBatch)
{
//1.上色
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlue);
pBatch->Draw();
//2.设置线相关内容
// 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
glPolygonOffset(-1.0f, -1.0f);
//根据glPolygonOffset的设置,启用线的深度偏移
glEnable(GL_POLYGON_OFFSET_LINE);
//启用锯齿
glEnable(GL_LINE_SMOOTH);
//启用颜色混合
glEnable(GL_BLEND);
//混合方式,使用alpha,1-alpha方式混合
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();
//3.复原状态
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glLineWidth(1.0f);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
}
- 填充颜色,使用平面着色器进行图形内部颜色填充
- 设置线相关内容
- glEnable()用于启用各种功能
- GL_POLYGON_OFFSET_LINE:偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
- GL_LINE_SMOOTH:启用锯齿
- GL_BLEND:启用颜色混合
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA):混合方式,使用alpha,1-alpha方式混合
- glPolygonMode多边形模式,正反面都用画线模式
- 画线,用定义好的黑色
- 复原相关设置
网友评论