GLSL
着色器源码
// shader.vsh
attribute vec4 position; // 顶点坐标
attribute vec4 positionColor; // 顶点颜色
uniform mat4 projectionMatrix; // 投影矩阵
uniform mat4 modelViewMatrix; // 模型视图矩阵
varying lowp vec4 varyColor; // 桥接的顶点颜色
void main()
{
varyColor = positionColor;
vec4 vPos;
vPos = projectionMatrix * modelViewMatrix * position;
gl_Position = vPos;
}
// shader.fsh
varying lowp vec4 varyColor;
void main()
{
gl_FragColor = varyColor;
}
这里我们只会把顶点颜色传递给片元着色器,系统则会自动将顶点之间的颜色进行计算和渲染.
GLSL索引绘图的案例,与EGL&OpenGL着色语言及案例中前五步骤一模一样,不同的在于第六步中的
6.3 顶点、纹理数据和6.4 开始绘制、显示,
顶点、纹理数据
// 顶点坐标、顶点颜色
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
};
// 索引数组
GLuint indices[] =
{
0, 3, 2,
0, 1, 3,
0, 2, 4,
0, 4, 1,
2, 3, 4,
1, 4, 3,
};
GLuint vBuffer;
glGenBuffers(1, &vBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
// 传递顶点数据
GLuint position = glGetAttribLocation(self.myProgram, "position");
glEnableVertexAttribArray(position);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, NULL);
// 传递顶点颜色
GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor");
glEnableVertexAttribArray(positionColor);
glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, (GLfloat *)NULL+3);
GLuint projectionMatrixSlot = glGetUniformLocation(self.myProgram, "projectionMatrix");
GLuint modelViewMatrixSlot = glGetUniformLocation(self.myProgram, "modelViewMatrix");
// 投影矩阵
float width = self.frame.size.width;
float height = self.frame.size.height;
KSMatrix4 _projectionMatrix;
ksMatrixLoadIdentity(&_projectionMatrix);
float aspect = width / height;
ksPerspective(&_projectionMatrix, 30.0f, aspect, 5.0f, 20.0f);
// 传递投影矩阵数据
glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
// 模型视图矩阵
KSMatrix4 _modelViewMatrix;
ksMatrixLoadIdentity(&_modelViewMatrix);
ksTranslate(&_modelViewMatrix, 0, 0, -10.0f);
KSMatrix4 _rotateMatrix;
ksMatrixLoadIdentity(&_rotateMatrix);
//XYZ
ksRotate(&_rotateMatrix, xDegree, 1.0, 0.0, 0.0);
ksRotate(&_rotateMatrix, yDegree, 0.0, 1.0, 0.0);
ksRotate(&_rotateMatrix, zDegree, 0.0, 0.0, 1.0);
// 矩阵相乘
ksMatrixMultiply(&_modelViewMatrix, &_rotateMatrix, &_modelViewMatrix);
// 传递模型矩阵数据
glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);
// 正背面剔除
glEnable(GL_CULL_FACE);
开始绘制、显示
glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_INT, indices);
GLKit
因为GLKit已经帮我们省略了很多工作,这里只需要两个步骤
- 初始化上下文、GLKview等准备工作
- 渲染
初始化
// 初始化设置
- (void)setupContext{
self.mContext = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
GLKView *glkView = (GLKView *)self.view;
glkView.context = self.mContext;
// 设置颜色格式
glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
// 设置深度测试精度
glkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;
[EAGLContext setCurrentContext:self.mContext];
glEnable(GL_DEPTH_TEST);
}
渲染
- (void)render{
GLfloat attrArr[] =
{
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //左上
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //右上
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //左下
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //右下
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //顶点
};
//2.绘图索引
GLuint indices[] =
{
0, 3, 2,
0, 1, 3,
0, 2, 4,
0, 4, 1,
2, 3, 4,
1, 4, 3,
};
// 将顶点数据放入数组缓冲区
GLuint vBuffer;
glGenBuffers(1, &vBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, NULL);
glEnableVertexAttribArray(GLKVertexAttribColor);
glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, (float *)NULL+3);
// 将索引数组存储到索引缓冲区
GLuint iBuffer;
glGenBuffers(1, &iBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// 基础着色器
self.mEffect = [[GLKBaseEffect alloc]init];
// 设置投影矩阵
CGSize size = self.view.bounds.size;
float aspect = fabs(size.width / size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.0), aspect, 0.1f, 100.0f);
projectionMatrix = GLKMatrix4Scale(projectionMatrix, 1.0, 1.0, 1.0);
self.mEffect.transform.projectionMatrix = projectionMatrix;
// 设置模型视图矩阵
GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -2.0f);
self.mEffect.transform.modelviewMatrix = modelViewMatrix;
// 索引数据个数
self.count = sizeof(indices)/sizeof(indices[0]);
// 定时器
double seconds = 0.1;
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC, 0.0);
__weak typeof(self) weakSelf = self;
dispatch_source_set_event_handler(timer, ^{
weakSelf.xDegree += 0.1f * weakSelf.XB;
weakSelf.yDegree += 0.1f * weakSelf.YB;
weakSelf.zDegree += 0.1f * weakSelf.ZB;
});
dispatch_resume(timer);
// 设置颜色
glClearColor(0.3, 0.3, 0.3, 1.0);
}
GLKit代理方法
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
[self.mEffect prepareToDraw];
glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0);
}
以上两个案例的不同
- attrib属性数据传输
// GLSL
GLuint position = glGetAttribLocation(self.myProgram, "position");
glEnableVertexAttribArray(position);
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, NULL);
// GLKit
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*6, NULL);
GLKit封装了着色器源码,使用GLKVertexAttribPosition通道用于顶点数据的传输,而在GLSL使用中,使用自己编写的着色器源码中的position作为顶点数据传输通道,所以首先需要glGetAttribLocation进行获取后将通道开启进行传输。
- 渲染方法
// GLSL
glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_INT, indices);
// 最后的参数传递索引数组
// GLKit
GLuint iBuffer;
glGenBuffers(1, &iBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0);
// 最后参数传递0
GLKit利用索引缓冲区保存索引数组进行渲染,GLSL是直接将索引数组通过传递给glDrawElements函数来渲染。
- 矩阵数据
// GLSL
glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);
// GLKit
self.mEffect.transform.projectionMatrix = projectionMatrix;
GLSL顶点着色器源码中uniform修饰投影矩阵参数,所以使用glUniformMatrix4fv来进行传递,uniform修饰的参数不用开启开关的操作。GLKit因为已经过封装的缘故,可以直接传递给基础着色器。