zoukankan      html  css  js  c++  java
  • Camera三维动画

    一、概述

    在Android中说到3D开发,我们首先想到的是OpenGL,但用起来比较复杂繁琐,不适合做应用级别的3D变换。Android为我们提供了一个简化版的3D开发入口:Camera(这里的Camera位于android.graphics下,需要区分android.hardware下用于拍照的Camera类):

     

    (1)Camera工作原理

    我们看一下android.graphics下的Camera介绍:

    /**
     * A camera instance can be used to compute 3D transformations and
     * generate a matrix that can be applied, for instance, on a
     * {@link Canvas}.
     */

    Camera可以做3D变换并且导出一个matrix供其他对象(如Canvas)使用。

    官方解释非常精准地表达了Camera的作用,我再来扩展一下:Camera并不直接操纵View或绘制类来实现变换效果,而是通过自身3D变换后导出结果到一个matrix,然后将这个matrix与其他实例的的matrix对接!

    比如Canvas的matrix

      canvas.setMatrix(matrix);
      canvas.concat(matrix);

    或者Animation 中Transformation的matrix

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            final Matrix matrix = t.getMatrix();
        }

    举个简单的例子:

     绕Y轴旋转45度

    代码如下:

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            camera.save();  //保存Camera
            camera.rotateY(45);   //绕Y轴旋转45度
            camera.getMatrix(matrix);   //Camera将变换输出到Matrix
            camera.restore();   //恢复Camera
            matrix.preTranslate(-dog.getWidth() / 2, -dog.getHeight() / 2);  //旋转之前将图片中心点与坐标系原点对齐
            matrix.postTranslate(dog.getWidth() / 2, dog.getHeight() / 2);   //旋转之后将图片移动回原位置
            matrix.postTranslate(50, 70);   //因旋转后图片左上角超出了View边界,将其向右下角移动一点,以便显示完整
            canvas.concat(matrix);  //将Camera导出的Matrix和Canvas对接
            canvas.drawBitmap(dog, 0, 0, paint);  //绘制图片
        } 

    那么,我们来总结一下Camera的工作原理:Android中所有几何变换的底层数学模型都是matrix矩阵变换,Camera有很好的3D变换的方法,且变换结果可以输出到指定的matrix上,我们继而将其映射到Canvas或Transformation等的matrix上,使其达到相同的3D变换效果。这里Camera实际上扮演了3D变换方案输出者的角色。

     利用Camera实现3D变换

    (2)两个坐标系

    到目前为止,你肯定会有一个疑问:既然Camera和Canvas的几何变换对应的都是matrix,那Canvas为什么不自己提供一套3D接口,而要去借用Camera呢?这要牵扯出更底层的设计。

    首先,Canvas是做View绘制的,其对应的坐标系自然是View的二维平面坐标系,在Android中其设计如下:

    Android View坐标系

    让Canvas基于平面坐标系输出三维空间变换矩阵,实在是强人所难!

    Camera就不一样了,其底层依赖OpenGL,玩的就是空间坐标系,其设计符合左手坐标系(这点网上有人怀疑,本人验证确认轴向符合左手坐标系,但是Y轴旋转方向是反的):

    Camera空间坐标系

    将手机竖直正面放置,向右是X轴正向,向上是Y轴正向,垂直屏幕向里是Z轴正向。

    两个坐标系的区别:

    坐标系2D3D
    原点位置 左上角
    X轴正向
    Y轴正向
    Z轴正向 垂直屏幕向里

    所以Camera是基于空间坐标系,可以提供很好的3D变换方法;这是Canvas们无法做到的。

    既然说到了坐标系,我们不妨继续往下刨:既然Camera和Canvas几何变换的底层模型都是矩阵变换,那我能不能绕过Canvas,直接去操作它的Matrix,让它像Camera那样做3D变换?对不起,就算你的大学几何学得很好,答案依然是不可能(尽管我知道这很容易被打脸,有人可能会说通过Matrix的setPolyToPoly方法可以实现任意变换,我只能说它依然只是2D模仿3D,不是真正意义上的3D空间变换)。为什么呢?这要深入研究一下Matrix了:

    实际上,在Android中也有两个Matrix类:

    matrix

    •  一个位于android.graphics包下,是一个3*3的矩阵,只能表示二维平面的几何变换,Canvas、Transformation和Camera输出的Matrix都是这个类
    • 另一个位移android.opengl包下,是一个4*4的矩阵,可以表示三维空间的几何变换,Camera的底层运算就是基于这个Matrix类

     你可能也发现了,Camera做空间变换所用到的Matrix和最终输出到的Matrix不是同一个Matrix!为什么这样设计呢?我是这样理解的:

    最初,View运行在二维坐标系,OpenGL存在于三维坐标系,两者互不相容;

    后来,开发View的同学也希望做出像OpenGL里酷炫的三维效果,可是又不想因此引入复杂的OpenGL;

    于是Google就基于OpenGL造了一个轻量级的3D开发工具——Camera,因为是方便View开发的同学用的,自然输出结果就是基于二维平面的Matrix了。

    至于Camera将四阶矩阵映射成三阶矩阵的算法, 被封装在了Camera类getMatrix方法的native层,有兴趣可以去研究。


     二、Camera实现3D动画

    知道了Camera的三维变换原理,实现三维动画就不难了。连续的变换就是动画,连续的3D变换不就是3D动画嘛。

    下面参考AppDemo的示例,效果如下:

     Camera 3D翻转动画

    自定义一个3D旋转的Animation,重写applyTransformation方法,对接Camera和Transformation的Matrix,核心代码:

        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            final float fromDegrees = mFromDegrees;
            float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
            final float centerX = mCenterX;
            final float centerY = mCenterY;
            final Camera camera = mCamera;
            final Matrix matrix = t.getMatrix();
            camera.save();
    
            // 调节深度,
            if (mReverse) {
                camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
            } else {
                camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
            }
    
    //        camera.rotateY(degrees);  // 绕y轴旋转
            camera.rotateX(degrees);  // 绕x轴旋转
    //        camera.rotateZ(degrees);  // 绕z轴旋转
    
            camera.getMatrix(matrix);
            camera.restore();
    
            // 修正透视效果,主要修改 MPERSP_0 和 MPERSP_1
            float[] mValues = new float[9];
            matrix.getValues(mValues);                //获取数值
            mValues[6] = mValues[6] / scale;            //数值修正
            mValues[7] = mValues[7] / scale;            //数值修正
            matrix.setValues(mValues);                //重新赋值
    
            // 调节中心点
            matrix.preTranslate(-centerX, -centerY);    //移到物体中心
            matrix.postTranslate(centerX, centerY);     //移回原位置
        }

    Github源码:https://github.com/JiaxtHome/AnimDemo
     


    三、总结

     现在我们已经知道简单的3D变换应该首先考虑Camera,下面总结一下Camera的关键API:

    类别相关方法功能介绍
    基本方法 save、store 保存、回滚
    对接方法 getMatrix、applyToCanvas 获取Matrix、对接画布
    变换方法 translate、rotate、rotate* 位移、旋转
    相机位置 setLocation、getLocation* 设置、获取相机位置

    Camera的方法并不多,其3D效果主要是通过旋转方法实现的。尽管如此,还是可以做出很多既实用又酷炫的动画切换效果,下面列举一些Github上的优秀例子:

    Github源码地址:https://github.com/githubwing/ThreeDLayout

     22

    Github源码地址:https://github.com/ImmortalZ/StereoView

     

    Github源码地址:https://github.com/youxiaochen/WheelView-3d

    参考文献:

    三维空间矩阵变换

    二维图形的矩阵变换(一)——基本概念

    安卓图形matrix矩阵变换的数学原理及代码

    HenCoder Canvas对绘制的辅助和Matrix

    GcsSloop 安卓自定义View进阶-Matrix Camera

    android matrix 最全方法详解与进阶(完整篇)

    Android中利用Camera与Matrix实现3D效果详解

    Android Camera&Matrix图像变换

     

  • 相关阅读:
    软件需求与分析课堂讨论一
    问题账户需求分析
    个人阅读计划
    个人总结
    团队其他各组项目意见
    大白鱼备考云笔记冲刺周期第七天
    大白鱼备考云笔记冲刺周期第六天
    大白鱼备考云笔记冲刺周期第五天
    大白鱼备考云笔记冲刺周期第四天
    大白鱼备考云笔记冲刺周期第三天
  • 原文地址:https://www.cnblogs.com/not2/p/10895801.html
Copyright © 2011-2022 走看看