This article still belongs to Matrix, mainly explaining Camera. There are many Camera applications under Android, among which there are many beauty cameras. However, this Camera is not the one we usually take pictures with, but a Camera under graphic package, a professional Camera for taking pictures of views. They all work the same way, basically flattening 3D content into 2D content.

As we all know, the screen of our mobile phone is a 2D plane, so we can’t directly display 3D information. Therefore, all 3D effects we see are only 3D projection on 2D plane. The main function of Camera in this paper is to convert 3D information into projection on 2D plane. In fact, this class is more like a tool class for manipulating Matrix. Using Camera and Matrix, you can create simple 3D effects without using OpenGL.

Camera common methods table

Method category The relevant API Introduction to the
Basic method The save and restore Save and roll back
Commonly used method GetMatrix, applyToCanvas Get Matrix and apply it to canvas
translation translate The displacement
rotating Rotat (API 12), rotateX, rotateY, rotateZ All kinds of rotating
The camera position GetLocationX (API 16), getLocationY (API 16), getLocationZ (API 16) Sets and gets the camera position

There are not too many methods of Camera, many of which are similar to Canvas and Matrix, but slightly different. The previous Canvas operation and Matrix are mainly applied to 2D space, while Camera is mainly applied to 3D space.

Basic concept

Before explaining the method in detail, I will add a few basic concepts for later understanding.

3 d coordinate system

The 3d coordinate system used by the Camera is the left coordinate system, that is, the left arm points in the positive direction of x axis, the four fingers bend in the positive direction of Y axis, and the thumb points in the positive direction of Z axis.

So why do we use left-handed coordinates? I guess it’s the right hand that’s hard to do when I’m working on it. Fog. In fact, different platforms use different coordinate systems, some are left hand, some are right hand, there seems to be no unified standard, just remember that the Android platform uses the left hand coordinate system.

2D and 3D coordinates are related through the Matrix, so you can think of them as the same coordinate system, but there are differences, the important point is that the Y-axis direction is different.

Coordinate system The 2 d coordinate system 3 d coordinate system
Origin Default position The upper left corner The upper left corner
Default X direction right right
The default Y direction Under the on
Z-axis default direction There is no Straight into the screen

The 3D coordinate system is displayed in the default orientation of each coordinate axis on the screen:

Note that the default y axis direction is up, while 2D is down, and this figure does not represent the actual 3D coordinate system position.

3 d projection

A three-dimensional projection is a method of mapping points in a three-dimensional space onto a two-dimensional plane. At present, most graphics data display is still two-dimensional, so three-dimensional projection is widely used, especially in computer graphics, engineering and engineering drawing.

There are two kinds of three-dimensional projection, orthogonal projection and perspective projection.

Orthogonal projection is what we learned in mathematics, “front view, front view, side view, top view” things like that.

Perspective projection is more like taking photos, in line with the relationship between near big and far small, with a sense of three-dimensional, we use here is perspective projection.

The camera

If you have studied Unity, you should have a good understanding of the concept of camera. In a virtual 3D three-dimensional space, since we cannot directly observe this space with our eyes, we need to collect information with the help of a camera and make 2D images for us to observe. Simply put, cameras are our eyes for viewing virtual 3D space.

Android watch the View camera above the default position on the left upper corner of the screen, and it is a distance from the screen, assuming that the grey part is the phone’s screen, white is a View of the above, the camera position is below the roughly look like (in order to better display the camera position, made a space conversion diagram).

The default camera position is (0, 0, -576). Where -576 = -8 x 72, although the official documentation says the distance from the screen is -8, the actual distance tested is -576 pixels, when the distance is -10, the actual distance is -720 pixels. However, I don’t know what the value of 72 is. I have used three mobile phones for testing, with different screen sizes and pixel densities, but the results are the same. If you know, please let me know.

Basic method

The basic method has two save and restore functions, mainly to save the current state and restore to the last saved state. Usually used in pairs, the common format is as follows:

camera.save(); // Save state... Camera.retore (); // Rollback statusCopy the code

Commonly used method

These two methods are the most basic and commonly used methods in Camera.

getMatrix

void getMatrix (Matrix matrix)
Copy the code

Calculate the corresponding state of the matrix in the current state, and assign the calculated matrix to the parameter matrix.

applyToCanvas

void applyToCanvas (Canvas canvas)
Copy the code

Calculate the current state of the single order matrix, and apply the calculated matrix to the specified canvas.

translation

Disclaimer: postTranslate is used to demonstrate the translation of the Matrix in the following examples. In practice, the use of set, Pre, or Post depends on the situation.

void translate (float x, float y, float z)
Copy the code

It’s similar to 2D translation, but with an extra dimension, from only 2D to 3D, but there are a few important points to consider here.

It’s shifted along the X-axis

camera.translate(x, 0, 0);

matrix.postTranslate(x, 0);
Copy the code

Both are in the same X-axis direction, so Camera and Matrix are consistent in translation along the X-axis.

Conclusion:

Consistent means that the direction of translation and the distance of translation are the same, and by default, both of these can move the coordinate system x units to the right.

It’s shifted along the Y-axis

This is a little bit more interesting, because the coordinate systems are related to each other, but they’re in opposite y directions, so it’s very confusing. You can play it like this:

Camera camera = new Camera(); camera.translate(0, 100, 0); // camera - camera = new Matrix(); // camera - camera = new Matrix(); camera.getMatrix(matrix); Matrix. PostTranslate (0100); Log. I (TAG, "matrix: "+ matrix.toshortString ());Copy the code

Matrix Matrix = new Matrix(); Matrix Matrix = new Matrix(); Again, it’s the identity matrix. And it doesn’t seem to be a problem, because both shifts are going to be 100. (If you meet a leader who doesn’t understand technology and thinks you don’t write a lot of code, you can write it several times, but the average person will not see the problem.)

Matrix: [1.0, 0.0, 0.0] [0.0, 1.0, 0.0] [0.0, 0.0, 1.0]Copy the code

Conclusion:

Camera. Translate (0, -y, 0); With matrix. PostTranslate (0, y); The direction of translation is the same as the distance, and by default, both of these methods move the coordinate system down by y units.

Translation along the Z-axis

Not only is this fun, but it’s also easy to confuse. In both cases, the noise is only in 2D, and the z-axis gives it a sense of space.

When the View and the camera are in the same line: at this point, panning along the Z axis is equivalent to the effect of zooming. The zooming center is the (x, y) coordinate of the camera. When the View is close to the camera, it will look bigger; when it is far away from the camera, it will look smaller.

When the View and the camera are not in the same line: When the View is away from the camera, the View shrinks and approaches the projection position of the camera on the screen (usually the Z-axis, which is represented as close to the origin of coordinates in the plane). In contrast, when the View is close to the camera, it zooms in and moves away from the camera’s projection position on the screen.

I know, it says you must be forced, saying why when we are away from the camera location close to the camera in the screen projection (´, _, `), play, must think I’m kidding you are completely inconsistent, logic, but this is not contradictory here, because it is in 3 d space away from, and close to just in 2 d space projection, See below.

Assume that the large rectangle is the phone screen, the small white rectangle is the View, and the camera is at the top left corner of the screen. Please note the distance between the View above and the camera, the size of the View below, and the distance from the top left corner (where the camera is projected on the screen).

As to why this is so, because we are human is like that, when we look into the distance, the line of sight will eventually disappear on the apparent horizontal line, if you stand in the middle of the two parallel lines, looks like they will be at a distance (depending on the flat line) intersection, although both in 3 d space distance is the same, but on the 2 d projection is more and more close, As shown below (picture from network):

Conclusion:

It is difficult to talk about 3D effect translation, but you can actually experience it yourself, after all, we live in 3D space, take a piece of paper to simulate the View, use your eyes as a camera, move the paper back and forth in front of your eyes, try it a few times and you will get a general idea of what is going on.

translation The key content
The x axis 2D is the same as 3D.
y 2D is the opposite of 3D.
The z axis Near big far small, line of sight intersection.

rotating

Rotation is the core of Camera 3D, but it’s not really 3D, it’s fake 3D, because the View has no thickness.

// (API 12) Allows the View to rotate around the x, y, and z axes simultaneously. void rotate (float x, float y, float z); // Rotate View around a single axis void rotateX (float deg); void rotateY (float deg); void rotateZ (float deg);Copy the code

This thing nonsense theory is not easy to understand, directly above:

The above three pictures are rotation around x axis, y axis and Z axis respectively. The reason why z axis is not shown is that z axis is perpendicular to the mobile phone screen, and the projection on the screen is a point.

There are a few things to note about rotation:

Center of rotation

The rotation center defaults to the origin of the coordinates, which is the upper left corner position for the image.

We all know that in 2D it’s possible to specify the center of action whether it’s rotation, split-cut or zoom, but in 3D there’s no default method. What if we want to rotate the image around the center? This is done using the method we mentioned in the Matrix principle:

Matrix temp = new Matrix(); // temporary Matrix variable this.getmatrix (temp); PreTranslate (-centerx, -centery); // Use pre to move the rotation center to the same position as the Camera. temp.postTranslate(centerX, centerY); // Use post to move the View to its original positionCopy the code

Official example -Rotate3dAnimation

When it comes to 3D rotation, the most classic one is Rotate3dAnimation in ApiDemo. I have seen many blog posts that modify the effect of Rotate3dAnimation according to Rotate3dAnimation. This is a very classic 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; /** * Create a 3D animation that rotates about the Y-axis with depth adjustment and can specify the center of rotation. * * @param fromDegrees starting Angle * @param toDegrees ending Angle * @param centerX rotating centerX coordinates * @param centerY rotating centerY coordinates * @param depthZ * @param reverse true indicates a sequence from 0 to depthZ, Public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) { mFromDegrees = fromDegrees; mToDegrees = toDegrees; mCenterX = centerX; mCenterY = centerY; mDepthZ = depthZ; mReverse = reverse; } @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(); // Interpolate depth if (mReverse) {camera. Translate (0.0f, 0.0f, mDepthZ * interpolatedTime); } else {camera. Translate (0.0f, 0.0f, mDepthZ * (0.0f-interpolatedTime)); } // Rotate camera. RotateY (degrees) around the y axis; camera.getMatrix(matrix); camera.restore(); // Adjust the center point matrix. PreTranslate (-centerx, -centery); matrix.postTranslate(centerX, centerY); }}Copy the code

As you can see, it takes only a few dozen lines of code, while the core code (with comments) is only a few lines long and easy to understand. However, this piece of code is still unfinished code (how else is it called ApiDemo?). And many people don’t know how to modify it.

I wonder if you could find a problem when using, the same code in different phone display effect is also different, the pixel density lower phones, rotating effect is more normal, but in the higher pixel density effect will be very exaggerated displayed on the phone, what happens to the specific, just look at the specific effect.

As you can see, the picture is not only because deformation distortion, and in the middle period of because excessive deformation cause pictures cannot show, of course, the distortion of a single mobile phone, you can use depthZ bluff, when depthZ set numerical compare greatly, image will be far away from the camera, at the same time in the flip relatively far distance, would not seem serious distortion, But that doesn’t hide the fact that it looks different on different phones.

How to solve this problem?

In fact, it is not difficult to solve the problem, just need to modify two values, which are MPERSP_0 and MPERSP_1 in Matrix, which have been ignored by many developers

Here is the modified code (highlights have been highlighted):

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; // /** * Creates a 3D animation that rotates around the Y-axis with depth adjustment and can specify the rotation center. * @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; 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(); // Interpolate depth if (mReverse) {camera. Translate (0.0f, 0.0f, mDepthZ * interpolatedTime); } else {camera. Translate (0.0f, 0.0f, mDepthZ * (0.0f-interpolatedTime)); } // Rotate camera. RotateY (degrees) around the y axis; camera.getMatrix(matrix); camera.restore(); Float [] MPERSP_0 and MPERSP_1 float[] mValues = new float[9]; matrix.getValues(mValues); MValues [6] = mValues[6]/scale; MValues [7] = mValues[7]/scale; // matrix. SetValues (mValues); PreTranslate (-centerx, -centery); preTranslate(-centerx, -centery); matrix.postTranslate(centerX, centerY); }}Copy the code

Effect after modification:

The difference between the top and bottom is still very big, by the way, attach the test code, layout file is not written, just put an ImageView.

setContentView(R.layout.activity_test_camera_rotate2); ImageView view = (ImageView) findViewById(R.id.img); assert view ! = null; view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Compute centerpoint (here using the center of the view as the rotation center) Final float centerX = v.getwidth () / 2.0f; Final float centerY = v.getheight () / 2.0f; // The parentheses are (context, start Angle, end Angle, X-axis center point, Y-axis center point, depth, Rotate3dAnimation rotation = new Rotate3dAnimation(MainActivity.this, 0, 180, centerX, centerY, 0f, true, 2); rotation.setDuration(3000); Rotation. SetFillAfter (true); // Keep the effect of rotation.setinterpolator (new LinearInterpolator()); // Set the interpolator v.startAnimation(rotation); }});Copy the code

The camera position

Translate and Rotate can be used to control the object and rotate can be used to move the camera itself, but these methods are not often used (see add time).

void setLocation (float x, float y, float z); // (API 12) Set the camera position. The default position is (0, 0, -8) float getLocationX (); // (API 16) get the x coordinate of the camera position, same as float getLocationY (); float getLocationZ ();Copy the code

We know that the distance between objects is relative. Moving an object away from the camera has the same effect as moving the camera away from the object.

While setting the camera’s position isn’t very useful, there are a few things to note:

The z distance between the camera and View cannot be 0

This is easy to understand, when you put an object in the same position as the camera, the camera will not be able to photograph the object, just as if you hold a card on the side of a mobile phone, the camera will not be able to photograph the object.

The virtual camera can take pictures before and after

You can still see the View as it approaches the camera and passes over the camera position, and the View becomes smaller and smaller as you move further and further away from the camera. You can think of it as having a front camera and a rear camera.

Camera shift to the right equals View shift to the left

The state of the View depends only on the relative position between the View and the camera, but due to different units, a camera shift equals 72 pixels of View shift. The following two pieces of code are equivalent:

Camera camera = new Camera(); Camera. SetLocation (1, 0, - 8). // Camera default position is (0, 0, -8) Matrix Matrix = new Matrix(); camera.getMatrix(matrix); Log.e(TAG, "location: "+matrix.toShortString() ); Camera camera2 = new Camera(); Camera2. Translate (- 0, 72); Matrix matrix2 = new Matrix(); camera2.getMatrix(matrix2); Log.e(TAG, "translate: "+matrix2.toShortString() );Copy the code

Results:

Location: [1.0, 0.0, 72.0] [0.0, 1.0, 0.0] [0.0, 0.0, 1.0] translate: [1.0, 0.0, 72.0] [0.0, 1.0, 0.0] [0.0, 0.0, 1.0Copy the code

The main points of

  • The View display state depends on the relative position between the View and the camera
  • The z-axis distance between the View and the camera cannot be 0

Tip: For the camera and View position, you can turn on the rear camera of your phone, take a card, rotate it, pan it, or move it around, and watch how the card changes on the screen.

conclusion

This article mainly explains some basic knowledge about Camera and Matrix. If Camera is used properly, it can create a lot of cool effects. I’m here to introduce some cool controls.

Build an Android 3D rotating container from scratch

The resources

Camera FlipShare builds an Android 3D rotating container from scratch

About Me

Author’s Microblog:@GcsSloop