`
cev773wq
  • 浏览: 14623 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

Android中的3D相册

 
阅读更多

Android中的3D相册
2011年11月28日
      最近学习,工作走很忙,空闲之余,我还学习了一下Android编程和Android上的一些好玩的东西。
  这几天,我做了一个Android的3D相册,简单但是听好玩的,算是学习吧。也借鉴了一些别人的东西。这个相册的开发过程中,我用到了OpenGL ES中的图形绘制技术,包括纹理映射技术、物体旋转技术glRotatef()、物体平移技术glTranslatef(),并且用到了屏幕触控技术。
  下图是3D相册的效果图,通过滑动手机屏幕可以改变照片呈现的角度。
  
  
  
  通过单击操作来查看相册中的某张图片,按返回键会返回相册显示。
  3D相册的具体代码已上传到日志,感兴趣的可以查看,有什么不足和待改进的地方请大神们指教。
  界面实现类MySufaceView中的代码如下:
  package com.bn.ex11f;
  import java.io.IOException;
  import java.io.InputStream;
  import java.util.ArrayList;
  import java.util.Collections;
  import android.opengl.GLSurfaceView;
  import android.opengl.GLUtils;
  import android.view.KeyEvent;
  import android.view.MotionEvent;
  import javax.microedition.khronos.egl.EGLConfig;
  import javax.microedition.khronos.opengles.GL10;
  import android.content.Context;
  import android.graphics.Bitmap;
  import android.graphics.BitmapFactory;
  import static com.bn.ex11f.Constant.*;
  class MySurfaceView extends GLSurfaceView
  {
  public float screenWidth;//屏幕宽带
  public float screenHeight;//屏幕高度
  public float ratio;//屏幕宽高比
  private final float TOUCH_SCALE_FACTOR = 180.0f/320;//角度缩放比例
  private SceneRenderer mRenderer;//场景渲染器
  float mPreviousX;//上次按下位置x坐标
  float mPreviousY;//上次按下位置y坐标
  long previousTime;//上次按下的时间
  boolean isCheck=false;//是否点击查看图片
  boolean isMove=false;
  int[] textureIds=new int[PHOTO_COUNT];//n张照片纹理id数组
  float yAngle=0;//总场景旋转角度
  int currIndex=0;//当前选中的索引
  float yAngleV=0;//总场景角度变化速度
  public MySurfaceView(Context context) {
  super(context);
  mRenderer = new SceneRenderer(); //创建场景渲染器
  setRenderer(mRenderer);    //设置渲染器 
  setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//设置渲染模式为主动渲染  
  //启动一个线程根据当前的角速度旋转场景
  threadWork=true;
  new Thread()
  {
  public void run()
  {
  while(threadWork)
  {
  if(Float.isNaN(yAngle)||Float.isNaN(yAngleV))
  {
  throw new RuntimeException("yangle "+yAngle+"yAngleV="+yAngleV);
  }
  //根据角速度计算新的场景旋转角度
  yAngle+=yAngleV;
  if(Float.isNaN(yAngle))
  {
  throw new RuntimeException("yangle"+yAngle);
  }
  //将角度规格化到0~360之间
  yAngle=(yAngle+360)%360;
  if(Float.isNaN(yAngle)||Float.isNaN(yAngleV))
  {
  throw new RuntimeException("yangle "+yAngle+"yAngleV="+yAngleV);
  }
  //若当前手指已经抬起则角速度衰减
  if(!isMove)
  {
  yAngleV=yAngleV*0.7f;
  }
  //若 角速度小于阈值则归0
  if(Math.abs(yAngleV)5||Math.abs(dy)>5)
  {//触控位移大于阈值则进入移动状态
  isMove=true;
  }           
  if(isMove)
  {//若在移动状态则计算角度变化速度
  if(timeSpan!=0)
  {
  yAngleV=dx * TOUCH_SCALE_FACTOR/timeSpan;   
  }                       
  }           
  break;
  case MotionEvent.ACTION_UP:
  //若在非移动状态且角度速度为0则看选中的是哪幅照片来显示
  if(!isMove&&yAngleV==0)
  {  
  //折算出触控点在NEAR面上的位置
  float nearX=(x-screenWidth/2)*ratio/(screenWidth/2);
  float nearY=(screenHeight/2-y)/(screenHeight/2);
  //先判断点下去的是左边还是右边
  if(x>screenWidth/2)
  {//右边
  ArrayList al=new ArrayList();
  for(int i=0;i270&&tempAngle al=new ArrayList();
  for(int i=0;i180&&tempAngle纹理矩形   
  @Override
  public void onDrawFrame(GL10 gl)
  {
  //清除颜色缓存于深度缓存
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  //设置当前矩阵为模式矩阵
  gl.glMatrixMode(GL10.GL_MODELVIEW);
  //设置当前矩阵为单位矩阵
  gl.glLoadIdentity();   
  if(isCheck)
  {
  //显示某一幅照片,detail状态
  gl.glPushMatrix();
  gl.glTranslatef(0, 0f, -52f);
  gl.glTranslatef(-Board.length-Board.width*0.5f, 0, 0);
  tp.drawSelf(gl,textureIds[currIndex]);
  gl.glPopMatrix(); 
  }
  else
  {
  //显示照片组,可触控旋转选择
  gl.glPushMatrix();
  gl.glTranslatef(0, 0f, CENTER_Z); 
  yAngle=yAngle%360;
  gl.glRotatef(yAngle, 0, 1, 0);
  for(int i=0;i纹理数组,显示每幅照片
  gl.glPushMatrix();
  gl.glRotatef(i*PHOTO_ANGLE_SPAN, 0, 1, 0);
  tp.drawSelf(gl,textureIds);
  gl.glPopMatrix();
  }
  gl.glPopMatrix();
  }
  }
  @Override
  public void onSurfaceChanged(GL10 gl, int width, int height) {
  //设置视窗大小及位置
  gl.glViewport(0, 0, width, height);
  //设置当前矩阵为投影矩阵
  gl.glMatrixMode(GL10.GL_PROJECTION);
  //设置当前矩阵为单位矩阵
  gl.glLoadIdentity();
  //调用此方法计算产生透视投影矩阵
  gl.glFrustumf(-ratio, ratio, -1, 1, NEAR, 100);
  //设置为关闭背面剪裁
  gl.glDisable(GL10.GL_CULL_FACE);
  }
  @Override
  public void onSurfaceCreated(GL10 gl, EGLConfig config)
  {                 
  //关闭抗抖动
  gl.glDisable(GL10.GL_DITHER);
  //设置特定Hint项目的模式,这里为设置为使用快速模式
  gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST);
  //设置屏幕背景色黑色RGBA
  gl.glClearColor(0,0,0,0);           
  //启用深度测试
  gl.glEnable(GL10.GL_DEPTH_TEST);
  //加载n幅纹理图
  textureIds[0]=initTexture(gl,R.drawable.fj1);//图片1
  textureIds[1]=initTexture(gl,R.drawable.fj2);//图片2
  textureIds[2]=initTexture(gl,R.drawable.fj3);//图片3
  textureIds[3]=initTexture(gl,R.drawable.fj4);//图片4
  textureIds[4]=initTexture(gl,R.drawable.fj5);//图片5
  textureIds[5]=initTexture(gl,R.drawable.fj6);//图片6
  textureIds[6]=initTexture(gl,R.drawable.fj7);//图片7
  textureIds[7]=initTexture(gl,R.drawable.fj8);//图片8
  textureIds[8]=initTexture(gl,R.drawable.fj9);//图片9
  textureIds[9]=initTexture(gl,R.drawable.fj10);//图片10
  textureIds[10]=initTexture(gl,R.drawable.fj11);//图片11
  textureIds[11]=initTexture(gl,R.drawable.fj12);//图片12
  textureIds[12]=initTexture(gl,R.drawable.fj13);//图片13
  textureIds[13]=initTexture(gl,R.drawable.fj14);//图片14
  }
  }
  //初始化纹理
  public int initTexture(GL10 gl,int drawableId)//textureId
  {
  //生成纹理ID
  int[] textures = new int[1];
  gl.glGenTextures(1, textures, 0);   
  int currTextureId=textures[0];   
  gl.glBindTexture(GL10.GL_TEXTURE_2D, currTextureId);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_NEAREST);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,GL10.GL_CLAMP_TO_EDGE);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,GL10.GL_CLAMP_TO_EDGE);       
  InputStream is = this.getResources().openRawResource(drawableId);
  Bitmap bitmapTmp;
  try
  {
  bitmapTmp = BitmapFactory.decodeStream(is);
  }
  finally
  {
  try
  {
  is.close();
  }
  catch(IOException e)
  {
  e.printStackTrace();
  }
  }
  GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapTmp, 0);
  bitmapTmp.recycle();
  return currTextureId;
  }
  }
  其中,public MySurfaceView (Context context) {    }是界面类的构造部分,设置渲染器对象,根据当前的角度旋转场景的线程。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics