OpenGL与着色器
在OpenGL 3.0之前,OpenGL包含一个固定功能的管线,它可以在不使用着色器的情况下处理几何与像素数据。从3.1版本开始,固定管线从核心模式去掉。因此现在需要使用着色器来完成工作.
我们会使用GLSL,(OpenGL Shading Language,它是在OpenGL 2.0版本发布的)。 语法与“C、C++”类似。
基础图形管线
OpenGL中的图元只不过是顶点的集合以预定义的方式结合在一起。
管线分为:2个部分,上半部分是 客户机端,下半部分是服务器端。
服务器 和 客户端 在功能和运行上都是异步的。它们是各自独立的软件块或硬件块。
三种向OpenGL 着色器传递渲染数据的方法:
- 属性:
就是对一个顶点都要作改变的数据元素。实际上,顶点位置本身就是一个属性。属性可以是浮点类型、整型、布尔类型.
- Uniform:
通过设置Uniform 变量发送一个图元批次命令。Uniform 变量实际上可以无限次限制地使用,比如设置一个应用于整个表面的单个颜色值。还可以设置一个时间值
纹理
基本图元类型
注意着重区分以下三种绘制方式的区别
存储着色器的使用
着色器有以下分类:
• 单位着色器
• 平面着色器
• 上色着色器
• 默认光源着色器
• 点光源着色器
• 纹理替换矩阵
• 纹理调整着色器
• 纹理光源着色器1
2
3
4
5
6//定义着色器
GLShaderMananger shaderManager;
//初始化着色器
shaderManager.InitalizeStockShaders()
//使用
shaderManager userStockManager(参数列表)
单位着色器
GLShaderManager::UserStockShader(GLT_ATTRIBUTE_VERTEX,GLfloat vColor[4]);
平面着色器
GLShaderManager::UserStockShader(GLT_SHADER_FLAT,GLfloat mvp[16],GLfloat vColor[4]);
上色着色器
GLShaderManager::UserStockShader(GLT_SHADER_SHADED,GLfloat mvp[16]);
默认光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vColor[4]);
点光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_DEFAULT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vColor[4]);
纹理替换矩阵着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_REPLACE,GLfloat mvMatrix[16],GLint nTextureUnit);
纹理调整着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_MODULATE,GLfloat mvMatrix[16],GLfloat vColor[4],GLint nTextureUnit);
纹理光源着色器
GLShaderManager::UserStockShader(GLT_SHADER_TEXTURE_POINT_LIGHT_DIEF,GLfloat mvMatrix[16],GLfloat pMatrix[16],GLfloat vLightPos[3],GLfloat vBaseColor[4],GLint nTextureUnit);
绘制不同类型的图元
1 | // 各种需要的类 |
点/线/线段/线环绘制
1 | // 准备一些随机点数据 |
- 效果如下:
三角形绘制方式 - GL_TRIANGLES
1 | //通过三角形绘制(GL_TRIANGLES) -- 生成一个金字塔的形状 |
// 三角形扇绘制(GL_TRIANGLE_FAN) -- 生成一个六边形
GLfloat vPoints[100][3]; //超过我们需要的数组
int nVerts = 0;
//半径
GLfloat r = 3.0f;
//原点(x,y,z) = (0,0,0);
vPoints[nVerts][0] = 0.0f;
vPoints[nVerts][1] = 0.0f;
vPoints[nVerts][2] = 0.0f;
//M3D_2PI 就是2Pi 的意思,就一个圆的意思。 绘制圆形
for(GLfloat angle = 0; angle < M3D_2PI; angle += M3D_2PI / 6.0f) {
//数组下标自增(每自增1次就表示一个顶点)
nVerts++;
/*
弧长=半径*角度,这里的角度是弧度制,不是平时的角度制
既然知道了cos值,那么角度=arccos,求一个反三角函数就行了
*/
//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个顶点(包括圆心)
printf("三角形扇形顶点数:%d\n",nVerts);
//添加闭合的终点, 若不添加, 则三角形扇形是无法闭合的。
nVerts++;
vPoints[nVerts][0] = r;
vPoints[nVerts][1] = 0;
vPoints[nVerts][2] = 0.0f;
//GL_TRIANGLE_FAN 以一个圆心为中心呈扇形排列,共用相邻顶点的一组三角形
triangleFanBatch.Begin(GL_TRIANGLE_FAN, 8);
triangleFanBatch.CopyVertexData3f(vPoints);
triangleFanBatch.End();
1 | * 效果图: |
//三角形条带绘制(GL_TRIANGLE_STRIP) -- 生成一个小环或圆柱段
//顶点下标
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++;
// GL_TRIANGLE_STRIP 共用一个条带(strip)上的顶点的一组三角形
triangleStripBatch.Begin(GL_TRIANGLE_STRIP, iCounter);
triangleStripBatch.CopyVertexData3f(vPoints);
triangleStripBatch.End();
`
- 效果图: