ข้อมูลทั้งหมดเกี่ยวกับเฟรมลูป
และเมื่อเร็วๆ นี้ ฉันได้เผยแพร่บทความ 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
ลิงก์หนึ่งจะขึ้นอยู่กับอุปกรณ์ของผู้ดูและอีกส่วนสอดคล้องกับหน้าเว็บ
ระบบจะส่ง 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
จะมี FrameBuffer สำหรับ WebGLRenderingContext
ที่มีให้เพื่อใช้กับ WebXR โดยเฉพาะ และแทนที่บริบทการแสดงภาพเริ่มต้นของ Framebuffer สิ่งนี้เรียกว่า "การเชื่อมโยง" ในภาษาของ 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 แต่อาจสร้างความสับสนหากคุณเพิ่งเริ่มใช้เทคโนโลยีนี้
วาดสิ่งที่อยู่ในเฟรมบัฟเฟอร์
หากต้องการลองใช้ WebGL โดยตรง คุณก็ทำได้ แต่เราไม่แนะนํา การใช้เฟรมเวิร์กอย่างใดอย่างหนึ่งที่แสดงอยู่ด้านบนนั้นง่ายกว่ามาก
บทสรุป
บทความนี้ไม่ใช่บทความสุดท้ายเกี่ยวกับการอัปเดต WebXR คุณดูข้อมูลอ้างอิงสำหรับอินเทอร์เฟซและองค์ประกอบทั้งหมดของ WebXR ได้บน MDN หากต้องการดูการปรับปรุงอินเทอร์เฟซที่กำลังจะมาถึง โปรดติดตามฟีเจอร์แต่ละรายการในสถานะ Chrome
รูปภาพโดย JESHOOTS.COM ใน Unsplash