LayaBox引擎源码阅读笔记(五、从图集加载到纹理的使用理解)

-前言-

在H5游戏上实现的纹理图像数据源都是Image对象。我们在正常游戏开发的时候,是无需关系图集的打包过程及Laya是如何解析图集的。只有闲得慌才会去看吧~

-正文-

图集打包过程

Laya是按照文件夹进行图集打包的,每次我们在发布资源的时候就会打包图集。我们只需要按照使用情况分类好文件夹即可。

图集加载过程

在Laya中所有加载都通过统一接口进行加载。

Laya.loader.load("res/atlas/comp.atlas",Laya.Handler.create(this,()=>{
    console.log("success");
});

上面代码加载了Laya示例工程的comp.atlas图集。加载完成后开始进入图集解析的步骤。

图集解析

在成功加载atlas文件后,开始解析图集文件

//image:Browser.window.Image
var tex = new Texture2D(image.width,image.height,1,false,false);
tex.wrapModeU = BaseTexture.WARPMODE_CLAMP;
tex.wrapModeV = BaseTexture.WARPMODE_CLAMP;
tex.loadImageSource(image,true);
tex._setCreateURL(url);
_this.onLoaded(tex);

从上面代码可以看到每个图集最终会被存储到一个Texture2D对象中。下面来看实际的解析代码。

/**@param premultiplyAlpha 是否预称Alpha值**/
loadImageSource(source,premultiplyAlpha = false){
    var gl = LayaGL.instance;
    var width = source.width;
    var height = source.height;
    this._width = width;
    this._height = height;
    if (!(this._isPot(width) && this._isPot(height)))
        this._mipmap = false;
   this._setWarpMode(gl.TEXTURE_WRAP_S,this._wrapModeU);//设置纹理坐标 平铺
   this._setWarpMode(gl.TEXTURE_WRAP_T,this._wrapModeV);
   this._setFilterMode(this._filterMode);//设置纹理在放大缩小的滤镜方式
   WebGLContext.bindTexture(gl,this._glTexture,this._glTexture);
   var glFormat = this._getGLFormat();//RGBA
   if(ILaya.Render.isConchApp){
       if(source.setPremultiplyAlpha){
           source.setPremultiplyAlhap(premultiplyAlpha);
       }
       gl.texImage2D(this._glTextureType,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,source);
   }else{
       //图片空白处Alpha为0,显示透明像素。
        (premultiplyAlpha) && (gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL,true));
        gl.texImage2D(this._glTextureType, 0, glFormat, glFormat, gl.UNSIGNED_BYTE, source);//将纹理绑定到gl程序
        (premultiplyAlpha) && (gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false));
   }
}

当图集被绑定到了WebGL之后,就可以开始解析每个碎图的数据了。每个数据当然都会持有这个图集的引用。

解析碎图

this._data.pics.push(data);//Loader存储数据,pics为每个图集数据
//这一步是对加载逻辑的处理 与图集不相关
if(this._data.toLoads.length > 0){
    this.event(Event.PROGRESS,0.3 + 1 / this._data.toLoads.length * 0.6);
    return this._loadResourceFilter(Loader.IMAGE,this._data.toLoads.pop()));
}
//以下是对于图集的碎图数据的准备
var frames = this._data.frames;
var cleanUrl = this._url.split("?")[0];//祛除mdn校验
var directory = (this._data.meta && this._data.meta.prefix) ? this._data.meta.prefix : cleanUrl.substring(0,cleanUrl.lastIndexOf(".")) + "/";
var pics = this._data.pics;
var atlasURL = URL.formatURL(this._url);
var map = Loader.atlasMap[atlasURL] || (Loader.atlasMap[atlasURL] = []);
map.dir = directory;
var scaleRate = 1;
//实际处理碎图逻辑
if(this._data.meta && this._data.meta.scale && this._data.meta.scale != 1){
    scaleRate = parseFloat(this._data.meta.scale);
    for(var name in frames){
        var obj = frames[name];
        var tPic = pics[obj.frame.idx ? obj.frame.idx : 0];
        var url = URL.formatURL(directory + name);
        tPic.scaleRate = scaleRate;
        var tTexture;
        tTexture = Texture._create(tPic, obj.frame.x, obj.frame.y, obj.frame.w, obj.frame.h, obj.spriteSourceSize.x, obj.spriteSourceSize.y, obj.sourceSize.w, obj.sourceSize.h, Loader.getRes(url));
        Loader.cacheRes(url, tTexture);
        tTexture.url = url;
        map.push(url);
    }
}else{
//解析碎图
    for (name in frames) {
        obj = frames[name];
        tPic = pics[obj.frame.idx ? obj.frame.idx : 0];
        url = URL.formatURL(directory + name);
        tTexture = Texture._create(tPic, obj.frame.x, obj.frame.y, obj.frame.w, obj.frame.h, obj.spriteSourceSize.x, obj.spriteSourceSize.y, obj.sourceSize.w, obj.sourceSize.h, Loader.getRes(url));
        Loader.cacheRes(url, tTexture);
        tTexture.url = url;
        map.push(url);
    }
}
delete this._data.pics;
this.complete(this._data);

以上这一步是在加载一张图集的最后一步,每个碎图也是一个Texture对象。这里会把每张碎的图片坐标转换为uv坐标,并存储到Texture对象中。纹理坐标通常表示一个纹理矩形,就是4个点,长度为8的数组存储这些顶点坐标。

在处理完以下步骤后,所有碎图(Texture)对象都会被存在Loader对象的缓存中,以便我们之后使用。

图片对象的实例

我们需要使用一张纹理的时候可以直接使用如下代码

var img:Laya.Image = new Laya.Image("comp/image.png");
img.pos(100,100);
Laya.stage.addChild(img);

以上代码初始化了一张图片,并添加到了舞台上。

Image对象本身是继承显示基类Sprite的,作为绘制所持有的纹理数据Texture的绘制容器。

这里的URL相当于一个Key值,默认会从Laya中Loader对象去寻找对应缓存。

你可能感兴趣的:(LayaBox,WebGL)