Android Camera&Matrix image transformation

Camera与Matrix

In the Android UI system, Camera acts as a camera, whether it is system imaging or UI drawing. Can't do without Camera. But in the Android system, there are two kinds of Cameras, one is for visual imaging (photography, video), and the other is for graphics rendering (games, maps, 3D), in fact, both are inseparable from Matrix, so the essence It can be understood that one is responsible for imaging objects other than the camera, and the other is responsible for the imaging of Android View. Here we focus on introducing the Camera for system UI imaging.

        UI imaging requires the use of a canvas and a coordinate system. In the Android system, View is finally displayed in two-dimensional form, but Camera is three-dimensional imaging. When encountering this problem, we need to use Matrix here, which is used to convert three-dimensional into two-dimensional. The principle is that the Matrix matrix transfers the projection of the Camera to the Canvas, so we can see the 3D graphics displayed in the two-dimensional coordinate system.

For Matrix please see:

Detailed explanation and advanced of the most complete method of android matrix (complete article)

Detailed explanation of using Camera and Matrix to achieve 3D effect in Android

 

 

Camera coordinate system and Android coordinate system

  The camera's coordinate system is a left-handed coordinate system. Extend the left hand, let the thumb and index finger form an L shape, the thumb is to the right, the index finger is up, and the middle finger is pointing forward, so that we have established a left-hand coordinate system. The pointing of the thumb, index finger, and middle finger represents the x, y, and z axes respectively. positive direction. As shown below:

Here are some details:

1. The camera is located at the coordinate point (0,0), which is the upper left corner of the view;

2. camera.translate(10, 20, 30) means to move the observed object to the right by 10, up by 20, and forward by 30 (that is, keep the object away from the camera, so that the object will become smaller);
3, camera.rotateX (45) means to rotate 45 degrees clockwise around the x-axis. For example, if the center line of the object coincides with the x-axis, rotating 45 degrees clockwise around the x-axis means that the upper half of the object is turned inward and the lower half is turned outward;
4, camera.rotateY(45) means Rotate 45 degrees clockwise around the y-axis. For example, if the center line of the object coincides with the y-axis, rotating 45 degrees clockwise around the y-axis means that the right half of the object is turned inward and the left half is turned outward;
5, camera.rotateZ(45) means Rotate 45 degrees clockwise around the z-axis. For example, if the center line of the object coincides with the z-axis, a 45-degree clockwise rotation around the z-axis means that the top half of the object is flipped to the left, and the bottom half is flipped to the right;

 

Android coordinate system is two-dimensional

1. The camera is located at the coordinate point (0,0), which is the upper left corner of the view;

2. Vertically downward is the positive direction of the y-axis

3. Vertically to the right is the positive direction of the x-axis

 

Comparison of two types of coordinate systems

 

Camera与Matrix API

Camera creates a new Camera instance without any transitions

  • applyToCanvas(Canvas canvas) Calculates the corresponding matrix according to the current transformation, and then applies it to the specified canvas
  • getLocationX() Get the x coordinate of the Camera
  • getLocationY() Get the y coordinate of the Camera
  • getLocationZ() Get the z coordinate of the Camera
  • getMatrix(Matrixmatrix) Get the Matrix object after conversion
  • restore() restores the saved state
  • rotate(float x, float y, float z) rotate along X, Y, Z coordinates
  • rotateX (float you)
  • rotateY (float deg)
  • rotateZ (float you)
  • save() saves the state
  • setLocation(float x, float y, float z)
  • translate(float x, float y, float z) translate along the X, Y, Z axes

Matrix related methods are as follows

  • setTranslate(floatdx, floatdy): control the Matrix to translate
  • setSkew(floatkx,floatky,floatpx,floatpy): Control the Matrix to tilt with px, py as the axis, kx, ky as the tilt distance in the X and Y directions
  • setRotate(floatdegress): Controls the Matrix to rotate, and degress controls the angle of rotation
  • setRorate(floatdegress,floatpx,floatpy): Set the rotation with px, py as the axis, and degress controls the rotation angle
  • setScale(floatsx,floatsy): Set the Matrix for scaling, sx, sy control the scaling in the X, Y directions
  • setScale(floatsx,floatsy,floatpx,floatpy): Set the Matrix to scale with px, py as the axis, sx, sy control the scaling in the X and Y directions

The API provides three operations: set, post and pre. Let’s take a look at the key points below. The effect will be used later.

post is a post-multiplication, the current matrix is ​​multiplied by the matrix given by the parameter. Post can be used multiple times in a row to complete the entire transformation required.


pre is the pre-multiplication, the matrix given by the parameter is multiplied by the current matrix. So the operation happens at the front of the current matrix.

 

director and camera

In 3D photography, the director controls the position of the lens to present different effects, and the effect of the camera at different positions in space is different. Since we cannot directly observe this space with our eyes, we need to use cameras to collect information and make 2D images for us to observe. In simple terms, the camera is our eye to observe the virtual 3D space, and we are both the director and the audience . All we see on TV are three-dimensional projections.

Note: The default camera position is (0, 0, -576)

3D projection

3D projection is a method of mapping points in 3D space onto a 2D plane. Since the vast majority of graphics data are still displayed in two-dimensional, three-dimensional projection is widely used, especially in computer graphics, engineering and engineering drawing.

There are generally two types of 3D projection, orthogonal projection  and  perspective projection .

Orthographic projection is the "front view, front view, side view, top view" that we have learned mathematically.

Perspective projection is more like taking pictures, in line with the relationship between near and far , and has a three-dimensional sense. What we use here is perspective projection.

 

actual combat

Simple example

The original image transformation diagram

The second picture is actually the camera moving to x, y, and z respectively (the transition of this effect, we can assume that when the original View image has been drawn, take a camera to shoot, and then project the projection through the Material again Go to Canvas)

code show as below:

public class CameraTestView extends View{

    private Camera camera;
    private Matrix matrix;
    private Paint paint;
    public CameraTestView(Context context, AttributeSet attrs) {
        super(context, attrs);
        camera = new Camera();
        matrix = new Matrix();
        setBackgroundColor(Color.parseColor("#3f51b5"));
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setStyle(Style.FILL);
        paint.setColor(Color.parseColor("#ff4081"));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        matrix.reset();
        camera.save();
        camera.translate(10, 50, -180);
        camera.getMatrix(matrix);
        camera.restore();
        canvas.concat(matrix);
        
        canvas.drawCircle(60, 60, 60, paint);
    }

}

 

3D Rotation Animation Example

public class Rotate3dAnimation extends Animation {
    private final float mFromDegrees;
    private final float mToDegrees;
    private final float mCenterX;
    private final float mCenterY;
    private final float mDepthZ;
    private final boolean mReverse;
    private Camera mCamera;
    float scale = 1;    // 

    /**
     * 创建一个绕y轴旋转的3D动画效果,旋转过程中具有深度调节,可以指定旋转中心。
     * @param context     
    public Rotate3dAnimation(Context context, float fromDegrees, float toDegrees,
                             float centerX, float centerY, float depthZ, boolean reverse) {
        mFromDegrees = fromDegrees;
        mToDegrees = toDegrees;
        mCenterX = centerX;
        mCenterY = centerY;
        mDepthZ = depthZ;
        mReverse = reverse;

        // 获取手机像素密度 (即dp与px的比例)
        scale = context.getResources().getDisplayMetrics().density;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        mCamera = new Camera();
    }

    @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));
        }

        // 绕y轴旋转
        camera.rotateY(degrees);

        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);
    }
}

 

Of course, the above implementation is more complicated, we can use Animation or Animator to achieve, through rotationY animation.

 final float targetVal = 180f;
            final int width = v.getMeasuredWidth();
            v.setPivotX(width/2);
            v.clearAnimation();
            final Drawable  before= getResources().getDrawable(R.mipmap.img_cake);
            final Drawable  after = getResources().getDrawable(R.mipmap.img_heart);
            Animator animator = ObjectAnimator.ofFloat(v,"rotationY",targetVal,360);
            animator.setDuration(1000);
            v.setRotationY(180f);
            v.setBackground(before);
            final float distance = v.getCameraDistance();  //获取相机距离

            ((ValueAnimator)animator).addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    float fraction = animation.getAnimatedFraction();

                    if(Math.abs(360+180)/2<=Math.abs(value)){
                        v.setBackground(after);
                    }
                    float f = (float) Math.abs(Math.sin(Math.toRadians(fraction * targetVal)));
                    Log.i("Animator","value="+value +" ,fraction="+fraction+", f="+f);
                    v.setCameraDistance(distance + f*(distance*width)/2);
                }
            });

            animator.start();
        }

 

The camera requires from near to far, and then from far to near, here we use the trigonometric function sin to achieve

float f = (float) Math.abs(Math.sin(Math.toRadians(fraction * targetVal)));

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324997828&siteId=291194637