圖片來源:http://tw.freeimages.com/photo/blank-e-box-for-software-etc-4-1238246
圖片來源:http://tw.freeimages.com/photo/blank-e-box-for-software-etc-4-1238246

要進到這系列最後一篇文章了,這篇文章拖了很久,一直沒有時間整理,結果到最後 … 程式碼留下來了,記憶卻有些模糊了,這邊小蛙配著程式碼盡可能的把還記得的東西寫下來。

 

設計自己的物件

因為這邊要載入多個模型,而每個模型搭配的參數都不同,例如:刀鋒戰士要放大 10 倍並且往 y 軸位移 50、茶壺要 blablabla …,這邊可以根據自己的需求去做設計,小蛙隨意列了幾個可能會隨著不同模型調整的屬性

class MyObjs {
    private String symbol;
    private String obj;
    private String mtl;
    private List<String> textures;
    private float scale = 1;
    private float postScale = 1;
    // 0 度躺著正面朝上
    private float rotateX = 0;
    private float rotateY = 0;
    private float rotateZ = 0;
    private float traslateX = 0;
    private float traslateY = 0;
    private float traslateZ = 0;
    private Object3D target;
}

有看不懂的可以往前翻,屬性也不一一介紹了。
 

初始化物件

初始化這些物件,將每個要載入的物件及他的參數一一創建出來,

// 要觸發的圖片(ImageTarget)
private static List<String> SYMBOL = new ArrayList<>();
// 要呈現出來的 3D 模型
private List<MyObjs> objs = new ArrayList();
private void initObjs(){
    SYMBOL = Arrays.asList("stones", "chips", "tarmac");
    // 木頭櫃子
    MyObjs m = new MyObjs();
    m.symbol = SYMBOL.get(0);
    m.mtl = "Bedside_Table_D.mtl";
    m.obj = "Bedside Table D.obj";
    m.textures = Arrays.asList("Bedside_Table_D_default_1_1.png");
    m.scale = 5;
    m.rotateX = -1.5f;
    m.traslateX = -110;
    m.traslateY = -160;
    objs.add(m);
    // 灰色櫃子
    MyObjs w = new MyObjs();
    w.symbol = SYMBOL.get(2);
    w.mtl = "Bedside_Table_B.mtl";
    w.obj = "Bedside Table B.obj";
    w.textures = Arrays.asList("Bedside_Table_B_default_1_1.png");
    w.scale = 5;
    w.rotateX = -1.5f;
    w.traslateX = -110;
    w.traslateY = -160;
    objs.add(w);
    // 木桶
    MyObjs n = new MyObjs();
    n.symbol = SYMBOL.get(1);
    n.mtl = "MedievalBarrel_OBJ.mtl";
    n.obj = "MedievalBarrel_OBJ.obj";
    n.textures = Arrays.asList("MedBarrelDiffuse.jpg", "MedBarrelNormal.jpg");
    n.scale = 20;
    n.rotateX = -1.5f;
    n.traslateX = 0;
    n.traslateY = 0;
    objs.add(n);
}

在載入 obj 的範例中我們知道需要同時載入 mtl 搭配 textures,不然載進來的模型沒有材質貼圖。上面的例子中將屬性一一設定好,並且加入 objs 中,我們透過 m.symbol 來得知當出現哪張影像的時候,載入這個模型 (m.mtl, m.obj, m.textures), 並可設定縮放(scale)、翻轉(rotate)以及位移(traslate),這邊可以自己把自己要設定的屬性加上去。
 

載入物件

當把所有的物件都設定好之後,在 ImageTargetRenderer 建構子中載入這些物件們

... 以上省略 ...
initObjs();
try{
    for(int i = 0; i < objs.size(); i++){
        MyObjs m = objs.get(i);
        for(int j = 0; j < m.textures.size(); j++){
            TextureManager.getInstance().addTexture(
                m.textures.get(j),
                new Texture(mActivity.getAssets().open(TXT_PATH + m.textures.get(j)))
                );
        }
        Object3D[] tmp = Loader.loadOBJ(
            mActivity.getAssets().open(OBJ_PATH + m.obj),
            "".equals(m.mtl) ? null : mActivity.getAssets().open(MTL_PATH + m.mtl),
            m.scale
        );
        if(tmp != null && tmp.length >= 1){
            m.target = tmp[0];
        }
        m.target.strip();
        m.target.build();
        if(m.rotateX != 0)
            m.target.rotateX(m.rotateX);
        if(m.rotateY != 0)
            m.target.rotateY(m.rotateY);
        if(m.rotateZ != 0)
            m.target.rotateY(m.rotateZ);
        if(m.traslateX != 0 || m.traslateY != 0 || m.traslateZ != 0)
            m.target.translate(m.traslateX, m.traslateY, m.traslateZ);
        if(m.postScale != 1)
            m.target.scale(m.postScale);
        if("".equals(m.mtl)) {
            for(int z = 0; z < m.textures.size(); z++)
                m.target.setTexture(m.textures.get(z));
        }
        world.addObject(m.target);
        cam = world.getCamera();
        SimpleVector sv = new SimpleVector();
        sv.set(m.target.getTransformedCenter());
        sv.y -= 100;
        sv.z -= 100;
        sun.setPosition(sv);
    }
}catch(Exception e){
    e.printStackTrace();
}

將 objs 中的 MyObj 一一取出,並設定該物件之屬性,到這個階段,就可以依照不同影像載入不同模型,但,這還不夠。
 

移除模型

剩最後一個步驟,到上一個步驟會發現每個 render 出來的模型,他不會消失 … 不會消失 … 不會消失 … 加上這個步驟讓他消失吧!

// The render function.
private void renderFrame() {
    // clear color and depth buffer
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    // get the state, and mark the beginning of a rendering section
    State state = mRenderer.begin();
    // explicitly render the video background
    mRenderer.drawVideoBackground();
    float[] modelviewArray = new float[16];
    // did we find any trackables this frame?
    for (int tIdx = 0; tIdx < state.getNumTrackableResults(); tIdx++) {
        // get the trackable
        TrackableResult result = state.getTrackableResult(tIdx);
        Trackable trackable = result.getTrackable();
        printUserData(trackable);
        Matrix44F modelViewMatrix = Tool.convertPose2GLMatrix(result.getPose());
        Matrix44F inverseMV = SampleMath.Matrix44FInverse(modelViewMatrix);
        Matrix44F invTranspMV = SampleMath.Matrix44FTranspose(inverseMV);
        try{world.removeAllObjects();}catch (Exception e){}
        for(int i = 0; i < objs.size(); i++){
            MyObjs m = objs.get(i);
            if(m.symbol.equals(trackable.getName())){
                world.addObject(m.target);
                SimpleVector sv = new SimpleVector();
                sv.set(m.target.getTransformedCenter());
                sv.y -= 100;
                sv.z -= 100;
                sun.setPosition(sv);
            }
        }
        modelviewArray = invTranspMV.getData();
        updateModelviewMatrix(modelviewArray);
    }
    // hide the objects when the targets are not detected
    if (state.getNumTrackableResults() == 0) {
    	float m [] = {
    		1,0,0,0,
    		0,1,0,0,
    		0,0,1,0,
    		0,0,-10000,1
    	};
    	modelviewArray = m;
    	updateModelviewMatrix(modelviewArray);
    }
    mRenderer.end();
}

這個 function 小蛙已經忘記哪些是小蛙自己加的,哪些是原本的 code 了,就整個附上來試試看吧!
小蛙之前也遇過有網友詢問動畫的部份,經過這一段時間的研究發現 … 如果真的要用到會動的 3D model,就直接使用 Unity 吧!畢竟在 native code 中要讓做到動畫真的太麻煩了 >< 之前 survey 了好久,因為變數太大、複雜度也太高,直接放棄轉向 render 動畫原本就是強項的 Unity。祝各位好運囉!
 

Android Vuforia with jPCT-AE 系列文章

Android Vuforia with jPCT-AE (1) – 基本範例
Android Vuforia with jPCT-AE (2) – 載入 obj 測試
Android Vuforia with jPCT-AE (3) – 載入 md2 測試
Android Vuforia with jPCT-AE (4) – 載入 3ds 測試
Android Vuforia with jPCT-AE (5) – 多重模型載入

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *