2012年2月23日 星期四

Android 開發教學筆記 - 研究 Renderscript 以 Carousel 為例 @ PandaBoard


這個 Carousel 例子是一個類似翻頁動作的特效,仔細看一下,是不是覺得自己在一個圓心中間,被很多照片包圍住呢?這個例子是 10 張照片,等於你走進了一個 10 面牆的房間,隨著你觸動移動事件,等於房間每面牆近似以你為中心旋轉。猜測原理後,就可以去驗證實做了。


six
此圖為正六邊形。左下角用來推邊長 len,右上角用來推各點 P1, P2, ... 的座標,θ就是兩頂點的夾角,此外,定義右下角是第一象限,左下是第二。


首先,讓我驗證這是個正 n 邊形的效果,主要是看到這段程式碼:


@ initBitmaps(): // Calculate the length of the polygon
len = RADIUS * 2 * sin(M_PI/NUM_ITEMS);


這是計算正 n 邊形的邊長公式,其中 n = NUM_ITEMS,此例就是 10 張照片


接著,開始計算正 n 邊形各頂點的三維座標資訊:


此例是把 y 軸當作 0 來看代 (x,y,z) = ( sinθ * RADIUS, 0, -cosθ * RADIUS)


@ initBitmaps(): // Calculate the vertices of rectangles
vertices[i*3] = sin(angle * M_PI / 180) * RADIUS;
vertices[i*3 + 1] = 0;
vertices[i*3 + 2] = -cos(angle * M_PI / 180) * RADIUS;


畫出正 n 邊形:


@ displayCarousel(): // Draw the rectangles
for (int i = 0; i < 10; i++) {
        ...
        rsgDrawQuadTexCoords(...);
        ...
}


rsgDrawQuadTexCoords 則是輸入長方形四個座標點,但是每一個頂點傳入的參數還有多了兩個,該數值通常定義為 (u, v),其中 u = 0 代表左邊,反之右邊,而 v =0 代表上面,反之下面,因此此例依序透過 (u, v) = (0, 1), (0, 0), (1, 0), (1, 1)來描述頂點位置。其中 (0, 1) 和 (0, 0) 使用的頂點座標位置分別是 ( r*sinθ , -(len/2), -r*cosθ ) 和 ( r*sinθ , len/2, -r*cosθ ),還記得最初定義得座標系嗎? y 軸是縱軸,此例第一張照片左上角座標為 ( r*sinθ , len/2, -r*cosθ ),左下角為 ( r*sinθ , -(len/2), -r*cosθ ),至於第一張圖的右上角跟右下角得座標,那就是用正 n 邊形第二個頂點來計算,以此規則算出 10 張照片的座標位置


至於觸動時的旋轉效果,則是透過 rotate 的功能實作的:


@ displayCarousel():
// Load vertex matrix as model matrix
rs_matrix4x4 matrix;
rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, -400.0f); // camera position
rsMatrixRotate(&matrix, rot, 0.0f, 1.0f, 0.0f); // camera rotation
rsgProgramVertexLoadModelMatrix(&matrix);


先把 camera(觀看照片的位置?) 位置移到 (0,0,-400) 位置,由於此正 n 邊形半徑為 828,因此距離照片 428 各單位。接著讓 camera 的位置對 (0,1,0) 向量旋轉,就達成這個效果囉


其他資訊:


rsMatrixLoadPerspective 對應 OpenGL:gluPerspective,以 void gluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); 來說,分別為視角、寬高(長)比、前景和背景,查 wiki 可知人的視角大約 120 度,魚眼是 180 度,在此例是 30 度視角為例,接著寬高(長)比沒啥問題,而 near 和 far 的參數,若有玩單眼相機的話,應該不會太陌生,在網路上找資料的結果,通常前景是用一個大於 0 的數值,如 0.1f 等。


rsMatrixLoadTranslate 對應 OpenGL: glTranslate,以 void glTranslated(GLdouble x, GLdouble y, GLdouble z); 來說,就是切換到 (x,y,z) 座標


rsMatrixRotate 對應 OpenGL: glRotate,以 void glRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); 來說,代表以 (x,y,z) 向量為軸心,旋轉 angle 弧度。此外,(0,1,0) 和 (0,100,0) 都是一樣的向量,網路資料是說用 (0,1,0) 所造成的運算量較低。


而 rsMatrixLoadTranslate 和 rsMatrixRotate 定義可在 Renderscript Reference 查詢。


沒有留言:

張貼留言