前段时间研究了一下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;
}
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 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>
|
绘制图形的部分就体现出min3D的优势了,很短的函数就能把完整的md2文件导入进去,这里再次建议大家看一看
min3D的代码,有助于下面的理解。
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);
}
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的代码,有助于下面的理解。
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;
}
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时,判定为再次触摸屏幕,此时停止播放动画
四、获得传感器数据,动态设置虚拟人物的位置。
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例子的源代码