Android下利用min3D引擎實現擴增實境的簡單例子

yangxi_001發表於2014-03-27
     前段時間研究了一下Min3D遊戲開發引擎,發現這個引擎很好用,例子非常細,使用起來很方便,尤其給的最後一

個例子“ExampleAccelerometer”,很有意思,結合重力感應,這對於最近在做的擴增實境專案有一點啟發,

於是這裡把自己探索的過程和大家分享一下。

      這裡對於min3D我就不詳細介紹了,以後我會在寫篇關於min3D的文章,  大家可以先

http://code.google.com/p/min3d/去了解,在這裡為了更好地理解我的意思,建議大家把我提到的那個例子執行一下,體驗一下效果.

      我先把做好的效果說明一下,先上圖:


背景是手機的攝像頭,作為實時的預覽,在預覽圖層的上面利用min3D繪製一個三維影象,而且這是一個md2檔案

,當第一次點選螢幕時,3D人物會“跳舞”,再次點選螢幕時,停止動畫。另外,我還結合了加速度感測器,這樣,當

螢幕向左傾斜時,人物向右移動,向右傾斜時,任務向左移動。

好了,下面該說說原理了。

總的來說,實現步驟有四個:

1、開啟攝像頭,並將預覽影象作為底層;
2、利用min3D在預覽圖層上繪製或者匯入一個虛擬人物;
3、新增觸屏事件,在觸屏時播放動畫;
4、獲得感測器資料,動態設定虛擬人物的位置。


下面該是分解動作了:
一、開啟攝像頭,並將預覽影象作為底層
直接上程式碼:下面是Screen類,專門用來定義攝像頭檢視的
package com.example.animalar;
 
import java.io.IOException;
import android.content.Context;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
//這個類是用來開啟攝像頭的
public class Screen extends SurfaceView implements SurfaceHolder.Callback {
         
        public Screen(Context context) {
                super(context);
                // Install a SurfaceHolder.Callback so we get notified when the
                // underlying surface is created and destroyed.
                previewHolder = this.getHolder();
                previewHolder.addCallback(this);
                //************
                previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        }
         
 
 
        /**
         * Initialize the hardware camera. holder The holder
         */
        public void surfaceCreated(SurfaceHolder holder) {
                //************
                if(!isPreviewRunning)
                        mCamera = Camera.open();
                else
                        mCamera.stopPreview();
 
         
        }
 
        public void surfaceDestroyed(SurfaceHolder holder) {
                // Surface will be destroyed when we return, so stop the preview.
                // Because the CameraDevice object is not a shared resource, it's very
                // important to release it when the activity is paused.
                try {
                        if (mCamera!=null) {
                                //**********
                                mCamera.setPreviewCallback(null);
                                mCamera.stopPreview();  
                                mCamera.release();
                                //**********
                                mCamera=null;
                                isPreviewRunning=false;
                        }
                } catch (Exception e) {
 
                }
        }
 
        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
                if(mCamera!=null&&isPreviewRunning!=true)
                {
                        try{
                                Camera.Parameters p = mCamera.getParameters();  
                                p.setPreviewSize(w, h);
                                mCamera.setPreviewDisplay(holder);
                                //mCamera.setParameters(p);
                                mCamera.setPreviewCallback(null);
                                mCamera.startPreview();
                        }
                        catch (IOException e) {
                                e.printStackTrace();
                        }
 
 
                        isPreviewRunning = true;
                }
 
        }
 
 
        private Camera mCamera;
        private SurfaceHolder previewHolder;
        private boolean isPreviewRunning=false;
        //private Camera.PreviewCallback imageCaptureCallback;
 
}

這個類是用來開啟攝像頭的,繼承自surfaceview,要注意出現"//********"的地方,這些地方很容易導致錯誤。
這個只是一個SurfaceView定義,還沒有加到圖層中去,所以別急  
哦,對了,忘了說佈局檔案了,看程式碼吧:
<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > 
        
        <FrameLayout android:id="@+id/abc1"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
        />
         <FrameLayout android:id="@+id/abc2"
                android:layout_height="wrap_content"
                android:layout_width="wrap_content"
        />
 
<div align="\"left\""></FrameLayout> </div>
總共有三個FrameLayout,分別是總體佈局、攝像頭預覽圖層和min3D繪製圖層。
繪製圖形的部分就體現出min3D的優勢了,很短的函式就能把完整的md2檔案匯入進去,這裡再次建議大家看一看
min3D的程式碼,有助於下面的理解。
二、利用min3D在預覽圖層上繪製或者匯入一個虛擬人物
public void initScene() {
                scene.backgroundColor().setAll(0x00000000);        
                scene.lights().add(new Light()); // 新增光源        
                IParser parser = Parser.createParser(Parser.Type.MD2, getResources(),
                                "com.example.animalar:raw/ogro", false);
                parser.parse();
                ogre = parser.getParsedAnimationObject();
                ogre.scale().x = ogre.scale().y = ogre.scale().z = .07f;
                ogre.rotation().z = -90;
                ogre.rotation().x = -90;
                ogre.position().z = -4f;
                ogre.position().y = -2f;
                scene.addChild(ogre);
                mSensorManager.registerListener(this, mAccelerometer,
                                SensorManager.SENSOR_DELAY_UI);
        }


繪製圖形的部分就體現出min3D的優勢了,很短的函式就能把完整的md2檔案匯入進去,這裡再次建議大家看一看
min3D的程式碼,有助於下面的理解。

三、新增觸屏事件,在觸屏時播放動畫;
public boolean onTouchEvent(MotionEvent e) {
                if (e.getAction() == MotionEvent.ACTION_DOWN) {
                        if (twice == false) {
                                ogre.setFps(30);
                                ogre.play();
                                twice = true;
                        } else {
                                ogre.pause();
                                twice = false;
                        }
                }
                return true;
        }

注意boolean twice這個變數,當twice=false,判定為第一次觸控螢幕,播放動畫。

當twice=true時,判定為再次觸摸螢幕,此時停止播放動畫



四、獲得感測器資料,動態設定虛擬人物的位置。
public void onSensorChanged(SensorEvent event) {
                if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER)
                        return;
                //float Acc_Z = (float) event.values[2];
 
                mAccVals.x = (float) (-event.values[1] * FILTERING_FACTOR + mAccVals.x
                                * (1.0 - FILTERING_FACTOR));
                mAccVals.y = (float) (event.values[0] * FILTERING_FACTOR + mAccVals.y
                                * (1.0 - FILTERING_FACTOR));
                // mAccVals.x=-event.values[1];
                scene.camera().position.x = mAccVals.x * .5f;
                scene.camera().position.y = mAccVals.y * .2f;
                scene.camera().target.x = scene.camera().position.x;
 
        }
 
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
                // TODO Auto-generated method stub
        }

關於Android下感測器的使用方法這裡就不在贅述了,網上的教程挺多的。其實這裡的程式碼是min3D引擎中的

ExampleAccelerometer例子的原始碼

相關文章