Fun revolving around an axis in game programming

Please add image description

foreword

In game design, the rotation around the axis combines the two spatial changes of displacement and rotation. It is a very interesting thing to obtain the effect of rotation through displacement transformation. The whole process has a lot of basic high school geometry and mathematics knowledge to help us make transformation derivation

However, if you simply deduce a mathematical formula for rotation, it is too boring for game development. As far as I am concerned, the fun of learning theoretical knowledge lies in the flexibility to use it in engineering after understanding, just like Howard and Sheldon in The Big Bang Theory, theoretical physics Sheldon's string theory research is certainly cool , but not always fun, instead engineer Howard's work output brings more joy

Therefore, after doing some simple derivation of the theoretical knowledge of rotation, a small application of the derivation knowledge will be made to realize the application of rotation around the axis in the game, that is, the function of moving the character left and right in the locked state of the perspective in action games or RPG games. ,As shown below

Coordinate calculation formula in analysis rotation

1. Rotate the two-dimensional coordinate system around a point

From a mathematical point of view, in a two-dimensional coordinate system, a point rotates at a certain angle around another point, and the point coordinates are fixed and can be calculated. The calculation formula is derived from a simple graphical representation:
insert image description here

In the two-dimensional coordinates of the above figure, suppose a point A ( x 1 , y 1 ) (x_1, y_1)x1,and1) around a fixed point B( x 2 , y 2 ) (x_2, y_2)x2and2) rotate a certain angle θ to get a new point coordinate B(x, y) (x, y)( x , y ) , at the same time, for the convenience of understanding, draw a horizontal auxiliary line through point C, map points A and B to the auxiliary line, and declare that the intersection points are point D and point E respectively

In order to facilitate the derivation, the length of the statement ACand the angle is α, and then the equation can be established according to the conditions of the self (since no other paper can be found, we can only make do with paper) as follows:BCBCE

insert image description here

In the above equation, the angle α is unknown, but after decomposing the equation, it happens that α can be eliminated to get about ( x , y ) (x, y)The solution formula for ( x , y )
is as follows: x = ( x 1 − x 2 ) cos θ − ( y 1 − y 2 ) sin θ + x 2 x = (x_1 - x_2)cosθ - (y_1 - y_2)sinθ + x_2x=(x1x2)cosθ( and1and2)sinθ+x2x = ( x 1 − x 2 ) c o s θ − ( y 1 − y 2 ) s i n θ + x 2 x = (x_1 - x_2)cosθ - (y1 - y2)sinθ + x_2x=(x1x2)cosθ(y1y2)sinθ+x2

Expressed in programming language:

 Vector3 GetRotatePoint(Vector3 startPos,Vector3 centerPos,float angle)
    {
    
    
        float randian = angle * Mathf.PI / 180;
        float tragetX = (startPos.x - centerPos.x) * Mathf.Cos(randian) - (startPos.y - centerPos.y) * Mathf.Sin(randian) +centerPos.x ;
        float targetY = (startPos.y - centerPos.y) * Mathf.Cos(randian) +(startPos.x - centerPos.x) * Mathf.Sin(randian) + centerPos.y;       
        return new Vector3(tragetX, targetY, centerPos.z);
    }

2. Rotation around the axis of the three-dimensional coordinate system

To understand the rotation in the three-dimensional state based on the two-dimensional rotation calculation formula, it is necessary to use an additional rotation axis vector parameter to establish the rotation plane of the object in the three-dimensional space, that is, the rotation axis is used as the plane normal vector to participate in the rotation of the three-dimensional coordinate system. Coordinate solution calculation

As for the specific calculation method, the rotation around the axis is Unityprovided in , but because the engine is in closed source mode, the operation process cannot be understood through the source code. RotateAround()Coincidentally, it is currently in UEtransition, UEand happens to be open source. That is, you can UEget the implementation method through. However, considering that the current Unitynumber of developers is more, it is still Unityexplained by migrating this method to China. After making some modifications, it is as follows:

    Vector3 RotateAngleAxis(Vector3 centerPos, Vector3 aroundPos, float AngleDeg, Vector3 Axis) 
    {
    
    
        Vector3 radius = aroundPos - centerPos;
        float S = Mathf.Sin(AngleDeg * Mathf.PI / 180);
        float C = Mathf.Cos(AngleDeg * Mathf.PI / 180);
        
        float XX = Axis.x * Axis.x;
        float YY = Axis.y * Axis.y;
        float ZZ = Axis.z * Axis.z;

        float XY = Axis.x * Axis.y;
        float YZ = Axis.y * Axis.z;
        float ZX = Axis.z * Axis.x;

        float XS = Axis.x * S;
        float YS = Axis.y * S;
        float ZS = Axis.z * S;

        float OMC = 1f - C;

        return new Vector3(
            (OMC * XX + C) * radius.x + (OMC * XY - ZS) * radius.y + (OMC * ZX + YS) * radius.z + centerPos.x,
            (OMC * XY + ZS) * radius.x + (OMC * YY + C) * radius.y + (OMC * YZ - XS) * radius.z + centerPos.y,
            (OMC * ZX - YS) * radius.x + (OMC * YZ + XS) * radius.y + (OMC * ZZ + C) * radius.z + centerPos.z
            );
    }


In order to improve the calculation efficiency, the axial vector calculation in the code has a unique design, and it is difficult to reverse the calculation process from it. solution, and then do certain projection calculations with the rotation axis, but these mathematical knowledge is slightly beyond the scope of high school mathematics, and it is also beyond my ability, so I will skip this part of the demonstration and derivation, but it is harmless, the game Developers are not mathematicians. They need mathematics but do not rely entirely on mathematics. Our main purpose is to apply it later.

Unity implements a small case of rotating around the axis

After the boring mathematical derivation, finally came to the important part. If you have a little experience with console games, you will find that in some games, usually some RPG-type games, such as the Assassin's Creed series of games, there is a mechanism to lock the perspective of the enemy. By locking on to the enemy, the player can ignore the camera changes and focus on the combat controls

Under this mechanism, the movement of the character will have some subtle changes. Generally speaking, the left and right translation will be converted into a circular motion around the point in this case, as shown in the following figure about the locked rotation in Assassin's Creed:

Please add image description
Split transformation process, the rotation around the axis is composed of the character's circular movement and rotation. The logic subdivided into each frame is that the character Forwardfaces the center point, and the line connecting the vertical and the center point moves left and right, that is, the direction of movement is always the tangent of the circle, Unitywhich is expressed in programming language as:

        playerTran.LookAt(centerTran);
        float inputAxisX = Input.GetAxis("Horizontal");
        float inputAxisY = Input.GetAxis("Vertical");
        playerTran.Translate(inputX*Time.deltaTime*rotateSpeed, 0, inputY * Time.deltaTime * moveSpeed);

The above code can get a less rigorous effect of rotating around the axis. The reason why it is not strict is because the rotation radius of the object will be additionally increased when controlling the left and right displacement of the character in each frame. After a period of accumulation, it will generate Perceived radius calculation error. It's easy to understand, just think a little bit, every time the character moves along the tangent of a circle, no matter how far it moves, it will deviate from the original circular path by a distance, as shown in the following figure:

insert image description here

Assuming that the character is located at point A before the start of the current frame and rotates around the axis with OA as the radius, and the distance moved in each frame is AB, then after the logic of this frame ends and the next frame starts, the character will rotate at point B with OB as the radius The axis rotates, so that the radius of the entire rotation around the axis becomes larger and larger. The following is a more extreme demonstration:
Please add image description

Generally speaking, when the object is moving slowly, the error accumulation is not very obvious, but it is not small enough to be ignored. Of course, such a statement is not convincing enough, so here we use the mathematical knowledge of almighty high school to quantify the error. We can assume the following scene, in a 60-frame game scene, when the character starts to make a circle around the center point with a radius of 1 meter axis rotation and set a common movement speed for it

In order to make the data representative, it can be used as a reference to the real human movement speed. Through Baidu, we can know that the normal moving speed of a person is 5 to 7 kilometers per hour, and the intermediate value is converted to about 1.67m/s. We already know that the number of game frames is 60 frames per second, that is, the moving distance of the character in each frame. is 0.028m

With the above data, we can calculate the radius error of each frame. From the previous figure, we can know that the calculation method of the error generated by each frame is the length of OB minus the length of OA, and the length of OB can be calculated by The OA length obtained in the previous frame and the AB obtained through common sense are obtained, and expressed through the program code as:

   double GetRadius(double startRadius, double moveLenght,int frameNum)
    {
    
    
        if (frameNum == 0) return startRadius;
        double powNum = GetRadius(startRadius, moveLenght, frameNum - 1);
        return Math.Sqrt(Math.Pow(powNum,2) + Math.Pow(moveLenght, 2));
    }

This code is only a logic demonstration. Because there are a large number of double-precision floating-point calculations, do not try to demonstrate directly on the real machine (high probability of being stuck, a lesson from the past), you can split the logic into Updatemedium, and calculate once per frame to distribute performance pressure. Through the operation program, the following results are obtained. It can be seen that after the system runs for five seconds, the radius error of the character reaches 0.1 meters, which is enough to have a greater impact on the player's grasp of the attack distance in a strict action game.
insert image description here

Precompute Circumferential Points Using the Around Axis Formula

In order to avoid this problem, we can control the movement of the object through the rotation formula just mentioned. Although the calculation process is more complicated, the accuracy of the obtained results is very high, even under the influence of the error of floating-point calculation.

After we get the above formula code for rotating around the axis, the whole process is much simpler, we only need to prepare the corresponding parameters to pass in to get the target position of the corresponding frame. But for the current rotation project, one thing to note is that , usually the character's movement speed is fixed. If a fixed angle is directly passed in this function, the moving speed of the object will be linked to the radius of the circle. It is well understood that if each frame rotates by the same angle, the larger the rotation radius, the longer the corresponding arc. Longer, meaning the object moves faster

Due to the above problems, some conversions need to be done in advance, that is, the moving arc length is converted into radians. Through high school knowledge, we can know that the conversion formula of arc length and radian is:

arc length = radian* radius arc length = radian * radiusarc length=radianradius

But what's interesting is that the radius we used before is not necessarily the radius corresponding to the object's rotation plane, and we need to use high school mathematics again to calculate the radius:
insert image description here

As shown in the figure above, object B rotates around the axis of OAA , and the actual rotation plane of object B is the plane OAthat is normal and passes through point B. According to the unit vector of the direction in the known conditions and OAthe coordinate information of point A and point B, OBthe length obtained by using the knowledge of vector plane projection, the code structure is:

    Vector3 ProjectOnPlane(Vector3 target, Vector3 noraml)
    {
    
    
        return target - noraml * Vector3.Dot(target, noraml) / Vector3.Dot(noraml, noraml);
    }

The above solution process is simply to obtain the projection distance on the above through point multiplication target, normaland then normaldivide by the length to obtain the multiple, and normalconstruct a right triangle by proportional expansion, and perform vector subtraction to obtain the projection vector.

After getting the actual radius of rotation, rewrite the previous method of rotating around the axis RotateAngleAxis, so that the corresponding arc length can be calculated by the object unit motion arc length

    Vector3 RotateAngleAxis(Vector3 centerPos, Vector3 aroundPos, float moveSpeed, Vector3 Axis)
    {
    
    
        Vector3 radius = aroundPos - centerPos;
        Vector3 changeRadius = ProjectOnPlane(radius, Axis);
        float S = Mathf.Sin(moveSpeed /changeRadius.magnitude);
        float C = Mathf.Cos(moveSpeed /changeRadius.magnitude);
        ...
     }

It can be seen that by using the source code, you can flexibly modify some codes to suit your own needs. Even if the performance is not very helpful, it Unitywill be cooler than the repackaged method based on the given method. Run the above program, as shown in the figure:Please add image description

follow-up

Since I have been getting started recently UE, there is nothing particularly interesting to write and share. But I will work hard later, because UEI feel that there are too few related articles when I am studying, so I hope I can contribute my own strength to enrich UEthe community environment!

Guess you like

Origin blog.csdn.net/xinzhilinger/article/details/123459840