OpenGL学习- 4.图元解析

691 阅读8分钟

4.图元解析

OpenGL管线渲染流程

15682754597107.jpg 从客户端向服务端传递数据有3种形式:Texture Data、Uniforms、Attributes。每种形式都只是一种数据传递方式,并不限制传输数据类型 顶点着色器(Vertex Shader)接收Texture Data、Uniforms、Attributes,但是顶点着色器只会处理Uniforms、Attributes,对Texture Data只是起到传递作用 Texture Data、Uniforms都可以传递到顶点着色器和片元着色器,但是Attributes只能传递到顶点着色器,不能直接传递到片元着色器

Uniforms、Attributes使用区别:

比较通用型的用Uniforms,对每个顶点都可能要变化的用Attributes Attributes一般用来传递颜色、顶点数据、纹理坐标、光照法线等值, Uniforms一般用来传递旋转矩阵(顶点着色器用来旋转顶点数据)、颜色转换矩阵(片元着色器用来把YUV色值转化到RGB色值)。

注意Attributes变量不支持整数、布尔值、结构或者属性数组,不能在片段着色器中声明。

正投影

15682770003323.jpg

透视投影

15682770371075.jpg 15682770501033.jpg

固定管线(存储着色器)

使用存储着色器,我们可以简便的实现我们的需求,而不需要去进行太多自定义操作,只要根据需求选择合适的存储着色器就好。要是用固定管线,首先要先初始化着色器管理器。

GLShaderManager shaderManager;
shaderManager.InitializeStockShaders();

存储着色器

单元着色器 GLShaderManager::UserStockShader(GLT_SHADER_IDENTITY,GLfloat vColor[4]);
参数1:存储着色器类型-单元着色器
参数2:颜色
使用场景:绘制默认OpenGL坐标系(-1,1)下图形。图形所有片段都会以一种颜色填充

平面着色器 GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
参数1:存储着色器类型-平面着色器
参数2:允许变化的4x4矩阵
参数3:颜色
使用场景:在绘制图形时,可以应用变换(模型/投影变化)

上色着色器 GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
参数1:存储着色器类型-上色着色器
参数2:允许变化的4x4矩阵
使用场景:在绘制图形时,可以应用变换(模型/投影变化),颜色将会平滑的插入到顶点之间称为平滑着色

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

点光源着色器 GLShaderManager::UserStockShader(GLT_SHADER_POINT_LIGHT_DIFF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vColor[4]);
参数1:存储着色器类型-点光源着色器
参数2:模型4x4矩阵
参数3:投影4x4矩阵
参数4:点光源位置
参数5:漫反射颜色值
使用场景:在绘制图形时,可以应用变换(模型/投影变化),这种着色器会使绘制的图形产生阴影和光照的效果。它与默认光源着色器非常类似,区别只是光源位置可能是特定的。

纹理替换矩阵着色器 GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);
参数1:存储着色器类型-纹理替换矩阵着色器
参数2:模型4x4矩阵
参数3:纹理单元
使用场景:在绘制图形时,可以应用变换(模型/投影变化),这种着色器通过给定的模型视图投影矩阵。使用纹理单元来进行颜色填充。其中每个像素点的颜色是从纹理中获取

纹理调整着色器 GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit);
参数1:存储着色器-纹理调整着色器
参数2:模型4x4矩阵
参数3:颜色值
参数4:纹理单元
使用场景:在绘制图形时,可以应用变换(模型/投影变化)这种着色器通过给定的模型视图投影矩阵。着色器将一个基本色乘以一个取自纹理单元nTextureUnit的纹理,将颜色与纹理进行混合后才填充到片段中。

纹理光源着色器 GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit);
参数1:存储着色器类型-纹理光源着色器
参数2:模型4x4矩阵
参数3:投影4x4矩阵
参数4:点光源位置
参数5:颜色值(几何图形的基本色)
参数6:纹理单元
使用场景:在绘制图形时,可以应用变换(模型/投影变化)。这种着色器通过给定的模型视图投影矩阵。着色器将一个纹理通过漫反射照明计算进行调整(相乘)。

基本图元

图元描述
GL_POINT每个顶点在屏幕上都是单独点
GL_LINES每一对顶点定义一条线段
GL_LINE_STRIP从第一个顶点依次经过后续每一个顶点绘制线条
GL_LINE_LOOP从第一个顶点依次经过后续每一个顶点,再把最后一个顶点连接第一个顶点绘制一个环
GL_TRIANGLES每3个顶点定义一个三角形
GL_TRIANGLE_STRIP共用一个条带(strip)上的顶点的一组三角形
GL_TRIANGLE_FAN以第一个点为中心呈扇形排列,共用相邻顶点的一组三角形

15680121959599.jpg

OpenGL 点/线/三角形

设置点的大小glPointSize(4.0f)
设置线宽度glLineWidth(2.5f)
OpenGL默认逆时针环绕的多边形为正面,我们也可以通过代码来自己配置:
glFrontFace(GL_CW)顺时针环绕的为正面
glFrontFace(GL_CCW)逆时针环绕的为正面
为什么三角形是OpenGL中最受欢迎的图元?
因为GL_TRIANGLE_STRIP(三角形带)和GL_TRIANGLE_FAN(三角形扇)图元时,前三个顶点指定1个三角形后,对接下来的一个三角形,只需要再指定一个顶底。需要绘制大量三角形的时候,采用这种方式可以节省大量的程序代码和数据存储空间。其次,还能够提升运算性能和节省带宽,更少的顶点意味着数据从内存传输到图形卡的速度更快,并且顶点着色器需要处理的次数也更少。

GLBatch

GLBatch是GLTools中包含的一个简单的容器类

  • 开始填充数组 void GLBatch::Begin(GLenum primitive, GLuint nVerts, GLuint nTextureUnits = 0);
    参数1:图元
    参数2:顶点数
    参数3:一组或者2组纹理坐标(可选)
  • 复制顶点数据(一个由3分量x,y,z顶点组成的数组) void GLBatch::CopyVerterxData3f(GLfloat *vVerts);
  • 复制表面法线数据 void GLBatch::CopyNormalDataf(GLfloat *vNorms);
  • 复制颜色数据 void GLBatch::CopyColorData4f(GLfoat *vColors);
  • 复制纹理坐标数据 void GLBatch::CopyTexCoordData2f(GLfloat *vTex, GLuint uiTextureLayer)
  • 结束数据复制 void GLBatch::End(void)
  • 绘制图形 void GLBatch::Draw(void)

绘制可旋转的点/线/环/金字塔/雨伞/圆柱

main函数没什么特殊的,不过要注意,普通键位和特殊键位走的不是同一个回调函数 15707808528248.jpg 数据 15707819731047.jpg GLMatrixStack 变化管线使用矩阵堆栈,构造函数允许指定堆栈的最大深度、默认的堆栈深度为64.这个矩阵堆在初始化时已经在堆栈中包含了单位矩阵。
初始化GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
在堆栈顶部载入单位矩阵void GLMatrixStack::LoadIndentiy(void);
在堆栈顶部载入矩阵mvoid GLMatrixStack::LoadMatrix(const M3DMatrix44f m);


GLFrame 参考帧,可以表示世界坐标系中任意物体的位置与方向,涉及到的坐标系有两个:永远不变的世界坐标系,针对于自身的物体坐标系(即绘图坐标系)。可以用来产生模型视图矩阵,来产生位置的移动。

GLFrame的变化都是逆变化 例如:

GLFrame objectFrame
objectFrame.MoveRight(1)

看代码是向右移动1,实际上的效果是物体在画布上向左移动了1


GLFrustum 投影方式 用来设置投影方式和获取投影矩阵 15708741451200.jpg


GLGeometryTransform 进行几何变换的管道 15708741733223.jpg


渲染环境设置

15708840335579.jpg 开启深度测试glEnable(GL_DEPTH_TEST);

设置矩阵堆栈,管理模型矩阵和投影矩阵transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

观察者位置改变(世界坐标改变)cameraFrame.MoveForward(-15.0f);观察者向后移动15

15708840924838.jpg 15708841092309.jpg 15708841236701.jpg

重塑函数

15708843959636.jpg 透视投影设置viewFrustum.SetPerspective(50, float(w)/float(h), 1.0f, 500.0f);

空格键点击监听(空格键值:32)

15708845514793.jpg

上下左右按键监听

15708846420446.jpg 参考帧旋转objectFrame.RotateWorld(m3dDegToRad(-10.0f), 1.0, 0.0, 0.0);(m3dDegToRad:角度转弧度)

渲染函数

15708847737579.jpg

压栈出栈是为了使每次渲染相互独立,避免本次的设置影响后续设置,因为OpenGL是个状态机,每次操作都会记录的,所以要压栈出当前状态的复制,用这次复制来进行操作,操作完后把副本出栈,现在状态机里就的就还是本次操作之前的状态了

15708848993220.jpg 15708849256538.jpg 15708849403908.jpg 15708849518267.jpg

运行截图

15708839162775.jpg 15708839259545.jpg 15708839353365.jpg 15708839442300.jpg 15708839682537.jpg 15708839911384.jpg 15708840025905.jpg

代码资源见:Github