该文章主要针对OpenGL渲染正方形&平移文中的绘制连接方式
的运用.
绘制流程
整体的绘制流程,仍旧主要使用了main函数,ChangeSize函数,SetupRC函数,RenderScene函数;
main函数
自定义函数的注册以及glutMainLoop,进入GLUT事件处理循环
SetupRC函数
上下文中进行必要的初始化
- 背景颜色
- 固定着色器初始化
shaderManager.InitializeStockShaders();
- 顶点数据的创建和传输
// 例如 `GL_POINTS` 点的绘制方式
GLfloat vCoast[9] = {
3,3,0,
0,3,0,
3,0,0
};
// 提交批次类pointBatch
// 1.点
pointBatch.Begin(GL_POINTS, 3);
//copy方法会将顶点数据传输到着色器中
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
- 设置变换管道
// 初始化几何变换的管道
GLGeometryTransform transformPipeline;
//模型视图矩阵栈与投影矩阵栈放到变换管道中,可以帮助快速进行矩阵相乘,在RenderScene函数中可以直接通过变换管道的Get方法得到相应的矩阵结果
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
- 设置观察者的位置
// 观察者位置 负数=拉远观察者的位置
cameraFrame.MoveForward(-15.0f);
ChangeSize函数
- 在setupRC对图形绘制做初始化后,调用设置视口,当改变屏幕窗口时也会调用,重新设置.
- 创建投影矩阵,将它载入投影矩阵栈中
//投影矩阵
GLFrustum viewFrustum;
//投影矩阵栈
GLMatrixStack projectionMatrix;
/*
SetPerspective:设置透视投影
void SetPerspective(float fFov, float fAspect, float fNear, float fFar)
* fFov:眼睛打开的角度
* fAspect:纵横比 w/h
* fNear:近裁剪面距离
* fFar:远距离
SetOrthographic:是设置正投影
*/
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 500.0f);
// viewFrustum.GetProjectionMatrix() 获取投影矩阵
// LoadMatrix 加载存储到投影矩阵栈
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
因为我们同样需要模型矩阵的数据,将投影矩阵和模型矩阵相乘后,才是最终绘制的矩阵数据,所以此处先将投影矩阵存入投影矩阵栈中.
RenderScene函数
在图元绘制案例中,RenderScene中需要将观察者矩阵和物体矩阵相乘后,存储在模型视图矩阵栈,根据变换管道的get方法获取相应的矩阵,进行渲染.
- 首先会在模型视图矩阵栈中压入一个单元矩阵,作用类似1,与任何数据相乘,数据都不变
- 将观察者矩阵放到模型视图矩阵栈中
// 观察者矩阵初始化变量
GLFrame cameraFrame;
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
// 矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果 存储在栈的顶部
modelViewMatrix.MultMatrix(mCamera);
- 将物体矩阵放到模型视图矩阵栈中
// 物体矩阵初始化变量
GLFrame objectFrame;
M3DMatrix44f mObjectFrame;
// 只要使用GetMatrix 函数就可以获取矩阵栈顶部的值。 这个函数可以进行2次重载,用来使用GLShaderManager的使用,或者是获取顶部矩阵的顶点副本数据
objectFrame.GetMatrix(mObjectFrame);
// 矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果 存储在栈的顶部
modelViewMatrix.MultMatrix(mObjectFrame);
- 渲染从变换管道中get到的矩阵
/**
GLShaderManager 中的Uniform 值 -- 平面着色器
参数1:平面着色器
参数2:运行为几何图形变换 指定一个 4*4 变换矩阵 -- transformPipeline.GetModelViewProjectionMatrix() 获取的 GetMatrix函数就可以获得矩阵堆栈顶部的值 它是一个变换矩阵
参数3:颜色值
*/
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vBlack);
变换管道transformPipeline可通过get到的矩阵有四种:
方式 | 矩阵 |
---|---|
GetProjectionMatrix() | 投影矩阵 |
GetNormalMatrix() | 法线矩阵 |
GetModelViewMatrix() | 模型视图矩阵 |
GetModelViewProjectionMatrix() | 模型视图投影矩阵 |
- 渲染后记得要将模型视图矩阵中相乘的结果进行出栈,恢复栈顶为默认的单元矩阵
辅助函数有:
- SpecialKeys:对特殊键位的回调处理,上下左右
- KeyPressFunc:对空格键的回调处理
- DrawWireFrameBatch:对立体图形的填充,边框绘制
图元绘制方式
GL_POINTS 点
// 点初始化
GLBatch pointBatch;
//setupRC中构建顶点数据以及传输
GLfloat vCoast[9] = {
3,3,0,
0,3,0,
3,0,0
};
// 1.点
pointBatch.Begin(GL_POINTS, 3);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
//RenderScene中绘制
//设置点的大小
glPointSize(4.0f);
pointBatch.Draw();
glPointSize(1.0f); // 恢复
GL_LINES 线段
// 线初始化
GLBatch lineBatch;
//setupRC中构建顶点数据同样使用上边vCoast的顶点数据
// 2.线
lineBatch.Begin(GL_LINES, 3);
lineBatch.CopyVertexData3f(vCoast);
lineBatch.End();
//RenderScene中
glLineWidth(2.0f);
lineBatch.Draw();
glLineWidth(1.0f);
// GL_LINES是对每一对顶点定义线段,只有三个点,所有绘制了一条线
GL_LINE_STRIP线环
// 初始化线段
GLBatch lineStripBatch;
//SetupRC中
// 3.线段
lineStripBatch.Begin(GL_LINE_STRIP, 3);
lineStripBatch.CopyVertexData3f(vCoast);
lineStripBatch.End();
//RenderScene
// 线段
glLineWidth(2.0f);
lineStripBatch.Draw();
glLineWidth(1.0f);
//GL_LINE_STRIP 从第一个顶点以此经过每一个后续顶点绘制的线条
GL_LINE_LOOP
// 初始化
GLBatch lineLoopBatch;
// SetupRC中
// 4.线环
lineLoopBatch.Begin(GL_LINE_LOOP, 3);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();
// RenderScene中
glLineWidth(2.0f);
lineLoopBatch.Draw();
glLineWidth(1.0f);
// GL_LINE_LOOP 会将第一个顶点和最后一个顶点进行连接构成环
triangleBatch
// 初始化
GLBatch triangleBatch;
// SetupRC中
// 5.三角形
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
};
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
// RenderScene中会调用DrawWireFramedBatch方法,对立体图形中的面和边框进行绘制
特殊键位调整后
GL_TRIANGLE_FAN 三角形扇
//初始化
GLBatch triangleFanBatch;
// 6.三角形扇面-六边形
// 初始化顶点数组
GLfloat vPoints[100][3];
int nVerts = 0;
// 半径
GLfloat r = 3.0f;
// 原点
vPoints[nVerts][0] = 0.0f;
vPoints[nVerts][1] = 0.0f;
vPoints[nVerts][2] = 0.0f;
// M3D_2PI 就是2Pi的意思 就是一个圆, 绘制圆
// angle角度。 圆/6 = 360/60
for (GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
// 数组下标自增 ,每次自增代表一个顶点
nVerts ++;
// x点坐标 cos(angle) * 半径
vPoints[nVerts][0] = float(cos(angle)) * r;
// y点坐标 sin(angle) * 半径
vPoints[nVerts][1] = float(sin(angle)) * r;
// z点坐标
vPoints[nVerts][2] = -0.5f;
}
// 结束扇形 前面循环中一共绘制了7个顶点(包括圆心)
// 添加闭合的终点
// 课程添加演示:
nVerts ++;
vPoints[nVerts][0] = r;
vPoints[nVerts][1] = 0.0f;
vPoints[nVerts][2] = 0.0f;
// 加载
triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
triangleFanBatch.CopyVertexData3f(vPoints);
triangleFanBatch.End();
同样在RenderScene中调用DrawWireFramedBatch
GL_TRIANGLE_STRIP
//初始化
GLBatch triangleStripBatch;
//SetupRC中
//7.三角形条带 一个小环或圆柱段
// 初始化顶点下标
int iCounter = 0;
// 半径
GLfloat radius = 3.0f;
// 从0度到360度,以0.3弧度为步长
for (GLfloat angle = 0.0f; angle <= (2.0f*M3D_PI); angle+=0.3f) {
//获取圆形的顶点的X,Y
GLfloat x = radius * sin(angle);
GLfloat y = radius * cos(angle);
//绘制2个三角形(他们的x,y顶点一样,只是z点不一样)
vPoints[iCounter][0] = x;
vPoints[iCounter][1] = y;
vPoints[iCounter][2] = -0.5;
iCounter++;
vPoints[iCounter][0] = x;
vPoints[iCounter][1] = y;
vPoints[iCounter][2] = 0.5;
iCounter++;
}
// 关闭循环
printf("三角形带的顶点数:%d\n",iCounter);
//结束循环,在循环位置生成2个三角形
vPoints[iCounter][0] = vPoints[0][0];
vPoints[iCounter][1] = vPoints[0][1];
vPoints[iCounter][2] = -0.5;
iCounter++;
vPoints[iCounter][0] = vPoints[1][0];
vPoints[iCounter][1] = vPoints[1][1];
vPoints[iCounter][2] = 0.5;
iCounter++;
triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
triangleStripBatch.CopyVertexData3f(vPoints);
triangleStripBatch.End();
RenderScene中调用DrawWireFramedBatch