天空盒

天空盒Get知识点:

  • 1、立方体贴图是和其它纹理一样的,所以如果想创建一个立方体贴图的话,我们需要生成一个纹理,并将其绑定到纹理目标上,之后再做其它的纹理操作。这次要绑定到GL_TEXTURE_CUBE_MAP:
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);

因为立方体贴图包含有6个纹理,每个面一个,我们需要调用glTexImage2D函数6次,参数和之前教程中很类似。但这一次我们将纹理目标(target)参数设置为立方体贴图的一个特定的面,告诉OpenGL我们在对立方体贴图的哪一个面创建纹理。这就意味着我们需要对立方体贴图的每一个面都调用一次glTexImage2D。

 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 
        0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

设定它的环绕和过滤方式:

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
  • 2.1、天空盒绘制优化:
    先渲染天空盒,之后再渲染场景中的其它物体。这样子能够工作,但不是非常高效。如果我们先渲染天空盒,我们就会对屏幕上的每一个像素运行一遍片段着色器,即便只有一小部分的天空盒最终是可见的。可以使用提前深度测试.所以,最后渲染天空盒,以获得轻微的性能提升。这样子的话,深度缓冲就会填充满所有物体的深度值了,我们只需要在提前深度测试通过的地方渲染天空盒的片段就可以了,很大程度上减少了片段着色器的调用.

  • 2.2、天空盒顶点着色器:

attribute vec3 aPos;

uniform mat4 projectionM;
uniform mat4 modelViewM;

varying lowp vec3 outTextCoord;

void main(){

    outTextCoord = aPos;
    vec4 pos = projectionM * modelViewM * vec4(aPos,1.0);
    //gl_Position = pos.xyww; //透视除法的应用
    //需要通过多边形偏移解决 边界闪烁的问题 (下面那个0.99是可以不乘的,而直接使用gl_Position = pos.xyww;),再查一下
    gl_Position =  vec4(pos.x,pos.y,pos.w*0.99,pos.w);
    
}
  • 3、天空盒片段着色器:

varying lowp vec3 outTextCoord;

uniform samplerCube boxTexture;

void main(){
    
    //gl_FragColor = vec4(0.2,0.2,0.3,1.0);
    gl_FragColor = textureCube(boxTexture,outTextCoord);
}
  • 4、纹理加载:
#pragma mark - cubeShafer
+(GLuint)loadCubeTextureWithImageNames:(NSArray*)fileNames
{
    //glActiveTexture(tex);
       GLuint textId ;
       glGenTextures(1, &textId);
       //绑定纹理
       glBindTexture(GL_TEXTURE_CUBE_MAP, textId);
    [self glCheckError];
    
    for (int i = 0; i < fileNames.count; ++i) {
        NSString* fileName = fileNames[I];
        size_t width,height;
        GLubyte *spriteData = [self getImageData:fileName width:&width height:&height];
        float fw = width,fh = height;
        if (spriteData) {
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X +i , 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
            //绑定纹理
            //glBindTexture(GL_TEXTURE_2D, 0);
            free(spriteData);
        } else {
            NSLog(@"立方体纹理加载错误---- ");
        }
    }
    [self glCheckError];
    
    //设置纹理的相关参数
    //参数不记得的同学,可以回顾一下OpenGL中的纹理课程
    //放大过滤器,缩小过滤器
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    [self glCheckError];
    return textId;
}
  • 5、绘制
- (void)draw{
    glViewport(0, 0, _viewWidth,_viewHeight);
    glUseProgram(self.myProgram);

//先绘制盒子  填充深度缓冲区 
    glBindVertexArray(self.blackBoxVAO);
    glBindTexture(GL_TEXTURE_2D, self.textId);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    [ZKLodaShader glCheckError];
    
//再绘制天空盒  判断天空盒的深度缓冲区小于等于 当前深度缓冲区值,才比较通过。 
//结果就是天空盒只会在没有可见物体的地方渲染了(只有这样才能通过深度测试,其它所有的东西都在天空盒前面)
    glDepthFunc(GL_LEQUAL);
    glPolygonOffset(1.0, 1.0);
    glUseProgram(self.skyBoxProgram);
    glBindVertexArray(self.VAO);
    glBindTexture(GL_TEXTURE_CUBE_MAP, self.cubemapTexture);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    [ZKLodaShader glCheckError];
    glDepthFunc(GL_LESS);
    
    if (_myColorRenderBuffer) {
        glBindRenderbuffer(GL_RENDERBUFFER, _myColorRenderBuffer);
    }
    //绘制
    [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
    
    glDeleteVertexArrays(1,&_VAO);
    glDeleteVertexArrays(1, &_blackBoxVAO);
}
  • 6、效果


    天空盒.gif

反射

折射

这两个等哪天心情好了在写,又懒了,这样不好_

你可能感兴趣的:(天空盒)