Requirement from game
For the purpose of FPS attack predication I have to synchronized Hitboxs/BoxColliders between Unity Client And Java Game Server
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.
- 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
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:
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.
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;
}



