本案例的主要目的是理解GLSL中如何索引绘图
本文案例代码有OC及Swift版本,详情见文末链接,讲解以OC版本为主
在介绍本案例之前,首先说说什么是索引绘图
一个图形中,有许多顶点,例如本案例中的金字塔,有5个面,由6个三角形组成,一共有18个顶点,然而实际肉眼可见的只有5个顶点,如下图所示
索引绘图技巧就是指将图形中的肉眼可见的顶点,通过索引的方式表示顶点之间的连接,将重复顶点复用进行图形绘制的一种技巧
案例的整体效果图如下
主要包含三部分
下面主要说说后面三部分
顶点着色器
投影矩阵
和模型视图矩阵
列向量
为主,position
是列向量,即4*1矩阵
,而投影矩阵、模型视图矩阵是4*4矩阵
,矩阵相乘 本质是 矩阵叉乘
,需要满足A x B 时, A的列数 = B的行数
,所以需要将position X mvp
相乘的顺序 颠倒为 pvm X position
//顶点坐标
attribute vec4 position;
//顶点颜色
attribute vec4 positionColor;
//投影矩阵
uniform mat4 projectionMatrix;
//模型视图矩阵
uniform mat4 modelViewMatrix;
//顶点颜色--用于与片元着色器桥接
varying lowp vec4 varyColor;
void main(){
//将顶点颜色赋值给桥接的顶点颜色变量
varyColor = positionColor;
vec4 vPos;
//顶点坐标变换: 4*4 x 4*4 x 4*1
vPos = projectionMatrix * modelViewMatrix * position;
//将变换后的顶点坐标赋值给内建变量
gl_Position = vPos;
}
片元着色器
gl_FragColor
//桥接的顶点颜色
varying lowp vec4 varyColor;
void main(){
//顶点颜色赋值给内建变量
gl_FragColor = varyColor;
}
这部分主要是绘制前的准备工作和图形的绘制
这部分内容与OpenGL ES 案例04:GLSL加载图片中并没有什么区别
如图所示,共有5个步骤,这里简要说明下
绘制的流程图如图所示,主要分为5部分
其中初始化、自定义着色器两部分的代码可参考OpenGL ES 案例04:GLSL加载图片,也可直接在文末的github上查看源代码,在下面的说明中只简述下大致步骤
初始化
这部分主要有以下几步:
GLSL自定义着色器加载
加载着色器中主要分为4步
到此,GLSL编写的自定义着色器就加载完成了。
设置顶点数据
由于图形的绘制是使用的索引绘制,所以除了创建顶点数组外,还需要创建索引数组,大致流程如下
GLfloat attrArr[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //左上0
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //右上1
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //左下2
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //右下3
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //顶点4
};
//(2).索引数组
GLuint indices[] =
{
0, 3, 2,
0, 1, 3,
0, 2, 4,
0, 4, 1,
2, 3, 4,
1, 4, 3,
};
后面3步的代码在之前的案例OpenGL ES 案例04:GLSL加载图片中也有涉及,就不再过多说明
构建矩阵
这部分主要是构建mvp矩阵,由于案例图形有旋转操作,还需要构建旋转矩阵
主要有以下4步
GLuint projectionMatrixSlot = glGetUniformLocation(self.myPrograme, "projectionMatrix");
GLuint modelViewMatrixSlot = glGetUniformLocation(self.myPrograme, "modelViewMatrix");
float width = self.frame.size.width;
float height = self.frame.size.height;
//获取纵横比
float aspect = width / height;
ksMatrixLoadIdentity
将投影矩阵初始化为单元矩阵ksPerspective
方法,设置透视投影glUniformMatrix4fv
方法,将投影矩阵传递到vertex shader矩阵涉及的方法均为数学三方库中的封装好的
KSMatrix4 _projectionMatrix;
//(1)获取单元矩阵
ksMatrixLoadIdentity(&_projectionMatrix);
//(3)获取透视矩阵
/*
参数1:矩阵
参数2:视角,度数为单位
参数3:纵横比
参数4:近平面距离
参数5:远平面距离
*/
ksPerspective(&_projectionMatrix, 30.0, aspect, 5.0f, 20.0f);
//(4)将投影矩阵传递到顶点着色器
/*
参数1-location:指要更改的uniform变量的位置
参数2-count:更改矩阵的个数
参数3-transpose:是否要转置矩阵,并将它作为uniform变量的值。必须为GL_FALSE
参数4-value:执行count个元素的指针,用来更新指定uniform变量
*/
glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
ksMatrixLoadIdentity
载入一个单元矩阵ksMatrixLoadIdentity
载入一个单元矩阵ksRotate
分别设置x、y、z相对应的旋转//创建4*4的模型视图矩阵
KSMatrix4 _modelViewMatrix;
//初始化
//(1)获取单元矩阵
ksMatrixLoadIdentity(&_modelViewMatrix);
//为了方便观察,围绕z轴往屏幕里平移10个像素点
//(2)平移,z轴平移-10
ksTranslate(&_modelViewMatrix, 0.0, 0.0, -10.0);
//创建旋转
//(3)创建一个4 * 4 矩阵,旋转矩阵
KSMatrix4 _rotationMatrix;
//初始化
//(4)初始化为单元矩阵
ksMatrixLoadIdentity(&_rotationMatrix);
//有可能围绕 x / y / z任一轴旋转(为什么不写一行?不确定围绕哪个轴旋转)
//(5)旋转
ksRotate(&_rotationMatrix, xDegree, 1, 0, 0);
ksRotate(&_rotationMatrix, yDegree, 0, 1, 0);
ksRotate(&_rotationMatrix, zDegree, 0, 0, 1);
//(6)把变换矩阵相乘.将_modelViewMatrix矩阵与_rotationMatrix矩阵相乘,结合到模型视图
//矩阵相乘 modelview = rotation x modelview
ksMatrixMultiply(&_modelViewMatrix, &_rotationMatrix, &_modelViewMatrix);
//将mv矩阵传递到顶点着色器
//(7)将模型视图矩阵传递到顶点着色器
/*
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
参数列表:
location:指要更改的uniform变量的位置
count:更改矩阵的个数
transpose:是否要转置矩阵,并将它作为uniform变量的值。必须为GL_FALSE
value:执行count个元素的指针,用来更新指定uniform变量
*/
glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
glEnable(GL_CULL_FACE);
glDrawElements
函数,使用索引绘图,方法中3个参数
mode模式 | type 类型 |
---|---|
GL_POINTS | GL_BYTE |
GL_LINES | GL_UNSIGNED_BYTE |
GL_LINE_LOOP | GL_SHORT |
GL_LINE_STRIP | GL_UNSIGNED_SHORT |
GL_TRIANGLES | GL_INT |
GL_TRIANGLE_STRIP | GL_UNSIGNED_INT |
GL_TRIANGLE_FAN | ---- |
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices);
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];
主要是3个按钮的点击事件,点击事件实现分为以下两步
完整的代码见github - 11_01_GLSL三角形变换_OC、11_01_GLSL三角形变换_Swift