天空盒

作者: 一毛钱 | 来源:发表于2020-03-22 10:23 被阅读0次

    天空盒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

    反射

    折射

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

    相关文章

      网友评论

          本文标题:天空盒

          本文链接:https://www.haomeiwen.com/subject/uydmyhtx.html