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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章