Realize VR multiplayer collaboration function based on XR Interaction ToolKit and PUN

        Recently, I have been working on the development of multi-person collaboration in the entire VR. Because I have not contacted too many people to develop this area, I have encountered many pits. Here is a summary of some personal experiences.

1. Development environment configuration

       Unity version: 2019.3.4

       Related plug-in version:

      Universal RP 7.1.8

      XR Interaction Tookit preview -0.9.4

      PUN2 2.22

    About XR Interaction Tookit

      I have done relevant introductions and instructions before. Refer to this article  based on the VR dual-platform compatible project developed by XR Interaction ToolKit (1) I  won’t explain too much here.

    About PUN2

        PUN (Photon Unity Networking) is a well-known multi-person interaction solution on Unity. There are many introductions and explanations about it on the Internet, so I won't repeat them here. However, there is a network configuration that can be optimized for PUN to be explained here. Because PUN servers are all overseas by default, there may be delays in domestic use. You can go to Poton's official website in China to apply for a free domestic server, the specific method is as follows

1. Enter the official website ( https://vibrantlink.com/ )

2. Find "Free Application for China Photonic Cloud" on the homepage

3. Fill in the relevant information and submit it for review. It should be noted here that the appid created on the official website that needs to be cut to the China area needs to be entered into the application form, and be careful not to select the wrong type.

4. After a successful email is received in the mailbox after one or two working days, you can configure it in Unity.

5. Find the PUN configuration file PhotonServerSettings in unity, modify the Fixed Region inside to CN; find the script LoadBalancingClient.cs and modify the attribute of NameServerHost inside to ns.photonengine.cn

After configuring the above options, tested that the network speed is basically under 50ms.

2. Some details of development

1. Model loading and synchronization

Through the PhotonNetwork.Instantiate method provided by PUN, local models can be created and synchronized to their respective clients. But if you want to download the model resources on the server and synchronize to other users, you need to cooperate with other related methods to achieve.

I use the component synchronization method provided by Photon to achieve similar effects. The specific implementation is as follows:

a. Create an empty object through PhotonNetwork.Instantiate, mount the photonView component on it, and also mount a custom synchronous loading class ModelEntity. This class must inherit the IPunObservable interface and implement the OnPhotonSerializeView method, it will automatically be photonView detected.

    The relevant code of ModelEntity is as follows:

public class ModelEntity : MonoBehaviourPunCallbacks, IPunObservable
    {

        string id;
        int num;
        public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
        {
            //拥有者 会把数据不断发送给其他人
            if (stream.IsWriting)
            {

                stream.SendNext(id);
                stream.SendNext(num);
            }
            else
            {

                // 其他用户 当拥有者发送数据会接收到数据
                id= (string)stream.ReceiveNext();
                num= (string)stream.ReceiveNext();


            }
        }

    }
}

b. After instantiating the synchronized gameObject object, the creator passes the id data that needs to be synchronized into the ModelEntity, and also loads the server scene to the local; other users will obtain the created gameObject object empty object through the Photon network After the corresponding id is detected, the model of the corresponding id is loaded to the local through the network. In this way, the function of synchronously loading the model of the server is simply realized

2. Takeover and operation of the object

The synchronization object created in the application can only be operated by the creator by default. If other users want to take over the object and perform transformation or deletion operations on it, they need to obtain the right to operate the object. The specific operations are as follows:

a. Set the Ownership Transfer on the photonView component mounted by the synchronized object to Takeover, indicating that this object can be taken over

b. Get the photonView of this object through code, set gameObject.GetComponent<PhotonView>().TransferOwnership(PhotonNetwork.LocalPlayer), this operation is to force a control right of the object to the local user

c. If you need to synchronize the transformation information of the object, you can hang the PhotonTransformView component on the object, and check the position, rotation and scale according to your needs. In this way, local users can drag and drop directly in the scene or set in the code. Sync to other network users

d. Deleting objects Through PhotonNetwork.Destroy(), the objects synchronized by the network can be destroyed.

 

3. Creation of VR user objects

In multiplayer VR, there is no need to create a camera for each user, because we only need to see world objects through a Camera component, and adding other user cameras will cause an error instead. If you really need to synchronize other VR users, just create an object model of the player through PhotonNetwork.Instantiate, and continuously synchronize the local camera position to this object model (the position of the avatar in VR is the position of the camera)

4. Realization of VR line drawing function

In multi-person interaction, if you need to use the handle as a "pen" to draw a line and synchronize it to other users, this involves the knowledge points of LineRenderer and synchronization. Use LineRenderer to record each path point the handle passes through and draw it as a line, and synchronize it to the world coordinates of other users. It should be noted here that the operation of synchronously drawing a line "point" is after the user draws a line, rather than synchronously while drawing. Because I'm not sure what the delay of the network conditions on both sides is, if you are drawing and synchronizing the route, it looks normal locally, but what other network users see is basically a mess.

At the same time, it is not recommended to take points every frame, otherwise the load on the network is too large. And it is not recommended to take a point at each position, but to take the point after judging that the distance between the point and the point is greater than a certain threshold, so as to avoid the situation that a large number of points are in the same position.

5. Handling of the user leaving the room

When the user leaves the room or due to abnormal network disconnection, the objects created by the user through PhotonNetwork.Instantiate are not deleted, but are transferred to ClientMaster by default. If the user has created a character model to synchronize the position, it will be left in the scene at this time. Therefore, the dropped objects need to be processed. My processing method is to add a detection event of the user leaving the room to the created user avatar. When it is detected that the user is a model corresponding to this avatar, the object is deleted. The specific implementation code is as follows:

    public override void OnPlayerLeftRoom(Player otherPlayer)
    {
        if (owner == otherPlayer.NickName)
        {
            PhotonNetwork.Destroy(gameObject);
        }
    }

The owner is the LocalPlayer.NickName obtained when the object is instantiated. Some people may ask why not directly use photonView.owner.NickName to judge the disconnected user name. As mentioned above, when the user disconnects, the model will switch to ClientMaster by default, and the naturally obtained photonView.owner will not correspond to it. Online users.

Casually summarize

Because it’s the first time I have come into contact with multi-person interactive programming, a lot of things are made out of blindness, and most of them may not be the optimal solution. If there is a mistake, I hope someone can correct it. At the same time, I am very grateful to [I am a orange] this blogger's article tutorial, I really learned a lot.

 

Guess you like

Origin blog.csdn.net/ssssssilver/article/details/109531179