zoukankan      html  css  js  c++  java
  • Cesium原理篇:6 Renderer模块(2: Texture)

           Texture也是WebGL中重要的概念,使用起来也很简单。但有句话叫大道至简,如果真的想要用好纹理,里面的水其实也是很深的。下面我们来一探究竟。

           下面是WebGL中创建一个纹理的最简过程:

    var canvas = document.getElementById("canvas");
    var gl = canvas.getContext("webgl");
    // 创建纹理句柄
    var texture = gl.createTexture();
    // 填充纹理内容
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    // 设置纹理参数
    //gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    //gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    // 释放
    gl.bindTexture(gl.TEXTURE_2D, null);

           如果你觉得上面的这段代码简单易懂,不妨在看看WebGL中提供的gl.glTexImage2D的重载方法:

    void gl.texImage2D(target, level, internalformat, width, height, border, format, type, ArrayBufferView? pixels);
    void gl.texImage2D(target, level, internalformat, format, type, ImageData? pixels);
    void gl.texImage2D(target, level, internalformat, format, type, HTMLImageElement? pixels);
    void gl.texImage2D(target, level, internalformat, format, type, HTMLCanvasElement? pixels);
    void gl.texImage2D(target, level, internalformat, format, type, HTMLVideoElement? pixels);

         一个再简单的纹理调用,在实际中也会有变幻无穷的方式,而这就是实现功能和产品封装上的区别,Cesium中提供了Texture类,整体上考虑了主要的使用场景,在代码设计上简化了学习成本,当然在编码上也较为优雅,我们不妨看一下Cesium中创建纹理的伪代码:

    function Texture(options) {
        // 如下三个if判断,用来查看是否是深度纹理、深度模版纹理或浮点纹理
        //  并判断当前浏览器是否支持,数据类型是否满足要求
        if (pixelFormat === PixelFormat.DEPTH_COMPONENT) {
        }
    
        if (pixelFormat === PixelFormat.DEPTH_STENCIL) {
        }
    
        if (pixelDatatype === PixelDatatype.FLOAT) {
        }
    
        var preMultiplyAlpha = options.preMultiplyAlpha || pixelFormat === PixelFormat.RGB || pixelFormat === PixelFormat.LUMINANCE;
        var flipY = defaultValue(options.flipY, true);
    
        var gl = context._gl;
        var textureTarget = gl.TEXTURE_2D;
        var texture = gl.createTexture();
    
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(textureTarget, texture);
    
        if (defined(source)) {
            gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, preMultiplyAlpha);
            // Y轴方向是否翻转
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipY);
    
            if (defined(source.arrayBufferView)) {
                // 纹理数据是arraybuffer的形式下,调用此方法
                gl.texImage2D(textureTarget, 0, internalFormat, width, height, 0, pixelFormat, pixelDatatype, source.arrayBufferView);
            } else if (defined(source.framebuffer)) {
                // 纹理数据是纹理缓冲区中的数据时,调用此方法
                if (source.framebuffer !== context.defaultFramebuffer) {
                    source.framebuffer._bind();
                }
    
                gl.copyTexImage2D(textureTarget, 0, internalFormat, source.xOffset, source.yOffset, width, height, 0);
    
                if (source.framebuffer !== context.defaultFramebuffer) {
                    source.framebuffer._unBind();
                }
            } else {
                // 纹理数据是其他类型: ImageData, HTMLImageElement, HTMLCanvasElement, or HTMLVideoElement
                gl.texImage2D(textureTarget, 0, internalFormat, pixelFormat, pixelDatatype, source);
            }
        } else {
            // 纹理数据为空
            gl.texImage2D(textureTarget, 0, internalFormat, width, height, 0, pixelFormat, pixelDatatype, null);
        }
        gl.bindTexture(textureTarget, null);
    }

           Cesium.Texture支持纹理贴图,还有深度和模版,以及浮点纹理等扩展性的用法,保证了Cesium可以支持深度值,模版等操作,满足一些复杂情况下的需求,同时,通过Texture.fromFramebuffer方式,可以支持FBO作为一张纹理,实现离屏渲染的效果。因此,在纹理数据创建上,Cesium还是比较完整的。

           同时,Cesium.Sample类提供了数据的一些显示风格设置,比如TextureWrap,Filter的设置,在Texture类中有一个sampler的属性,用户在赋值时自动设置:

    sampler : {
        get : function() {
            return this._sampler;
        },
        set : function(sampler) {
            // ……
    
            gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(target, this._texture);
            gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, minificationFilter);
            gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, magnificationFilter);
            gl.texParameteri(target, gl.TEXTURE_WRAP_S, sampler.wrapS);
            gl.texParameteri(target, gl.TEXTURE_WRAP_T, sampler.wrapT);
            if (defined(this._textureFilterAnisotropic)) {
                gl.texParameteri(target, this._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, sampler.maximumAnisotropy);
            }
            gl.bindTexture(target, null);
    
            this._sampler = sampler;
        }
    },

           另外,为了解决纹理闪烁的情况,Cesium中提供了MipMap的设置方式:

    Texture.prototype.generateMipmap = function(hint) {
        hint = defaultValue(hint, MipmapHint.DONT_CARE);
    
        var gl = this._context._gl;
        var target = this._textureTarget;
    
        gl.hint(gl.GENERATE_MIPMAP_HINT, hint);
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(target, this._texture);
        gl.generateMipmap(target);
        gl.bindTexture(target, null);
    };

           当然,这种方式比较方便,浏览器内部自己创建MipMap,相当于一个影像金字塔的过程,如果你出于效率和效果的优化,希望自己创建MipMap也是可以的,不过目前的Cesium.Texture还不支持这种情况。

           个人认为,目前Texture实现的中规中矩,基本支持了各种纹理情况,能够满足后面模版缓存,深度缓存等高级用法,并对这一部分做了一个很好的封装,能够满足各类应用。但如果想要用好纹理,其实里面还有很多可以扩展的地方,比如支持压缩纹理,这对于显存的意义,特别是Cesium这种比较消耗显存的应用(特别是移动端),还是很有意义的。对纹理压缩技术感兴趣的,可以读一下这篇《为什么需要纹理压缩》,当然效率高也是有代价了,比如效果和兼容性,另外,随着对纹理创建的增加,个人认为增加一个纹理管理器TextureManager还是很有必要的,而且并不复杂。

  • 相关阅读:
    自适应网页设计?
    布局设置加版心?
    bootstrap框架使用?
    Electron框架下,如何使用jquery?
    轮播插件swiper.js?
    表格出现滚动条设置?
    overflow问题--滚动设置?
    移动端页面适配ipad?
    移动端页面构建需注意?
    复杂的Sql分组
  • 原文地址:https://www.cnblogs.com/fuckgiser/p/5974272.html
Copyright © 2011-2022 走看看