ข้อมูลทั้งหมดเกี่ยวกับเฟรมลูป
เมื่อเร็วๆ นี้ เราได้เผยแพร่บทความVirtual Reality มาถึงเว็บแล้ว ซึ่งเป็นบทความที่อธิบายแนวคิดพื้นฐานเบื้องหลัง WebXR Device API เรายังระบุวิธีการขอ เข้าสู่ และสิ้นสุดเซสชัน XR ด้วย
บทความนี้อธิบายเฟรมลูป ซึ่งเป็นลูปที่ไม่มีที่สิ้นสุดที่ควบคุมโดย User Agent ซึ่งจะวาดเนื้อหาบนหน้าจอซ้ำๆ เนื้อหาจะวาดเป็นบล็อกแยกต่างหากที่เรียกว่าเฟรม เฟรมที่แสดงต่อกันจะทำให้เกิดภาพลวงตาว่าเคลื่อนไหว
สิ่งที่บทความนี้ไม่ได้กล่าวถึง
WebGL และ WebGL2 เป็นวิธีเดียวในการแสดงผลเนื้อหาระหว่างลูปเฟรมในแอป WebXR แต่โชคดีที่เฟรมเวิร์กหลายเฟรมเวิร์กมีเลเยอร์การแยกแยะชั้นบนของ WebGL และ WebGL2 เฟรมเวิร์กดังกล่าว ได้แก่ three.js, babylonjs และ PlayCanvas ส่วน A-Frame และ React 360 ออกแบบมาเพื่อโต้ตอบกับ WebXR
บทความนี้ไม่ใช่บทแนะนำ WebGL หรือเฟรมเวิร์ก ซึ่งอธิบายพื้นฐานของการทำเฟรมวนโดยใช้ตัวอย่างเซสชัน VR แบบสมจริงของกลุ่มทำงานเว็บที่สมจริง (เดโม, แหล่งที่มา) หากต้องการเจาะลึก WebGL หรือเฟรมเวิร์กใดเฟรมเวิร์กหนึ่ง อินเทอร์เน็ตมีบทความมากมายที่พร้อมให้อ่าน
ผู้เล่นและเกม
เมื่อพยายามทำความเข้าใจเฟรมลูป ฉันก็สับสนกับรายละเอียดต่างๆ อยู่ตลอด มีออบเจ็กต์จำนวนมากที่ทำงานอยู่ และบางรายการมีชื่อตามพร็อพเพอร์ตี้การอ้างอิงในออบเจ็กต์อื่นๆ เท่านั้น เราจะอธิบายออบเจ็กต์ซึ่งเรียกว่า "ผู้เล่น" เพื่อให้คุณเข้าใจได้ง่ายขึ้น จากนั้นเราจะอธิบายวิธีที่องค์ประกอบเหล่านี้โต้ตอบกัน ซึ่งเราเรียกว่า "เกม"
ผู้เล่น
XRViewerPose
ท่าทางคือตำแหน่งและการวางแนวของสิ่งต่างๆ ในพื้นที่ 3 มิติ ทั้งแว่นและอุปกรณ์อินพุตมีท่าทาง แต่สิ่งที่เราสนใจคือท่าทางของผู้ชม ทั้งท่าทางของผู้ชมและอุปกรณ์อินพุตมีแอตทริบิวต์ transform
ที่อธิบายตำแหน่งเป็นเวกเตอร์และการวางแนวเป็นควอตเทอร์เนิดน์ตามจุดต้นทาง ระบบจะระบุต้นทางตามประเภทพื้นที่อ้างอิงที่ขอเมื่อเรียกใช้ XRSession.requestReferenceSpace()
พื้นที่อ้างอิงนั้นอธิบายได้ยากสักหน่อย เราได้อธิบายเรื่องนี้อย่างละเอียดในเทคโนโลยีความจริงเสริม ตัวอย่างที่เราใช้เป็นพื้นฐานของบทความนี้ใช้พื้นที่อ้างอิง 'local'
ซึ่งหมายความว่าจุดเริ่มต้นอยู่ที่ตําแหน่งของผู้ดู ณ เวลาสร้างเซสชันโดยไม่มีพื้นที่กำหนดไว้อย่างชัดเจน และตําแหน่งที่แน่นอนอาจแตกต่างกันไปตามแพลตฟอร์ม
XRView
มุมมองสอดคล้องกับกล้องที่ดูฉากเสมือน มุมมองยังมีแอตทริบิวต์ transform
ที่อธิบายตำแหน่งของมุมมองเป็นเวกเตอร์และการวางแนว
ข้อมูลเหล่านี้มีทั้งในรูปแบบคู่เวกเตอร์/ควอร์เทอร์นियनและในรูปแบบเมทริกซ์ที่เทียบเท่า คุณจะใช้รูปแบบใดก็ได้ ทั้งนี้ขึ้นอยู่กับว่ารูปแบบใดเหมาะกับโค้ดของคุณมากที่สุด มุมมองแต่ละรายการสอดคล้องกับจอแสดงผลหรือส่วนหนึ่งของจอแสดงผลที่อุปกรณ์ใช้เพื่อแสดงภาพต่อผู้ชม ระบบจะแสดงผลออบเจ็กต์ XRView
ในอาร์เรย์จากออบเจ็กต์ XRViewerPose
จํานวนการดูในอาร์เรย์จะแตกต่างกันไป ในอุปกรณ์เคลื่อนที่ ฉาก AR จะมีมุมมองเดียว ซึ่งอาจครอบคลุมหรือไม่ครอบคลุมหน้าจออุปกรณ์
โดยปกติแล้วชุดหูฟังจะมี 2 มุมมองสำหรับตาแต่ละข้าง
XRWebGLLayer
เลเยอร์เป็นแหล่งที่มาของรูปภาพบิตแมปและคําอธิบายวิธีแสดงผลรูปภาพเหล่านั้นในอุปกรณ์ คำอธิบายนี้ไม่ได้สื่อถึงสิ่งที่โปรแกรมเล่นนี้ทำได้ เราเริ่มคิดว่า WebGLRenderingContext
เป็นสื่อกลางระหว่างอุปกรณ์กับ
WebGLRenderingContext
MDN มีมุมมองที่คล้ายกัน โดยระบุว่า "ให้การเชื่อมโยง" ระหว่าง 2 รายการ ด้วยเหตุนี้ ผู้เล่นคนอื่นๆ จึงมีสิทธิ์เข้าถึง
โดยทั่วไปแล้ว ออบเจ็กต์ WebGL จะจัดเก็บข้อมูลสถานะสำหรับการเรนเดอร์กราฟิก 2 มิติและ 3 มิติ
WebGLFramebuffer
เฟรมบัฟเฟอร์จะส่งข้อมูลรูปภาพไปยัง WebGLRenderingContext
หลังจากดึงข้อมูลจาก XRWebGLLayer
แล้ว ให้ส่งค่าไปยัง WebGLRenderingContext
ในปัจจุบัน คุณจะเข้าถึงออบเจ็กต์นี้โดยตรงไม่ได้ ยกเว้นการเรียกใช้ bindFramebuffer()
(ดูข้อมูลเพิ่มเติมในภายหลัง) คุณเพียงแค่ส่งจาก XRWebGLLayer
ไปยัง WebGLRenderingContext
XRViewport
วิวพอร์ตระบุพิกัดและขนาดของภูมิภาคสี่เหลี่ยมผืนผ้าในWebGLFramebuffer
WebGLRenderingContext
บริบทการแสดงผลคือจุดเข้าใช้งานแบบเป็นโปรแกรมสําหรับผืนผ้าใบ (พื้นที่ที่เราวาด) โดยจะต้องมีทั้ง WebGLFramebuffer
และ XRViewport
สังเกตความสัมพันธ์ระหว่าง XRWebGLLayer
กับ WebGLRenderingContext
1 รายการจะสอดคล้องกับอุปกรณ์ของผู้ชม และอีกรายการจะสอดคล้องกับหน้าเว็บ
ระบบจะส่ง WebGLFramebuffer
และ XRViewport
จากรายการแรกไปยังรายการที่ 2
เกม
เมื่อทราบแล้วว่าผู้เล่นเป็นใคร เรามาดูเกมที่ผู้เล่นเล่นกัน เกมนี้จะเริ่มต้นใหม่ทุกครั้งที่มีเฟรม โปรดทราบว่าเฟรมเป็นส่วนหนึ่งของเฟรมที่วนซ้ำ ซึ่งเกิดขึ้นในอัตราที่ขึ้นอยู่กับฮาร์ดแวร์พื้นฐาน สำหรับแอปพลิเคชัน VR เฟรมต่อวินาทีอาจอยู่ที่ 60-144 เฟรม AR สำหรับ Android จะทำงานที่ 30 เฟรมต่อวินาที โค้ดไม่ควรกำหนดอัตราเฟรมใดๆ
ขั้นตอนพื้นฐานของเฟรมลูปมีดังนี้
- โทรมาที่
XRSession.requestAnimationFrame()
ในการตอบกลับ User Agent จะเรียกใช้XRFrameRequestCallback
ที่คุณกำหนดไว้ - ในฟังก์ชัน Callback ให้ทำดังนี้
- โทรหา
XRSession.requestAnimationFrame()
อีกครั้ง - จับท่าทางของผู้ชม
- ส่ง ('bind')
WebGLFramebuffer
จากXRWebGLLayer
ไปยังWebGLRenderingContext
- วนผ่านออบเจ็กต์
XRView
แต่ละรายการ โดยดึงข้อมูลXRViewport
จากXRWebGLLayer
และส่งไปยังWebGLRenderingContext
- วาดรูปภาพไปยังเฟรมบัฟเฟอร์
- โทรหา
เนื่องจากเราได้อธิบายขั้นตอนที่ 1 และ 2ก ในบทความก่อนหน้าแล้ว เราจะเริ่มต้นที่ขั้นตอน 2ข
ดูท่าทางของผู้ชม
ไม่ต้องบอกก็รู้ว่า หากต้องการวาดสิ่งใดก็ตามใน AR หรือ VR เราจำเป็นต้องทราบตำแหน่งของผู้ดูและจุดที่ผู้ดูกำลังมองอยู่ ตำแหน่งและการวางแนวของผู้ชมจะระบุโดยออบเจ็กต์ XRViewerPose ฉันรับท่าทางของผู้ชมโดยการเรียกใช้ XRFrame.getViewerPose()
ในเฟรมภาพเคลื่อนไหวปัจจุบัน ฉันส่งพื้นที่อ้างอิงที่ได้รับเมื่อตั้งค่าเซสชัน ค่าที่ออบเจ็กต์นี้แสดงผลจะสัมพันธ์กับพื้นที่อ้างอิงที่ผมขอเมื่อเข้าสู่เซสชันปัจจุบันเสมอ ดังที่คุณอาจทราบแล้ว เราต้องส่งพื้นที่อ้างอิงปัจจุบันเมื่อขอท่าทาง
function onXRFrame(hrTime, xrFrame) {
let xrSession = xrFrame.session;
xrSession.requestAnimationFrame(onXRFrame);
let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);
if (xrViewerPose) {
// Render based on the pose.
}
}
ท่าทางของผู้ชม 1 ท่าจะแสดงตำแหน่งโดยรวมของผู้ใช้ ซึ่งหมายถึงศีรษะของผู้ชมหรือกล้องโทรศัพท์ในกรณีที่เป็นสมาร์ทโฟน
ท่าทางบอกแอปพลิเคชันว่าผู้ชมอยู่ที่ไหน การแสดงผลรูปภาพจริงใช้ออบเจ็กต์ XRView
ซึ่งเราจะพูดถึงในอีกสักครู่
ก่อนจะไปต่อ เราจะทดสอบว่าระบบแสดงผลท่าทางของผู้ชมหรือไม่ในกรณีที่ระบบสูญเสียการติดตามหรือบล็อกท่าทางเนื่องจากเหตุผลด้านความเป็นส่วนตัว การติดตามคือความสามารถของอุปกรณ์ XR ในการรู้ตำแหน่งของอุปกรณ์และ/หรืออุปกรณ์อินพุตของอุปกรณ์นั้นๆ เมื่อเทียบกับสภาพแวดล้อม การติดตามอาจหายไปได้หลายวิธีและแตกต่างกันไปตามวิธีการที่ใช้ติดตาม ตัวอย่างเช่น หากใช้กล้องในชุดหูฟังหรือโทรศัพท์เพื่อติดตาม อุปกรณ์อาจไม่สามารถระบุตำแหน่งของตนเองได้ในสถานการณ์ที่มีแสงน้อยหรือไม่มีแสง หรือหากกล้องถูกบดบัง
ตัวอย่างการบล็อกท่าทางด้วยเหตุผลด้านความเป็นส่วนตัวคือ หากชุดหูฟังแสดงกล่องโต้ตอบความปลอดภัย เช่น ข้อความแจ้งสิทธิ์ เบราว์เซอร์อาจหยุดส่งท่าทางไปยังแอปพลิเคชันขณะที่เหตุการณ์นี้เกิดขึ้น แต่เราได้โทรหา XRSession.requestAnimationFrame()
แล้วเพื่อให้เฟรมวนต่อไปได้หากระบบกู้คืนได้ หากไม่ User Agent จะสิ้นสุดเซสชันและเรียกใช้ตัวแฮนเดิลเหตุการณ์ end
เส้นทางอ้อมสั้นๆ
ขั้นตอนถัดไปต้องใช้ออบเจ็กต์ที่สร้างระหว่างการตั้งค่าเซสชัน โปรดทราบว่าเราได้สร้าง Canvas และสั่งให้สร้างบริบทการแสดงผล Web GL ที่เข้ากันได้กับ XR ซึ่งเราได้รับโดยการเรียกใช้ canvas.getContext()
การวาดทั้งหมดจะดำเนินการโดยใช้ WebGL API, WebGL2 API หรือเฟรมเวิร์กที่ใช้ WebGL เช่น Three.js ระบบส่งบริบทนี้ไปยังออบเจ็กต์เซสชันผ่าน updateRenderState()
พร้อมกับอินสแตนซ์ใหม่ของ XRWebGLLayer
let canvas = document.createElement('canvas');
// The rendering context must be based on WebGL or WebGL2
let webGLRenContext = canvas.getContext('webgl', { xrCompatible: true });
xrSession.updateRenderState({
baseLayer: new XRWebGLLayer(xrSession, webGLRenContext)
});
ส่ง ('bind') WebGLFramebuffer
XRWebGLLayer
มีเฟรมบัฟเฟอร์สำหรับ WebGLRenderingContext
ที่ระบุไว้เพื่อใช้กับ WebXR โดยเฉพาะ และแทนที่บริบทการแสดงผลของเฟรมบัฟเฟอร์เริ่มต้น ซึ่งเรียกว่า "การเชื่อมโยง" ในภาษาของ WebGL
function onXRFrame(hrTime, xrFrame) {
let xrSession = xrFrame.session;
xrSession.requestAnimationFrame(onXRFrame);
let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);
if (xrViewerPose) {
let glLayer = xrSession.renderState.baseLayer;
webGLRenContext.bindFramebuffer(webGLRenContext.FRAMEBUFFER, glLayer.framebuffer);
// Iterate over the views
}
}
วนซ้ำผ่านออบเจ็กต์ XRView แต่ละรายการ
หลังจากรับท่าทางและเชื่อมโยง Framebuffer แล้ว ก็ถึงเวลารับ Viewport XRViewerPose
มีอาร์เรย์ของอินเทอร์เฟซ XRView ซึ่งแต่ละรายการแสดงถึงจอแสดงผลหรือส่วนหนึ่งของจอแสดงผล โดยจะมีข้อมูลที่จําเป็นในการแสดงผลเนื้อหาที่วางตําแหน่งถูกต้องสําหรับอุปกรณ์และผู้ชม เช่น มุมมอง การเลื่อนตา และพร็อพเพอร์ตี้อื่นๆ ของแสง
เนื่องจากฉันวาดภาพสำหรับดวงตา 2 ข้าง ฉันจึงมีมุมมอง 2 มุมมอง ซึ่งฉันจะวนดูและวาดภาพแยกกันสำหรับแต่ละมุมมอง
เมื่อติดตั้งใช้งานสำหรับ Augmented Reality บนโทรศัพท์ ฉันจะมีมุมมองเดียว แต่จะใช้ลูป แม้ว่าการวนดูมุมมองเดียวอาจดูเหมือนไม่มีจุดหมาย แต่การดำเนินการนี้จะช่วยให้คุณมีเส้นทางการแสดงผลเดียวสำหรับประสบการณ์ที่สมจริงที่หลากหลาย นี่คือความแตกต่างที่สำคัญระหว่าง WebXR กับระบบอื่นๆ ที่ให้ประสบการณ์สมจริง
function onXRFrame(hrTime, xrFrame) {
let xrSession = xrFrame.session;
xrSession.requestAnimationFrame(onXRFrame);
let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);
if (xrViewerPose) {
let glLayer = xrSession.renderState.baseLayer;
webGLRenContext.bindFramebuffer(webGLRenContext.FRAMEBUFFER, glLayer.framebuffer);
for (let xrView of xrViewerPose.views) {
// Pass viewports to the context
}
}
}
ส่งออบเจ็กต์ XRViewport ไปยัง WebGLRenderingContext
ออบเจ็กต์ XRView
หมายถึงสิ่งที่สังเกตได้บนหน้าจอ แต่หากต้องการวาดในมุมมองนั้น ฉันต้องใช้พิกัดและมิติข้อมูลที่เจาะจงสำหรับอุปกรณ์ของฉัน เช่นเดียวกับเฟรมบัฟเฟอร์ เราจะขอข้อมูลจาก XRWebGLLayer
และส่งต่อให้ WebGLRenderingContext
function onXRFrame(hrTime, xrFrame) {
let xrSession = xrFrame.session;
xrSession.requestAnimationFrame(onXRFrame);
let xrViewerPose = xrFrame.getViewerPose(xrRefSpace);
if (xrViewerPose) {
let glLayer = xrSession.renderState.baseLayer;
webGLRenContext.bindFramebuffer(webGLRenContext.FRAMEBUFFER, glLayer.framebuffer);
for (let xrView of xrViewerPose.views) {
let viewport = glLayer.getViewport(xrView);
webGLRenContext.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
// Draw something to the framebuffer
}
}
}
webGLRenContext
ในการเขียนบทความนี้ เราโต้แย้งกับเพื่อนร่วมงานบางคนเรื่องการตั้งชื่อออบเจ็กต์ webGLRenContext
สคริปต์ตัวอย่างและโค้ด WebXR ส่วนใหญ่จะเรียกใช้ตัวแปรนี้ว่า gl
เมื่อพยายามทำความเข้าใจตัวอย่างเพลง เราลืมสิ่งที่ gl
อ้างถึงอยู่ตลอด เราตั้งชื่อให้ว่า webGLRenContext
เพื่อช่วยให้คุณจำได้ขณะเรียนรู้ว่านี่คืออินสแตนซ์ของ WebGLRenderingContext
เนื่องจากการใช้ gl
ช่วยให้ชื่อเมธอดมีลักษณะเหมือนกับชื่อเมธอดใน OpenGL ES 2.0 API ซึ่งใช้สำหรับสร้าง VR ในภาษาที่คอมไพล์ ความจริงนี้ชัดเจนหากคุณเคยเขียนแอป VR โดยใช้ OpenGL แต่อาจสร้างความสับสนหากคุณเพิ่งเริ่มใช้เทคโนโลยีนี้
วาดรูปใน Framebuffer
หากต้องการลองใช้ WebGL โดยตรง คุณก็ทำได้ แต่เราไม่แนะนํา การใช้เฟรมเวิร์กอย่างใดอย่างหนึ่งที่แสดงอยู่ด้านบนนั้นง่ายกว่ามาก
บทสรุป
บทความนี้ไม่ใช่บทความสุดท้ายเกี่ยวกับการอัปเดต WebXR คุณดูข้อมูลอ้างอิงสำหรับอินเทอร์เฟซและองค์ประกอบทั้งหมดของ WebXR ได้บน MDN หากต้องการดูการปรับปรุงอินเทอร์เฟซที่กำลังจะมาถึง โปรดติดตามฟีเจอร์แต่ละรายการในสถานะ Chrome
รูปภาพโดย JESHOOTS.COM ใน Unsplash