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.
⚠️ Warning: Turn hardware acceleration off before testing the examples in this article.
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? ~~ probably because the right hand is not convenient when rushing to work, 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. I tested three phones with different screen sizes and pixel densities, but the results were the same.
This magic number can be found in Skia, the underlying graphics engine on Android. In Skia, the position unit of Camera is inches, and the conversion unit between inches and pixels is fixed at 72 pixels in Skia, but this conversion unit is copied in Android.
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; // <------- pixel density /** * Creates a 3D animation that rotates around the Y-axis with depth adjustment and can specify the center of rotation. * @param context <------- add context to prepare for getting pixel density * @param fromDegrees start Angle * @param toDegrees end Angle * @param centerX rotation centerX coordinate * @param Reverse True indicates the rotation center from 0 to depthZ, Public Rotate3dAnimation(Context Context, float fromDegrees, float toDegrees, float centerX, float centerY, 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.
FlipShare
Build an Android 3D rotating container from scratch
Sequel:
- Android Custom control advanced 01- Custom control development routines and processes
- Android custom controls advanced 02-Canvas drawing graphics
- Android custom controls advanced 03-Canvas Canvas operation
- Android custom controls advanced 04-Canvas picture text
- Android custom controls advanced 05-PATH basic operations
- Android custom control advanced 06-Path bezier curve
- The end of Android Custom controls Advanced 07-Path
- Android custom controls advanced 08-PathMeasure details
- Android custom control advanced 09- Control core Matrix principle
- Android custom control advanced 10- control core Matrix Camera
- Android custom controls Advanced 11- Event distribution mechanism principle
- Android Custom controls Advanced 11- Event distribution mechanism 01
- Android Custom controls Advanced 12- Event distribution mechanism principle 02
- Android custom controls advanced 13-MotionEvent details
- Android Custom Controls Advanced 14- Special controls event handling scheme