对最近一段时间学习OpenGL ES一个阶段性的成果展示,对OpenGL ES从茫茫然,漫无目的的看资料到找到头绪,也算经历了一段时间了,学习GL的API ,学习SL语言,看懂别人的Demo,知道GL的编程思想,到自己写出一些简单的效果.由于之前没有接触过这种底层图形技术,又重新复习了线性代数,方便理解矩阵的变换.
这里不做基础知识的讲解,有很多大神的博客对此有精炼的讲解,落影loyinglin,OpenGL ES 2.0 笔记,在此分享的是没有使用GLKit框架的情况下,绘制地球和月球的一次实践.
GitHub(https://github.com/FengLeNever/FL-LearnOpenGL-ES---master)
1,启用GL的流程
- (void)setupOpenGL
{
//设置FBO
[self setupFrameBuffer];
//编译Shader并Link program
[self setupShader];
//读取 Uniform
_samplerTexture = glGetUniformLocation(self.program, "samplerTexture");
_modleViewMatrix = glGetUniformLocation(self.program, "modelViewMatrix");
_projectionMatrix = glGetUniformLocation(self.program, "projectionMatrix");
//加载两个纹理
_earthTexture = [self loadTextureWithImageName:@"Earth512x256.jpg"];
_moonTexture = [self loadTextureWithImageName:@"Moon.jpg"];
// 创建VBO,顶点buffer
glGenBuffers(1, &_ballVBO);
glBindBuffer(GL_ARRAY_BUFFER, _ballVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(sphereVerts), sphereVerts, GL_STATIC_DRAW);
// 纹理 buffer
glGenBuffers(1, &_ballTextcoord);
glBindBuffer(GL_ARRAY_BUFFER, _ballTextcoord);
glBufferData(GL_ARRAY_BUFFER, sizeof(sphereTexCoords), sphereTexCoords, GL_STATIC_DRAW);
}
2,绑定Framebuffer
- (void)setupFrameBuffer
{
//设置FBO,并给FBO绑定了colorRenderBuffer , depthRenderBuffer,如果不添加depthRenderBuffer深度缓冲区,因为画的是立体的东东 , 视图显示错误
glGenRenderbuffers(1, &_colorRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
// 为 color renderbuffer 分配存储空间
[self.mContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.mLayer];
// 拿到宽和高
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_width);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_height);
// depth renderbuffer 深度缓冲区
glGenRenderbuffers(1, &_depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _width, _height);
// Framebuffers 帧缓冲区
glGenFramebuffers(1, &_frameBufferHandle);
glBindFramebuffer(GL_FRAMEBUFFER, _frameBufferHandle);
// Framebuffers bind color renderbuffer and depth renderbuffer
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, _colorRenderBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, _depthRenderBuffer);
// 切换到color renderbuffer
glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);
// Check FBO satus
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"Error: Frame buffer is not completed.");
exit(1);
}
3,渲染Render
- (void)render
{
//计算转动角度
self.earthRotationAngleDegrees += 360.f / 60.f;
self.moonRotationAngleDegrees += 360.f / 60.f / SceneDaysPerMoonOrbit;
glEnable(GL_DEPTH_TEST);
glClearColor(0.2, 0.3,0.4, 1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
CGFloat scale = [UIScreen mainScreen].scale;
CGFloat x = self.frame.origin.x;
CGFloat y = self.frame.origin.y;
CGFloat w = self.frame.size.width;
CGFloat h = self.frame.size.height;
glViewport(x * scale, y * scale, w * scale, h * scale);
glUseProgram(self.program);
// ----------------------------- 绘制地球 -----------------------------//
glBindTexture(GL_TEXTURE_2D, _earthTexture);
glUniform1i(_samplerTexture, 0);
glBindBuffer(GL_ARRAY_BUFFER, _ballVBO);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3 , 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, _ballTextcoord);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE,sizeof(float) * 2, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
KSMatrix4 projectionMatrix;
ksMatrixLoadIdentity(&projectionMatrix);
//正交投影
// ksOrtho(&projectionMatrix, -1.f * w / h, 1.f * w / h, -1.f, 1.f, 1.f, 10.f);
//透视投影
ksPerspective(&projectionMatrix, 60.f, w / h, 1.f, 10.f);
glUniformMatrix4fv(_projectionMatrix, 1, GL_FALSE, &projectionMatrix.m[0][0]);
KSMatrix4 earthMatrix = [self earthMartix];
glUniformMatrix4fv(_modleViewMatrix, 1, GL_FALSE, &earthMatrix.m[0][0]);
glDrawArrays(GL_TRIANGLES, 0, sphereNumVerts);
// ----------------------------- 绘制月球 -----------------------------//
glBindBuffer(GL_ARRAY_BUFFER, _ballVBO);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3 , 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, _ballTextcoord);
glEnableVertexAttribArray(ATTRIB_TEXCOORD);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE,sizeof(float) * 2, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, _moonTexture);
KSMatrix4 moonMatrix = [self moonMartix];
glUniformMatrix4fv(_modleViewMatrix, 1, GL_FALSE, &moonMatrix.m[0][0]);
glDrawArrays(GL_TRIANGLES, 0, sphereNumVerts);
[self.mContext presentRenderbuffer:GL_RENDERBUFFER];
}
4,矩阵Matrix
- (KSMatrix4)earthMartix
{
KSMatrix4 modelViewMatrix = [self getBaseModelViewMatrix];
//倾斜
KSMatrix4 rotateMatrix;
ksMatrixLoadIdentity(&rotateMatrix);
ksRotate(&rotateMatrix, -SceneEarthAxialTiltDeg, 1.f, 0.f, 0.f);
ksMatrixMultiply(&modelViewMatrix, &rotateMatrix, &modelViewMatrix);
// 自转
KSMatrix4 rotateMatrix2;
ksMatrixLoadIdentity(&rotateMatrix2);
ksRotate(&rotateMatrix2, self.earthRotationAngleDegrees, 0.f, 1.f, 0.f);
ksMatrixMultiply(&modelViewMatrix, &rotateMatrix2, &modelViewMatrix);
return modelViewMatrix;
}
- (KSMatrix4)moonMartix
{
KSMatrix4 modelViewMatrix = [self getBaseModelViewMatrix];
// 设置公转
KSMatrix4 rotateMarix1;
ksMatrixLoadIdentity(&rotateMarix1);
ksRotate(&rotateMarix1, self.moonRotationAngleDegrees, 0.0, 1.0, 0.0);
ksMatrixMultiply(&modelViewMatrix, &rotateMarix1, &modelViewMatrix);
// 平移
KSMatrix4 totateMatrix2;
ksMatrixLoadIdentity(&totateMatrix2);
ksTranslate(&totateMatrix2, 0.0, 0.0, SceneMoonDistanceFromEarth);
ksMatrixMultiply(&modelViewMatrix, &totateMatrix2, &modelViewMatrix);
// 缩放
KSMatrix4 scaleMatrix;
ksMatrixLoadIdentity(&scaleMatrix);
ksScale(&scaleMatrix, SceneMoonRadiusFractionOfEarth, SceneMoonRadiusFractionOfEarth, SceneMoonRadiusFractionOfEarth);
ksMatrixMultiply(&modelViewMatrix, &scaleMatrix, &modelViewMatrix);
// 自转
KSMatrix4 rotateMatrix;
ksMatrixLoadIdentity(&rotateMatrix);
ksRotate(&rotateMatrix, self.moonRotationAngleDegrees, 0.f, 1.f, 0.f);
ksMatrixMultiply(&modelViewMatrix, &rotateMatrix, &modelViewMatrix);
return modelViewMatrix;
}
- (KSMatrix4)getBaseModelViewMatrix
{
KSMatrix4 modelViewMatrix;
ksMatrixLoadIdentity(&modelViewMatrix);
ksTranslate(&modelViewMatrix, 0.0, 0.0, -4.0);
return modelViewMatrix;
}
总结
在这种学习新知识过程中,探索是痛苦的,收获是喜人的.愿与诸君共勉.