OpenGL与着色器
在OpenGL 3.0之前,OpenGL包含一个固定功能的管线,它可以在不使用着色器的情况下处理几何与像素数据。从3.1版本开始,固定管线从核心模式去掉。因此现在需要使用着色器来完成工作.
我们会使用GLSL,(OpenGL Shading Language,它是在OpenGL 2.0版本发布的)。 语法与“C、C++”类似。
基础图形管线
OpenGL中的图元只不过是顶点的集合以预定义的方式结合在一起。
管线分为:2个部分,上半部分是 客户机端,下半部分是服务器端。
服务器 和 客户端 在功能和运行上都是异步的。它们是各自独立的软件块或硬件块。
三种向OpenGL 着色器传递渲染数据的方法:
- 属性:
就是对一个顶点都要作改变的数据元素。实际上,顶点位置本身就是一个属性。属性可以是浮点类型、整型、布尔类型.
- Uniform:
通过设置Uniform 变量发送一个图元批次命令。Uniform 变量实际上可以无限次限制地使用,比如设置一个应用于整个表面的单个颜色值。还可以设置一个时间值
- 纹理
基本图元类型
-
注意着重区分以下三种绘制方式的区别
存储着色器的使用
着色器有以下分类:
• 单位着色器
• 平面着色器
• 上色着色器
• 默认光源着色器
• 点光源着色器
• 纹理替换矩阵
• 纹理调整着色器
• 纹理光源着色器
//定义着色器
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);
绘制不同类型的图元
// 各种需要的类
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLFrame cameraFrame;
GLFrame objectFrame;
//投影矩阵
GLFrustum viewFrustum;
//容器类(7种不同的图元对应7种容器对象)
GLBatch pointBatch;
GLBatch lineBatch;
GLBatch lineStripBatch;
GLBatch lineLoopBatch;
GLBatch triangleBatch;
GLBatch triangleStripBatch;
GLBatch triangleFanBatch;
//几何变换的管道
GLGeometryTransform transformPipeline;
M3DMatrix44f shadowMatrix;
点/线/线段/线环绘制
// 准备一些随机点数据
GLfloat vCoast[24][3] = {
{2.80, 1.20, 0.0 }, {2.0, 1.20, 0.0 },
{2.0, 1.08, 0.0 }, {2.0, 1.08, 0.0 },
{0.0, 0.80, 0.0 }, {-.32, 0.40, 0.0 },
{-.48, 0.2, 0.0 }, {-.40, 0.0, 0.0 },
{-.60, -.40, 0.0 }, {-.80, -.80, 0.0 },
{-.80, -1.4, 0.0 }, {-.40, -1.60, 0.0 },
{0.0, -1.20, 0.0 }, { .2, -.80, 0.0 },
{.48, -.40, 0.0 }, {.52, -.20, 0.0 },
{.48, .20, 0.0 }, {.80, .40, 0.0 },
{1.20, .80, 0.0 }, {1.60, .60, 0.0 },
{2.0, .60, 0.0 }, {2.2, .80, 0.0 },
{2.40, 1.0, 0.0 }, {2.80, 1.0, 0.0 }};
//用点的形式绘制(GL_POINTS)
pointBatch.Begin(GL_POINTS, 24);
pointBatch.CopyVertexData3f(vCoast);
pointBatch.End();
//通过线的形式绘制(GL_LINES)
lineBatch.Begin(GL_LINES, 24);
lineBatch.CopyVertexData3f(vCoast);
lineBatch.End();
//通过线段的形式绘制(GL_LINE_STRIP)
lineStripBatch.Begin(GL_LINE_STRIP, 24);
lineStripBatch.CopyVertexData3f(vCoast);
lineStripBatch.End();
//通过线环的形式绘制(GL_LINE_LOOP)
lineLoopBatch.Begin(GL_LINE_LOOP, 24);
lineLoopBatch.CopyVertexData3f(vCoast);
lineLoopBatch.End();
-
效果如下:
三角形绘制方式 - GL_TRIANGLES
//通过三角形绘制(GL_TRIANGLES) -- 生成一个金字塔的形状
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};
//GL_TRIANGLES 每3个顶点定义一个新的三角形
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
-
效果图:
三角形扇绘制方式 - GL_TRIANGLE_FAN
// 三角形扇绘制(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();
-
效果图:
三角形条带绘制方式 - GL_TRIANGLE_STRIP
//三角形条带绘制(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();
-
效果图: