قررت في إجازة لدراسة تطوير Vive in Unity3D. غوغل بضعة أمثلة وبدأت في المحاولة ، ولكن لسبب ما لم ينجح. بعد أن بدأت تفهم بمزيد من التفاصيل ووجدت أن Valve طرحت مؤخرًا تحديثًا للمكون الإضافي لـ Unity3D - إصدار جديد تم إعادة بنائه بشدة. ظهر فيها ابتكاران أساسيان جعلا الدروس القديمة غير ذات صلة. قررت أن أكتب واحدة جديدة

سنحتاج إلى Unity> = 5.4.0 والمكوّن الإضافي SteamVR الإضافي الجديد ( GitHub )
في البرنامج المساعد نفسه ، هناك ثلاثة ملفات PDF مفيدة للتعرف
\ الأصول \ SteamVR \ SteamVR Unity Plugin.pdf
\ الأصول \ SteamVR \ SteamVR Unity Plugin - Input System.pdf
\ الأصول \ SteamVR \ InteractionSystem \ InteractionSystem.pdf
ومثالين:
\ الأصول \ SteamVR \ Simple Sample.unity
\ الأصول \ SteamVR \ InteractionSystem \ Samples \ Interactions_Example.unity
يدعم المكون الإضافي وضع المحاكاة - يتم تشغيله إذا لم يتم تشغيل الخوذة
حسنا ، الآن خطوة بخطوة.
قم بإنشاء مشروع قالب ثلاثي الأبعاد جديد باستخدام المكون الإضافي SteamVR
نحن نتفق مع الإعدادات

الآن النقطة الأساسية هي أنك تحتاج إلى تكوين الإدارة. حدد عنصر القائمة Window \ SteamVR Imput

ستسأل الوحدة عن الإجراءات المفقودة. json وعرض نسخ ملف المثال (الموجود في \ Assets \ SteamVR \ Input \ ExampleJSON) - أنصحك بالموافقة.

تظهر ملفات json أن المكون الإضافي مصمم ليس فقط لـ Vive ، ولكن أيضًا لـ Oculus و Windows MR ، بالإضافة إلى وحدات التحكم المفصلة الجديدة. ترتبط التغييرات الرئيسية بهذا.
في النافذة التي تفتح ، ما عليك سوى النقر فوق "حفظ وإنشاء"

تحتاج الآن إلى إضافة المشغل (المشغل من \ Assets \ SteamVR \ InteractionSystem \ Core \ Prefabs) إلى المشهد وإزالة الكاميرا الرئيسية

لكي يعمل وضع المحاكاة - يجب تمكينه في خصائص المشغل

من المفيد أيضًا نسخ مجلد \ Assets \ SteamVR \ InteractionSystem \ Core \ Icons إلى \ Assets وإعادة تسميته إلى Gizmos
يمكنك النقر فوق تشغيل - ولكن لن تعمل سوى اليد المزيفة في المحاكاة ، تحتاج إلى نسخ البرنامج النصي من هنا وتعليقه على Player-> NoSteamVRFallbackObjects-> FallbackHand
رمز النص اليدوي المزيفusing System.Collections.Generic; using UnityEngine; using Valve.VR; public class VrSimulatorHandFixer156 : SteamVR_Behaviour_Pose { Valve.VR.InteractionSystem.Hand _hand; protected override void Start() { base.Start(); _hand = this.gameObject.GetComponent<Valve.VR.InteractionSystem.Hand>(); _hand.handType = SteamVR_Input_Sources.RightHand; GameObject broHand = GameObject.Instantiate(_hand.gameObject); Destroy(broHand.GetComponent<VrSimulatorHandFixer156>()); broHand.SetActive(false); _hand.otherHand = broHand.GetComponent<Valve.VR.InteractionSystem.Hand>(); _hand.otherHand.handType = SteamVR_Input_Sources.LeftHand; var spoofMouse = new SpoofMouseAction(); _hand.grabGripAction = spoofMouse; spoofMouse.InitializeDictionariesExposed(_hand.handType); this.poseAction = new Poser_SteamVR_Action_Pose(); } protected override void OnEnable() { } protected override void Update() { _hand.grabGripAction.UpdateValue(SteamVR_Input_Sources.RightHand); } protected override void OnDisable() { } protected override void CheckDeviceIndex() { }
في وضع VR مع تشغيل وحدات التحكم - ستكون مرئية

أضفنا VR ، ولكن لا يمكننا حتى التنقل. البرنامج المساعد لديه تطبيق النقل عن بعد
لتمكينه ، تحتاج إلى الإضافة إلى مشهد النقل الفوري من \ Assets \ SteamVR \ InteractionSystem \ Teleport \ Prefabs
وأيضا ترتيب TeleportPoint من هناك

يمكنك أيضًا الانتقال الفوري في التقليد باستخدام مفتاح T.
يمكنك إنشاء سطح انتقال فوري - قم بإنشاء طائرة وتعليق البرنامج النصي TeleportArea.cs من \ Assets \ SteamVR \ InteractionSystem \ Teleport \ Scripts عليه

دعونا نحاول التفاعل مع الكائنات - قم بإنشاء مكعب وتعليق البرنامج النصي Interactable.cs من \ Assets \ SteamVR \ InteractionSystem \ Core \ Scripts عليه
الآن يتم تسليط الضوء عليه ، ولكن لا شيء يحدث له

نحن بحاجة إلى تسجيل التفاعل - سنقوم بإنشاء برنامج نصي جديد لـ Cube
كود للتفاعل using System.Collections; using System.Collections.Generic; using UnityEngine; using Valve.VR.InteractionSystem; public class NewBehaviourScript : MonoBehaviour { private Hand.AttachmentFlags attachmentFlags = Hand.defaultAttachmentFlags & (~Hand.AttachmentFlags.SnapOnAttach) & (~Hand.AttachmentFlags.DetachOthers) & (~Hand.AttachmentFlags.VelocityMovement); private Interactable interactable; // Use this for initialization void Start () { interactable = this.GetComponent<Interactable>(); } private void HandHoverUpdate(Hand hand) { GrabTypes startingGrabType = hand.GetGrabStarting(); bool isGrabEnding = hand.IsGrabEnding(this.gameObject); if (startingGrabType != GrabTypes.None) { // Call this to continue receiving HandHoverUpdate messages, // and prevent the hand from hovering over anything else hand.HoverLock(interactable); // Attach this object to the hand hand.AttachObject(gameObject, startingGrabType, attachmentFlags); } else if (isGrabEnding) { // Detach this object from the hand hand.DetachObject(gameObject); // Call this to undo HoverLock hand.HoverUnlock(interactable); } } }
يمكن العثور على مزيد من التفاصيل حول التفاعل في أمثلة المكون الإضافي ، ولا سيما في \ Assets \ SteamVR \ InteractionSystem \ Samples \ Scripts \ InteractableExample.cs
ثم سنحاول القيام بما هو غير موجود في الأمثلة - أضف إجراءات جديدة
افتح البرنامج النصي Player.cs وأضف الحقول
[SteamVR_DefaultAction("PlayerMove", "default")] public SteamVR_Action_Vector2 a_move; [SteamVR_DefaultAction("PlayerRotate", "default")] public SteamVR_Action_Vector2 a_rotate; [SteamVR_DefaultAction("MenuClick", "default")] public SteamVR_Action_Boolean a_menu;
يمكن العثور على أنواع الإرجاع الصالحة في \ Assets \ SteamVR \ Input
وطريقة التحديث:
private void Update() { bool st = a_menu.GetStateDown(SteamVR_Input_Sources.Any); if (st) { this.transform.position = new Vector3(0, 0, 0); } else { Camera camera = this.GetComponentInChildren<Camera>(); Quaternion cr = Quaternion.Euler(0, 0, 0); if (camera != null) { Vector2 r = a_rotate.GetAxis(SteamVR_Input_Sources.RightHand); Quaternion qp = this.transform.rotation; qp.eulerAngles += new Vector3(0, rx, 0); this.transform.rotation = qp; cr = camera.transform.rotation; } Vector2 m = a_move.GetAxis(SteamVR_Input_Sources.LeftHand); m = Quaternion.Euler(0, 0, -cr.eulerAngles.y) * m; this.transform.position += new Vector3(mx / 10, 0, my / 10); } }
كود Player.cs الكامل //======= Copyright (c) Valve Corporation, All rights reserved. =============== // // Purpose: Player interface used to query HMD transforms and VR hands // //============================================================================= using UnityEngine; using System.Collections; using System.Collections.Generic; namespace Valve.VR.InteractionSystem { //------------------------------------------------------------------------- // Singleton representing the local VR player/user, with methods for getting // the player's hands, head, tracking origin, and guesses for various properties. //------------------------------------------------------------------------- public class Player : MonoBehaviour { [Tooltip( "Virtual transform corresponding to the meatspace tracking origin. Devices are tracked relative to this." )] public Transform trackingOriginTransform; [Tooltip( "List of possible transforms for the head/HMD, including the no-SteamVR fallback camera." )] public Transform[] hmdTransforms; [Tooltip( "List of possible Hands, including no-SteamVR fallback Hands." )] public Hand[] hands; [Tooltip( "Reference to the physics collider that follows the player's HMD position." )] public Collider headCollider; [Tooltip( "These objects are enabled when SteamVR is available" )] public GameObject rigSteamVR; [Tooltip( "These objects are enabled when SteamVR is not available, or when the user toggles out of VR" )] public GameObject rig2DFallback; [Tooltip( "The audio listener for this player" )] public Transform audioListener; public bool allowToggleTo2D = true; [SteamVR_DefaultAction("PlayerMove", "default")] public SteamVR_Action_Vector2 a_move; [SteamVR_DefaultAction("PlayerRotate", "default")] public SteamVR_Action_Vector2 a_rotate; [SteamVR_DefaultAction("MenuClick", "default")] public SteamVR_Action_Boolean a_menu; //------------------------------------------------- // Singleton instance of the Player. Only one can exist at a time. //------------------------------------------------- private static Player _instance; public static Player instance { get { if ( _instance == null ) { _instance = FindObjectOfType<Player>(); } return _instance; } } //------------------------------------------------- // Get the number of active Hands. //------------------------------------------------- public int handCount { get { int count = 0; for ( int i = 0; i < hands.Length; i++ ) { if ( hands[i].gameObject.activeInHierarchy ) { count++; } } return count; } } //------------------------------------------------- // Get the i-th active Hand. // // i - Zero-based index of the active Hand to get //------------------------------------------------- public Hand GetHand( int i ) { for ( int j = 0; j < hands.Length; j++ ) { if ( !hands[j].gameObject.activeInHierarchy ) { continue; } if ( i > 0 ) { i--; continue; } return hands[j]; } return null; } //------------------------------------------------- public Hand leftHand { get { for ( int j = 0; j < hands.Length; j++ ) { if ( !hands[j].gameObject.activeInHierarchy ) { continue; } if ( hands[j].handType != SteamVR_Input_Sources.LeftHand) { continue; } return hands[j]; } return null; } } //------------------------------------------------- public Hand rightHand { get { for ( int j = 0; j < hands.Length; j++ ) { if ( !hands[j].gameObject.activeInHierarchy ) { continue; } if ( hands[j].handType != SteamVR_Input_Sources.RightHand) { continue; } return hands[j]; } return null; } } //------------------------------------------------- // Get Player scale. Assumes it is scaled equally on all axes. //------------------------------------------------- public float scale { get { return transform.lossyScale.x; } } //------------------------------------------------- // Get the HMD transform. This might return the fallback camera transform if SteamVR is unavailable or disabled. //------------------------------------------------- public Transform hmdTransform { get { if (hmdTransforms != null) { for (int i = 0; i < hmdTransforms.Length; i++) { if (hmdTransforms[i].gameObject.activeInHierarchy) return hmdTransforms[i]; } } return null; } } //------------------------------------------------- // Height of the eyes above the ground - useful for estimating player height. //------------------------------------------------- public float eyeHeight { get { Transform hmd = hmdTransform; if ( hmd ) { Vector3 eyeOffset = Vector3.Project( hmd.position - trackingOriginTransform.position, trackingOriginTransform.up ); return eyeOffset.magnitude / trackingOriginTransform.lossyScale.x; } return 0.0f; } } //------------------------------------------------- // Guess for the world-space position of the player's feet, directly beneath the HMD. //------------------------------------------------- public Vector3 feetPositionGuess { get { Transform hmd = hmdTransform; if ( hmd ) { return trackingOriginTransform.position + Vector3.ProjectOnPlane( hmd.position - trackingOriginTransform.position, trackingOriginTransform.up ); } return trackingOriginTransform.position; } } //------------------------------------------------- // Guess for the world-space direction of the player's hips/torso. This is effectively just the gaze direction projected onto the floor plane. //------------------------------------------------- public Vector3 bodyDirectionGuess { get { Transform hmd = hmdTransform; if ( hmd ) { Vector3 direction = Vector3.ProjectOnPlane( hmd.forward, trackingOriginTransform.up ); if ( Vector3.Dot( hmd.up, trackingOriginTransform.up ) < 0.0f ) { // The HMD is upside-down. Either // -The player is bending over backwards // -The player is bent over looking through their legs direction = -direction; } return direction; } return trackingOriginTransform.forward; } } //------------------------------------------------- void Awake() { SteamVR.Initialize(true); //force openvr if ( trackingOriginTransform == null ) { trackingOriginTransform = this.transform; } } //------------------------------------------------- private IEnumerator Start() { _instance = this; while (SteamVR_Behaviour.instance.forcingInitialization) yield return null; if ( SteamVR.instance != null ) { ActivateRig( rigSteamVR ); } else {
قم بتشغيل Window \ SteamVR Imput ، وقم بإنشاء إجراءاتنا في المجموعة الافتراضية وحفظها ، حدد الآن "فتح واجهة مستخدم الربط" (يجب تشغيل SteamVR وتشغيل وحدة تحكم واحدة على الأقل)

تفتح علامة التبويب ربط وحدة التحكم في المستعرض - تحتاج فيها إلى تكوين اتصال إجراءاتنا مع وحدات التحكم: سنعلق PlayerMove على TRACKPAD الأيسر (لا تنس إيقاف تشغيل وضع المرآة) ، PlayerRotate على TRACKPAD الأيمن ، وتعليق القائمة انقر على مفاتيح القائمة

أغلق ربط وحدة التحكم واحفظ التغييرات.
في خصائص المشغل ، نربط الإجراءات الجديدة

شغّل Play
المشروع
الخلاصة
يجب ملاحظة بضع نقاط. يمكن لبعض الإجراءات في SteamVR Imput أن تجعل Unity تفكر لفترة طويلة ، من حيث المبدأ ، يمكنك إجراء هذه التغييرات بنفسك في التعليمات البرمجية ، وبدلاً من استخدام وحدة تحكم Binding ، يمكنك تحرير ملفات json مباشرة ، ولكن هناك خطر كبير من الأخطاء التي يصعب اكتشافها.
لدراسة أعمق للبرنامج المساعد - من المفيد دراسة الأمثلة بالتفصيل ، وبالطبع - اقرأ الوثائق.