【摘 要】本文介紹了手機動態(tài)壁紙的設計方法,以及實現(xiàn)的過程。運行的目標平臺為Android,使用OpenGL ES3.0渲染技術。
【關鍵詞】Android;動態(tài)壁紙;設計
一、引言
隨著移動互聯(lián)網(wǎng)的快速發(fā)展,單一的圖片壁紙已經(jīng)不能滿足用戶的需求,動態(tài)壁紙用動態(tài)的影像替換了原始古板的靜態(tài)壁紙,并且不影響圖標的顯示和應用程序的使用。通過動態(tài)壁紙讓桌面顯得更加酷炫、個性,增加手機的魅力。本項目采用的動態(tài)壁紙為3D水族館,在該壁紙中有許多自由游動的魚,地面有不斷一張一合的珍珠貝和不斷閃爍的珍珠。還有幾處不斷冒出氣泡,并且這些氣泡隨高度增加而不斷變大。用戶可以單擊地面給魚喂食,也可以左右滑動屏幕,使壁紙跟隨滑動。使用3ds Max對模型進行設計與貼圖,所有相關圖片資源統(tǒng)一放在一個項目文件夾中。采用OpenGL ES3.0渲染技術,使得場景中有很強的立體感,以及非常逼真的光影效果。
二、類的設計
在水族館壁紙的制作中設計了很多類,主要有以下五個方面。(1)壁紙實現(xiàn)類,具體又有壁紙服務類和自定義場景渲染器類。前者是水族館壁紙的基礎類,通過繼承GLWallpaperService類,重寫onCreateEngine方法等來實現(xiàn)壁紙功能;后者是水族館壁紙的核心類,在本類中首先設置使用渲染技術,然后創(chuàng)建需要繪制的所有對象,設置繪制方式,加載各類物體模型以及所需紋理,設置攝像機位置,使用投影矩陣,初始化光源位置等。
(2)繪制類,具體包括群魚控制類、單條魚類、單個魚群類、喂食類、魚食類、氣泡控制類以及珍珠貝類等。群魚控制類定義了群魚列表,存放所有的單條魚對象,創(chuàng)建并啟動魚的移動線程,最后遍歷列表對魚進行繪制。單條魚類定義了魚的所有屬性,包括位置、速度、外力、質(zhì)量以及旋轉(zhuǎn)角度等,單個魚群類定義了魚群中每條魚的所有相關屬性。喂食類是食物的控制類,其中的startFeed方法由攝像機與觸控點確定一條與場景地面高度交叉的拾取射線,并計算出交點的坐標。魚食類的作用是創(chuàng)建并啟動線程,繪制魚食。
(3)線程類,具體包括群魚游動線程類、魚食移動線程類和氣泡移動線程類等。群魚游動線程類的作用是通過遍歷群魚列表判斷兩條魚之間的距離,若距離小于閾值,則兩條魚之間產(chǎn)生力的作用。還可以進行碰撞檢測,修改外力、速度和位置等屬性值。魚食移動線程類的主要作用是判斷魚群中的魚與相對位置的距離,若大于閾值就會對該魚產(chǎn)生向心力,并對魚群進行碰撞檢測。氣泡移動線程類的作用是遍歷氣泡列表,判斷氣泡移動方向,然后調(diào)用氣泡對象中的bubbleMove方法,實現(xiàn)氣泡的移動。
(4)工具常量類,具體包括常量類、向量類、屏幕拾取類和存儲矩陣狀態(tài)類等。常量類是整個壁紙中用到的所有靜態(tài)常量的集合,向量類包含了相關向量算法、獲取力的大小等方法。屏幕拾取類通過拾取計算獲得觸控點在攝像機坐標系中的坐標,再乘以攝像機矩陣的逆矩陣,即可得到該點在世界坐標系中的坐標。
(5)輔助繪制類,具體包括背景圖輔助繪制類、氣泡輔助繪制類和珍珠貝輔助繪制類等。以背景圖輔助繪制類為例,它給出背景圖的頂點坐標和紋理坐標,并生成緩沖送進渲染管線,用來繪制背景圖。
三、類的實現(xiàn)
以自定義場景渲染器類為例,介紹動態(tài)壁紙相關類的實現(xiàn)。首先清除深度緩沖與顏色緩沖,進行現(xiàn)場保護,依次繪制背景圖、魚食、單條魚魚群以及珍珠貝。相關代碼如下:
GLE30.glClear(GLES30.GL_DEPTH_BUFFER_BIT| GLES30.GL_COLOR_BUFFER_BIT);
if(bg!=null){bg.drawSelf(back);}
if(singlefood!=null){singlefood.drawSelf();}
if(fishControl!=null){fishControl.drawSelf();}
…………
重寫onSurfaceChanged方法,設置視窗的尺寸和位置,計算寬高比,產(chǎn)生投影矩陣以及攝像機參數(shù)位置矩陣。相關代碼如下:
GLES30.glViewport(0,0,width,height);
float ratio=(float)width/height;
…………
重寫onSurfaceCreated方法,初始化光源位置,加載紋理,加載BNModel模型,創(chuàng)建魚群、珍珠貝等對象,開啟深度檢測等。相關代碼如下:
MatrixState.setInitStack();
MatrixState.setLightLocation(0,9,13);
dpm=initTexture(MySurfaceView,this,getResources(),”dpm.png”);
back=initTexture(MySurfaceView,this,getResources(),”background.png”);
…………
重寫initTexture方法,通過輸入流從assets中加載圖片,生成紋理ID,設置紋理的拉伸方式,設置紋理采樣方式,最后釋放Bitmap。相關代碼如下:
GLES30.glGenTextures(1,textures,0);
int textureId=textures[0];
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D,textureId);
back=initTexture(MySurfaceView,this,getResources(),”background.png”);
…………
bitmapTmp.recycle();
四、結語
在軟件設計過程中,重點是著色器的應用,以及魚游動過程中魚與魚之間作用力的變化規(guī)律等。動態(tài)壁紙的界面和風格還可以繼續(xù)改進,使其更加完美。例如水族館背景壁紙、魚的骨骼動畫及紋理圖、珍珠貝的紋理圖都可以進一步完善,從而達到更加理想的效果。本項目將明暗紋理和法向量的計算放在了片元著色器上進行,這樣的處理方式占用資源過多。可以考慮將片元著色器中這部分計算任務轉(zhuǎn)移到頂點著色器中進行,預期會顯著減少壁紙在運行時對手機GPU資源的消耗。
【參考文獻】
[1] 吳亞峰. Android應用案例開發(fā)大全(第4版)[M].北京:人民郵電出版社, 2018.
作者簡介:王曉東(1971—),男,漢族,湖北十堰人,副教授,主要研究方向:軟件開發(fā)。