In the OpenGL coordinate system article, the following formula is obtained according to the coordinate transformation of points:
This formula represents a transformation of the coordinate system every time you multiply it by a matrix.
Convert to shader script language as follows:
attribute vec4 a_Position;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ProjectionMatrix;
uniform mat4 u_ViewMatrix;
void main()
{
gl_Position = u_ProjectionMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;
}
Copy the code
This article is mainly on the projection matrix to analyze.
OpenGL uses projection matrix when viewing space is converted to clipping space. In the shader script, you also need to provide a projection matrix to the corresponding u_ProjectionMatrix variable.
First bind to the corresponding variable in the program, and then assign a value to the variable.
// Bind to the corresponding variable in the shader script
private static final String U_ProMatrix = "u_ProjectionMatrix";
private int uProMatrixLocation;
uProMatrixLocation = glGetUniformLocation(mProgram,U_ProMatrix);
// assign values to variables. ProjectionMatrix is the projectionMatrix
glUniformMatrix4fv(uProMatrixLocation,1.false,projectionMatrix,0)
Copy the code
As mentioned above, the projection matrix creates a viewframe that trims the object coordinates. The resulting clipping coordinates are then passed through perspective division to obtain normalized device coordinates. The normalized device coordinates are then transformed by the viewport to map the coordinates to the screen.
OpenGL provides two kinds of projection: orthogonal projection and perspective projection.
Orthogonal projection matrix
Whether it is orthogonal projection or perspective projection, the object in the body of the view is finally projected on the near plane, which is also a key step in the transformation of 3D coordinates to 2D coordinates.
The coordinates in the near plane are then converted to normalized device coordinates and mapped to the screen viewport.
In order to solve the previous image stretching problem, it is necessary to ensure that the aspect ratio of the near plane is consistent with the aspect ratio of the viewport, and the shorter side is taken as the standard of 1, so that the image remains centered.
OpenGL provides the Matrix. OrthoM function to generate orthogonal projection matrices.
/**
* Computes an orthographic projection matrix.
*
* @paramM returns the result orthogonal projection matrix *@paramMOffset Specifies the offset. The default value is 0@paramLeft Left plane distance *@paramRight distance from the right plane *@paramBottom Distance from the bottom plane *@paramDistance from top plane *@param* Near plane distance@paramFar Far plane distance */
public static void orthoM(float[] m, int mOffset,
float left, float right, float bottom, float top,
float near, float far)
Copy the code
Note that our left, up, right, and down distances are relative to the center of the near plane.
The coordinate origin of the near plane is in the center, and to the right isThe positive direction of the axis, up isThe axis is positive, so our left and bottom are negative and our right and top are positive. Meanwhile, the distance between the near plane and the far plane both refers to the distance relative to the viewpoint, so near and far should be positive, and.
The orthogonal projection matrix can be set inside the surfaceChanged GLSurfaceView.
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
float aspectRatio = width > height ? (float) width / (float) height : (float) height / (float) width;
if (width > height){
Matrix.orthoM(projectionMatrix,0,-aspectRatio,aspectRatio,-1f,1f,0f,10f);
}else{ Matrix.orthoM(projectionMatrix,0,-1f,1f,-aspectRatio,aspectRatio,0f,10f); }}Copy the code
In this case, the aspect ratio of the near plane is set to be the same as that of the viewport.
Perspective projection matrix
OpenGL provides two functions for creating perspective projection matrices: frustumM and perspectiveM.
frustumM
The frustumM function creates a viewframe that is a cone.
Its view frame is somewhat similar to that of orthogonal projection, with basically the same understanding of parameters.
/**
* Defines a projection matrix in terms of six clip planes.
*
* @param m the float array that holds the output perspective matrix
* @param offset the offset into float array m where the perspective
* matrix data is written
* @param left
* @param right
* @param bottom
* @param top
* @param near
* @param far
*/
public static void frustumM(float[] m, int offset,
float left, float right, float bottom, float top,
float near, float far)
Copy the code
Note that the values of the NEAR and FAR variables must be greater than 0. Because they’re all relative to the point of view, which is the distance of the camera.
When the position of the camera is determined by the view matrix, make sure that the object is within the range of near and FAR from the viewpoint, otherwise the object will not be seen.
Since perspective projection will produce the effect of large near and small far, when the camera position remains unchanged, the object size will also be changed when the value of NEAR is changed. The smaller the NEAR is, the closer it is to the viewpoint, which is equivalent to the farther the object is, the smaller the object displayed will be.
Of course, the size of the observed object can also be changed by changing the position of the camera without moving near and far.
perspectiveM
OpenGL also provides the perspectiveM function for creating the projection matrix, which has the same view as frustumM, but with different parameters.
/**
* Defines a projection matrix in terms of a field of view angle, an
* aspect ratio, and z clip planes.
*
* @param m the float array that holds the perspective matrix
* @param offset the offset into float array m where the perspective
* matrix data is written
* @param fovy field of view in y direction, in degrees
* @param aspect width to height aspect ratio of the viewport
* @param zNear
* @param zFar
*/
public static void perspectiveM(float[] m, int offset,
float fovy, float aspect, float zNear, float zFar)
Copy the code
Viewports no longer need to determine the left, top, right, and bottom distances of the near-plane.
The Angle of view determines the size of the field of view we can see. The Angle of view is the Angle shown in the picture. Other parameters are the width-to-height ratio of the viewport, and the distance between the near and far planes. The number of parameters has been reduced.
The above image shows a 90-degree Angle on the left and a 45-degree Angle on the right. Obviously, the bigger the field of view, the more you see, but the smaller the object, and the smaller the field of view, the less you see, but the larger the object.
Unlike frustumM, once the Angle of view and aspect ratio are determined, the entire camera field of view is determined. At this point, the complete cone-shaped field of view has been formed, that is, the effect of objects being larger and smaller is completed. At this point, the near-plane and far-plane distances are just that part of the conical field of view that you want to intercept. Unlike the frustumM function, the distance between the near plane and the far plane can also adjust the effect of large near and small far.
reference
- OpenGL ES Application Development Practice Guide
- OpenGL ES 3.x Game Development
For details of the code, please refer to my Github project:
https://github.com/glumes/AndroidOpenGLTutorial
Finally, if you think the article is good, welcome to pay attention to wechat public number: