Camera的研究与封装

本文出自Zone的博客,如需转载请标明出处,尊重原创谢谢 博客地址:https://luhaoaimama1.github.io/2017/01/23/Camera调研/

关于坐标轴分析 最终理解 Camera 与封装lib

View,Camera 坐标轴分析

下面的多图在此项目中

ViewCamera(锚点:左上角点)Camera Lib
同view
左手坐标系 判断依据camera视角的图片锚点坐标系同view

camera视角的图片锚点坐标系:其实用的也是左手坐标系,但是为什么会围绕X旋转180呢?

回答:因为我们的API名字叫做Camera 他是以摄像机的角度去 理解做操作的; 可以自己拿手机拍照去 通过移动摄像机 而让里面的物体移动。就会明白了。

Tips:Camera真实没有移动(因为getLocationX、Y、Z都是没有移动的),只是以他的角度去理解;

理解 Camera的translate与rotate

    /**
     * Applies a translation transform on all three axis.
     * 
     * @param x The distance to translate by on the X axis
     * @param y The distance to translate by on the Y axis
     * @param z The distance to translate by on the Z axis
     */
    public native void translate(float x, float y, float z);
     /**
     * Applies a rotation transform around all three axis.
     * 
     * @param x The angle of rotation around the X axis, in degrees
     * @param y The angle of rotation around the Y axis, in degrees
     * @param z The angle of rotation around the Z axis, in degrees
     * 
     * @see #rotateX(float)
     * @see #rotateY(float)
     * @see #rotateZ(float)
     */
    public native void rotate(float x, float y, float z);

看到没关键点是-> axis 的位移与旋转

想要理解上面 先跟我做一些事情

锚点:左上角点

拿起你的手机 平行面对你,已左上角为手机坐标系原点(任何时候 包括 旋转位移以后)。

  • 围绕Y轴做旋转45,然后X位移一段距离distanceX。在旋转75°

从中明白了什么

锚点:左上角点

  • 明白什么叫做 axis 的位移与旋转。 就是每次操作都是以 手机左上角(相当于咱们的图片左上角)为坐标系

  • 从整体来看我们经过了 三次操作,以每次操作之前,手机左上角的点为例,第一次操作点 记为 operate1,依次 operate2 ,operate3.那么从整体来看 我相当于 operate1 X轴:distanceX的点 rorate1 围绕operate1 旋转45°,然后围绕本身operate3 75°。总结为:

    • 既 旋转之后 +位移操作,就是相当于 [旋转之前+位移]之后的点 围绕 旋转之前的点 旋转,

    • 旋转不加位移 就相当于 [锚点] 旋转。

    • 这个手机外边的世界就暂且叫做合成坐标系,而手机左上角则暂且叫做锚点坐标系;

      不管做了多少次操作都遵循这个 规律;

Camera 传说中 移动旋转点的 解释

camera的合成坐标系 是

Matrix temp = new Matrix();     // 临时Matrix变量
this.getMatrix(temp);           // 获取Matrix
temp.preTranslate(-centerX, -centerY);  // 使用pre将旋转中心移动到和Camera位置相同。
temp.postTranslate(centerX, centerY);   // 使用post将图片(View)移动到原来的位置

temp.preTranslate操作:是把最开的图片移动位置。

center为例: 左上角(锚点)是center点了,因为开始的图片变了位置,左上角(锚点)对于camera的合成坐标系依然没变

temp.postTranslate操作 移动的是 camera的合成坐标系

Tips: 旋转的中心点依然是左上角点(锚点 例子中的center点),而不是post中的点。

最后我还要提示下:

我们的视角 就是view坐标系(所有View 大小 padding等等都是参考此来设计的);

  • camera translate,rotate 是在合成坐标系里 的视角 ,位移旋转, 位移和旋转的值都是相对于 合成坐标系里 的视角,因为里面有摄像机

    假如camera向下移动100 以我们的视角可能是89等,因为以camera坐标系的视角(包含摄像机 Z轴 视差等等因素)判定的;

  • Matrix postTranslate 系列,则是 对于合成坐标系的操作, 更改的位置和旋转等。都是 相对于View坐标系的值

    假如Matrix向下移动100 就是100 这是以View坐标系既我们的视角来判定的;

实例讲解

此demo在此项目中

左图关键代码:

      camera.save();
        camera.rotateX(-rotateDegree);
        camera.getMatrix(matrix);
        camera.restore();
        // -viewWidth / 2 保持着竖线高度不变的,其他会倾斜;
        matrix.preTranslate(-viewWidth / 2, 0);
        matrix.postTranslate(viewWidth / 2, (float) axisY);

右图关键代码:把 postTranslate移动的 移动到了camera.transalte

 camera.save();
        camera.rotateX(-rotateDegree);
        camera.translte(0,(float) axisY,0)
        camera.getMatrix(matrix);
        camera.restore();
        // -viewWidth / 2 保持着竖线高度不变的,其他会倾斜;
        matrix.preTranslate(-viewWidth / 2, 0);
        matrix.postTranslate(viewWidth / 2, 0);

这里的问题是,0度的时候 还能看到?因为你camera.translte(0,(float) axisY,0),因为Y不在是0,和摄像机不保持相同高度后是可以看到的。所以这里用matrix.postTranslate比较好

这还算好的 如果摄像机移动Z轴的话 会出现和严重的问题,因为这仅仅是一段代码补全就暂且不说了;

封装Lib

通过上面的理解 我们开始封装lib

  1. 首先更改Camera视角的坐标系为view坐标系 而不是camera的视角。

  2. 我们希望setPivot(float px, float py)或者setPivot(PivotType pivotType)的预设方式;``` /**

    • 0---1---2
    • | |
    • 7 8 3
    • | |
    • 6---5---4 */ public enum PivotType { None, LeftTop, LeftCenter, LeftBottom, RightTop, RightCenter, RightBottom, CenterTop, Center, CenterBottom, }
  3. getMatrix的时候,matrix.preTranslate(x,y);操作, 但是不要postTranslate操作 因为post是移动整个camera的合成坐标系的;

  4. 最后我希望 类似AE那种可以绑定parent的形式,并且parent也可以绑定

关于第4点,未改进的方式,记得这个上面提到的规律吧---->旋转之后 +位移操作,就是相当于 [旋转之前+位移]之后的点 围绕 旋转之前的点 旋转

        cameraFinal.translate(parent.parent.tx, parent.parent.ty, parent.parent.tz);
        cameraFinal.rotate(parent.parent.rx, parent.parent.ry, parent.parent.rz);
        cameraFinal.translate(parent.tx, parent.ty, parent.tz);
        cameraFinal.rotate(parent.rx, parent.ry, parent.rz);
        cameraFinal.translate(tx, ty, tz);
        cameraFinal.rotate(rx, ry, rz);

关于第4点,改进成

   List<Layer> parentlist = new ArrayList<>();
        parentlist.add(this);
        Layer rootParent = parent;
        while (rootParent!=null) {
            parentlist.add(rootParent);
            rootParent = rootParent.parent;
        }
        cameraFinal.save();
        for (int i = parentlist.size() - 1; i >= 0; i--) {
            Layer layer = parentlist.get(i);
            cameraFinal.translate(layer.tx, layer.ty, layer.tz);
            cameraFinal.rotate(layer.rx, layer.ry, layer.rz);
        }
        cameraFinal.getMatrix(matrix);
        cameraFinal.restore();

最后封装成两个类

Camera封装类CameraCorrect 绑定parent封装类Layer

demo范例:

Reference&Thanks:

https://github.com/zhangyuChen1991/Roll3DImageView