本文源地址: http://blog.csdn.net/xiaominghimi/archive/2010/12/07/6059650.aspxcss
Himi 原創, 轉載請註明! 謝謝。java
爲何要先構造一個立方體的例子,其實在論證概念時,立方體是一種極好的示例,固然它並非複雜的 3D 設計的里程碑。數組
首先介紹構造一個3D立方體須要的步驟:(大概步驟哦)框架
第一:構造一個立方體的空間頂點post
第二:構造一個立方體的各個面這裏會用到三角形帶 ,詳細三角形帶的解釋看 @備註1學習
第三:構造一個攝像機ui
第四:綁定畫筆this
第五:渲染.spa
那麼下面先上代碼,都有註釋的,相信都能看懂!一些備註 下文有解釋!.net
import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.game.GameCanvas; import javax.microedition.m3g.Appearance; import javax.microedition.m3g.Camera; import javax.microedition.m3g.Graphics3D; import javax.microedition.m3g.Transform; import javax.microedition.m3g.TriangleStripArray; import javax.microedition.m3g.VertexArray; import javax.microedition.m3g.VertexBuffer; /** * * @author Himi * */ public class My3DWorld extends GameCanvas implements Runnable { private Thread th; /** * @author Himi * * @VERTEX_POSITIONS 以三角形帶形式定義一個裝入了立方體全部的頂點數組 * * @VERTEX_COLORS 以三角形帶形式定義了顏色數組 * * @TRIANGLE_INDICES 以三角形帶形式裝入了立方體的全部面 * * @VertexArray 此類做用: 雖然VERTEX_POSITIONS 定義了頂點數組可是不是空間的點, * 因此此類將頂點數組保存成空間頂點座標信息、保存法線信息、 * 保存帖圖信息、保存 顏色信息等 * * @VertexBuffer 此類對象經過保存設置空間頂點位置、發現、帖圖信息,來創建圖形 * (這個類纔是保存多邊形的框架信息的類) 設定頂點屬性 * ,包括的位置,法線,色彩,紋理座標 * * @Transform 對立方體進行一系列操做,例如反轉 、平移、縮放 * * @Camera 3d空間中的攝像機 設置投影、觀察視角等 * * @TriangleStripArray 此類按三角形帶方式將面串成立方體 */ private static final byte[] VERTEX_POSITIONS = { -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1 }; // @備註1 private static final byte[] VERTEX_COLORS = { 0, (byte) 255, 0, 0, (byte) 255, (byte) 255, (byte) 255, 0, 0, (byte) 255, 0, (byte) 255, (byte) 255, (byte) 255, 0, (byte) 255, (byte) 255, (byte) 255, 0, 0, (byte) 128, 0, 0, (byte) 255, }; private static int[] TRIANGLE_INDICES = { 0, 1, 2, 3, 7, 1, 5, 4, 7, 6, 2, 4, 0, 1 }; private Graphics3D g3d; private VertexArray va_vertex; private VertexBuffer vb; private VertexArray va_color; private Transform tf; private Camera camera; private TriangleStripArray tsa; public My3DWorld(boolean suppressKeyEvents) { super(suppressKeyEvents); th = new Thread(this); g3d = Graphics3D.getInstance(); // 獲得一個g3d實例 vb = new VertexBuffer(); camera = new Camera(); tf = new Transform(); tsa = new TriangleStripArray(TRIANGLE_INDICES, new int[] { TRIANGLE_INDICES.length }); // 參數1 傳入一個三角形形式的面數組,第二參數表明將參數一的數組複製到新的數組裏 // 把三角帶處理成正常的三點一面的形式 va_vertex = new VertexArray(VERTEX_POSITIONS.length / 3, 3, 1); // 這裏是定義空間頂點數組,第一個參數表明頂點的個數 // 第二個參數表示幾個點成一個空間點;第三個參數表示每一個頂點佔得字節數 va_vertex.set(0, VERTEX_POSITIONS.length / 3, VERTEX_POSITIONS); // 此方法是將一開始定義的頂點數組VERTEX_POSITIONS 設置成空間頂點(與頂點數組一一對應) // 第一參數能夠理解成從第一個頂點數組下標爲0開始, //第二參數封裝的空間頂點數個數有POINTS.length/3個, // 第三 參數傳入須要轉換成空間頂點的數組 va_color = new VertexArray(VERTEX_COLORS.length / 3, 3, 1); // 這裏是定義空間顏色頂點數組,第一個參數表明顏色頂點的個數(與頂點數組一一對應) // 第二個參數表示幾個點成一個空間點;第三個參數表示每一個頂點佔得字節數 va_color.set(0, VERTEX_COLORS.length / 3, VERTEX_COLORS); // 此方法是將一開始定義的頂點數組VERTEX_COLORS 設置成空間頂點顏色數組 // 第一參數能夠理解成從第一個頂點數組下標爲0開始, //第二參數封裝的空間頂點顏色數個數有POINTS.length/3個, // 第三 參數傳入須要轉換成空間頂點顏色的數組 float pc[] = { 0, 0, 1 }; vb.setPositions(va_vertex, 1.0f, pc);// @備註2 // 設定頂點位置 第一個參數 傳入頂點空間數組 // 第二個參數標識對縮放大小1.0不縮放 // 第三個參數標識誤差 ,詳細看下文解釋的@備註2 vb.setColors(va_color); // 設定空間顏色數組 camera.setPerspective(30, (float) this.getWidth() / (float) this.getHeight(), 1, 1000); // @備註3 // 設定透視投影 // 詳細解釋看@備註3 Transform transform = new Transform(); // @備註4 // 詳細解釋看@備註4 transform.postTranslate(0, 0, 10); // 這裏是設置攝像機投影位置 g3d.setCamera(camera, transform); // 用3d畫筆設定3d空間攝像機 th.start();// 啓動線程 } public void draw(Graphics g) { try { g3d.bindTarget(g);// @備註5 // 將畫筆綁定在3d空間畫筆 g3d.clear(null); // 清屏 參數null 標識默認刷屏方式 g3d.render(vb, tsa, new Appearance(), tf);// @備註6 // 渲染 第一個參數傳入一個創建圖形所須要的信息,包括法線、頂點信息,顏色等 // 第二個參數標識 立體圖形所需的三角形帶面信息 // 第三個信息標識外觀的設定這裏默認,後續文章會有學習 } catch (Exception e) { System.out.println("draw -> Error!! "); } finally { g3d.releaseTarget();// @備註7 } } public void keyPressed(int key) { if (key == -1 || key == -3) tf.postRotate(10, 1, 0, 0);// @備註8 else if (key == -2 || key == -4) tf.postRotate(10, 0, 1, 0);// @備註8 } protected void keyRepeated(int key) { keyPressed(key); } public void run() { while (true) { try { draw(this.getGraphics()); flushGraphics();// midp2.0 刷新畫筆 Thread.sleep(100); // 休眠線程 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
模擬器截圖:
備註1 : 這裏要詳細講解下三角形帶,下面引用一張圖a,你們根據圖示來看這個頂點數組就應該明白了!
你們看咱們一開始定義的以三角帶形式的頂點數組
VERTEX_POSITIONS = { -1, -1, 1, 1, -1, 1, -1,1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1 };
咱們以立方體的中心爲{0, 0,0},那麼若是頂點 0座標就是(-1, -1, 1) 那麼頂點 2 是否是 {-1,1,1}了,確定是!
這裏座標的三個點其實就是表明就是X軸 Y軸 Z軸
也就是說兩個頂點0和頂點2這兩個頂點都有共同的 -1, 1 ,而三角形帶形式就是這種重複利用重複點的形式來標識了全部的立方體的頂點!
備註2:這裏我們定義了一個誤差數組 float pc[] = { 0, 0, 1 }; 爲何要以數組形式呢?其實你換種形式看看,實際上是一個座標點,
畢竟這是3D世界了 娃哈哈,其實意思就是 X軸+=0,Y軸+=0,Z軸+=1,當咱們把這個誤差點傳入setPositions()這個方法裏之後,
也就是表明將這個立方體中心點從{0,0,0}變成了{0,0,1}這一點,若是你運行此項目當按下左右按鍵對其立方體進行旋轉的時候,
發現立方體旋轉不是圍繞中心點進行的旋轉了,而是以{0,0,1}這一點作的旋轉;因此setPositions()其實也是對中心點的一個誤差處理。
有些同窗該說爲何中心點就是{0,0,0}這一點呢,其實沒人規定而是我們一開始定義立方體數組頂點的時候就本身在內心定下了一個規定,
以{0,0,0}爲中心點了。若是你一開始定義VERTEX_POSITIONS 的時候不以{0,0,0}爲中心點,而是以頂點0 座標爲中心點的話,
那麼頂點2這時候的頂點座標就成了{0,2,0} ,頂點3就成了{0,2,2}那麼也能寫成一個三角形帶形式,可是要注意你後面的顏色數組和
定義三角形帶數組的時候也要覺得頂點0爲中心點來寫噢,這點別忘了,要一一對應!
備註3:camera.setPerspective(30, (float) this.getWidth()/ (float) this.getHeight(), 1, 1000);
第一個參數指的是透視的角度!不是高度!第二個指的是屏幕寬高比例,第三個是可視範圍min和max
其實這裏經常使用還有一個方法是:camera.setParallel() 這兩個方法以及備註5在後續文章
《深度緩衝與投影》的時候再向你們講解。
備註4:Transform transform = new Transform(); 這裏我們定義了一個變換對象,其實我們一開始定義的成員變量裏也有一個
private Transform tf;可是這裏要注意,transform 是爲了設置攝像機的時候同時設定了相機的位置而定義的,而tf則是對渲染立方體的
候作反轉、縮放、平移等操做定義的一個變化對象,等後續文章會對渲染時這個變化對象加以說明。必定要注意這兩個Transform 區別!
備註5:備註3已經說明了 ,等後續文章學習《深度緩衝與投影》的時候再向你們講解。
備註6:這裏就是爲了強調與備註4的Transform兩個對象的區別!
備註7:這裏調用 releaseTarget() 意思是終止渲染,你們會發現g3d.releaseTarget();這一句被寫在了try catch塊裏,其實緣由是由於
許多 Graphics3D 的方法都會拋出不可控異常,但絕大多數錯誤都是不可恢復的, 因此不論是否出現異常都要保證能終止渲染!
備註8:這裏是對按鍵的操做,按鍵處理和對立方體操做(縮放、平移、旋轉)會在後續學習文章中詳細解釋的。
最後給你們放出源碼,但願你們一塊兒相互交流。全部文章都是原創,不少地方可能存在錯誤但願你們多多指點。謝謝!
源碼下載地址:http://download.csdn.net/source/2887681
但願你們支持下,雖然源碼須要一資源分,我相信你們不會吝嗇吧,大半夜的給你們分享 ,娃哈哈~
(推薦你們訂閱本博客,由於咱的更新速度但是很快的~娃哈哈)
2010/12/7 02:30