ทุกเรื่องเกี่ยวกับลูปเฟรม
เมื่อเร็วๆ นี้ ฉันได้เผยแพร่บทความเทคโนโลยีความจริงเสมือน (VR) มาสู่เว็บ ซึ่งเป็นบทความที่แนะนำแนวคิดพื้นฐานเบื้องหลัง WebXR Device API นอกจากนี้ ฉันยังได้ระบุวิธีการขอ เริ่ม และสิ้นสุดเซสชัน XR ด้วย
บทความนี้อธิบายลูปเฟรม ซึ่งเป็นลูปที่ไม่มีที่สิ้นสุดที่ควบคุมโดย User-Agent ซึ่งเนื้อหาจะวาดซ้ำๆ บนหน้าจอ เนื้อหาจะ วาดในบล็อกแยกกันที่เรียกว่าเฟรม การเรียงต่อกันของเฟรมทำให้เกิด ภาพลวงตาของการเคลื่อนไหว
สิ่งที่บทความนี้ไม่ได้กล่าวถึง
WebGL และ WebGL2 เป็นวิธีเดียวในการแสดงเนื้อหาระหว่างลูปเฟรมในแอป WebXR โชคดีที่เฟรมเวิร์กหลายรายการมีเลเยอร์การแยกข้อมูลอยู่เหนือ WebGL และ WebGL2 เฟรมเวิร์กดังกล่าว ได้แก่ three.js, babylonjs และ PlayCanvas ส่วน A-Frame และ React 360 ออกแบบมาเพื่อการโต้ตอบ กับ WebXR
บทความนี้อธิบายพื้นฐานของลูปเฟรมโดยใช้ตัวอย่างเซสชัน VR แบบสมจริงของ Immersive Web Working Group (เดโม แหล่งที่มา) หากต้องการเจาะลึก WebGL หรือเฟรมเวิร์กใดเฟรมเวิร์กหนึ่ง คุณสามารถดูรายการแหล่งข้อมูลออนไลน์ที่เพิ่มขึ้นเรื่อยๆ ได้
ผู้เล่นและเกม
เมื่อพยายามทำความเข้าใจลูปเฟรม ฉันก็ยังคงสับสนกับรายละเอียด มีออบเจ็กต์จำนวนมากที่ใช้งานอยู่ และออบเจ็กต์บางรายการจะตั้งชื่อโดยใช้พร็อพเพอร์ตี้อ้างอิง ในออบเจ็กต์อื่นๆ เท่านั้น เราจะอธิบายออบเจ็กต์ซึ่งเราเรียกว่า "ผู้เล่น" เพื่อช่วยให้คุณเข้าใจได้ง่ายขึ้น จากนั้นเราจะอธิบายวิธีที่องค์ประกอบเหล่านี้โต้ตอบกัน ซึ่งเราจะเรียกว่า "เกม"
ผู้เล่น
XRViewerPose
ท่าทางคือตำแหน่งและการวางแนวของวัตถุในพื้นที่ 3 มิติ ทั้งอุปกรณ์แสดงผล
และอุปกรณ์อินพุตมีท่าทาง แต่เราจะพิจารณาท่าทางของอุปกรณ์แสดงผล
ในที่นี้ ทั้งท่าทางของผู้ชมและอุปกรณ์อินพุตมีแอตทริบิวต์ transform ที่อธิบายตำแหน่งเป็นเวกเตอร์และทิศทางเป็นควอเทอร์เนียนที่สัมพันธ์กับจุดเริ่มต้น ระบบจะระบุต้นทางตามประเภทพื้นที่อ้างอิงที่ขอเมื่อเรียกใช้ XRSession.requestReferenceSpace()
พื้นที่อ้างอิงต้องใช้เวลาอธิบายสักหน่อย ฉันจะอธิบายรายละเอียดในความเป็นจริงเสริม ตัวอย่างที่ฉันใช้เป็นพื้นฐานสำหรับบทความนี้ใช้'local'พื้นที่อ้างอิง ซึ่งหมายความว่าจุดเริ่มต้นอยู่ที่ตำแหน่งของผู้ดู ณ เวลาที่สร้างเซสชันโดยไม่มีพื้นผิวที่กำหนดไว้อย่างชัดเจน และตำแหน่งที่แน่นอนอาจแตกต่างกันไปตามแพลตฟอร์ม
XRView
มุมมองจะสอดคล้องกับกล้องที่ดูฉากเสมือน นอกจากนี้ วิวยังมีแอตทริบิวต์
transformที่อธิบายตำแหน่งเป็นเวกเตอร์และการวางแนว
โดยจะแสดงทั้งในรูปแบบคู่เวกเตอร์/ควอเทอร์เนียนและเมทริกซ์ที่เทียบเท่า
คุณสามารถใช้การแสดงผลแบบใดก็ได้ตามที่เหมาะกับโค้ดของคุณมากที่สุด แต่ละ
มุมมองสอดคล้องกับจอแสดงผลหรือส่วนของจอแสดงผลที่อุปกรณ์ใช้เพื่อ
นำเสนอภาพต่อผู้ชม ระบบจะแสดงผลออบเจ็กต์ XRView ในอาร์เรย์จากออบเจ็กต์ XRViewerPose จำนวนมุมมองในอาร์เรย์จะแตกต่างกันไป ในอุปกรณ์เคลื่อนที่ ฉาก AR จะมีมุมมองเดียว ซึ่งอาจครอบคลุมหน้าจออุปกรณ์หรือไม่ก็ได้
โดยปกติแล้วชุดหูฟังจะมี 2 มุมมองสำหรับดวงตาแต่ละข้าง
XRWebGLLayer
เลเยอร์เป็นแหล่งที่มาของรูปภาพบิตแมปและคำอธิบายเกี่ยวกับวิธีแสดงรูปภาพเหล่านั้นในอุปกรณ์
คำอธิบายนี้ไม่ได้อธิบายสิ่งที่เพลเยอร์นี้ทำ
ได้อย่างถูกต้อง ฉันคิดว่ามันเป็นตัวกลางระหว่างอุปกรณ์กับ
WebGLRenderingContext MDN มีมุมมองที่คล้ายกันมาก โดยระบุว่า "ให้
การเชื่อมโยง" ระหว่างทั้ง 2 อย่าง ดังนั้นจึงให้สิทธิ์เข้าถึงแก่ผู้เล่นคนอื่นๆ
โดยทั่วไปแล้ว ออบเจ็กต์ WebGL จะจัดเก็บข้อมูลสถานะสำหรับการแสดงผลกราฟิก 2 มิติและ 3 มิติ
WebGLFramebuffer
เฟรมบัฟเฟอร์จะให้ข้อมูลรูปภาพแก่ WebGLRenderingContext หลังจากดึงข้อมูลจาก XRWebGLLayer แล้ว คุณจะส่งไปยัง WebGLRenderingContext ปัจจุบัน นอกจากการเรียกใช้ bindFramebuffer() (ดูข้อมูลเพิ่มเติมได้
ภายหลัง) คุณจะไม่มีสิทธิ์เข้าถึงออบเจ็กต์นี้โดยตรง คุณเพียงแค่ส่งผ่านจาก
XRWebGLLayer ไปยัง WebGLRenderingContext
XRViewport
วิวพอร์ตระบุพิกัดและขนาดของพื้นที่สี่เหลี่ยมใน WebGLFramebuffer
WebGLRenderingContext
บริบทการแสดงผลคือจุดเข้าถึงแบบเป็นโปรแกรมสำหรับ Canvas (พื้นที่ที่เราวาด) โดยต้องมีทั้ง WebGLFramebuffer และ XRViewport
สังเกตความสัมพันธ์ระหว่าง XRWebGLLayer กับ WebGLRenderingContext โดยค่าหนึ่งจะสอดคล้องกับอุปกรณ์ของผู้ชม และอีกค่าหนึ่งจะสอดคล้องกับหน้าเว็บ
WebGLFramebuffer และ XRViewport จะส่งจากอดีตไปยังปัจจุบัน
XRWebGLLayer กับ WebGLRenderingContext
เกม
เมื่อทราบแล้วว่าผู้เล่นคือใคร เรามาดูเกมที่ผู้เล่นเล่นกัน ซึ่งเป็น เกมที่เริ่มต้นใหม่ทุกเฟรม โปรดทราบว่าเฟรมเป็นส่วนหนึ่งของลูปเฟรมซึ่งเกิดขึ้นในอัตราที่ขึ้นอยู่กับฮาร์ดแวร์พื้นฐาน สำหรับแอปพลิเคชัน VR เฟรม ต่อวินาทีอาจมีได้ตั้งแต่ 60 ถึง 144 AR สำหรับ Android ทำงานที่ 30 เฟรมต่อ วินาที โค้ดไม่ควรสมมติอัตราเฟรมใดๆ
กระบวนการพื้นฐานสำหรับการวนซ้ำเฟรมมีลักษณะดังนี้
- โทรมาที่
XRSession.requestAnimationFrame()ในการตอบสนอง User Agent จะเรียกใช้XRFrameRequestCallbackซึ่งคุณเป็นผู้กำหนด - ภายในฟังก์ชัน Callback ให้ทำดังนี้
- โทรหา
XRSession.requestAnimationFrame()อีกครั้ง - รับท่าทางของผู้ชม
- ส่ง (ผูก)
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 มุมมอง ซึ่งฉันจะวนซ้ำและวาด
รูปภาพแยกกันสำหรับแต่ละมุมมอง
เมื่อใช้สำหรับเทคโนโลยีความจริงเสริม (AR) บนโทรศัพท์ ฉันจะมีเพียงมุมมองเดียว แต่ก็ยังคงใช้ลูป แม้ว่าการวนซ้ำผ่านมุมมองเดียวอาจดูเหมือนไม่มีประโยชน์ แต่การทำเช่นนี้จะช่วยให้คุณมีเส้นทางการแสดงผลเดียวสำหรับสเปกตรัมของประสบการณ์การดื่มด่ำ นี่คือความแตกต่างที่สำคัญระหว่าง 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
}
}
}
The webGLRenContext
ในการเขียน ฉันได้ถกเถียงกับเพื่อนร่วมงาน 2-3 คนเรื่องการตั้งชื่อwebGLRenContextออบเจ็กต์ สคริปต์ตัวอย่างและโค้ด WebXR ส่วนใหญ่
เรียกตัวแปรนี้ว่า gl ตอนที่พยายามทำความเข้าใจตัวอย่าง ฉันมักจะลืมว่า gl หมายถึงอะไร ฉันตั้งชื่อว่า webGLRenContext เพื่อเตือนคุณ
ขณะที่คุณกำลังเรียนรู้ว่านี่คืออินสแตนซ์ของ WebGLRenderingContext
สาเหตุคือการใช้ gl จะช่วยให้ชื่อเมธอดดูเหมือนชื่อเมธอดที่คล้ายกันใน OpenGL ES 2.0 API ซึ่งใช้สร้าง VR ในภาษาที่คอมไพล์แล้ว
ข้อเท็จจริงนี้ชัดเจนหากคุณเขียนแอป VR โดยใช้ OpenGL แต่
อาจสร้างความสับสนหากคุณเพิ่งเริ่มใช้เทคโนโลยีนี้
วาดอะไรบางอย่างลงในเฟรมบัฟเฟอร์
หากคุณมีความทะเยอทะยานอย่างแท้จริง คุณสามารถใช้ WebGL ได้โดยตรง แต่ฉันไม่ แนะนำให้ทำเช่นนั้น การใช้เฟรมเวิร์กใดเฟรมเวิร์กหนึ่งที่ระบุไว้ที่ด้านบนจะง่ายกว่ามาก
บทสรุป
นี่ไม่ใช่การสิ้นสุดการอัปเดตหรือบทความเกี่ยวกับ WebXR คุณดูข้อมูลอ้างอิงสำหรับ อินเทอร์เฟซและ สมาชิกทั้งหมดของ WebXR ได้ที่ MDN หากต้องการทราบข้อมูลการปรับปรุงอินเทอร์เฟซในอนาคต โปรดติดตาม ฟีเจอร์แต่ละรายการใน Chrome Status