OpenGL(二)-基本图元绘制

OpenGL与着色器

在OpenGL 3.0之前,OpenGL包含一个固定功能的管线,它可以在不使用着色器的情况下处理几何与像素数据。从3.1版本开始,固定管线从核心模式去掉。因此现在需要使用着色器来完成工作.
我们会使用GLSL,(OpenGL Shading Language,它是在OpenGL 2.0版本发布的)。 语法与“C、C++”类似。

基础图形管线

OpenGL中的图元只不过是顶点的集合以预定义的方式结合在一起。
管线分为:2个部分,上半部分是 客户机端,下半部分是服务器端。
服务器 和 客户端 在功能和运行上都是异步的。它们是各自独立的软件块或硬件块。
image.png

三种向OpenGL 着色器传递渲染数据的方法:

  • 属性:

    就是对一个顶点都要作改变的数据元素。实际上,顶点位置本身就是一个属性。属性可以是浮点类型、整型、布尔类型.

  • Uniform:

    通过设置Uniform 变量发送一个图元批次命令。Uniform 变量实际上可以无限次限制地使用,比如设置一个应用于整个表面的单个颜色值。还可以设置一个时间值

  • 纹理

    基本图元类型

    image.png
    image.png

  • 注意着重区分以下三种绘制方式的区别
    image.png
    image.png

image.png
image.png

存储着色器的使用

着色器有以下分类:
• 单位着色器
• 平面着色器
• 上色着色器
• 默认光源着色器
• 点光源着色器
• 纹理替换矩阵
• 纹理调整着色器
• 纹理光源着色器

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 各种需要的类
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;
点/线/线段/线环绘制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 准备一些随机点数据
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();
  • 效果如下:
    点.png
    线.png
    线段.png
    线环.png
三角形绘制方式 - GL_TRIANGLES
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    //通过三角形绘制(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_TRIANGLES.png](http://upload-images.jianshu.io/upload_images/1352344-a577c287b2f55072.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###### 三角形扇绘制方式 - 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();
1
2
3
4
* 效果图:
![GL_TRIANGLE_FAN.png](http://upload-images.jianshu.io/upload_images/1352344-ec20836c62236f9b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###### 三角形条带绘制方式 - 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();

`

  • 效果图:
    GL_TRIANGLE_STRIP.png
谢谢你赏我糖果吃