مرحبًا بك في شبكة الويب المجسَّمة

تعني شبكة الويب الغامرة تجارب العالم الافتراضي المستضافة من خلال المتصفح. يتم عرض تجارب الواقع الافتراضي هذه بالكامل في المتصفح أو في سماعات الرأس المتوافقة مع الواقع الافتراضي.

Joe Medley
Joe Medley

تعني شبكة الويب الشاملة تجارب العالم الافتراضي المستضافة من خلال المتصفح. ويغطي هذا تجارب الواقع الافتراضي بالكامل المعروضة في المتصفح أو في سماعات الرأس المتوافقة مع الواقع الافتراضي، مثل أجهزة Daydream وOculus Rift وSamsung Gear VR وHTC Vive وWindows Mixed Reality Headsets، بالإضافة إلى تجارب الواقع المعزز التي تم تطويرها للأجهزة الجوّالة المزوّدة بتقنية الواقع المعزّز.

على الرغم من أنّنا نستخدم مصطلحَين لوصف التجارب الغامرة، يجب اعتبارهما نطاقًا من الواقع الكامل إلى بيئة الواقع الافتراضي الشاملة، مع مستويات مختلفة من الواقع المعزّز بينهما.

تشمل الأمثلة على التجارب الغامرة ما يلي:

  • فيديوهات غامرة بزاوية 360 درجة
  • فيديوهات تقليدية ثنائية الأبعاد (أو ثلاثية الأبعاد) يتم عرضها في محيط غامر
  • الرسومات البيانية
  • التسوّق في المنازل
  • فنون
  • شيء رائع لم يفكر فيه أحد حتى الآن

كيف أصِل إلى هناك؟

توفّر شبكة الويب الغامرة منذ ما يقرب من عام في شكل جنيني. وتم إجراء ذلك من خلال واجهة برمجة التطبيقات WebVR 1.1 التي كانت متوفرة في مرحلة التجربة والتقييم منذ إصدار Chrome 62. يتم دعم واجهة برمجة التطبيقات هذه أيضًا من قبل Firefox وEdge بالإضافة إلى polyfill للمتصفح Safari.

لكن حان الوقت للمضي قدمًا.

انتهت مرحلة التجربة والتقييم في 24 تموز (يوليو) 2018، وحلّت واجهة برمجة التطبيقات WebXR Device API محلّ المواصفات في مرحلة التجربة والتقييم الجديد.

ماذا حدث لتطبيق WebVR 1.1؟

لقد تعلّمنا الكثير من الإصدار 1.1 من WebVR، ولكن مع مرور الوقت، اتّضح لنا أنّه كانت هناك حاجة إلى بعض التغييرات الرئيسية لدعم أنواع التطبيقات التي يريد المطوّرون إنشاءها. قائمة الدروس المستفادة طويلة جدًا بحيث لا يمكن تناولها هنا، ولكنها تتضمن مشاكل مثل ربط واجهة برمجة التطبيقات بشكل صريح بسلسلة تعليمات JavaScript الرئيسية، وفرص كثيرة جدًا للمطوّرين تتيح لهم إعداد عمليات إعداد غير صحيحة بوضوح، فضلاً عن استخدامات شائعة مثل كون النافذة السحرية أثرًا جانبيًا بدلاً من ميزة مقصودة. (النافذة السحرية هي تقنية لعرض المحتوى الغامر بدون سماعة رأس، حيث يعرض التطبيق عرضًا واحدًا بناءً على أداة استشعار اتجاه الجهاز).

يسهّل التصميم الجديد عمليات التنفيذ الأبسط وتحسينات الأداء الكبيرة. في الوقت نفسه، ظهرت تقنية الواقع المعزّز وحالات استخدام أخرى، وأصبح من المهم أن تكون واجهة برمجة التطبيقات قابلة للتوسّع لدعم تلك الواجهات في المستقبل.

تم تصميم WebXR Device API وتسميته بحالات الاستخدام الموسّعة هذه في الاعتبار وتوفير مسار أفضل للمضي قدمًا. التزمت جهات تنفيذ WebVR بالنقل إلى واجهة برمجة تطبيقات WebXR Device API.

ما هي WebXR Device API؟

إنّ WebXR Device API هي أحد منتجات مجموعة منتدى الويب المجسَّم التي تضم مساهمين من Google وMicrosoft وMozilla وغيرها، تمامًا مثل مواصفات WebVR. يُقصد بـ "X في XR" كنوع من المتغيرات الجبرية التي تعني أي شيء في مجموعة التجارب الغامرة. وهي متاحة في مرحلة التجربة والتقييم المذكورة سابقًا وكذلك من خلال polyfill.

عندما تم نشر هذه المقالة في الأصل خلال الفترة التجريبية من Chrome 67، تم تفعيل إمكانات الواقع الافتراضي فقط. أصبح الواقع المعزّز متاحًا في Chrome 69. يمكنك الاطّلاع على ذلك من خلال الواقع المعزّز على الويب.

هناك المزيد إلى واجهة برمجة التطبيقات الجديدة هذه أكثر مما يمكنني الانتقال إليه في مقالة مثل هذه. أريد أن أمنحك ما يكفي لبدء فهم عينات WebXR. يمكنك العثور على مزيد من المعلومات في كل من الشرح الأصلي ودليل المستخدمين في مرحلة مبكرة من الموقع الإلكتروني المجسَّم. سأقوم بتوسيعها مع تقدم تجربة الأصل. لا تتردد في فتح المشكلات أو إرسال طلبات السحب.

في هذه المقالة، سأناقش بدء جلسة XR وإيقافها وتشغيلها بالإضافة إلى بعض الأساسيات حول معالجة الإدخال.

لن أتحدث عن كيفية رسم محتوى الواقع المعزّز والواقع الافتراضي على الشاشة. لا توفّر واجهة برمجة التطبيقات WebXR Device API ميزات عرض الصور. هذا الأمر يرجع إليك. يتم الرسم باستخدام واجهات برمجة تطبيقات WebGL. يمكنك القيام بذلك إذا كنت طموحًا حقًا. بالرغم من ذلك، ننصح باستخدام إطار عمل. تستخدم نماذج الويب الشاملة نموذج تم إنشاؤه خصيصًا للإصدارات التجريبية المسماة Cottontail. يدعم 3.js WebXR منذ أيار (مايو). لم أسمع شيئًا عن A-Frame.

بدء تشغيل تطبيق وتشغيله

العملية الأساسية هي:

  1. اطلب جهاز XR.
  2. وإذا كانت متوفرة، اطلب جلسة XR. إذا كنت تريد من المستخدم أن يضع هاتفه في سماعة رأس، فإن ذلك يُطلق عليه جلسة غامرة ويتطلب إيماءة المستخدم للدخول.
  3. استخدِم الجلسة لتشغيل حلقة عرض توفّر 60 لقطة في الثانية. ارسم المحتوى المناسب على الشاشة في كل إطار.
  4. شغِّل حلقة العرض إلى أن يقرّر المستخدم الخروج.
  5. قم بإنهاء جلسة XR.

لنلقِ نظرة على ذلك بمزيد من التفصيل ونضمّن بعض التعليمات البرمجية. لن تكون قادرًا على تشغيل تطبيق مما أنا على وشك إظهاره لك. لكن مرة أخرى، هذا فقط لتوضيح ذلك.

طلب جهاز XR

وتتعرّف هنا على الرمز العادي لرصد الميزات. يمكنك التفاف هذا في دالة تسمى شيئًا مثل checkForXR().

إذا كنت لا تستخدم جلسة شاملة، يمكنك تخطي الإعلان عن الوظائف والحصول على إيماءة مستخدم والانتقال مباشرةً إلى طلب الجلسة. الجلسة الغامرة هي تلك التي تتطلّب سماعة رأس. تعرض الجلسة غير الغامرة المحتوى على شاشة الجهاز ببساطة. الأول هو ما يفكر فيه معظم الأشخاص عندما تشير إلى الواقع الافتراضي أو الواقع المعزز. تسمى الأخيرة أحيانًا "نافذة سحرية".

if (navigator.xr) {
    navigator.xr.requestDevice()
    .then(xrDevice => {
    // Advertise the AR/VR functionality to get a user gesture.
    })
    .catch(err => {
    if (err.name === 'NotFoundError') {
        // No XRDevices available.
        console.error('No XR devices available:', err);
    } else {
        // An error occurred while requesting an XRDevice.
        console.error('Requesting XR device failed:', err);
    }
    })
} else{
    console.log("This browser does not support the WebXR API.");
}

طلب جلسة XR

والآن بعد أن أصبح لدينا جهاز وإيماءة المستخدم، حان الوقت للحصول على جلسة. لإنشاء جلسة، يحتاج المتصفح إلى لوحة للرسم عليها.

xrPresentationContext = htmlCanvasElement.getContext('xrpresent');
let sessionOptions = {
    // The immersive option is optional for non-immersive sessions; the value
    //   defaults to false.
    immersive: false,
    outputContext: xrPresentationContext
}
xrDevice.requestSession(sessionOptions)
.then(xrSession => {
    // Use a WebGL context as a base layer.
    xrSession.baseLayer = new XRWebGLLayer(session, gl);
    // Start the render loop
})

تنفيذ حلقة العرض

يتطلّب رمز هذه الخطوة بعض التفكيك. لفهمها، أنا على وشك طرح مجموعة من الكلمات عليك. إذا كنت تريد إلقاء نظرة سريعة على الرمز النهائي، فيمكنك الانتقال سريعًا لإلقاء نظرة سريعة ثم الرجوع للاطّلاع على الشرح الكامل. هناك الكثير من المعلومات التي قد لا تكون قادرًا على استنتاجها.

تتمثل العملية الأساسية لتكرار العرض في ما يلي:

  1. اطلب إطارًا للصور المتحركة.
  2. طلب البحث عن موضع الجهاز
  3. ارسم المحتوى إلى موضع الجهاز استنادًا إلى موضعه.
  4. تنفيذ العمل المطلوب لأجهزة الإدخال.
  5. كرر 60 مرة في الثانية حتى يقرر المستخدم الاستقالة.

طلب إطار عرض تقديمي

هناك عدة معانٍ لكلمة "إطار" في سياق Web XR. الأول هو الإطار المرجعي الذي يحدّد من أين يتم احتساب أصل نظام الإحداثيات، وما يحدث لذلك المصدر عندما يتحرك الجهاز. (هل تظل طريقة العرض كما هي عندما يتحرك المستخدم أو تتغير كما هي في الحياة الواقعية؟)

النوع الثاني من الإطارات هو إطار العرض التقديمي، ويمثله كائن XRFrame. يحتوي هذا الكائن على المعلومات اللازمة لعرض إطار واحد من مشهد الواقع المعزّز/الواقع الافتراضي على الجهاز. ويكون هذا الأمر محيرًا بعض الشيء لأنه يتم استرداد إطار العرض التقديمي عن طريق استدعاء requestAnimationFrame(). وهذا يجعلها متوافقة مع window.requestAnimationFrame().

قبل أن أقدم لك المزيد من الملخّص، سأقدم بعض الرموز. ويوضّح النموذج التالي كيفية بدء حلقة العرض والحفاظ عليها. لاحظ الاستخدام المزدوج لإطار الكلمة. ولاحظ الاستدعاء المتكرر إلى requestAnimationFrame(). سيتم استدعاء هذه الدالة 60 مرة في الثانية.

xrSession.requestFrameOfReference('eye-level')
.then(xrFrameOfRef => {
    xrSession.requestAnimationFrame(onFrame(time, xrFrame) {
    // The time argument is for future use and not implemented at this time.
    // Process the frame.
    xrFrame.session.requestAnimationFrame(onFrame);
    }
});

الوضعيات

قبل رسم أي شيء على الشاشة، عليك أن تعرف إلى أين يشير جهاز العرض، وتحتاج إلى الوصول إلى الشاشة. بوجه عام، يُعرف وضع الجسم واتجاهه في الواقع المعزّز/الواقع الافتراضي على وضعية الجسم. كل من المشاهدين وأجهزة الإدخال لديهم وضعية. (أتناول أجهزة الإدخال لاحقًا). ويُعرَّف كل من وضعيات جهاز العرض وجهاز الإدخال بمصفوفة 4 × 4 مخزّنة في Float32Array بترتيب رئيسي. يمكنك الحصول على وضعية المشاهد من خلال استدعاء XRFrame.getDevicePose() على الكائن إطار الصورة المتحركة الحالي. اختبر دائما لمعرفة ما إذا كنت قد اتخذت وضعية العودة. إذا حدث خطأ ما، فلا تريد الرسم على الشاشة.

let pose = xrFrame.getDevicePose(xrFrameOfRef);
if (pose) {
    // Draw something to the screen.
}

مشاهدة

بعد التحقق من الوضع، حان الوقت لرسم شيء ما. ويُعرف الكائن الذي ترسم إليه باسم العرض (XRView)، وهنا يصبح نوع الجلسة مهمًا. يتم استرداد الملفات من كائن XRFrame كمصفوفة. إذا كنت في جلسة غير شاملة، فإن الصفيفة لها طريقة عرض واحدة. إذا كنت في جلسة شاملة، فإن الصفيف يحتوي على اثنتين، واحدة لكل عين.

for (let view of xrFrame.views) {
    // Draw something to the screen.
}

وهذا فرق مهم بين WebXR والأنظمة الشاملة الأخرى. على الرغم من أنه قد يبدو عدم جدوى التكرار من خلال عرض واحد، فإن القيام بذلك يتيح لك الحصول على مسار عرض واحد لمجموعة متنوعة من الأجهزة.

حلقة العرض بأكملها

إذا جمعت كل هذا معًا، أحصل على التعليمة البرمجية أدناه. لقد تركت عنصرًا نائبًا لأجهزة الإدخال، والتي سأتناولها في قسم لاحق.

xrSession.requestFrameOfReference('eye-level')
.then(xrFrameOfRef => {
    xrSession.requestAnimationFrame(onFrame(time, xrFrame) {
    // The time argument is for future use and not implemented at this time.
    let pose = xrFrame.getDevicePose(xrFrameOfRef);
    if (pose) {
        for (let view of xrFrame.views) {
        // Draw something to the screen.
        }
    }
    // Input device code will go here.
    frame.session.requestAnimationFrame(onFrame);
    }
}

إنهاء جلسة XR

قد تنتهي جلسة XR لعدة أسباب، بما في ذلك الإنهاء باستخدام رمزك الخاص من خلال الاتصال برقم XRSession.end(). تشمل الأسباب الأخرى فصل سماعة الرأس أو وجود تطبيق آخر يتحكم فيها. وهذا هو السبب في أنه يجب على التطبيق ذي الأداء الجيد مراقبة الحدث النهائي وعند حدوثه، تجاهل الجلسة وكائنات العارض. لا يمكن استئناف جلسة XR بمجرد انتهائها.

xrDevice.requestSession(sessionOptions)
.then(xrSession => {
    // Create a WebGL layer and initialize the render loop.
    xrSession.addEventListener('end', onSessionEnd);
});

// Restore the page to normal after immersive access has been released.
function onSessionEnd() {
    xrSession = null;

    // Ending the session stops executing callbacks passed to the XRSession's
    // requestAnimationFrame(). To continue rendering, use the window's
    // requestAnimationFrame() function.
    window.requestAnimationFrame(onDrawFrame);
}

كيف يعمل التفاعل؟

كما هو الحال مع عمر التطبيق، سأقدم لك عرضًا حول كيفية التفاعل مع الكائنات في الواقع المعزّز أو الواقع الافتراضي.

تعتمد واجهة برمجة التطبيقات WebXR Device API أسلوب "الإشارة والنقر" لإدخال المستخدم. من خلال هذه الطريقة، يكون لكل مصدر إدخال شعاع مؤشر محدّد للإشارة إلى موضع إشارة جهاز الإدخال والأحداث للإشارة إلى وقت اختيار عنصر. يرسم تطبيقك أشعة المؤشر وتعرض موضع المؤشر. عندما ينقر المستخدم على جهاز الإدخال، يتم تنشيط الأحداث، تحديدًا select وselectStart وselectEnd. يحدد تطبيقك ما تم النقر عليه ويستجيب بشكل مناسب.

جهاز الإدخال وشعاع المؤشر

بالنسبة إلى المستخدمين، يعتبر شعاع المؤشر مجرد خط خافت بين وحدة التحكم وأيًا كان يشير إليه. لكن التطبيق يجب أن يرسمها. وهذا يعني الحصول على وضع جهاز الإدخال ورسم خط من موقعه إلى كائن في مساحة الواقع المعزّز/الواقع الافتراضي. تبدو هذه العملية على النحو التالي تقريبًا:

let inputSources = xrSession.getInputSources();
for (let xrInputSource of inputSources) {
    let inputPose = frame.getInputPose(inputSource, xrFrameOfRef);
    if (!inputPose) {
    continue;
    }
    if (inputPose.gripMatrix) {
    // Render a virtual version of the input device
    //   at the correct position and orientation.
    }
    if (inputPose.pointerMatrix) {
    // Draw a ray from the gripMatrix to the pointerMatrix.
    }
}

هذه نسخة مبسّطة من نموذج تتبُّع الإدخال من مجموعة منتدى الويب Immersive Web Group. كما هو الحال مع عرض الإطار، فإن رسم شعاع المؤشر والجهاز متروك لك. وكما أشرنا سابقًا، يجب تشغيل هذه التعليمة البرمجية كجزء من حلقة العرض.

اختيار العناصر في المساحة الافتراضية

لا فائدة من مجرد الإشارة إلى الأشياء في الواقع المعزّز والواقع الافتراضي. للقيام بأي شيء مفيد، يحتاج المستخدمون إلى القدرة على تحديد الأشياء. توفّر WebXR Device API ثلاثة أحداث للاستجابة لتفاعلات المستخدم: select وselectStart و selectEnd. تتميز بمزايا لم أتوقعها: فهي تخبرك فقط أنه تم النقر على جهاز إدخال. وهي لا تخبرك بالعنصر الذي تم النقر عليه في البيئة المحيطة. تتم إضافة معالِجات الأحداث إلى العنصر XRSession ويجب إضافتها فور توفّرها.

xrDevice.requestSession(sessionOptions)
.then(xrSession => {
    // Create a WebGL layer and initialize the render loop.
    xrSession.addEventListener('selectstart', onSelectStart);
    xrSession.addEventListener('selectend', onSelectEnd);
    xrSession.addEventListener('select', onSelect);
});

يستند هذا الرمز إلى مثال على تحديد الإدخال، إذا كنت تريد الحصول على مزيد من السياق.

لمعرفة ما تم النقر عليه، تستخدم وضعية. (هل فاجأت؟ لم أكن أعتقد ذلك.) وتفاصيل ذلك خاصة بتطبيقك أو بأي إطار عمل تستخدمه، وبالتالي خارج نطاق هذه المقالة. يوجد أسلوب Cottontail في مثال تحديد الإدخال.

function onSelect(ev) {
    let inputPose = ev.frame.getInputPose(ev.inputSource, xrFrameOfRef);
    if (!inputPose) {
    return;
    }
    if (inputPose.pointerMatrix) {
    // Figure out what was clicked and respond.
    }
}

الخاتمة: التطلع إلى المستقبل

كما ذكرت سابقًا، من المتوقّع توفّر الواقع المعزّز في Chrome 69 (إصدار Canary في وقت ما في حزيران (يونيو) 2018). ومع ذلك، أشجعك على تجربة ما لدينا حتى الآن. ونحتاج إلى ملاحظات لتحسينه. تابع التقدم من خلال مشاهدة ChromeStatus.com لـ WebXR Hit Test. يمكنك أيضًا اتباع WebXR Anchors والتي ستعمل على تحسين تتبُّع الوضعية.