-
顶点变换管线
image.png -
GLMatrixStack 矩阵堆栈
//类型
GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
//在堆栈顶部载⼊⼀个单元矩阵
void GLMatrixStack::LoadIdentity(void);
//在堆栈顶部载⼊任何矩阵
//参数:4*4矩阵
void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
//矩阵乘以矩阵堆栈顶部矩阵,相乘结果存储到堆栈的顶部
void GLMatrixStack::MultMatrix(const M3DMatrix44f);
//获取矩阵堆栈顶部的值 GetMatrix 函数
//为了适应GLShaderMananger的使⽤,或者获取顶部矩阵的副本
const M3DMatrix44f & GLMatrixStack::GetMatrix(void);
void GLMatrixStack::GetMatrix(M3DMatrix44f mMatrix);
//将当前矩阵压⼊堆栈
void GLMatrixStack::PushMatrix(void);
//将M3DMatrix44f 矩阵对象压⼊当前矩阵堆栈
void PushMatrix(const M3DMatrix44f mMatrix);
//将GLFame 对象压⼊矩阵对象
void PushMatrix(GLFame &frame);
//出栈(出栈指的是移除顶部的矩阵对象)
void GLMatrixStack::PopMatrix(void);
// 仿射变换,旋转平移缩放
//Rotate 函数angle参数是传递的度数
void MatrixStack::Rotate(GLfloat angle,GLfloat x,GLfloat y,GLfloat z);
void MatrixStack::Translate(GLfloat x,GLfloat y,GLfloat z);
void MatrixStack::Scale(GLfloat x,GLfloat y,GLfloat z);
GLFrame -参考帧
- 其中存储了1个世界坐标点和2个世界坐标下的方向向量,也就是9个glFloat值,分别用来表示:当前位置点,向前方向向量,向上方向向量
- GLFrame可以表示世界坐标系中任意物体的位置与方向。无论是相机还是模型,都可以使用GLFrame来表示。对任意一个使用GLFrame来表示的物体而言,涉及到的坐标系有两个:永远不变的世界坐标系,针对于自身的物体坐标系(即绘图坐标系)
- 一般来说,针对于物体自身的物体坐标系有如下特点:X轴永远平行于视口的水平方向,+X的方向根据右手定则由+Y与+Z得出;Y轴永远平行于视口的竖直方向,竖直向上为+Y;Z轴永远平行于视口的垂直纸面向里方向,正前方为+Z。也就是说,在世界坐标系中,物体坐标系的Y轴看上去就是GLFrame的向上方向向量,Z轴看上去就是GLFrame的向前方向向量,而X轴由Y轴方向向量与Z轴方向向量根据右手定则可得出
class GLFrame {
protected:
M3DVector3f vOrigin; // Where am I?
M3DVector3f vForward; // Where am I going?
M3DVector3f vUp; // Which way is up?
public:
//默认构造函数(世界坐标系,位置在(0,0,0)点,up为(0,1,0)朝+Y,forward为(0,0,-1)朝向-Z)
GLFrame(void)
//设置/获取世界坐标系下模型/相机的位置
inline void SetOrigin(const M3DVector3f vPoint)
inline void SetOrigin(float x, float y, float z)
inline void GetOrigin(M3DVector3f vPoint)
//获取世界坐标系下模型/相机位置的X/Y/Z分量
inline float GetOriginX(void)
inline float GetOriginY(void)
inline float GetOriginZ(void)
//设置/获取世界坐标系下模型/相机向前的方向向量
inline void SetForwardVector(const M3DVector3f vDirection)
inline void SetForwardVector(float x, float y, float z)
inline void GetForwardVector(M3DVector3f vVector)
//设置/获取世界坐标系下模型/相机向上的方向向量
inline void SetUpVector(const M3DVector3f vDirection)
inline void SetUpVector(float x, float y, float z)
inline void GetUpVector(M3DVector3f vVector)
//获取世界坐标系下模型/相机X/Y/Z轴方向向量
inline void GetZAxis(M3DVector3f vVector) {GetForwardVector(vVector); }
inline void GetYAxis(M3DVector3f vVector) { GetUpVector(vVector); }
inline void GetXAxis(M3DVector3f vVector) {m3dCrossProduct(vVector, vUp, vForward); }
// 以世界坐标系下(x,y,z)偏移量移动模型/相机
inline void TranslateWorld(float x, float y, float z)
// 以物体坐标系下(x,y,z)偏移量移动模型/相机
inline void TranslateLocal(float x, float y, float z)
// 沿物体坐标系下Z轴以指定偏移fDelta量移动模型/相机
inline void MoveForward(float fDelta)
// 沿物体坐标系下Y轴以指定偏移fDelta移动物体/相机
inline void MoveUp(float fDelta)
// 沿物体坐标系下X轴以指定偏移fDelta移动物体/相机
inline void MoveRight(float fDelta)
// 获取一个用于描述模型属性的4×4的矩阵
void GetMatrix(M3DMatrix44f matrix, bool bRotationOnly = false)
// 获取一个用于描述相机属性的4×4的矩阵
inline void GetCameraOrientation(M3DMatrix44f m)
// 应用所有的相机变换。该函数仅用于相机
inline void ApplyCameraTransform(bool bRotOnly = false)
// 应用所有的物体变换。该函数仅用于除相机外的物体
void ApplyActorTransform(bool bRotationOnly = false)
// 令物体/相机以自身位置为中心,绕X/Y/Z轴旋转。其角度以PI为单位
void RotateLocalX(float fAngle)
void RotateLocalY(float fAngle)
void RotateLocalZ(float fAngle)
// Reset axes to make sure they are orthonormal. This should be called on occasion
// if the matrix is long-lived and frequently transformed.
// 规范化
void Normalize(void)
// 模型/相机绕世界坐标系下的指定轴(x,y,z)旋转fAngle度
void RotateWorld(float fAngle, float x, float y, float z)
// 模型/相机绕当前物体坐标系下的指定轴(x,y,z)旋转fAngle度
void RotateLocal(float fAngle, float x, float y, float z)
// 将点/向量vLocal从当前物体坐标系转换为世界坐标系
void LocalToWorld(const M3DVector3f vLocal, M3DVector3f vWorld)
// 将点/向量vLocal从世界坐标系转换为当前物体坐标系
void WorldToLocal(const M3DVector3f vWorld, M3DVector3f vLocal)
// 通过当前frame矩阵将vPointSrc点变换为vPointDst点
void TransformPoint(M3DVector3f vPointSrc, M3DVector3f vPointDst)
//通过当前frame矩阵将vVectorSrc向量旋转为vVectorDst向量
void RotateVector(M3DVector3f vVectorSrc, M3DVector3f vVectorDst)
}
- GLFrustum - 视景体
// 设置正投影
void SetOrthographic(GLfloat xMin, GLfloat xMax, GLfloat yMin, GLfloat yMax, GLfloat zMin, GLfloat zMax)
// 设置透视投影
void SetPerspective(float fFov, float fAspect, float fNear, float fFar)
// 获取透视矩阵
const M3DMatrix44f& GetProjectionMatrix(void) { return projMatrix; }
- GLBatch - 批次容器
GLTools库中,包含了一个容器类GLBatch,可以作为7种图元批次容器使用,它知道使用GLShaderManager支持的任意存储着色器时,如何对图元进行渲染。
// 参数1:图元
// 参数2:顶点个数
// 参数3:一组或两组纹理图标
void GLBatch::Begain(GLeunm primitive,GLuint nVerts,GLuint nTexttureUnints = 0);
// 复制顶点
void CopyVertexData3f(M3DVector3f *vVerts);
// 复制表面法线
void GLBatch::CopyNormalDataf(GLfloat *vNorms);
// 复制颜色
void GLBatch::CopyColorData4f(GLfloat *vColors);
// 复制纹理坐标
void GLBatch::CopyTexCoordData2f(GLFloat *vTextCoords,GLuint u
iTextureLayer);
// 重置
void Reset(void);
// 设置顶点
void Vertex3f(GLfloat x, GLfloat y, GLfloat z);
void Vertex3fv(M3DVector3f vVertex);
// 设置法线
void Normal3f(GLfloat x, GLfloat y, GLfloat z);
void Normal3fv(M3DVector3f vNormal);
// 设置颜色
void Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
void Color4fv(M3DVector4f vColor);
// 设置纹理
void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
void MultiTexCoord2fv(GLuint texture, M3DVector2f vTexCoord);
// 画
virtual void Draw(void);
// 绘制结束
void GLBatch::End(void);
- GLTriangleBatch - 三角形批次类
// Use these three functions to add triangles
void BeginMesh(GLuint nMaxVerts);
void AddTriangle(M3DVector3f verts[3], M3DVector3f vNorms[3], M3DVector2f vTexCoords[3]);
void End(void);
virtual void Draw(void);
- GLGeometryTransform - 几何变换管道
// 设置模型视图矩阵堆栈
inline void SetModelViewMatrixStack(GLMatrixStack& mModelView) { _mModelView = &mModelView; }
// 设置投影视图矩阵堆栈
inline void SetProjectionMatrixStack(GLMatrixStack& mProjection) { _mProjection = &mProjection; }
// 设置模型视图投影矩阵堆栈
inline void SetMatrixStacks(GLMatrixStack& mModelView, GLMatrixStack& mProjection) {
_mModelView = &mModelView;
_mProjection = &mProjection;
}
// 获取模型视图投影矩阵
const M3DMatrix44f& GetModelViewProjectionMatrix(void)
// 获取模型视图矩阵
inline const M3DMatrix44f& GetModelViewMatrix(void) { return _mModelView->GetMatrix(); }
// 获取投影视图矩阵
inline const M3DMatrix44f& GetProjectionMatrix(void) { return _mProjection->GetMatrix(); }
绘制流程
- main函数
int main(int argc, char* argv[])
{
// 设置工作路径
gltSetWorkingDirectory(argv[0]);
// 这个函数用来初始化 GLUT 库
glutInit(&argc, argv);
//申请一个双缓存区,颜色缓存区、深度缓存区、模板缓存区
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//设置window 的尺寸
glutInitWindowSize(800, 600);
//创建window的名称
glutCreateWindow("GL_POINTS");
//注册回调函数(改变尺寸)
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;
}
// 此函数在呈现上下文中进行任何必要的初始化。.
// 这是第一次做任何与opengl相关的任务。
SetupRC();
//runloop运行循环
glutMainLoop();
return 0;
}
- 上下文初始化等工作
void SetupRC()
{
// Black background
glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
//初始化固定着色管理器
shaderManager.InitializeStockShaders();
//开启深度测试
glEnable(GL_DEPTH_TEST);
//通过GLGeometryTransform管理矩阵堆栈
//使用transformPipeline 管道管理模型视图矩阵堆栈 和 投影矩阵堆栈
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
//将观察者坐标位置Z移动往屏幕里移动15个单位位置
//表示离屏幕之间的距离 负数,是往屏幕后面移动;正数,往屏幕前面移动
cameraFrame.MoveForward(-15.0f);
//利用三角形批次类构造图形对象
// 球
/*
gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks);
参数1:sphereBatch,三角形批次类对象
参数2:fRadius,球体半径
参数3:iSlices,从球体底部堆叠到顶部的三角形带的数量;其实球体是一圈一圈三角形带组成
参数4:iStacks,围绕球体一圈排列的三角形对数
建议:一个对称性较好的球体的片段数量是堆叠数量的2倍,就是iStacks = 2 * iSlices;
绘制球体都是围绕Z轴,这样+z就是球体的顶点,-z就是球体的底部。
*/
gltMakeSphere(sphereBatch, 3.0, 10, 20);
// 环面
/*
gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
参数1:torusBatch,三角形批次类对象
参数2:majorRadius,甜甜圈中心到外边缘的半径
参数3:minorRadius,甜甜圈中心到内边缘的半径
参数4:numMajor,沿着主半径的三角形数量
参数5:numMinor,沿着内部较小半径的三角形数量
*/
gltMakeTorus(torusBatch, 3.0f, 0.75f, 15, 15);
// 圆柱
/*
void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks);
参数1:cylinderBatch,三角形批次类对象
参数2:baseRadius,底部半径
参数3:topRadius,头部半径
参数4:fLength,圆形长度
参数5:numSlices,围绕Z轴的三角形对的数量
参数6:numStacks,圆柱底部堆叠到顶部圆环的三角形数量
*/
gltMakeCylinder(cylinderBatch, 2.0f, 2.0f, 3.0f, 15, 2);
//锥
/*
void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks);
参数1:cylinderBatch,三角形批次类对象
参数2:baseRadius,底部半径
参数3:topRadius,头部半径
参数4:fLength,圆形长度
参数5:numSlices,围绕Z轴的三角形对的数量
参数6:numStacks,圆柱底部堆叠到顶部圆环的三角形数量
*/
//圆柱体,从0开始向Z轴正方向延伸。
//圆锥体,是一端的半径为0,另一端半径可指定。
gltMakeCylinder(coneBatch, 2.0f, 0.0f, 3.0f, 13, 2);
// 磁盘
/*
void gltMakeDisk(GLTriangleBatch& diskBatch, GLfloat innerRadius, GLfloat outerRadius, GLint nSlices, GLint nStacks);
参数1:diskBatch,三角形批次类对象
参数2:innerRadius,内圆半径
参数3:outerRadius,外圆半径
参数4:nSlices,圆盘围绕Z轴的三角形对的数量
参数5:nStacks,圆盘外网到内围的三角形数量
*/
gltMakeDisk(diskBatch, 1.5f, 3.0f, 13, 3);
}
- 屏幕大小发生改变
void ChangeSize(int w, int h)
{
// 修改视口大小
glViewport(0, 0, w, h);
//设置透视投影
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
//projectionMatrix 矩阵堆栈 加载透视投影矩阵
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//modelViewMatrix 矩阵堆栈 加载单元矩阵
modelViewMatrix.LoadIdentity();
}
- 绘制场景
//召唤场景
void RenderScene(void)
{
//用当前清除颜色清除窗口背景
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//模型视图矩阵栈堆,压栈
modelViewMatrix.PushMatrix();
//获取摄像头矩阵
M3DMatrix44f mCamera;
//从camereaFrame中获取矩阵到mCamera
cameraFrame.GetCameraMatrix(mCamera);
//模型视图堆栈的 矩阵与mCamera矩阵 相乘之后,存储到modelViewMatrix矩阵堆栈中
modelViewMatrix.MultMatrix(mCamera);
//创建矩阵mObjectFrame
M3DMatrix44f mObjectFrame;
//从ObjectFrame 获取矩阵到mOjectFrame中
objectFrame.GetMatrix(mObjectFrame);
//将modelViewMatrix 的堆栈中的矩阵 与 mOjbectFrame 矩阵相乘,存储到modelViewMatrix矩阵堆栈中
modelViewMatrix.MultMatrix(mObjectFrame);
//判断你目前是绘制第几个图形
switch(nStep) {
case 0:
DrawWireFramedBatch(&sphereBatch);
break;
case 1:
DrawWireFramedBatch(&torusBatch);
break;
case 2:
DrawWireFramedBatch(&cylinderBatch);
break;
case 3:
DrawWireFramedBatch(&coneBatch);
break;
case 4:
DrawWireFramedBatch(&diskBatch);
break;
}
modelViewMatrix.PopMatrix();
// Flush drawing commands
glutSwapBuffers();
}
void DrawWireFramedBatch(GLTriangleBatch* pBatch)
{
//平面着色器,绘制三角形
shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
//传过来的参数,对应不同的图形Batch
pBatch->Draw();
// 画出黑色轮廓
glPolygonOffset(-1.0f, -1.0f);
//开启线段抗锯齿
glEnable(GL_LINE_SMOOTH);
//开启混合功能
glEnable(GL_BLEND);
//颜色混合,设置混合因子
//表示源颜色乘以自身的alpha 值,目标颜色乘以1.0减去源颜色的alpha值,这样一来,源颜色的alpha值越大,则产生的新颜色中源颜色所占比例就越大,而目标颜色所占比例则减 小。这种情况下,我们可以简单的将源颜色的alpha值理解为“不透明度”。这也是混合时最常用的方式。
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//通过程序点大小模式来设置点的大小
glEnable(GL_POLYGON_OFFSET_LINE);
//多边形模型(背面、线) 将多边形背面设为线框模式
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 SpecialKeys(int key, int x, int y)
{
if(key == GLUT_KEY_UP)
//移动世界坐标系,而不是去移动物体。
//将世界坐标系在X方向移动-5.0
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 KeyPressFunc(unsigned char key, int x, int y)
{
if(key == 32)
{
nStep++;
if(nStep > 4)
nStep = 0;
}
switch(nStep)
{
case 0:
glutSetWindowTitle("Sphere");
break;
case 1:
glutSetWindowTitle("Torus");
break;
case 2:
glutSetWindowTitle("Cylinder");
break;
case 3:
glutSetWindowTitle("Cone");
break;
case 4:
glutSetWindowTitle("Disk");
break;
}
glutPostRedisplay();
}
网友评论