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还是很有必要的,而且并不复杂。
Cesium原理篇:6 Renderer模块(2: Texture)的更多相关文章
- Cesium原理篇:7最长的一帧之Entity(下)
上一篇,我们介绍了当我们添加一个Entity时,通过Graphics封装其对应参数,通过EntityCollection.Add方法,将EntityCollection的Entity传递到DataSo ...
- Cesium原理篇:5最长的一帧之影像
如果把地球比做一个人,地形就相当于这个人的骨骼,而影像就相当于这个人的外表了.之前的几个系列,我们全面的介绍了Cesium的地形内容,详见: Cesium原理篇:1最长的一帧之渲染调度 Cesium原 ...
- Cesium原理篇:3最长的一帧之地形(2:高度图)
这一篇,接着上一篇,内容集中在高度图方式构建地球网格的细节方面. 此时,Globe对每一个切片(GlobeSurfaceTile)创建对应的TileTerrain类,用来维 ...
- Cesium原理篇:6 Renderer模块(1: Buffer)
刚刚结束完地球切片的渲染调度后,打算介绍一下目前大家都很关注的3D Tiles方面的内容,但发现要讲3D Tiles,或者充分理解它,需要对DataSource,Primitive要有基础,而这要求对 ...
- Cesium原理篇:6 Renderer模块(1: Buffer)【转】
https://www.bbsmax.com/A/n2d9P1Q5Dv/ 刚刚结束完地球切片的渲染调度后,打算介绍一下目前大家都很关注的3D Tiles方面的内容,但发现要讲3D Tiles,或者充分 ...
- Cesium原理篇:6 Render模块(3: Shader)
在介绍Renderer的第一篇,我就提到WebGL1.0对应的是OpenGL ES2.0,也就是可编程渲染管线.之所以单独强调这一点,算是为本篇埋下一个伏笔.通过前两篇,我们介绍了VBO和Textur ...
- Cesium原理篇:6 Render模块(6: Instance实例化)
最近研究Cesium的实例化,尽管该技术需要在WebGL2.0,也就是OpenGL ES3.0才支持.调试源码的时候眼前一亮,发现VAO和glDrawBuffers都不是WebGL1.0的标准函数,都 ...
- Cesium原理篇:6 Render模块(6: Instance实例化)【转】
https://www.cnblogs.com/fuckgiser/p/6027520.html 最近研究Cesium的实例化,尽管该技术需要在WebGL2.0,也就是OpenGL ES3.0才支持. ...
- Cesium原理篇:6 Render模块(3: Shader)【转】
https://www.cnblogs.com/fuckgiser/p/5975274.html 在介绍Renderer的第一篇,我就提到WebGL1.0对应的是OpenGL ES2.0,也就是可编程 ...
随机推荐
- Python之路第一课Day8--随堂笔记(socket 承接上节---网络编程)
本节内容 Socket介绍 Socket参数介绍 基本Socket实例 Socket实现多连接处理 通过Socket实现简单SSH 通过Socket实现文件传送 作业:开发一个支持多用户在线的FTP程 ...
- 正确获取访问者ip
使用$_SERVER['REMOTE_ADDR']获取访问者ip具有局限性.比如访问者系统位于docker环境时,$_SERVER['REMOTE_ADDR']获取到的ip为虚拟ip,而不是我们真正需 ...
- EL表达式判断
今天在做开发时遇到个小问题,就百度一番很快找到答案.这里记一下免得以后到处找... 在项目中显示项目名称时因为名字太长所以影响我的样式问题. 解决办法就是将固定长度之后的用"..." ...
- properties文件使用{0}...
例如properties文件的配置 weixin.token.url=https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credent ...
- 封装自己的DB类(PHP)
封装一个DB类,用来专门操作数据库,以后凡是对数据库的操作,都由DB类的对象来实现.这样有了自己的DB类,写项目时简单的sql语句就不用每次写了,直接调用就行,很方便! 1.封装一个DB类.一个类文件 ...
- dev GridControl 根据鼠标坐标 选中行
if (e.Button == System.Windows.Forms.MouseButtons.Right) { DevExpress.XtraGrid.Views.Grid.ViewInfo.G ...
- CYQ.Data V5 从入门到放弃ORM系列:框架的优势
前言: 框架开源后,学习使用的人越来越多了,所以我也更加积极的用代码回应了. 在框架完成了:数据库读写分离功能 和 分布式缓存功能 后: 经过三天三夜的不眠不休,终于完成框架第三个重量级的功能:自动化 ...
- Async All the Way
Asynchronous code reminds me of the story of a fellow who mentioned that the world was suspended in ...
- 如何调试ANDROID下面黑屏问题
最近很多朋友在问,为毛在WINDOWS下对了,跑ANDROID的虚拟机或者真机就黑屏了, 有的是只有FPS信息,有的是连FPS信息都没有.如果是程序能够正常启动,不会闪退,但显示不对. 那十有八九都是 ...
- spring-boot 和 docker 集成
描述 java 的 Spring是一个很火的框架,Spring boot 这个也不用说了,Docker 近年也很火热, 本文就介绍下我在 Spring boot + Docker的集成一些经验 :) ...