WebVR ตอนที่ 5: การออกแบบและการใช้งาน
เผยแพร่แล้ว: 2022-03-11ฉันชอบที่จะทำโครงการให้ "เสร็จสิ้น" เรามาถึงจุดสิ้นสุดของการเดินทางแล้ว - และการกำเนิดของการจำลองแรงโน้มถ่วงบนท้องฟ้าใน WebVR
ในโพสต์สุดท้ายนี้ เราจะเสียบโค้ดการจำลองประสิทธิภาพสูงของเรา (บทความ 1,2,3) ลงในโปรแกรมสร้างภาพ WebVR โดยอิงจากโปรแกรมสร้างภาพแคนวาส (มาตรา 4)
- "ปัญหาร่างกาย" บทนำและสถาปัตยกรรม
- Web Workers รับเธรดเบราว์เซอร์เพิ่มเติมให้เรา
- WebAssembly และ AssemblyScript สำหรับรหัสคอขวดด้านประสิทธิภาพ O(n²) ของเรา
- การแสดงข้อมูลผ้าใบ
- การแสดงข้อมูล WebVR
นี่เป็นบทความที่ยาวขึ้น ดังนั้นเราจะข้ามรายละเอียดทางเทคนิคที่กล่าวถึงก่อนหน้านี้ ตรวจสอบโพสต์ก่อนหน้านี้หากคุณต้องการปฐมนิเทศหรืออ่านในเชิงอันตราย
เราได้สำรวจการเปลี่ยนกระบวนทัศน์ของเบราว์เซอร์จากรันไทม์ JavaScript แบบเธรดเดียวไปเป็นแบบมัลติเธรด (ผู้ทำงานเว็บ) รันไทม์ประสิทธิภาพสูง (WebAssembly) คุณลักษณะการประมวลผลเดสก์ท็อปที่มีประสิทธิภาพเหล่านี้มีอยู่ใน Progressive Web Apps และรูปแบบการแจกจ่าย SaaS
VR จะสร้างสภาพแวดล้อมการขายและการตลาดที่ปราศจากสิ่งรบกวนที่น่าสนใจเพื่อสื่อสาร โน้มน้าวใจ และวัดผลการมีส่วนร่วม (การติดตามการมองและการโต้ตอบ) ข้อมูลจะยังคงเป็นศูนย์และหนึ่ง แต่บทสรุปสำหรับผู้บริหารที่คาดหวังและประสบการณ์ของผู้บริโภคจะเป็น WebVR เช่นเดียวกับที่เราสร้างประสบการณ์แดชบอร์ดบนมือถือสำหรับเว็บทั่วไปในปัจจุบัน
เทคโนโลยีเหล่านี้ยังเปิดใช้งานการประมวลผลขอบเบราว์เซอร์แบบกระจาย ตัวอย่างเช่น เราสามารถสร้างแอปพลิเคชันบนเว็บเพื่อเรียกใช้การคำนวณ WebAssembly สำหรับดาวนับล้านในการจำลอง อีกตัวอย่างหนึ่งคือแอปพลิเคชันแอนิเมชั่นที่แสดงการสร้างสรรค์ของผู้ใช้รายอื่นในขณะที่คุณกำลังแก้ไขของคุณเอง
เนื้อหาความบันเทิงเป็นผู้นำในการเข้าถึง Virtual Reality เช่นเดียวกับความบันเทิงบนมือถือ อย่างไรก็ตาม เมื่อ VR เป็นเรื่องปกติ (เช่น การออกแบบเพื่ออุปกรณ์พกพาเป็นหลักในปัจจุบัน) ก็จะเป็นประสบการณ์ที่คาดหวัง (การออกแบบที่เน้น VR เป็นหลัก) นี่เป็นช่วงเวลาที่น่าตื่นเต้นมากในการเป็นนักออกแบบและนักพัฒนา และ VR เป็นกระบวนทัศน์การออกแบบที่แตกต่างไปจากเดิมอย่างสิ้นเชิง
คุณไม่ใช่นักออกแบบ VR หากคุณจับไม่ได้ นั่นเป็นคำกล่าวที่ชัดเจน และวันนี้เป็นการเจาะลึกในการออกแบบ VR ฟิลด์นี้กำลังถูกประดิษฐ์ขึ้นเมื่อคุณอ่านข้อความนี้ จุดประสงค์ของฉันคือการแบ่งปันประสบการณ์ของฉันในซอฟต์แวร์และภาพยนตร์เพื่อเน้นการสนทนา “การออกแบบที่เน้น VR เป็นหลัก” เราทุกคนเรียนรู้จากกันและกัน.
เมื่อคำนึงถึงการคาดการณ์อันยิ่งใหญ่เหล่านั้น ฉันต้องการทำโปรเจ็กต์นี้ให้เสร็จด้วยการสาธิตเทคโนโลยีระดับมืออาชีพ - WebVR เป็นตัวเลือกที่ยอดเยี่ยมสำหรับสิ่งนั้น!
WebVR และ Google A-Frame
WebVR git repo เป็นทางแยกของเวอร์ชันแคนวาสด้วยเหตุผลสองประการ ทำให้การโฮสต์โปรเจ็กต์บนหน้า Github ง่ายขึ้น และ WebVR ต้องการการเปลี่ยนแปลงสองสามอย่างซึ่งจะทำให้เวอร์ชันแคนวาสและบทความเหล่านี้รก
หากคุณจำโพสต์แรกของเราเกี่ยวกับสถาปัตยกรรมได้ เราได้มอบหมายการจำลองทั้งหมดไปที่ nBodySimulator
โพสต์ของ Web Worker แสดงให้เห็นว่า nBodySimulator
มีฟังก์ชัน step()
ที่เรียกว่าทุกๆ 33ms ของการจำลอง step()
เรียก calcForces calculateForces()
เพื่อเรียกใช้โค้ดจำลอง O(n²) WebAssembly ของเรา (ข้อ 3) จากนั้นอัปเดตตำแหน่งและทาสีใหม่ ในโพสต์ก่อนหน้าของเราที่สร้างการแสดงภาพแคนวาส เราได้ใช้งานสิ่งนี้กับองค์ประกอบแคนวาส โดยเริ่มจากคลาสพื้นฐานนี้:
/** * Base class that console.log()s the simulation state. */ export class nBodyVisualizer { constructor(htmlElement) { this.htmlElement = htmlElement this.resize() this.scaleSize = 25 // divided into bodies drawSize. drawSize is log10(mass) // This could be refactored to the child class. // Art is never finished. It must be abandoned. } resize() {} paint(bodies) { console.log(JSON.stringify(bodies, null, 2)) } }
กำหนดความท้าทายในการบูรณาการ
เรามีแบบจำลอง ตอนนี้ เราต้องการผสานรวมกับ WebVR โดยไม่ต้องออกแบบโครงการใหม่ ไม่ว่าเราจะทำการปรับเปลี่ยนอะไรกับการจำลองทุกๆ 33ms ในเธรด UI หลักในฟังก์ชัน paint(bodies)
นี่คือวิธีที่เราจะวัดว่า "เสร็จสิ้น" ฉันตื่นเต้น - ไปทำงานกันเถอะ!
วิธีสร้างความจริงเสมือน
อันดับแรก เราต้องออกแบบ:
- VR ทำมาจาก อะไร?
- การออกแบบ WebVR แสดงออก อย่างไร ?
- เราจะ โต้ตอบ กับมันได้อย่างไร
Virtual Reality ย้อนเวลากลับไปสู่รุ่งอรุณของเวลา เรื่องราวแคมป์ไฟทุกเรื่องเป็นโลกเสมือนจริงเล็ก ๆ ของการพูดเกินจริงที่บรรยายโดยรายละเอียดเล็กน้อย
เราเพิ่มเรื่องราวแคมป์ไฟได้ 10 เท่าด้วยการเพิ่มภาพและเสียงสามมิติแบบสามมิติ ผู้สอนด้านงบประมาณการผลิตภาพยนตร์ของฉันเคยพูดว่า “เราจ่ายแค่ค่าโปสเตอร์เท่านั้น เราไม่ได้สร้างความเป็นจริง”
หากคุณคุ้นเคยกับ DOM ของเบราว์เซอร์ คุณจะรู้ว่ามันสร้างโครงสร้างแบบลำดับชั้นเหมือนต้นไม้
โดยนัยในการออกแบบเว็บคือการที่ผู้ชมดูจาก "ด้านหน้า" เมื่อมองจากด้านข้างจะเห็นองค์ประกอบ DOM เป็นเส้น และจากด้านหลัง เราจะเห็นแท็ก <body>
เพราะมันบดบังลูกๆ
ส่วนหนึ่งของประสบการณ์เสมือนจริงของ VR คือการให้ผู้ใช้ควบคุมมุมมอง สไตล์ ฝีเท้า และลำดับของการโต้ตอบ พวกเขาไม่ต้องสนใจอะไรเป็นพิเศษ หากคุณย้ายหรือหมุนกล้องโดยทางโปรแกรม กล้องจะ อ้วก จากการเจ็บป่วย VR
โปรดทราบว่าการเจ็บป่วย VR ไม่ใช่เรื่องตลก ทั้งตาและหูชั้นในของเราตรวจจับการเคลื่อนไหว มันสำคัญมากสำหรับสัตว์ที่เดินตัวตรง เมื่อเซ็นเซอร์ตรวจจับความเคลื่อนไหวเหล่านั้นไม่เห็นด้วย สมองของเราจะถือว่าโดยธรรมชาติแล้วปากของเราได้กินเรื่องไร้สาระอีกแล้วและอาเจียนออกมา เราทุกคนเคยเป็นเด็กมาก่อน มีการเขียนเกี่ยวกับสัญชาตญาณการเอาชีวิตรอดใน VR ไว้มากมายแล้ว ชื่อ “Epic Fun” นั้นเล่นได้ฟรีบน Steam และรถไฟเหาะเป็นการสาธิตการเจ็บป่วย VR ที่ดีที่สุดที่ฉันเคยพบ
ความเป็นจริงเสมือนจะแสดงเป็น "กราฟฉาก" กราฟฉากมีรูปแบบคล้ายต้นไม้เหมือนกับ DOM เพื่อซ่อนรายละเอียดและความซับซ้อนของสภาพแวดล้อม 3 มิติที่น่าเชื่อ อย่างไรก็ตาม แทนที่จะเลื่อนและกำหนดเส้นทาง เราวางตำแหน่งผู้ดูในตำแหน่งที่พวกเขาต้องการดึงประสบการณ์ไปทางพวกเขา
นี่คือกราฟฉาก Hello World จาก A-Frame WebVR Framework ของ Google:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello, WebVR! • A-Frame</title> <meta name="description" content="Hello, WebVR! • A-Frame"> <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script> </head> <body> <a-scene background="color: #FAFAFA"> <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" shadow></a-box> <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E" shadow></a-sphere> <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D" shadow></a-cylinder> <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow></a-plane> </a-scene> </body> </html>
เอกสาร HTML นี้สร้าง DOM ในเบราว์เซอร์ แท็ก <a-*>
เป็นส่วนหนึ่งของเฟรมเวิร์ก A-Frame และ <a-scene>
เป็นรากของกราฟฉาก ในที่นี้ เราจะเห็นภาพ 3D primitives สี่ภาพที่แสดงอยู่ในฉาก
อันดับแรก สังเกตว่าเรากำลังดูฉากนี้จากเว็บเบราว์เซอร์แบบเรียบ หน้ากากเล็ก ๆ ที่ด้านล่างขวาเชิญชวนให้ผู้ใช้เปลี่ยนไปใช้โหมดสามมิติสามมิติ
ตามทฤษฎีแล้ว คุณควรจะสามารถ:
- เปิดสิ่งนี้บนโทรศัพท์ของคุณ
- ถือโทรศัพท์แนบหน้า
- ดื่มด่ำกับความงดงามของความเป็นจริงครั้งใหม่!
ฉันไม่เคยใช้งานมันเลยหากไม่มีเลนส์แฟนซีของชุดหูฟัง VR คุณสามารถรับชุดหูฟัง VR สำหรับโทรศัพท์ Android ในราคาถูก (อุปกรณ์พื้นฐานที่ใช้ Google Cardboard) อย่างไรก็ตาม สำหรับการพัฒนาเนื้อหา ฉันขอแนะนำ HMD แบบสแตนด์อโลน (Head Mounted Display) เช่น Oculus Quest
เหมือนกับการดำน้ำลึกหรือดิ่งพสุธา Virtual Reality เป็นกีฬาที่มีอุปกรณ์ครบครัน
การเรียนรู้ของนักออกแบบ VR "หน้าผา"
สังเกตว่าฉาก A-Frame Hello World มีแสงและกล้องเริ่มต้น:
- ใบหน้าของลูกบาศก์มีสีต่างกัน - ลูกบาศก์มีเงาในตัว
- ลูกบาศก์กำลังขว้างเงาบนเครื่องบิน - มีแสงบอกทิศทาง
- ไม่มีช่องว่างระหว่างลูกบาศก์กับระนาบ - นี่คือโลกที่มีแรงโน้มถ่วง
นี่เป็นสัญญาณสำคัญที่บอกผู้ชมว่า “ผ่อนคลาย สิ่งนี้บนใบหน้าของคุณเป็นเรื่องปกติโดยสิ้นเชิง”
นอกจากนี้ โปรดสังเกตว่าการตั้งค่าเริ่มต้นนี้มีนัยในโค้ดของฉาก Hello World ด้านบน A-Frame เป็นค่าเริ่มต้นที่สมเหตุสมผล แต่โปรดทราบว่ากล้องและแสงเป็นช่องว่างที่นักออกแบบต้องข้ามเพื่อสร้าง VR
เราใช้การตั้งค่าแสงเริ่มต้นตามที่เห็นสมควร ตัวอย่างเช่น ปุ่ม:
สังเกตว่าแสงโดยนัยนี้แพร่หลายมากเพียงใดในการออกแบบและการถ่ายภาพ แม้แต่ปุ่ม "การออกแบบเรียบๆ" ก็ไม่สามารถหลีกหนีจากแสงเริ่มต้นของเว็บได้ เนื่องจากมันทำให้เงาตกกระทบไปทางขวา
การออกแบบ สื่อสาร และใช้งานการจัดแสงและการตั้งค่ากล้องคือจุดเริ่มต้นการเรียนรู้ของนักออกแบบ WebVR “ภาษาของภาพยนตร์” คือชุดของบรรทัดฐานทางวัฒนธรรม ซึ่งแสดงเป็นกล้องและการจัดแสงที่แตกต่างกัน ซึ่งจะสื่ออารมณ์เรื่องราวให้ผู้ชมได้ทราบ มืออาชีพในภาพยนตร์ที่ออกแบบ/ย้ายไฟและกล้องไปรอบๆ ฉากคือแผนกกริป
กลับสู่ความเป็นจริงเสมือนของเรา
งั้นเรากลับไปทำงานกันเถอะ ฉาก WebVR บนท้องฟ้าของเรามีรูปแบบที่คล้ายกัน:
<!DOCTYPE> <html> <head> <script src="https://aframe.io/releases/0.9.2/aframe.min.js"></script> <script src="https://unpkg.com/[email protected]/dist/aframe-event-set-component.min.js"></script> <script src="main.js"></script> </head> <body> <a-scene> <a-sky color="#222"></a-sky> <a-entity geometry="primitive: circle; radius: 12" position="0 0 -.5" material="color: #333; transparent: true; opacity: 0.5"> <a-sphere color="black" radius=."02"></a-sphere> </a-entity> <a-entity></a-entity> <a-entity geometry="primitive: plane; width: 2; height: auto" position="0 -10 .3" rotation="55 0 0" material="color: blue" text="value: Welcome Astronaut!..."> </a-entity> <a-entity position="0 -12 .7" rotation="55 0 0"> <a-camera> <a-cursor color="#4CC3D9" fuse="true" timeout="1"></a-cursor> </a-camera> </a-entity> </a-scene> </body> </html>
เอกสาร HTML นี้โหลดเฟรมเวิร์ก A-Frame และปลั๊กอินการโต้ตอบ ฉากของเราเริ่มต้นที่ <a-scene>
ข้างใน เราเริ่มด้วยองค์ประกอบ <a-sky color="#222"></a-sky>
เพื่อสร้างสีพื้นหลังทุกอย่างที่เราไม่ได้กำหนดไว้ในฉาก
ต่อไป เราสร้าง "ระนาบโคจร" เพื่อให้ผู้ชม "จับ" ขณะที่พวกเขาบินผ่านโลกที่แปลกประหลาดและไม่รู้จักของเรา เราสร้างสิ่งนี้เป็นแผ่นดิสก์และทรงกลมสีดำขนาดเล็กที่ (0,0,0) หากปราศจากสิ่งนี้ การหันกลับรู้สึกว่า "ไม่มีเหตุผล" สำหรับฉัน:
<a-entity geometry="primitive: circle; radius: 12" position="0 0 -.5" material="color: #333; transparent: true; opacity: 0.5"> <a-sphere color="black" radius=."02"></a-sphere> </a-entity>
ต่อไป เรากำหนดคอลเล็กชันที่เราสามารถเพิ่ม/ลบ/เปลี่ยนตำแหน่งเอนทิตี A-Frame
<a-entity></a-entity>
นี่คือการล้างเพื่อให้ paint(bodies)
ของ nBodyVisualizer
ทำงาน
จากนั้นเราก็สร้างความสัมพันธ์ระหว่างผู้ดูกับโลกนี้ ในการสาธิตเทคโนโลยี จุดประสงค์ของโลกนี้คือเพื่อให้ผู้ดูสำรวจ WebVR และเทคโนโลยีของเบราว์เซอร์ที่เปิดใช้งาน การเล่าเรื่องแบบ "นักบินอวกาศ" ที่เรียบง่ายช่วยสร้างความรู้สึกสนุกสนาน และป้ายบอกทางที่เป็นตัวเอกนี้ก็เป็นอีกจุดอ้างอิงสำหรับการนำทาง
<a-entity geometry="primitive: plane; width: 2; height: auto" position="0 -10 .3" rotation="55 0 0" material="color: blue" text="value: Welcome Astronaut!\n ..."> </a-entity>
นั่นทำให้กราฟฉากของเราสมบูรณ์ สุดท้ายนี้ ฉันต้องการปฏิสัมพันธ์ บางอย่าง ในการสาธิตทางโทรศัพท์ระหว่างผู้ใช้กับโลกที่ปั่นป่วนนี้ เราจะสร้างปุ่ม "โยนเศษซาก" ใน VR ได้อย่างไร?
ปุ่มนี้เป็นองค์ประกอบหลักของการออกแบบที่ทันสมัย ปุ่ม VR อยู่ที่ไหน
การโต้ตอบใน WebVR
Virtual Reality มี "ด้านบน" และ "ครึ่งหน้าล่าง" ของตัวเอง การโต้ตอบครั้งแรกของผู้ดูคือผ่านอวาตาร์หรือกล้อง นี่คือการควบคุมทั้งหมดสำหรับการซูมไปรอบๆ
หากคุณกำลังอ่านข้อความนี้บนเดสก์ท็อป คุณสามารถ WASD เพื่อย้ายและเลื่อนเมาส์เพื่อหมุนกล้อง การสำรวจนี้เปิดเผยข้อมูลแต่ไม่ได้แสดงเจตจำนงของคุณ
Real Reality มีคุณสมบัติที่สำคัญสองสามอย่างที่ไม่ค่อยพบในเว็บ:
- มุมมอง - วัตถุจะเล็กลงอย่างเห็นได้ชัดเมื่อพวกมันเคลื่อนตัวออกห่างจากเรา
- การ บดเคี้ยว - วัตถุถูกซ่อนและเปิดเผยตามตำแหน่ง
VR จำลองคุณสมบัติเหล่านี้เพื่อสร้างเอฟเฟกต์ 3D นอกจากนี้ยังสามารถใช้ใน VR เพื่อเปิดเผยข้อมูลและอินเทอร์เฟซ และเพื่อสร้างอารมณ์ก่อนที่จะนำเสนอการโต้ตอบ ฉันพบว่าคนส่วนใหญ่ต้องใช้เวลาสักครู่เพื่อเพลิดเพลินกับประสบการณ์นี้ก่อนที่จะก้าวไปข้างหน้า

ใน WebVR เราโต้ตอบในพื้นที่ 3 มิติ เรามีเครื่องมือพื้นฐานสองอย่างสำหรับสิ่งนี้:
- Collision - เหตุการณ์ 3D แบบพาสซีฟเกิดขึ้นเมื่อวัตถุสองชิ้นใช้พื้นที่เดียวกัน
- การฉายภาพ - การเรียกใช้ฟังก์ชัน 2D ที่ใช้งานอยู่ซึ่งแสดงรายการวัตถุทั้งหมดที่ตัดกันเป็นเส้น
การชนกันเป็นการโต้ตอบที่ "เหมือน VR" ที่สุด
ใน VR "การชนกัน" คือสิ่งที่ดูเหมือน: เมื่อวัตถุสองชิ้นใช้พื้นที่เดียวกัน A-Frame จะสร้างเหตุการณ์ขึ้น
เพื่อให้ผู้ใช้ "กดปุ่ม" เราต้องให้สัญลักษณ์แทนตัวและบางสิ่งที่จะกดปุ่มด้วย
น่าเสียดายที่ WebVR ยังไม่สามารถคาดเดาตัวควบคุมได้ หลายคนจะดูเวอร์ชันเว็บแบบเรียบบนเดสก์ท็อปหรือโทรศัพท์ และหลายคนจะใช้ชุดหูฟัง เช่น Google Cardboard หรือ Gear VR ของ Samsung เพื่อแสดงเวอร์ชันสามมิติ
หากผู้ใช้ไม่มีตัวควบคุม พวกเขาจะเอื้อมมือออกไปและ "สัมผัส" สิ่งต่างๆ ไม่ได้ ดังนั้นการชนกันจะต้องอยู่ที่ "พื้นที่ส่วนตัว"
เราสามารถให้ผู้เล่นจำนำรูปนักบินอวกาศเพื่อเคลื่อนที่ไปรอบ ๆ ได้ แต่การบังคับผู้ใช้ให้กลายเป็นดาวเคราะห์ที่หมุนวนดูเหมือนจะไม่ค่อยดีนักและขัดกับความกว้างขวางของการออกแบบของเรา
การฉายภาพเป็นแบบ 2 มิติ “เหมือนเว็บ” คลิกใน 3D Space
นอกจาก "การชน" เรายังสามารถใช้ "การฉายภาพ" ได้อีกด้วย เราสามารถฉายเส้นผ่านฉากของเราและดูสิ่งที่สัมผัสได้ ตัวอย่างที่พบบ่อยที่สุดคือ "รังสีเทเลพอร์ต"
รังสีเทเลพอร์ตลากเส้นในโลกเพื่อแสดงตำแหน่งที่ผู้เล่นสามารถเคลื่อนที่ได้ “การฉายภาพ” นี้มองหาสถานที่ที่จะลงจอด ส่งคืนวัตถุอย่างน้อยหนึ่งรายการในเส้นทางของการฉายภาพ นี่คือตัวอย่างรังสีเทเลพอร์ต:
สังเกตว่าจริง ๆ แล้วรังสีถูกนำมาใช้เป็นพาราโบลาที่ชี้ลง ซึ่งหมายความว่าธรรมชาติตัดกับ "พื้นดิน" เหมือนวัตถุที่ถูกขว้าง สิ่งนี้ยังกำหนดระยะการเคลื่อนย้ายสูงสุดโดยธรรมชาติ ข้อจำกัดคือตัวเลือกการออกแบบที่สำคัญที่สุดใน VR โชคดีที่ความเป็นจริงมีข้อ จำกัด ตามธรรมชาติมากมาย
การฉายภาพ “แผ่” โลก 3D ให้เป็น 2D เพื่อให้คุณสามารถชี้ไปที่สิ่งต่างๆ เพื่อคลิกได้เหมือนเมาส์ เกมยิงมุมมองบุคคลที่หนึ่งเป็นเกมที่ซับซ้อนของการ "คลิก 2 มิติ" บนปุ่มที่น่าผิดหวัง - มักจะมีเรื่องราวที่ซับซ้อนเพื่ออธิบายว่าทำไมมันจึงไม่โอเคที่ปุ่มเหล่านั้นจะ "คลิก" คุณกลับ
มีปืนจำนวนมากใน VR เนื่องจากปืนได้รับการปรับปรุงให้สมบูรณ์แบบเหมือนเมาส์ 3 มิติที่แม่นยำและเชื่อถือได้ และการคลิกคือสิ่งที่ผู้บริโภครู้วิธีการทำโดยไม่ต้องเรียนรู้
การฉายภาพยังให้ความปลอดภัยในระยะห่างในความสัมพันธ์กับฉาก จำไว้ว่าการเข้าใกล้บางสิ่งใน VR จะทำให้สิ่งอื่น ๆ ที่อาจยังไม่เปิดเผยความสำคัญหายไปโดยธรรมชาติ
การฉายภาพโดยไม่ใช้ตัวควบคุมโดยใช้ “จ้อง”
ในการสร้างปฏิสัมพันธ์แบบดั้งเดิมใน WebVR โดยไม่ต้องใช้ตัวควบคุม เราสามารถฉายภาพ "จ้องมอง" ของผู้ดูเป็น "เคอร์เซอร์" ในสายตา เคอร์เซอร์นี้สามารถใช้โดยทางโปรแกรมเพื่อโต้ตอบกับวัตถุด้วย "ฟิวส์" นี่คือการสื่อสารไปยังผู้ชมเป็นวงกลมสีน้ำเงินขนาดเล็ก ตอนนี้เรากำลังคลิก!
หากคุณจำเรื่องราวเกี่ยวกับแคมป์ไฟได้ ยิ่งเรื่องโกหกมากเท่าไหร่ รายละเอียดก็น้อยลงในการขาย ปฏิสัมพันธ์ "จ้องมอง" ที่เห็นได้ชัดและไร้สาระคือการจ้องไปที่ดวงอาทิตย์ เราใช้ "การจ้อง" นี้เพื่อกระตุ้นการเพิ่มดาวเคราะห์ "เศษซาก" ใหม่ลงในการจำลองของเรา ผู้ชมไม่เคยตั้งคำถามกับตัวเลือกนี้ - VR ค่อนข้างมีเสน่ห์เมื่อไร้สาระ
ใน A-Frame เราแสดงกล้อง (สัญลักษณ์แทนตัวที่มองไม่เห็นของผู้เล่น) และ "เคอร์เซอร์" ของสายตานี้เป็นอุปกรณ์สำหรับกล้องของเรา การวาง <a-cursor>
ไว้ใน <a-camera>
จะทำให้การแปลงของกล้องมีผลกับเคอร์เซอร์ด้วย เมื่อผู้เล่นเคลื่อนที่/หมุนสัญลักษณ์แทนตัว ( a-camera
) ผู้เล่นก็จะเคลื่อนที่/หมุนการจ้องมองด้วย ( a-cursor
)
// src/index.html <a-entity position="0 -12 .7" rotation="55 0 0"> <a-camera> <a-cursor color="#4CC3D9" fuse="true" timeout="1"></a-cursor> </a-camera> </a-entity>
"ฟิวส์" ของเคอร์เซอร์จะรอจนกระทั่ง "จ้อง" ครบหนึ่งวินาทีก่อนที่จะปล่อยเหตุการณ์
ฉันใช้แสงเริ่มต้น ดังนั้นคุณอาจสังเกตเห็นว่ามี "ด้านหลัง" ของดวงอาทิตย์ที่ไม่มีแสงสว่าง แม้ว่าฉันจะไม่ได้อยู่นอกระนาบโคจร ฉันก็ไม่คิดว่าดวงอาทิตย์จะทำงานแบบนั้น อย่างไรก็ตาม มันใช้ได้กับโปสเตอร์สาธิตเทคโนโลยีของความเป็นจริงของเรา
อีกทางเลือกหนึ่งคือการจัดแสงภายในองค์ประกอบของกล้องเพื่อให้เคลื่อนที่ไปพร้อมกับผู้ใช้ สิ่งนี้จะสร้างประสบการณ์การขุดดาวเคราะห์น้อยที่ใกล้ชิดและน่ากลัวยิ่งขึ้น นี่เป็นตัวเลือกการออกแบบที่สนุกสนาน
เรามีแผนบูรณาการ
ด้วยเหตุนี้ เราจึงมีจุดรวมระหว่าง A-Frame <a-scene>
และการจำลอง JavaScript ของเรา:
A-Frame <a-scene>
:
คอลเลกชันที่มีชื่อสำหรับเนื้อหา:
<a-entity></a-entity>
เคอร์เซอร์ที่จะปล่อยเหตุการณ์การฉาย:
<a-cursor color="#4CC3D9" fuse="true" timeout="1"></a-cursor>
การจำลอง JavaScript ของเรา:
nBodyVisWebVR.paint(bodies)
- เพิ่ม/ลบ/เปลี่ยนตำแหน่งเอนทิตี VR จากตัวจำลองaddBodyArgs(name, color, x, y, z, mass, vX, vY, vZ)
เพื่อเพิ่มวัตถุใหม่ลงในการจำลอง
index.html
โหลด main.js
ซึ่งเริ่มต้นการจำลองของเราเหมือนกับเวอร์ชันผ้าใบ:
// src/main.js import { nBodyVisualizer, nBodyVisWebVR } from ."/nBodyVisualizer" import { Body, nBodySimulator } from ."/nBodySimulator" window.onload = function() { // Create a Simulation const sim = new nBodySimulator() // this Visualizer manages the UI sim.addVisualization(new nBodyVisWebVR(document.getElementById("a-bodies"), sim)) // making up stable universes is hard // name color xyzm vz vy vz sim.addBody(new Body("star", "yellow", 0, 0, 1, 1e9)) sim.addBody(new Body("hot-jupiter", "red", -1, -1, 1, 1e4, .24, -0.05, 0)) sim.addBody(new Body("cold-jupiter", "purple", 4, 4, .5, 1e4, -.07, 0.04, 0)) // Start simulation sim.start() // Add another sim.addBody(new Body("saturn", "blue", -8, -8, .1, 1e3, .07, -.035, 0)) }
คุณจะสังเกตเห็นว่าที่นี่เราตั้งค่า htmlElement
ของ visualizer เป็นคอลเล็กชัน a-bodies
เพื่อเก็บศพ
การจัดการอ็อบเจ็กต์ A-Frame โดยทางโปรแกรมจาก JavaScript
หลังจากประกาศฉากของเราใน index.html
แล้ว เราก็พร้อมที่จะโค้ดโปรแกรมสร้างภาพ
อันดับแรก เราตั้งค่า nBodyVisualizer
ให้อ่านจากรายการเนื้อหา nBodySimulation
และสร้าง/อัปเดต/ลบออบเจ็กต์ A-Frame ในคอลเล็กชัน <a-entity></a-entity>
// src/nBodyVisualizer.js /** * This is the WebVR visualizer. * It's responsible for painting and setting up the entire scene. */ export class nBodyVisWebVR extends nBodyVisualizer { constructor(htmlElement, sim) { // HTML Element is a-collection#a-bodies. super(htmlElement) // We add these to the global namespace because // this isn't the core problem we are trying to solve. window.sim = sim this.nextId = 0 } resize() {}
ในตัวสร้าง เราบันทึกคอลเลกชัน A-Frame ของเรา ตั้งค่าตัวแปรส่วนกลางสำหรับเหตุการณ์การจ้องมองของเราเพื่อค้นหาการจำลอง และเริ่มต้นตัวนับรหัสที่เราจะใช้เพื่อจับคู่เนื้อหาระหว่างการจำลองของเรากับฉากของ A-Frame
paint(bodies) { let i // Create lookup table: lookup[body.aframeId] = body const lookup = bodies.reduce( (total, body) => { // If new body, give it an aframeId if (!body.aframeId) body.aframeId = `a-sim-body-${body.name}-${this.nextId++}` total[body.aframeId] = body return total }, {}) // Loop through existing a-sim-bodies and remove any that are not in // the lookup - this is our dropped debris const aSimBodies = document.querySelectorAll(."a-sim-body") for (i = 0; i < aSimBodies.length; i++) { if (!lookup[aSimBodies[i].id]) { // if we don't find the scene's a-body in the lookup table of Body()s, // remove the a-body from the scene aSimBodies[i].parentNode.removeChild(aSimBodies[i]); } } // loop through sim bodies and upsert let aBody bodies.forEach( body => { // Find the html element for this aframeId aBody = document.getElementById(body.aframeId) // If html element not found, make one. if (!aBody) { this.htmlElement.innerHTML += ` <a-sphere class="a-sim-body" dynamic-body ${ (body.name === "star") ? "debris-listener event-set__enter='_event: mouseenter; color: green' event-set__leave='_event: mouseleave; color: yellow'" : ""} position="0 0 0" radius="${body.drawSize/this.scaleSize}" color="${body.color}"> </a-sphere>` aBody = document.getElementById(body.aframeId) } // reposition aBody.object3D.position.set(body.x, body.y, body.z) }) }
ขั้นแรก เราวนลูปผ่านเนื้อความของซิมเพื่อติดป้ายกำกับและ/หรือสร้างตารางค้นหาสำหรับการจับคู่เอนทิตี A-Frame กับเนื้อหาการจำลอง
ต่อไป เราจะวนรอบร่างกาย A-Frame ที่มีอยู่และลบส่วนใดก็ตามที่ถูกตัดแต่งโดยการจำลองสำหรับการเดินทางออกนอกขอบเขต สิ่งนี้ช่วยเพิ่มประสิทธิภาพการรับรู้ของประสบการณ์
สุดท้าย เราวนลูปผ่านเนื้อความของซิมเพื่อสร้าง <a-sphere>
ใหม่สำหรับร่างกายที่หายไป และเพื่อปรับตำแหน่งอื่นๆ ด้วย aBody.object3D.position.set(body.x, body.y, body.z)
เราสามารถปรับเปลี่ยนองค์ประกอบในฉาก A-Frame โดยทางโปรแกรมได้โดยใช้ฟังก์ชัน DOM มาตรฐาน ในการเพิ่มองค์ประกอบให้กับฉาก เราผนวกสตริงเข้ากับ innerHTML ของคอนเทนเนอร์ รหัสนี้มีรสชาติแปลกสำหรับฉัน แต่ใช้งานได้ และฉันไม่พบอะไรที่ดีกว่านี้
คุณจะสังเกตเห็นว่าเมื่อเราสร้างสตริงที่จะผนวก เรามีตัวดำเนินการ ternary ใกล้ "star" เพื่อตั้งค่าแอตทริบิวต์
<a-sphere class="a-sim-body" dynamic-body ${ (body.name === "star") ? "debris-listener event-set__enter='_event: mouseenter; color: green' event-set__leave='_event: mouseleave; color: yellow'" : ""} position="0 0 0" radius="${body.drawSize/this.scaleSize}" color="${body.color}"> </a-sphere>`
หากร่างกายเป็น "ดาว" เราจะเพิ่มคุณลักษณะพิเศษบางอย่างที่อธิบายเหตุการณ์ของมัน นี่คือลักษณะของดาวของเราเมื่อติดตั้งใน DOM:
<a-sphere class="a-sim-body" dynamic-body="" debris-listener="" event-set__enter="_event: mouseenter; color: green" event-set__leave="_event: mouseleave; color: yellow" position="0 0 0" radius="0.36" color="yellow" material="" geometry=""></a-sphere>
แอตทริบิวต์สามอย่าง, debris-listener
, event-set__enter
และ event-set__leave
ตั้งค่าการโต้ตอบของเราและเป็นรอบสุดท้ายของการรวมระบบของเรา
การกำหนดเหตุการณ์ A-Frame และการโต้ตอบ
เราใช้แพ็คเกจ NPM "aframe-event-set-component" ในแอตทริบิวต์ของเอนทิตีเพื่อเปลี่ยนสีของดวงอาทิตย์เมื่อผู้ดู "มอง" ไปที่มัน
“การจ้องมอง” นี้เป็นการฉายภาพจากตำแหน่งและการหมุนของผู้ดู และการโต้ตอบให้ข้อเสนอแนะที่จำเป็นว่าการจ้องมองของพวกเขากำลังทำอะไรบางอย่าง
ทรงกลมดาวของเราตอนนี้มีเหตุการณ์ชวเลขสองเหตุการณ์ที่เปิดใช้งานโดยปลั๊กอิน event-set__enter
และ event-set__leave
:
<a-sphere ... event-set__enter="_event: mouseenter; color: green" event-set__leave="_event: mouseleave; color: yellow" … ></a-sphere>
ต่อไป เราตกแต่งทรงกลมดาวของเราด้วยเครื่อง debris-listener
เราจะนำไปใช้เป็นส่วนประกอบ A-Frame ที่กำหนดเอง
<a-sphere ... debris-listener="" … ></a-sphere>
ส่วนประกอบ A-Frame ถูกกำหนดในระดับโลก:
// src/nBodyVisualizer.js // Component to add new bodies when the user stares at the sun. See HTML AFRAME.registerComponent('debris-listener', { init: function () { // Helper function function rando(scale) { return (Math.random()-.5) * scale } // Add 10 new bodies this.el.addEventListener('click', function (evt) { for (let x=0; x<10; x++) { // name, color, x, y, z, mass, vx, vy, vz window.sim.addBodyArgs("debris", "white", rando(10), rando(10), rando(10), 1, rando(.1), rando(.1), rando(.1)) } }) } })
คอมโพเนนต์ A-Frame นี้ทำหน้าที่เหมือนผู้ฟัง 'คลิก' ที่เคอร์เซอร์การจ้องมองสามารถกระตุ้นเพื่อเพิ่ม 10 เนื้อหาแบบสุ่มใหม่ให้กับฉากของเรา
เพื่อสรุป:
- เราประกาศฉาก WebVR ด้วย A-Frame ใน HTML มาตรฐาน
- เราสามารถเพิ่ม/ลบ/อัปเดตเอนทิตี A-Frame ในฉากจาก JavaScript โดยทางโปรแกรม
- เราสามารถสร้างการโต้ตอบใน JavaScript กับตัวจัดการเหตุการณ์ผ่านปลั๊กอินและส่วนประกอบ A-Frame
WebVR: Veni, Vidi, Vici
ฉันหวังว่าคุณจะได้รับประโยชน์จากการสาธิตเทคโนโลยีนี้มากเท่ากับที่ฉันทำ เมื่อเราใช้คุณลักษณะเหล่านี้ (ผู้ปฏิบัติงานเว็บและ WebAssembly) กับ WebVR ก็สามารถใช้คุณลักษณะเหล่านี้กับการประมวลผลขอบของเบราว์เซอร์ได้
คลื่นเทคโนโลยีขนาดใหญ่มาถึงแล้ว - Virtual Reality (VR) ไม่ว่าคุณจะรู้สึกอะไรในครั้งแรกที่คุณถือสมาร์ทโฟน การได้สัมผัสกับ VR เป็นครั้งแรกจะมอบประสบการณ์ทางอารมณ์ 10 เท่าในทุกแง่มุมของการใช้คอมพิวเตอร์ เป็นเวลาเพียง 12 ปีแล้วตั้งแต่ iPhone เครื่องแรก
VR มีมานานแล้ว แต่เทคโนโลยีที่จำเป็นในการนำ VR มาสู่ผู้ใช้ทั่วไปได้มาถึงแล้วผ่านการปฏิวัติมือถือและ Oculus Quest ของ Facebook ไม่ใช่การปฏิวัติพีซี
อินเทอร์เน็ตและโอเพ่นซอร์สเป็นหนึ่งในสิ่งมหัศจรรย์ที่ยิ่งใหญ่ที่สุดในโลกของมนุษยชาติ ถึงทุกคนที่สร้างอินเทอร์เน็ตแบบแบน - ฉันขอแสดงความยินดีกับความกล้าหาญและความรู้สึกของการผจญภัย
ประกาศ! เราจะสร้างโลก เพราะเรามีพลังที่จะสร้าง