OpenGL ES -2.0 绘制地球,月球(公转,自转)

对最近一段时间学习OpenGL ES一个阶段性的成果展示,对OpenGL ES从茫茫然,漫无目的的看资料到找到头绪,也算经历了一段时间了,学习GL的API ,学习SL语言,看懂别人的Demo,知道GL的编程思想,到自己写出一些简单的效果.由于之前没有接触过这种底层图形技术,又重新复习了线性代数,方便理解矩阵的变换.

这里不做基础知识的讲解,有很多大神的博客对此有精炼的讲解,落影loyinglin,OpenGL ES 2.0 笔记,在此分享的是没有使用GLKit框架的情况下,绘制地球和月球的一次实践.

OpenGL ES -2.0 绘制地球,月球(公转,自转)_第1张图片
Erath&Moon.PNG

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;
}

总结
在这种学习新知识过程中,探索是痛苦的,收获是喜人的.愿与诸君共勉.

你可能感兴趣的:(OpenGL ES -2.0 绘制地球,月球(公转,自转))