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