# 紋理
紋理Texture是GPU中的圖像,供著色器采樣使用。在框架中其一般被作為材質(zhì)的一部uniforms使用。
由于紋理來源的復(fù)雜性,有普通紋理、立方體紋理、視頻紋理、渲染紋理等,它們均有不同的創(chuàng)建或者加載方式,卻往往有相同的用法,所以框架為其特別約定了一套資源引用方式,詳見使用紋理一節(jié)。
# 普通紋理
普通紋理即2D紋理,創(chuàng)建普通紋理一般有以下幾種方式:
# 通過加載器
通過加載器加載是最為通用的方式,我們可以用標(biāo)簽來加載:
<xr-asset-load type="texture" asset-id="waifu" src="/assets/waifu.png" options="wrapU:1,wrapV:2" />
也可以使用代碼加載:
scene.assets.loadAsset({type: 'texture', assetId: 'waifu', src: '/assets/waifu.png'});
注意這里的options我們可以給紋理添加一些配置選項,比如wrap、filter等,其對應(yīng)的值都是枚舉,詳細(xì)可見ITextureLoaderOptions。
# 代碼創(chuàng)建
除了加載器,還可以通過代碼創(chuàng)建的方式,這里的options詳見ITextureOptions:
function createGreenTexture(scene: XrFrame.Scene) {
return scene.createTexture({
source: [new Uint8Array([0, 1, 0, 1])],
pixelFormat: xrFrameSystem.ETextureFormat.RGBA8,
width: 1,
height: 1,
magFilter: xrFrameSystem.EFilterMode.NEAREST,
minFilter: xrFrameSystem.EFilterMode.NEAREST,
wrapU: xrFrameSystem.EWrapMode.CLAMP_TO_EDGE,
wrapV: xrFrameSystem.EWrapMode.CLAMP_TO_EDGE,
anisoLevel:1
});
}
// 可以將其注冊到資源系統(tǒng)
xrFrameSystem.registerTexture('green', createGreenTexture);
# 更新
除了一開始就創(chuàng)建完畢,有時候開發(fā)者可能需要去動態(tài)更新紋理的內(nèi)容:
tex.update({
buffer: source,
xoffset: 0, yoffset: 0,
width: 256, height: 256
});
這里面的buffer可以是ArrayBuffer、ArrayBufferView或者IImage(圖像)。
# 圖像
圖像資源在框架中一般用于作為紋理的source或者AR識別的來源等,有兩種方式來創(chuàng)建圖片,首先是xml中:
<xr-asset-load type="image" asset-id="waifu-img" src="/assets/waifu.png" />
也可以用代碼加載:
scene.createImage({type: 'texture', assetId: 'waifu-img', src: '/assets/waifu.png'})
還可以代碼創(chuàng)建:
const image = scene.createImage();
image.onload = () => {};
image.onerror = error => {};
image.src = '/assets/waifu.png';
# 立方體紋理
立方體紋理CubeTexture是一種特殊的紋理,一般用于實現(xiàn)天空盒或者環(huán)境貼圖,雖然在框架中一般使用普通全景紋理,但仍然提供給開發(fā)者一個選擇。
# 通過加載器
立方體紋理的創(chuàng)建也可以通過加載的方式創(chuàng)建。用xml加載:
<xr-asset-load
type="cube-texture" asset-id="sky" src="/assets/sky/"
options="faces: right.jpg left.jpg top.jpg bottom.jpg front.jpg back.jpg,wrapU:1,wrapV:2"
/>
或是使用代碼加載:
scene.assets.loadAsset({
type: 'cube-texture', assetId: 'sky', src: '/assets/sky/',
options: {faces: ['right.jpg', 'left.jpg', 'top.jpg', 'bottom.jpg', 'front.jpg', 'back.jpg']}
});
options中除了faces用于配置每個面的紋理地址,其他參數(shù)和TextureLoader一致。
# 代碼創(chuàng)建
也可以代碼創(chuàng)建,通過注冊加入資源系統(tǒng):
function createGreenCubeTexture(scene: XrFrame.Scene) {
const buffer = new Uint8Array([0, 1, 0, 1]);
return scene.createTexture({
type: xrFrameSystem.ETextureType.Cube,
slices: 6,
source: [buffer, buffer, buffer, buffer, buffer, buffer],
pixelFormat: xrFrameSystem.ETextureFormat.RGBA8,
width: 1,
height: 1,
magFilter: xrFrameSystem.EFilterMode.NEAREST,
minFilter: xrFrameSystem.EFilterMode.NEAREST,
wrapU: xrFrameSystem.EWrapMode.CLAMP_TO_EDGE,
wrapV: xrFrameSystem.EWrapMode.CLAMP_TO_EDGE,
anisoLevel:1
});
}
// 可以將其注冊到資源系統(tǒng)
xrFrameSystem.registerCubeTexture('green', createGreenCubeTexture);
可見其實它也是一種普通的紋理,只不過類型不一樣。
立方體紋理也支持更新,和普通紋理基本一致,只不過必須提供slice參數(shù)。
# 視頻紋理
有時候我們需要將視頻放入場景中進(jìn)行渲染,使用視頻紋理VideoTexture資源就可以實現(xiàn)這個需求。視頻紋理本質(zhì)上是創(chuàng)建一個普通紋理,然后定時用視頻解碼數(shù)據(jù)對它進(jìn)行更新。
# 通過加載器
視頻紋理的創(chuàng)建也可以通過加載的方式創(chuàng)建。用xml加載:
<xr-asset-load
type="video-texture" asset-id="vt" src="/assets/video.mp4"
options="autoPlay:true,loop:true,abortAudio:false,placeHolder:/assets/video.jpg"
/>
或是使用代碼加載:
scene.assets.loadAsset({
type: 'video-texture', assetId: 'vt', src: '/assets/video.mp4',
options: {autoPlay: true}
});
注意到視頻紋理的幾個選項,autoPlay開啟后視頻加載成功時會自動播放,loop開啟時會循環(huán)播放,abortAudio用于指定是否要禁止聲音(默認(rèn)禁止),placeHolder則是作為視頻尚未加載成功時的一個占位圖,可選。
特別注意,
placeHolder的尺寸必須和視頻完全一致?。。?/span>
# 代碼創(chuàng)建
視頻紋理也可以手動在代碼中創(chuàng)建:
const vt = await createVideoTexture({src, autoPlay, loop, placeHolder});
注意這是個異步方法,在有placeHolder時會在圖片加載完畢時返回,否則將在視頻準(zhǔn)備好時返回。
# 控制
視頻紋理對于開發(fā)者而言主要是視頻,所以我們提供了一些用于控制視頻播放的方法:
// 開始播放,異步方法
await vt.play();
// 從`pos`秒開始播放,異步方法
await vt.seek(pos);
// 停止播放
vt.stop();
// 釋放視頻
vt.release();
// 在播放結(jié)束并且非loop的情況下,會執(zhí)行
vt.onEnd = () => {};
// 在基礎(chǔ)庫`v2.33.0`及以上,提供了暫停/喚醒方法
// 同時可以配合新暴露的播放狀態(tài)使用
const xrSystem = wx.getXrFrameSystem();
if (vt.state === xrSystem.EVideoState.Playing) {
vt.pause();
} else if (vt.state === xrSystem.EVideoState.Paused) {
vt.resume();
}
注意,如果是自己創(chuàng)建的視頻資源,請務(wù)必自己調(diào)用release方法釋放?。?!
# 渲染紋理
渲染紋理比較特殊,詳見渲染紋理。
# 使用紋理
加載或者創(chuàng)建了紋理后,便可以在組件或者材質(zhì)的uniforms中使用。但通過以上的章節(jié),我們知道了紋理的種類有許多,雖然組件數(shù)據(jù)可以通過指定具體的類型,比如cube-texture來取得具體的類型的資源,但對于uniforms來說是無法判斷的,同時也比較繁瑣。
為了解決這個問題,我們遵循約定大于配置的原則,對于所有這些紋理資源,開發(fā)者只需要將組件數(shù)據(jù)類型指定為texture,加上不同的前綴,資源系統(tǒng)會自動匹配獲取對應(yīng)的資源:
- 不加前綴,取得普通紋理。
cube-前綴,取得立方體紋理資源。video-前綴,取得視頻紋理。render-前綴,取得渲染紋理。
如果是應(yīng)用于uniforms中,開發(fā)者不需要自己去關(guān)心它們的區(qū)別,只需要uniforms="u_baseColorMap:video-vt"這樣即可,但如果是自定義組件數(shù)據(jù),就需要開發(fā)者自己處理一下了:
onUpdate(data: {texture: XrFrame.Texture | XrFrame.ITextureWrapper}) {
const realTex = xrFrameSystem.isTextureWrapper(data.texture)
? data.texture.texture
: data.texture;
}