Ejemplo n.º 1
0
    // Called by ObjectSync when become ready
    async void OnSyncReady()
    {
        Debug.Log("OnSyncReady");

        SyncObject obj  = GetComponent <ObjectSync>().SyncObject;
        SyncNode   node = GetComponent <ObjectSync>().Node;

        obj.BeforeSync += OnBeforeSync;
        obj.AfterSync  += OnAfterSync;
        obj.RegisterFieldUpdateHandler("leftHand", OnLeftHandUpdated);
        obj.RegisterFieldUpdateHandler("rightHand", OnRightHandUpdated);
        obj.RegisterFieldUpdateHandler("mouseGrabber", OnMouseGrabberUpdated);

        OnLeftHandUpdated();
        OnRightHandUpdated();
        OnMouseGrabberUpdated();

        Blob vrmBlob;

        if (GetComponent <ObjectSync>().IsOriginal)
        {
            byte[] vrmData = File.ReadAllBytes(Settings.Instance.AvatarPath);
            // Use MIME type for GLTF binary https://www.iana.org/assignments/media-types/model/gltf-binary
            vrmBlob = new Blob(vrmData, "model/gltf-binary");
            BlobHandle vrmHandle = vrmBlob.GenerateHandle();
            node.WriteBlob(vrmHandle, vrmBlob);
            obj.SetField("vrm", vrmHandle);
        }
        else
        {
            while (!obj.HasField("vrm") || !(obj.GetField("vrm") is BlobHandle))
            {
                obj.WriteDebugLog("PlayerAvatar", "Field vrm not ready");
                await UniTask.WaitForFixedUpdate();
            }
            BlobHandle blobHandle = (BlobHandle)obj.GetField("vrm");
            vrmBlob = await node.ReadBlob(blobHandle);
        }

        // Disable collision detection (and character control) during VRM load
        // When the avatar collides with something during creation,
        // it goes to wrong position (e.g. floating).
        // Note: CharacterController inherits Collider.
        //  (See https://docs.unity3d.com/2019.3/Documentation/ScriptReference/CharacterController.html )
        GetComponent <CharacterController>().enabled = false;

        // Load VRM from byte array
        // https://github.com/vrm-c/UniVRM/wiki/Runtime-import
        // https://qiita.com/sh_akira/items/8155e4b69107c2a7ede6
        ctx      = new VRMImporterContext();
        ctx.Root = new GameObject();    // VRM is loaded as a separate object
        ctx.ParseGlb(vrmBlob.Data);

        var meta = ctx.ReadMeta();

        obj.WriteLog("PlayerAvatar", $"Loading VRM {meta.Title} created by {meta.Author} ({meta.ContactInformation})");
        obj.WriteLog("PlayerAvatar", $"AllowedUser={meta.AllowedUser}, ViolentUsage={meta.ViolentUssage}");
        obj.WriteLog("PlayerAvatar", $"SexualUsage={meta.SexualUssage}, CommercialUsage={meta.CommercialUssage}");
        obj.WriteLog("PlayerAvatar", $"OtherPermissionUrl={meta.OtherPermissionUrl}");
        obj.WriteLog("PlayerAvatar", $"LicenseType={meta.LicenseType}");
        obj.WriteLog("PlayerAvatar", $"OtherLicenseUrl={meta.OtherLicenseUrl}");

        await ctx.LoadAsyncTask();

        ctx.EnableUpdateWhenOffscreen();
        ctx.ShowMeshes();

        // Enable collision (and character controller) again (see the disabling line above)
        GetComponent <CharacterController>().enabled = true;

        // Move VRM avatar inside this gameObject
        ctx.Root.transform.SetParent(transform);
        ctx.Root.transform.localPosition = Vector3.zero;
        ctx.Root.transform.localRotation = Quaternion.identity;

        GetComponent <Animator>().avatar = ctx.Root.GetComponent <Animator>().avatar;

        obj.WriteLog("PlayerAvatar", $"VRM loaded");

        if (GetComponent <ObjectSync>().IsOriginal)
        {
            // Set up first person view (do not display avatar of the player)
            //  https://vrm.dev/en/univrm/components/univrm_firstperson/
            //  https://vrm.dev/en/dev/univrm-0.xx/programming/univrm_use_firstperson/
            var fp = GetComponentInChildren <VRMFirstPerson>();
            fp.Setup();
            if (XRRig != null)
            {
                XRRig.transform.position = fp.FirstPersonBone.position + fp.FirstPersonBone.rotation * fp.FirstPersonOffset;
                XRRig.transform.rotation = transform.rotation;  // face forward
                // Do not render layer "VRMThirdPersonOnly" on first person camera
                xrCamera.cullingMask &= ~LayerMask.GetMask("VRMThirdPersonOnly");
                SetHeadShadow();
            }
            if (ThirdPersonCamera != null)
            {
                // Do not render layer "VRMFirstPersonOnly" on third person camera
                ThirdPersonCamera.cullingMask &= ~LayerMask.GetMask("VRMFirstPersonOnly");
            }

            // Left hand
            if (leftController.HasValue)
            {
                // If left hand device is present
                var leftId = await node.CreateObject();

                leftHandObj = node.Objects[leftId];
                leftHandObj.SetField("parent", obj.GetObjectRef());
                leftHandObj.SetField("tags", new Sequence(new IValue[] {
                    new Primitive <string>("constantVelocity"),
                    new Primitive <string>("collider")
                }));
                obj.SetField("leftHand", leftHandObj.GetObjectRef());
            }
            // Right hand
            if (rightController.HasValue)
            {
                // If right hand device is present
                var rightId = await node.CreateObject();

                rightHandObj = node.Objects[rightId];
                rightHandObj.SetField("parent", obj.GetObjectRef());
                rightHandObj.SetField("tags", new Sequence(new IValue[] {
                    new Primitive <string>("constantVelocity"),
                    new Primitive <string>("collider")
                }));
                obj.SetField("rightHand", rightHandObj.GetObjectRef());
            }
            // Mouse
            var mouseGrabberId = await node.CreateObject();

            mouseGrabberObj = node.Objects[mouseGrabberId];
            mouseGrabberObj.SetField("parent", obj.GetObjectRef());
            mouseGrabberObj.SetField("tags", new Sequence(new IValue[] {
                new Primitive <string>("constantVelocity"),
                new Primitive <string>("collider")
            }));
            obj.SetField("mouseGrabber", mouseGrabberObj.GetObjectRef());
        }
    }