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还是很有必要的,而且并不复杂。

Cesium原理篇:6 Renderer模块(2: Texture)的更多相关文章

  1. Cesium原理篇:7最长的一帧之Entity(下)

    上一篇,我们介绍了当我们添加一个Entity时,通过Graphics封装其对应参数,通过EntityCollection.Add方法,将EntityCollection的Entity传递到DataSo ...

  2. Cesium原理篇:5最长的一帧之影像

    如果把地球比做一个人,地形就相当于这个人的骨骼,而影像就相当于这个人的外表了.之前的几个系列,我们全面的介绍了Cesium的地形内容,详见: Cesium原理篇:1最长的一帧之渲染调度 Cesium原 ...

  3. Cesium原理篇:3最长的一帧之地形(2:高度图)

           这一篇,接着上一篇,内容集中在高度图方式构建地球网格的细节方面.        此时,Globe对每一个切片(GlobeSurfaceTile)创建对应的TileTerrain类,用来维 ...

  4. Cesium原理篇:6 Renderer模块(1: Buffer)

    刚刚结束完地球切片的渲染调度后,打算介绍一下目前大家都很关注的3D Tiles方面的内容,但发现要讲3D Tiles,或者充分理解它,需要对DataSource,Primitive要有基础,而这要求对 ...

  5. Cesium原理篇:6 Renderer模块(1: Buffer)【转】

    https://www.bbsmax.com/A/n2d9P1Q5Dv/ 刚刚结束完地球切片的渲染调度后,打算介绍一下目前大家都很关注的3D Tiles方面的内容,但发现要讲3D Tiles,或者充分 ...

  6. Cesium原理篇:6 Render模块(3: Shader)

    在介绍Renderer的第一篇,我就提到WebGL1.0对应的是OpenGL ES2.0,也就是可编程渲染管线.之所以单独强调这一点,算是为本篇埋下一个伏笔.通过前两篇,我们介绍了VBO和Textur ...

  7. Cesium原理篇:6 Render模块(6: Instance实例化)

    最近研究Cesium的实例化,尽管该技术需要在WebGL2.0,也就是OpenGL ES3.0才支持.调试源码的时候眼前一亮,发现VAO和glDrawBuffers都不是WebGL1.0的标准函数,都 ...

  8. Cesium原理篇:6 Render模块(6: Instance实例化)【转】

    https://www.cnblogs.com/fuckgiser/p/6027520.html 最近研究Cesium的实例化,尽管该技术需要在WebGL2.0,也就是OpenGL ES3.0才支持. ...

  9. Cesium原理篇:6 Render模块(3: Shader)【转】

    https://www.cnblogs.com/fuckgiser/p/5975274.html 在介绍Renderer的第一篇,我就提到WebGL1.0对应的是OpenGL ES2.0,也就是可编程 ...

随机推荐

  1. pip安装MySQL-python报错

    pip install MySQL-pythonerror: command 'gcc' failed with exit status 1 yum install -y python-develpi ...

  2. pythonchallenge 解谜 Level 2

    好吧,赶紧贴一下. #-*- coding:utf-8 -*- #代码版本均为python 3.5.1 #Level 2 import re file = open("Level 2.txt ...

  3. JavaScript 作用域知识点梳理

    JavaScript的作用域一直以来是前端开发中难以理解的知识点,对于JavaScript的作用域主要记住几句话. 一.“JavaScript” 中无块级作用域 在   Java 或 C# 中存在块级 ...

  4. Javascript初学篇章_8(事件)

    事件 HTML 事件是发生在 HTML 元素上的事情.例如用户点击按钮时,点击也是一个事件.事件可以用于处理表单验证,用户输入,用户行为及浏览器动作,如: 页面加载时触发事件 页面关闭时触发事件 用户 ...

  5. Struts 2的拦截器(Interceptor)总结

     什么是Struts 2拦截器? 从软件构架上来说,拦截器是实现了面向方面编程的组件.它将影响了多个业务对象的公共行为封装到一个个可重用的模块,减少了系统的重复代码,实现功能的高度内聚,确保了业务对象 ...

  6. <web Font的使用>

    使用font-face将字体引入web中 先将字体文件复制到项目的font文件夹中,CSS样式如下: @font-face { font-family: 'iconfont'; /*字体名称*/ sr ...

  7. USACO翻译:USACO 2013 NOV Silver三题

    USACO 2013 NOV SILVER 一.题目概览 中文题目名称 未有的奶牛 拥挤的奶牛 弹簧牛 英文题目名称 nocow crowded pogocow 可执行文件名 nocow crowde ...

  8. Visual 2015创建新项,缺少ADO.NET 实体数据模型的解决方法

    现在的某度查资料真的很麻烦,突然我自身的VS2015创建EF的时候找不到 ADO.NET 实体数据模型,但是使用CodeFrist是可以生成数据表的.所有特别郁闷. 打开界面如下 某度半天,都没有查出 ...

  9. 安卓中級教程(11):深入研究餓了麼的各個java檔運作關係(1)

    package com.example.ele_me.activity; import android.annotation.SuppressLint; import android.app.Acti ...

  10. ABP理论学习之依赖注入

    返回总目录 本篇目录 什么是依赖注入 传统方式产生的问题 解决办法 依赖注入框架 ABP中的依赖注入基础设施 注册 解析 其他 ASP.NET MVC和ASP.NET Web API集成 最后提示 什 ...