Saturday, November 18, 2017

Coordinate System Conversion Between Unity And A Java Game Server

Requirement from game

For the purpose of FPS attack predication I have to synchronized Hitboxs/BoxColliders between Unity Client And Java Game Server
enter image description here
To be more specific:
  • Each game character is exported to a DAE file for Server and to a FBX file for Client. These files contain geometry, joint and animation information.
  • HitBox information is manually defined and stored as a XML file and shared between Client&Server. Each Hitbox is attached to a Joint/Bone of the corresponding character.
  • When a player shoot a gun, both client and server will need to calculate the hit information. The server do so because it’s the arbitrator. The client do so to predicate the result and response immediately to the player.
The problem becomes complicated when:
  • For some reason we can’t ask unity to do the ray tracing. However there is a shared library between client and server that can calculate whether a bullet ( ray ) has hit a character and the bone being hit if so.
  • Client and server have different Coordinate Systems.
  • When imported to unity, character’s coordinate system is also changed.

Defining Problem

However, if we think about it, we can find the the problem is actually as simple as following:
For each hit box, given the transform (denoted as ) of the joint it attached to in Unity’s coordinate system, we need to find a matrix (denonated as ) that can transform it to the same state in server’s coordinate system.
In the game a character is rotated and translated after animated. Suppose a point has the hierarchy of the following:
- Translate Node
    - Rotate Node 
        - Character Pivot Node
            - Joint1 Node
                - Joint2 Node
                    - Joint3 Node
                        - P
Then in Unity can be defined as:

Where:
  • corresponds to translation
  • corresponds to rotation
  • corresponds to extra rotation introduced while imported by Unity
  • corresponds joint transform
Given we can transform the point from its local space coordinate to its world space coordinate :

Equally, in server we have :

And can use it to transform :

Note that there is a on Unity side, but no on server side. This will be explained latter.
We can easily convert between and and between and , because we know how two coordinate systems are defined. The unknown part is:

That is what Unity do when importing fbx files.

Coordinate Systems

The following image shows two coordinate systems:
enter image description here
Server’s on the left, Unity’s on the right. We can see that Unity’s left handed while server’s right handed. A point in server will be in Unity. The transform matrix would be:


What unity do when importing

After importing a FBX file, we can find that characters has the following changes:
  • If it is originally facing +X axis, it is now facing -X axis. This effectively changes it’s handness
  • It’s pivot is rotated around +x axis for +90 degrees. This step makes it head pointing to up direction again. Here is where the above mentioned comes from.
Given a point , if we change the character from binding pose to another pose, say run, we first transform from its model space to joint local space:

Where:
- is ’s coordinate in character’s binding pose.
- transform a point in joint1’s local space to joint1’s parent’s local space. So will have the reverse effect.
Then we transform to a new model space coordinate.

But if unity negates all model’s x axis. becomes . Suppose there is a matrix does the transform, that is: .
So we have:

Replacing with and with , we have:
$$

$$
For both of the above equations to be true. We can:

That way, the following equation also is true:

Here, stands for a matrix that can transform a point from jointX’s local coordinate to it’s parent’s local coordinate at posture posX.
Having the above information, we can now finish our task. Below is a code snippet of what I have written in our game:
public static Matrix3D Unity2SSJJ(Matrix4x4 result)
    {
        double[] data = new double[16];
        data[4 * 0 + 0] = result.m00;
        data[4 * 1 + 0] = result.m10;
        data[4 * 2 + 0] = result.m20;
        data[4 * 3 + 0] = result.m30;

        data[4 * 0 + 1] = result.m01;
        data[4 * 1 + 1] = result.m11;
        data[4 * 2 + 1] = result.m21;
        data[4 * 3 + 1] = result.m31;

        data[4 * 0 + 2] = result.m02;
        data[4 * 1 + 2] = result.m12;
        data[4 * 2 + 2] = result.m22;
        data[4 * 3 + 2] = result.m32;

        data[4 * 0 + 3] = result.m03;
        data[4 * 1 + 3] = result.m13;
        data[4 * 2 + 3] = result.m23;
        data[4 * 3 + 3] = result.m33;
        return new Matrix3D(data);
    }
    public static Matrix3D TransformToMatrix3D(Transform boneTransform, Matrix4x4 pivotWorldToLoal, PlayerEntity player)
    {
        Matrix4x4 mImportNegX = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(-1, 1, 1));
        Matrix3D m  = Unity2SSJJ(mImportNegX * pivotWorldToLoal * boneTransform.localToWorldMatrix * mImportNegX);
        m.AppendRotation(player.orientation.ViewYaw, Vector3D.Z_AXIS);
        m.AppendTranslation(player.position.Origin.x, player.position.Origin.y, player.position.Origin.z);
        return m;

    }

0 评论: