23
2015
12

安卓Camera实现3d效果

安卓应用中实现3d效果一般都是用Camera,确切的说应该是android.graphics.Camera,因为还有一个Camera类是用来操作摄像头的。

用android.graphics.Camera(后面直接用Camera)实现了一个3d效果。

效果图如下:

代码如下:

HSprite3d.java。

关键在于加粗的那几行。

package com.hanyeah.display3d;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import android.graphics.Bitmap;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.Log;



public class HSprite3d {
	
	public float x=0;
	public float y=0;
	public float z=0;
	public float rotationX=0;
	public float rotationY=0;
	public float rotationZ=0;
	public boolean visible=true;
	public double alpha=1.0;
	public String name;
	public boolean mouseChildren=true;
	public boolean mouseEnabled=true;
	protected HSprite3d parent;
	private List_childList=new ArrayList();
	
	public interface HRender{
		public void execute(Canvas canvas,Paint paint);
	}
	public HSprite3d.HRender hrender;
	public HSprite3d() {
		// TODO Auto-generated constructor stub
	}
	//-------------------------容器方法----------------------------
	/**
	 * [只读 (read-only)] 返回此对象的子项数目。
	 * @return
	 */
	public int getNumChildren(){
		return _childList.size();
	}
	/**
	 * 将一个 HSprite3d 子实例添加到该 HSprite3dContainer 实例中。
	 * @param child
	 * @return
	 */
	public HSprite3d addChild(HSprite3d child){
		_childList.remove(child);
		_childList.add(child);
		child.parent=this;
		return child;
	}
	/**
	 * 将一个 HSprite3d 子实例添加到该 HSprite3dContainer 实例中。 该子项将被添加到指定的索引位置。
	 * @param child
	 * @param index
	 * @return
	 */
	public HSprite3d addChildAt(HSprite3d child,int index){
		_childList.remove(child);
		_childList.add(index, child);
		child.parent=this;
		return child;
	}
	/**
	 * 从 HSprite3dContainer 实例的子列表中删除指定的 child HSprite3d 实例。
	 * @param child
	 * @return
	 */
	public HSprite3d removeChild(HSprite3d child){
		if(_childList.remove(child)){
			child.parent=null;
		}
		return child;
	}
	/**
	 * 从 HSprite3dContainer 的子列表中指定的 index 位置删除子 HSprite3d。
	 * @param index
	 * @return
	 */
	public HSprite3d removeChildAt(int index){
		HSprite3d child=_childList.remove(index);
		child.parent=null;
		return child;
	}
	/**
	 * 确定指定显示对象是否是 HSprite3dContainer 实例的子项。
	 * @param child
	 * @return
	 */
	public boolean contains(HSprite3d child){
		return _childList.contains(child);
	}
	/**
	 * 返回位于指定索引处的子显示对象实例
	 * @param index
	 * @return
	 */
	public HSprite3d getChildAt(int index){
		return _childList.get(index);
	}
	/**
	 * 返回具有指定名称的子显示对象。
	 * @param name
	 * @return
	 */
	public HSprite3d getChildByName(String name){
		int len = _childList.size();
		for(int i=0;i=0;i--){
			_childList.get(i).parent=null;
			_childList.remove(i);
		}
	}
	//--------------------点击判断--------------------
	
	//--------------------渲染-----------------
	/**
	 * 渲染,只供引擎调用。请不要在自定义类中调用。
	 */
	public void _render(Canvas canvas,Paint paint,Camera camera){
		if(!visible){
			return;
		}
		
		canvas.save();
		camera.save();
		int alp=paint.getAlpha();
		
		paint.setAlpha((int)(alp*alpha));
		canvas.translate(x,y);
		
		camera.translate(0, 0, z);
		camera.rotate(rotationX, rotationY, rotationZ);
		camera.applyToCanvas(canvas);
		
		if(hrender!=null){
			hrender.execute(canvas,paint);
		}
		for(int i=0,len=_childList.size();i<len;i++){
			_childList.get(i)._render(canvas, paint, camera);
		}
		
		paint.setAlpha(alp);
		canvas.restore();
		camera.restore();
	}
	
}

MainActivity.java:

package com.example.cameratest;


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.hanyeah.display3d.HSprite3d;

import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.Log;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        
        
        MyView myView=new MyView(this);
        setContentView(myView);
    }
    class MyView extends SurfaceView implements Callback, Runnable{

		public MyView(Context context) {
			super(context);
			// TODO Auto-generated constructor stub
			SurfaceHolder sfh=this.getHolder();
			sfh.addCallback(this);
	        
		}
		@Override
		public void surfaceCreated(SurfaceHolder arg0) {
			// TODO Auto-generated method stub
			
			sp=new HSprite3d();
			sp.x=300;
			sp.y=600;
			
			for(int i=0;i<num;i++){
				HSprite3d sp0=new HSprite3d();
				_list.add(sp0);
				sp0.hrender=new HSprite3d.HRender() {
					@Override
					public void execute(Canvas canvas,Paint paint) {
						// TODO Auto-generated method stub
						paint.setColor(0xffff0000);
						canvas.drawRect(-150, -400, 150, 0,paint);
					}
				};
			}
			
			Thread th=new Thread(this);
			th.start();
		}
		@Override
		public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
				int arg3) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void surfaceDestroyed(SurfaceHolder arg0) {
			// TODO Auto-generated method stub
			
		}
		private float rotationX=0;
		private HSprite3d con;
		private HSprite3d sp;
		private int num=20;
		private float n=0;
		private float r=1300;
		private List_list=new ArrayList();
		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(true){
				long start =System.currentTimeMillis();
				try{
					//Log.e("hanyeah", "======================");
					
					SurfaceHolder sfh=this.getHolder();
					Canvas canvas = sfh.lockCanvas();
					canvas.drawColor(Color.BLACK);
					/*
					
					rotationX++;
					canvas.save();
			        canvas.translate(200, 300);
			        Log.e("hanyeah", canvas.getMatrix().toString());
					
					Camera camera=new Camera();
			        Matrix matrix=new Matrix();
			      
			        camera.getMatrix(matrix);
			       
			        camera.rotateX(rotationX);
			        camera.applyToCanvas(canvas);
			        Log.e("hanyeah", canvas.getMatrix().toString());
			        
			        Paint paint=new Paint();
			        paint.setColor(0xffff0000);
			        canvas.drawRect(-150, -200, 150, 200,paint);
			        canvas.restore();
			        
			        
					*/
					for(int i=0;i<num;i++){
						HSprite3d sp0=_list.get(i);
						float _n=(n+i*360f/num);
						double angle=_n*Math.PI/180;
						sp0.x=(float) (r*Math.cos(angle));
						sp0.z=(float) (r*Math.sin(angle));
						sp0.rotationY=(180-_n+360)%180-90;
					}
					Collections.sort(_list,new Comparator() {

						@Override
						public int compare(HSprite3d arg0, HSprite3d arg1) {
							// TODO Auto-generated method stub
							return arg0.z-arg1.z>0?1:-1;
						}
						
					});
					sp.removeAllChildren();
					for(int i=0;i<num;i++){
						sp.addChild(_list.get(i));
					}
					sp.z=(float) (-1.8*r);
					//sp.rotationX=10;
					n++;
					Camera camera=new Camera();
					Paint paint=new Paint();
					sp._render(canvas, paint, camera);
					sfh.unlockCanvasAndPost(canvas);
					
				}
				catch(Exception e){
					Log.e("hanyeah_onEnterFrame:", "error:"+e);
				}
				
				long end=System.currentTimeMillis();
				long delay=(long)(1000/30);
				if(end-start<delay){
					try {
						Thread.sleep(delay-(end-start));
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    
}

请注意下面几行。

canvas.translate(x,y);

camera.translate(0, 0, z);
camera.rotate(rotationX, rotationY, rotationZ);	
camera.applyToCanvas(canvas);

新建一个camera对象;camera进行3d变换;再将变换后的camera应用于canvas。

其实这里面是有问题的,我们知道2d变化的变换矩阵是3*3的,3d变换的变换矩阵是4*4的,Matrix是3*3的矩阵,只能应用于2d变换,camera能进行3d变换,应该对应一个4*4的矩阵。因此camera.applyToCanvas(canvas)必然会丢失一些信息,虽然我们不知道内部是如何实现的,导致最终的显示效果是不符合物理规律的。从最上面那张效果图也能看出来,实际应该是越大的矩形之间的间距越大,越小的矩形间距越小,可对比:3d照片墙

因此,用Camera并不能实现真正的3d效果,应用时一定要注意。

网上好多安卓3d照片墙的例子都是用的Gallery+Camera。具体可自行搜索。


之前理解有误。camera.getMatrix(matrix)是将camera应用于matrix,不是根据matrix来设置camera。


源码打包下载

« 上一篇下一篇 »

相关文章:

场景的平移和缩放  (2020-6-8 9:1:2)

安卓原生控件做时钟  (2017-3-3 16:48:11)

安卓利用反射调用@Hide隐藏函数  (2017-3-3 10:2:2)

安卓FileDescriptor  (2017-2-21 11:28:53)

安卓zxing实现二维码扫描  (2017-2-20 13:42:56)

安卓webview中调试js脚本  (2016-8-2 14:21:51)

(十)hEngine—时钟  (2015-12-21 14:34:48)

(九)hEngine—画波形图  (2015-12-21 12:4:46)

(八)hEngine—打气球小游戏  (2015-12-18 11:0:22)

(七)hEngine—类继承关系  (2015-12-17 13:11:27)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。