天天看點

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對象去尋找對應緩存。

繼續閱讀