Android Vuforia with jPCT-AE (2) – 載入 obj 測試

上一篇 Android Vuforia with jPCT-AE (1) – 基本範例 我們已經把 Vuforia 與 jPCT-AE 的環境建立出來,也可以正常顯示 Vuforia + jPCT-AE 的範例─一個顏色有點昏暗的桶子,這篇繼續記錄怎麼直接載入一般常見的 .obj 檔案。

圖片來源:http://tw.freeimages.com/photo/3d-lines-and-sphere-photo-2-1165195
圖片來源:http://tw.freeimages.com/photo/3d-lines-and-sphere-photo-2-1165195

囉哩巴唆

透過 Android Vuforia with jPCT-AE (1) – 基本範例 是直接在 ImageTargetRenderer.java 的建構式中,將要畫出物件的座標以及一些參數設定好之後,透過 jPCT-AE 畫出來,聽起來不怎麼有彈性,加上一些複雜的模型要透過自己訂定座標點的方式畫出來,貌似非常不科學啊!因此,這篇要記錄如何透過 Loader 類別來載入 .obj 的檔案,而不是在程式中,自己把座標一一描繪出來。

到 TD3M 下載需要的檔案

這篇小蛙使用 Bedside Table (4 skins) @ TF3DM 當作範例,因為這個範例非常符合 jPCT-AE 載入的規則,後面會再提到這是什麼意思,總之先把這個範例下載下來,下載完解壓縮之後會看到如下圖

Bedside table 3d model

Bedside table 3d model

將這三個檔案通通複製到 Android Studio 專案中的 assets 目錄下

將模型放入 assets 目錄下

將模型放入 assets 目錄下

小蛙測試的時候用了很多模型,造成 assets 目錄下面亂七八糟,因此又在 assets 下新增了 obj、mtl、texture 等目錄,分別把上述「Bedside Table D.obj」、「Bedside_Table_D.mtl」、「Bedside_Table_D_default_1_1.png」依類別放入。

讓 jPCT-AE 載入 obj, mtl, texture

建議可以先把 jPCT-AE 的 ImageTargetRenderer.java 的建構式注解起來,到時候如果改壞了,還可以還原回去,然後把以下建構式的程式碼貼上

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public ImageTargetRenderer(ImageTargets activity, SampleApplicationSession session) {
    mActivity = activity;
    vuforiaAppSession = session;
    world = new World();
    // 如果亮度太暗或是亮度怪怪的,可以調整這裡
    world.setAmbientLight(150, 150, 150);
    world.setClippingPlanes(2.0f, 3000.0f);
    sun = new Light(world);
    // 如果亮度太暗或是亮度怪怪的,可以調整這裡
    sun.setIntensity(250, 250, 250);
    try{
        // 載入材質,第一個參數是 texture 名稱,這邊使用原始檔名
        // 因為當載入 mtl 時,mtl 的檔名會自動對應到該 texture
        TextureManager.getInstance().addTexture(
                "Bedside_Table_D_default_1_1.png",
                new Texture(mActivity.getAssets().open("texture/Bedside_Table_D_default_1_1.png"))
        );
        // loadOBJ 參數分別是:.obj, .mtl, 縮放大小
        Object3D[] tmp = Loader.loadOBJ(
                mActivity.getAssets().open("obj/Bedside Table D.obj"),
                mActivity.getAssets().open("mtl/Bedside_Table_D.mtl"),
                5
        );
        if(tmp != null && tmp.length >= 1){
            cylinder = tmp[0];
        }
        cylinder.strip();
        cylinder.build();
        // 位移
        cylinder.translate(-110, -160, 0);
        // x 軸旋轉,不然載入的櫃子可能是趴著或是躺著的
        cylinder.rotateX(-1.5f);
        // 如果有 mtl 就可以不用 setTexture,mtl 內有 texture 名稱會自動載入
        //cylinder.setTexture("Bedside_Table_D_default_1_1.png");
        world.addObject(cylinder);
        cam = world.getCamera();
        SimpleVector sv = new SimpleVector();
        sv.set(cylinder.getTransformedCenter());
        sv.y -= 100;
        sv.z -= 100;
        sun.setPosition(sv);
    }catch(Exception e){
        e.printStackTrace();
    }
    MemoryHelper.compact();
}

執行看看是不是可以正常載入一個櫃子了呢?

載入 .obj 測試

載入 .obj 測試

遭遇問題

小蛙之前弄了半天,遇到一拖拉庫的錯誤,有些事情後來才釐清到底為什麼會發生錯誤,在 texture 的部份,圖片大小必須要是 2 的次方,像是:128, 256, 512, 1024, 2048 … 等,只要邊長不是 2 的次方,就會得到圖片大小錯誤的訊息,外加因為載不到圖片隨之而來的 javaNullPointer Exception。
render 出來沒有東西,這個要仔細看,有時候是模型太小,小蛙有一次 render 出來的東西,必須要放大 30000 倍,才符合使用大小 … 有時候是座標軸不對導致 redner 在 image target 下面 (被紙張遮住了),有時候是沒有 mtl 也沒有材質,就會 render 出空的東西 (沒有東西) … 等,有時候是 mtl 裡面的 texture 有問題,像是根本沒有 texture 資訊,或是 texture 資訊還是錯誤的檔案路徑(如:C:\xxx\rrr\ccc\xx.png 但是實際上根本沒有這種路徑,此時就要手動修正他),有時候其實根本也不知道為什麼就是沒有東西。
到 TD3M 多下載幾個範例檔試試看,再慢慢釐清為什麼不能載入的原因,這個範例應該是不需要做什麼調整就可以直接載入,因此使用這個當作範例。

Android Vuforia 系列:

參考資料

1 個回應

  1. Rich表示:

    使用前相機好像有問題,某個方向的旋轉與移動是相反的。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *