A mental process of coordinate transformation.

In front of the basic graph drawing, encountered a very obvious problem, circle does not look like circle, regular polygon does not look like regular polygon? It looks like this:

It’s a nice regular pentagon, but it’s all twisted around, and that’s because we’ve been drawing it as a two-dimensional drawing, whereas in OpenGL we’re drawing it as a three-dimensional drawing. There is also a transformation between 2d and 3D, which I have ignored for the sake of learning, now I need to understand it – coordinate system!!

The coordinate system

Defining the position of a point in the coordinate system of solid geometry requires the values of the x, y and Z axes, and drawing 3D objects in OpenGL is also required.

When drawing the base shape, only the x and y coordinates are defined, so that the z coordinates default to 0.

OpenGL converts the value of the defined coordinate axis into the actual drawn coordinate, which requires five coordinate system conversion.

As shown below:

There are five coordinate Spaces and three transformation matrices involved:

Space:

  • Local Space
  • World Space
  • View Space
  • Clip Space
  • Screen Space

Matrix:

  • Model Matrix
  • View Matrix
  • Projection Matrix

According to the flow chart, each coordinate space transformation needs a transformation matrix to complete.

The final clipping space to screen space transformation is to map the coordinates after this series of transformations to screen coordinates, this process does not need a transformation matrix.

Before entering different coordinate Spaces, we need to understand The coordinate system of OpenGL:

OpenGL is a right handed coordinate system, plus X on the right hand side, plus Y up, plus Z across the screen toward you.

The opposite of that is the left hand coordinate system, where the positive Z axis is going through the screen toward the inside.

Local space

Local space coordinates are the starting point for OpenGL to draw coordinates, and all subsequent conversion operations are carried out on the basis of local space coordinates.

Local space coordinates are our own starting coordinates, relative to the origin.

The space we’re in is local space, which means we’re defining the initial coordinates of the object in local space.

The world space

We define each coordinate point as being in local space relative to phi. As a result, when multiple objects are drawn at the same time, they will cluster together.

And world space is a larger coordinate system that is still relative to the origin when all objects are drawn together.

The local space is somewhat similar to the world space, so the world coordinate system can be taken into account when the coordinate system is defined in the local space to avoid the clustering phenomenon when multiple objects are drawn.

Of course, a better way is to use the Model Matrix.

Using model matrices, objects can be shifted, scaled, and rotated.

This way you can move the object away from the origin of the coordinates, and you can do something about it, without having to worry about defining the coordinates of the world space in local space.

To observe the space

The horizontal view of the ridge side into the peak is different

Once the object is in place in world space, the next step is to consider the direction and Angle from which to view the object.

Viewing space, OpenGL’s camera, is the transformation of the coordinates of world space into the coordinates of space observed by the camera.

In other words, in the observation space, the coordinate origin is no longer the coordinate origin of the world space, but the perspective of the camera as the origin of the scene, which is no longer simply for translation and rotation, but to switch to another coordinate system.

OpenGL itself does not have a camera, but you can simulate a camera by moving all objects in the scene in opposite directions. So the scene doesn’t move and the camera moves.

To define a camera, or to define a coordinate system with the camera view as the origin, you need:

  • The position of the camera in world space
  • The direction the camera is looking at
  • Point to the vector to the right of the camera
  • Point to the vector above the camera

As shown in the figure, a coordinate system with the camera position as the origin is finally established.

The blue arrow is the Z axis in the camera coordinate system, the green arrow is the Y axis in the camera coordinate system, and the red arrow is the X axis in the camera coordinate system.

The next step is to convert the coordinates of the object in world space to the coordinates of the observation space starting from the camera’s point of view.

This also requires a transformation Matrix: View Matrix. Switch coordinate systems through the view matrix.

Cut out space

Once the object coordinates are in view space, the next step is clipping. Objects within a certain range are cropped according to our needs, and coordinates outside this range are ignored.

Clipping space is essentially a coordinate operation.

From observation space to cropping space, Projection Matrix is needed.

The projection matrix specifies a range of coordinates within which coordinates are transformed to normalized device coordinates, and coordinates outside this range are clipped.

The coordinates in the observation space are called projection coordinates or clipping coordinates after the transformation of projection matrix.

The clipping coordinates are actually to be clipped, and the clipping process will be done by OpenGL. The transformation of the projection matrix is just to filter out coordinates that do not need to be clipped.

The scope created by the projection matrix is a closed spatial geometry known as the viewport.

There are two different forms of projection matrix, and two styles of creating a viewscape.

Orthogonal projection

The orthogonal projection creates a cube like view. It is composed of left, up, right and down distance, near plane distance and far plane distance. The four-direction distances define the magnitude of the near and far planes. Coordinates outside the near plane and far plane are clipped out.

Objects in the body of the scene are projected onto the near-plane, which is then projected onto the screen.

The matrix it uses is the orthogonal projection matrix.

Because orthogonal projection is a kind of parallel projection, its projection lines are parallel, so the graphics projected on the near plane will not produce the effect of near larger and far smaller in the real world. Since orthographic projection does not take perspective into account, distant objects do not become smaller, which is suitable for certain situations.

Perspective projection

Perspective projection can produce the effect of being closer and smaller, just like our eyes, making distant objects seem smaller.

The matrix it uses is the perspective projection matrix.

A perspective projection also creates a viewframe, similar to a cone. It also has near-plane distance and far-plane distance, and the contents of the near-plane are mapped to the screen viewport, but the size is different from that of the orthogonal projection near-plane and far-plane, so its left, up, right, and down distances are relative to the near-plane.

It can be seen that the projection lines of perspective projection are not parallel to each other, but intersect at the viewpoint. Therefore, objects of the same size will appear large when projected near and small when projected far away.

The perspective divide

When the coordinates are transformed into the clipping space by the projection matrix, perspective division is followed.

Perspective division is a very important step to produce large and small effects in 3D rendering.

But before we do that, let’s take a look at the W component of OpenGL.

In addition to the x, y, and z coordinates, the OpenGL coordinate system has a w component, which by default is 1. But after the perspective projection transformation, the W component is no longer one, the orthogonal projection doesn’t change the W component.

OpenGL clipping is essentially a process of GPU clipping, which is to compare the absolute value of x, Y and Z coordinates with the absolute value of W component. As long as the absolute value of one component is greater than the absolute value of W, it is considered that it is not in the viewbody and will be clipped.

After clipping, perspective division is performed. You divide the x, y, and z coordinates by the W component to get the new x, y, and z coordinates. Since the absolute values of x, y and z coordinates are all less than the absolute values of W, the new coordinates obtained are locatedIs within the interval of. And then the coordinates that you get are going to be 0, 0, 0Normalized device coordinates.

The normalized device coordinates are screen independent and its coordinate system is left – handed.

After the transformation of the perspective projection matrix, the W component of each coordinate is different, which makes the distant object look smaller after the perspective division operation.

Screen space

With normalized device coordinates, the final step is to project the coordinates onto the screen, which is done by OpenGL.

OpenGL uses the glViewPort function to map normalized device coordinates to screen coordinates, each of which is associated with a point on the screen, a process called viewport transformation. I don’t need to change the matrix anymore.

And just like that, the coordinates of a point are done from local space coordinatesTo screen coordinatesThe shift.

Matrix manipulation of coordinates

The coordinates of a point can be viewed as a vector, thetaAnd the matrix usesSaid.

Then, from local space -> world space -> observation space -> clipping space, the transformation of the four Spaces requires three transformation matrices. When a point is transformed from one coordinate system to another coordinate system, it is left multiplied by some transformation matrix. Finally, the coordinates of the clipping space can be expressed as follows:

? V_{clip}=M_{projection} \cdot M_{view} \cdot M_{model} \cdot V_{local} ?

And in the shader script,gl_PositionCorresponding toClipping coordinates.

Once you have the clipping space coordinates, the next thing you need to do is hand in OpenGL to do clipping and perspective division.

Graphics adapt to aspect ratio

As mentioned at the beginning of the article, the circle that was drawn turned into an ellipse, while the regular polygon that was drawn turned out to be crooked, now it’s possible to explain why.

By default, coordinate systems for local space, world space, observation space, and clipping space are all overlappedIs the origin of coordinates. We start with an ideal plane coordinate and define the shader script as follows:

attribute vec4 a_Position;
void main(){
    gl_Position = a_Position;
}
Copy the code

So it goes through a bunch of transformations, and finally the coordinates that OpenGL uses to crop are the same plane-based coordinates that we defined, onlyValues, andThe coordinates default to 0,The default coordinate is 1. The normalized device coordinates after perspective division are still.

Normalized device coordinates assume that the coordinate space is a square, but the viewport on the phone’s screen is a rectangle, so one direction is stretched. The same number of portions, but the longer they are, the longer the portions are, the longer the portions are, so they’re stretched.

To solve this problem, operate on normalized device coordinates and multiply the longer side by the corresponding scaling factor to the same length ratio.

// 1280 * 720 aspect = width/height; x = x * aspect y = yCopy the code

That way, the longer side is scaled up, and the shorter side is the standard for 1.

Of course, you can also take the stretching into account during projection before the coordinates are converted to normalized device coordinates.

When using orthogonal projection and then projecting the width and height of the object onto the near plane, the aspect ratio coefficient of the screen is taken into account, so that the aspect ratio adaptation of the graph is completed before the conversion to normalized device coordinates.

In this case, you need to modify the shader scripting language to take the projection matrix into account.

attribute vec4 a_Position;
uniform mat4 u_Matrix;
void main(){
    gl_Position = u_Matrix * a_Position;
}
Copy the code

reference

  1. OpenGL ES Application Development Practice Guide
  2. OpenGL ES 3.x Game Development
  3. http://blog.csdn.net/iispring/article/details/27970937

Specific code details, you can refer to my making project: https://github.com/glumes/AndroidOpenGLTutorial

Finally, if you think the article is good, welcome to pay attention to wechat public number: