ส่วนขยาย XR_ANDROID_composition_layer_passthrough_mesh OpenXR

สตริงชื่อ

XR_ANDROID_composition_layer_passthrough_mesh

ประเภทชิ้นงาน

การขยายเวลาอินสแตนซ์

หมายเลขต่อที่จดทะเบียน

463

การแก้ไข

1

การพึ่งพาส่วนขยายและเวอร์ชัน

OpenXR 1.0

วันที่แก้ไขล่าสุด

2024-09-18

สถานะ IP

ไม่มีการอ้างสิทธิ์ IP ที่รู้จัก

ผู้เขียน

Grant Yoshida จาก Google

Kevin Moule จาก Google

Vasiliy Baranov จาก Google

Peter Chen จาก Google

Levana Chen จาก Google

ภาพรวม

สำหรับอุปกรณ์ที่รองรับโหมดการผสมผสานสภาพแวดล้อมหลายโหมด ระบบอาจให้การกำหนดค่าการส่งผ่านเพื่อแสดงสภาพแวดล้อมจริงของผู้ใช้จากมุมมองที่สมจริง

ส่วนขยายนี้ช่วยให้แอปพลิเคชันสามารถฉายพื้นผิวแบบส่งผ่านไปยังเรขาคณิตที่กำหนดเองผ่านเลเยอร์การคอมโพสเพิ่มเติม XrCompositionLayerPassthroughANDROID

ลักษณะของเลเยอร์พาสทรูจะระบุด้วยพารามิเตอร์ต่อไปนี้ ซึ่งโปรเจ็กชันจะแสดงด้วย XrPassthroughLayerANDROID

  XrPosef                      pose;
    XrVector3f                   scale;
    float                        opacity;
    XrPassthroughLayerANDROID    layer;

สําหรับการส่งผ่านแบบเต็มหน้าจอ แอปพลิเคชันสามารถใช้โหมดการผสมสภาพแวดล้อม

ตรวจสอบความสามารถของระบบ

แอปพลิเคชันสามารถตรวจสอบว่าระบบสามารถคอมโพสิชันเมชการส่งผ่านเลเยอร์ได้หรือไม่โดยการต่อโครงสร้าง XrSystemPassthroughLayerPropertiesANDROID กับ XrSystemProperties เมื่อเรียกใช้ xrGetSystemProperties

typedef struct XrSystemPassthroughLayerPropertiesANDROID {
    XrStructureType    type;
    void*              next;
    XrBool32           supportsPassthroughLayer;
    uint32_t           maxMeshIndexCount;
    uint32_t           maxMeshVertexCount;
} XrSystemPassthroughLayerPropertiesANDROID;

คำอธิบายสมาชิก

  • type คือ XrStructureType ของโครงสร้างนี้
  • next คือ NULL หรือพอยน์เตอร์ไปยังโครงสร้างถัดไปในเชนโครงสร้าง ไม่มีการกำหนดโครงสร้างดังกล่าวใน OpenXR หลักหรือส่วนขยายนี้
  • supportsPassthroughLayer คือ XrBool32 ซึ่งระบุว่าระบบปัจจุบันรองรับเมชการส่งผ่านเลเยอร์องค์ประกอบหรือไม่
  • maxMeshIndexCount คือ uint32_t แสดงผลจํานวนอินเด็กซ์สูงสุดที่จะยอมรับสําหรับเมชที่ส่งผ่าน
  • maxMeshVertexCount คือ uint32_t ซึ่งแสดงผลจํานวนจุดยอดสูงสุดที่ระบบจะยอมรับสําหรับเมชที่ส่งผ่าน

หาก supportsPassthroughLayer แสดงผลเป็น XR_FALSE แสดงว่าระบบไม่รองรับเมชการส่งผ่านเลเยอร์การคอมโพสชัน และจะได้รับ XR_ERROR_FEATURE_UNSUPPORTED จาก xrCreatePassthroughLayerANDROID แอปพลิเคชันควรหลีกเลี่ยงการใช้เมชการส่งผ่านเลเยอร์องค์ประกอบเมื่อ supportsPassthroughLayer เป็น XR_FALSE

หาก supportsPassthroughLayer แสดงผลเป็น XR_TRUE แสดงว่าระบบรองรับเมชการส่งผ่านเลเยอร์องค์ประกอบ ในกรณีนี้ maxMeshIndexCount และ maxMeshVertexCount จะแสดงผลเป็นตัวเลขที่ไม่ใช่ 0 แอปพลิเคชันควรใช้ maxMeshIndexCount และ maxMeshVertexCount เป็นค่าสูงสุดเพื่อตั้งค่าเมชที่ส่งผ่านเมื่อเรียกใช้ xrCreatePassthroughLayerANDROID และ xrSetPassthroughLayerMeshANDROID มิเช่นนั้นระบบอาจแสดงผล XR_ERROR_MESH_DATA_LIMIT_EXCEEDED_ANDROID เพื่อระบุว่าข้อมูลเมชเกินขีดจำกัดที่รองรับ

การใช้งานที่ถูกต้อง (โดยนัย)

องค์ประกอบเลเยอร์การแสดงผลผ่าน

XrCompositionLayerPassthroughANDROID มีข้อมูลที่จำเป็นในการเรนเดอร์เท็กเจอร์แบบพาสทรูบนเมชรูปสามเหลี่ยมเมื่อเรียกใช้ xrEndFrame XrCompositionLayerPassthroughANDROID เป็นประเภทแทนสำหรับโครงสร้างพื้นฐาน XrCompositionLayerBaseHeader ที่ใช้ใน XrFrameEndInfo

typedef struct XrCompositionLayerPassthroughANDROID {
    XrStructureType              type;
    const void*                  next;
    XrCompositionLayerFlags      layerFlags;
    XrSpace                      space;
    XrPosef                      pose;
    XrVector3f                   scale;
    float                        opacity;
    XrPassthroughLayerANDROID    layer;
} XrCompositionLayerPassthroughANDROID;

คำอธิบายสมาชิก

  • type คือ XrStructureType ของโครงสร้างนี้
  • next คือ NULL หรือพอยน์เตอร์ไปยังโครงสร้างถัดไปในเชนโครงสร้าง ไม่มีการกำหนดโครงสร้างดังกล่าวใน OpenXR หลักหรือส่วนขยายนี้
  • layerFlags คือบิตมาสก์ของ XrCompositionLayerFlags ที่อธิบาย Flag ที่จะใช้กับเลเยอร์
  • space คือ XrSpace ซึ่งประเมิน pose ของเมชเลเยอร์เมื่อเวลาผ่านไป
  • pose คือ XrPosef ที่กําหนดตําแหน่งและการวางแนวของเลเยอร์ เมชในเฟรมอ้างอิงของ space
  • scale คือ XrVector3f ที่กำหนดขนาดของเมชเลเยอร์
  • opacity คือ float ที่กำหนดความทึบแสงของพื้นผิวแบบส่งผ่านใน [0, 1]
  • layer คือ XrPassthroughLayerANDROID ที่สร้างขึ้นก่อนหน้านี้โดย xrCreatePassthroughLayerANDROID

แอปพลิเคชันสามารถสร้างโครงสร้าง XrCompositionLayerPassthroughANDROID ด้วย layer ที่สร้างขึ้นและเมชที่เกี่ยวข้องซึ่งได้จาก XrPassthroughLayerMeshANDROID

อาจส่งพอยน์เตอร์ไปยัง XrCompositionLayerPassthroughANDROID ใน xrEndFrame เป็นพอยน์เตอร์ไปยังโครงสร้างพื้นฐาน XrCompositionLayerBaseHeader ตามลําดับเลเยอร์ที่เลือก เพื่อขอให้รันไทม์คอมโพสเลเยอร์พาสทรูลงในเอาต์พุตเฟรมสุดท้าย

การใช้งานที่ถูกต้อง (โดยนัย)

สร้างแฮนเดิลเลเยอร์การส่งผ่าน

แฮนเดิล XrPassthroughLayerANDROID แสดงเลเยอร์พาสทรูซึ่งกำหนดลักษณะการทํางานของ XrCompositionLayerPassthroughANDROID

XR_DEFINE_HANDLE(XrPassthroughLayerANDROID)

แอปพลิเคชันสามารถสร้างตัวแฮนเดิล XrPassthroughLayerANDROID ได้โดยเรียกใช้ xrCreatePassthroughLayerANDROID แฮนเดิล XrPassthroughLayerANDROID ที่แสดงผลสามารถนําไปใช้กับการเรียก API ในภายหลัง

XrResult xrCreatePassthroughLayerANDROID(
    XrSession                                   session,
    const XrPassthroughLayerCreateInfoANDROID*  createInfo,
    XrPassthroughLayerANDROID*                  layer);

คําอธิบายพารามิเตอร์

  • session คือ XrSession ที่จะสร้างเลเยอร์การส่งผ่าน
  • createInfo คือพอยน์เตอร์ไปยังโครงสร้าง XrPassthroughLayerCreateInfoANDROID ที่ระบุพารามิเตอร์เลเยอร์การส่งผ่านเริ่มต้น ฟิลด์นี้สามารถเชื่อมโยงกับโครงสร้าง XrPassthroughLayerMeshANDROID เพื่อตั้งค่าเมชในเวลาเดียวกันได้ด้วย
  • layer คือพอยน์เตอร์ไปยังแฮนเดิลที่ระบบแสดงXrPassthroughLayerANDROID ที่สร้างขึ้น

แอปพลิเคชันควรระบุจำนวนดัชนีเมชที่ส่งผ่านใน XrPassthroughLayerCreateInfoANDROID::vertexCapacity และ XrPassthroughLayerCreateInfoANDROID::indexCapacity ให้น้อยกว่าหรือเท่ากับค่าสูงสุดที่แสดงผลโดย XrSystemPassthroughLayerPropertiesANDROID::maxMeshIndexCount และ XrSystemPassthroughLayerPropertiesANDROID::maxMeshVertexCount เมื่อเรียกใช้ xrGetSystemProperties xrCreatePassthroughLayerANDROID จะแสดงข้อผิดพลาด XR_ERROR_MESH_DATA_LIMIT_EXCEEDED_ANDROID หากจํานวนดัชนีเมชที่ระบุโดย createInfo มากกว่าค่าสูงสุด

ต้องยกเลิกการจัดการ XrPassthroughLayerANDROID โดยใช้ฟังก์ชัน xrDestroyPassthroughLayerANDROID

การใช้งานที่ถูกต้อง (โดยนัย)

รหัสการคืนสินค้า

สำเร็จ

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

ไม่สำเร็จ

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_VALIDATION_FAILURE
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_OUT_OF_MEMORY
  • XR_ERROR_LIMIT_REACHED
  • XR_ERROR_SIZE_INSUFFICIENT
  • XR_ERROR_MESH_DATA_LIMIT_EXCEEDED_ANDROID

โครงสร้าง XrPassthroughLayerCreateInfoANDROID มีคำจำกัดความดังนี้

typedef struct XrPassthroughLayerCreateInfoANDROID {
    XrStructureType    type;
    const void*        next;
    uint32_t           vertexCapacity;
    uint32_t           indexCapacity;
} XrPassthroughLayerCreateInfoANDROID;

คำอธิบายสมาชิก

  • type คือ XrStructureType ของโครงสร้างนี้
  • next เป็น NULL หรือพอยน์เตอร์ไปยังโครงสร้างถัดไปในเชนโครงสร้าง XrPassthroughLayerMeshANDROID สามารถระบุได้ในเชนถัดไปเพื่อระบุเมชเริ่มต้นของเลเยอร์พาสทรูเมื่อเรียกใช้ xrCreatePassthroughLayerANDROID
  • vertexCapacity คือ uint32_t ที่แสดงถึงความจุสูงสุดของบัฟเฟอร์เวิร์กเท็กซ์สำหรับเมชของเลเยอร์นี้ หรือ 0 หากไม่ได้ระบุ หากระบุ XrPassthroughLayerMeshANDROID::vertexCount ของเมชที่ตั้งค่าไว้สําหรับเลเยอร์นี้ต้องน้อยกว่าหรือเท่ากับ vertexCapacity
  • indexCapacity คือ uint32_t ที่แสดงถึงความจุสูงสุดของบัฟเฟอร์อินเด็กซ์สำหรับเมชของเลเยอร์นี้ หรือ 0 หากไม่ได้ระบุ หากระบุไว้ XrPassthroughLayerMeshANDROID::indexCount ของเมชที่ตั้งค่าไว้สําหรับเลเยอร์นี้ต้องน้อยกว่าหรือเท่ากับ indexCapacity

การใช้งานที่ถูกต้อง (โดยนัย)

แอปพลิเคชันสามารถใช้ฟังก์ชัน xrDestroyPassthroughLayerANDROID เพื่อปล่อยเลเยอร์พาสทรูและทรัพยากรที่เกี่ยวข้อง

XrResult xrDestroyPassthroughLayerANDROID(
    XrPassthroughLayerANDROID                   layer);

คําอธิบายพารามิเตอร์

การใช้งานที่ถูกต้อง (โดยนัย)

ความปลอดภัยของชุดข้อความ

  • การเข้าถึง layer และตัวแฮนเดิลย่อยต้องมีการซิงค์จากภายนอก

รหัสการคืนสินค้า

สำเร็จ

  • XR_SUCCESS

ไม่สำเร็จ

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_HANDLE_INVALID

ตั้งค่าเมชเลเยอร์การแสดงภาพ

แอปพลิเคชันสามารถใช้ฟังก์ชัน xrSetPassthroughLayerMeshANDROID เพื่อตั้งค่าเมชสําหรับเลเยอร์พาสทรู

XrResult xrSetPassthroughLayerMeshANDROID(
    XrPassthroughLayerANDROID                   layer,
    const XrPassthroughLayerMeshANDROID*        mesh);

คําอธิบายพารามิเตอร์

  • layer คือแฮนเดิล XrPassthroughLayerANDROID ที่จะอัปเดตด้วย mesh ที่ระบุ
    • mesh คือพอยน์เตอร์ไปยังโครงสร้าง XrPassthroughLayerMeshANDROID ที่ระบุข้อมูลของเมช

แอปพลิเคชันควรระบุจำนวนดัชนีของเมชที่ส่งผ่านใน XrPassthroughLayerMeshANDROID::vertexCount และ XrPassthroughLayerMeshANDROID::indexCount ให้น้อยกว่าหรือเท่ากับค่าสูงสุดที่แสดงผลโดย XrSystemPassthroughLayerPropertiesANDROID::maxMeshIndexCount และ XrSystemPassthroughLayerPropertiesANDROID::maxMeshVertexCount เมื่อเรียกใช้ xrGetSystemProperties หากจํานวนอินเด็กซ์ของเมชที่ได้จาก mesh จาก xrSetPassthroughLayerMeshANDROID มากกว่าค่าสูงสุด ระบบจะแสดงผล XR_ERROR_MESH_DATA_LIMIT_EXCEEDED_ANDROID

หากระบุความจุของบัฟเฟอร์เมชโดย XrPassthroughLayerCreateInfoANDROID::vertexCapacity และ XrPassthroughLayerCreateInfoANDROID::indexCapacity เมื่อสร้าง layer โดยใช้ xrCreatePassthroughLayerANDROID ระบบจะแสดงข้อผิดพลาด XR_ERROR_SIZE_INSUFFICIENT ใน xrSetPassthroughLayerMeshANDROID หากจํานวนอินเด็กซ์เมชที่กําหนดโดย mesh มากกว่าความจุ

การใช้งานที่ถูกต้อง (โดยนัย)

รหัสการคืนสินค้า

สำเร็จ

  • XR_SUCCESS
  • XR_SESSION_LOSS_PENDING

ไม่สำเร็จ

  • XR_ERROR_FUNCTION_UNSUPPORTED
  • XR_ERROR_VALIDATION_FAILURE
  • XR_ERROR_RUNTIME_FAILURE
  • XR_ERROR_HANDLE_INVALID
  • XR_ERROR_INSTANCE_LOST
  • XR_ERROR_SESSION_LOST
  • XR_ERROR_OUT_OF_MEMORY
  • XR_ERROR_LIMIT_REACHED
  • XR_ERROR_SIZE_INSUFFICIENT
  • XR_ERROR_MESH_DATA_LIMIT_EXCEEDED_ANDROID

โครงสร้าง XrPassthroughLayerMeshANDROID มีคำจำกัดความดังนี้

typedef struct XrPassthroughLayerMeshANDROID {
    XrStructureType          type;
    const void*              next;
    XrWindingOrderANDROID    windingOrder;
    uint32_t                 vertexCount;
    const XrVector3f*        vertices;
    uint32_t                 indexCount;
    const uint16_t*          indices;
} XrPassthroughLayerMeshANDROID;

คำอธิบายสมาชิก

  • type คือ XrStructureType ของโครงสร้างนี้
  • next คือ NULL หรือพอยน์เตอร์ไปยังโครงสร้างถัดไปในเชนโครงสร้าง
  • windingOrder คือ XrWindingOrderANDROID ของสามเหลี่ยมเมช ซึ่งจะใช้สำหรับการคัดทิ้งพื้นหลังเมื่อแสดงผลเมช
  • vertexCount คือ uint32_t ที่แสดงจํานวนจุดยอดในเมช เมื่อระบุ XrPassthroughLayerCreateInfoANDROID::vertexCapacity แล้ว vertexCount ต้องน้อยกว่าหรือเท่ากับ vertexCapacity
    • vertices เป็นพอยน์เตอร์ไปยังอาร์เรย์ของ XrVector3f ซึ่งมีตำแหน่งเวิร์กเท็กซ์ของเมชรูปสามเหลี่ยม
  • indexCount คือ uint32_t ที่แสดงจํานวนอินเด็กซ์ในเมชรูปสามเหลี่ยม ระบบจะไม่วาดดัชนี indexCount % 3 รายการสุดท้าย (หากมี) เมื่อระบุ XrPassthroughLayerCreateInfoANDROID::indexCapacity แล้ว indexCount ต้องน้อยกว่าหรือเท่ากับ indexCapacity
  • indices เป็นพอยน์เตอร์ไปยังอาร์เรย์ของ uint16_t ซึ่งมีดัชนีของเมชสามเหลี่ยม

การใช้งานที่ถูกต้อง (โดยนัย)

การแจกแจงค่า XrWindingOrderANDROID จะระบุลําดับการเลี้ยวของสามเหลี่ยมของเมช ซึ่งรันไทม์ใช้สำหรับการคัดทิ้งด้านหลังเมื่อแสดงผลเมชของเลเยอร์การส่งผ่าน

typedef enum XrWindingOrderANDROID {
    XR_WINDING_ORDER_UNKNOWN_ANDROID = 0,
    XR_WINDING_ORDER_CW_ANDROID = 1,
    XR_WINDING_ORDER_CCW_ANDROID = 2
} XrWindingOrderANDROID;

คำอธิบายรายการ

  • XR_WINDING_ORDER_UNKNOWN_ANDROID  — ไม่ทราบลําดับการบิดของสามเหลี่ยมของตาข่าย
  • XR_WINDING_ORDER_CW_ANDROID  — ลําดับการต่อรูปสามเหลี่ยมของตาข่ายคือตามเข็มนาฬิกา
  • XR_WINDING_ORDER_CCW_ANDROID  — ลําดับการต่อรูปสามเหลี่ยมของตาข่ายคือทวนเข็มนาฬิกา

ตัวอย่างโค้ดสำหรับองค์ประกอบเลเยอร์การส่งผ่าน

โค้ดตัวอย่างต่อไปนี้แสดงวิธีสร้างเลเยอร์การส่งผ่านและใช้ในการคอมโพส

XrInstance instance; // previously initialized
XrSystemId systemId; // previously initialized
XrSession session; // previously initialized
XrSpace space; // previously initialized

// The function pointers are previously initialized using xrGetInstanceProcAddr.
PFN_xrCreatePassthroughLayerANDROID xrCreatePassthroughLayerANDROID; // previously initialized
PFN_xrDestroyPassthroughLayerANDROID xrDestroyPassthroughLayerANDROID; // previously initialized
PFN_xrSetPassthroughLayerMeshANDROID xrSetPassthroughLayerMeshANDROID; // previously initialized

// Inspect passthrough mesh system properties
XrSystemPassthroughLayerPropertiesANDROID passthroughLayerSystemProperties{
  XR_TYPE_SYSTEM_PASSTHROUGH_LAYER_PROPERTIES_ANDROID};
XrSystemProperties systemProperties{
  XR_TYPE_SYSTEM_PROPERTIES, &passthroughLayerSystemProperties};
CHK_XR(xrGetSystemProperties(instance, systemId, &systemProperties));
if (!passthroughLayerSystemProperties.supportsPassthroughLayer) {
    // the system does not support composite layer passthrough mesh.
    return;
}

// The initial mesh for the layer.
XrPassthroughLayerMeshANDROID mesh = {
  .type = XR_TYPE_PASSTHROUGH_LAYER_MESH_ANDROID,
  .windingOrder = XR_WINDING_ORDER_CW_ANDROID,
  .vertexCount = 4,
  .vertices = {
    { 0, 0, 0 }, { 0, 1, 0 }, { 1, 1, 0 }, { 1, 0, 0 }
  },
  .indexCount = 6,
  .indices = {
    0, 1, 2,
    0, 2, 3
  },
};

// Create the layer. Layers are expected to persist across frames.
XrPassthroughLayerCreateInfoANDROID create_info = {
  .type = XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_ANDROID,
  .next = &mesh,
  .vertexCapacity = 0,
  .indexCapacity = 0,
};
XrPassthroughLayerANDROID layer;
CHK_XR(xrCreatePassthroughLayerANDROID(session, &create_info, &layer));

// Create a composition layer. Composition layers are submitted per frame.
XrCompositionLayerPassthroughANDROID passthrough_layer = {
  .type = XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_ANDROID,
  .next = nullptr,
  .layerFlags = 0,
  .space = space,
  .pose = {
    .orientation = { 0.0f, 0.0f, 0.0f, 1.0f }
    .position = { 0.0f, 0.0f, 0.0f }
  },
  .scale = { 1.0f, 1.0f, 1.0f },
  .opacity = 1.0f,
  .layer = layer
};

while (1) {
    // ...
    // For every frame in frame loop
    // ...

    // Submit composition layer in xrEndFrame.
    std::vector<XrCompositionLayerBaseHeader*> layers = {
        ...,
        &passthrough_layer,
        ...,
    };
    XrFrameEndInfo end_frame_info = { XR_TYPE_FRAME_END_INFO, nullptr };
    end_frame_info.layerCount = (uint32_t)layers.size();
    end_frame_info.layers = layers.data();
    CHK_XR(xrEndFrame(session, &end_frame_info));

    // Update the layer. Results can be seen the next time a passthrough composition
    // layer is submitted.
    mesh.indexCount = 9;
    const uint16_t new_index_buffer[] = {
        0, 1, 2,
        0, 2, 3,
        0, 1, 2
    };
    mesh.indexBuffer = &new_index_buffer[0];
    CHK_XR(xrSetPassthroughLayerMeshANDROID(&layer, &mesh));

    // ...
    // Finish frame loop
    // ...
}

// Clean up.
CHK_XR(xrDestroyPassthroughLayerANDROID(layer));

ประเภทออบเจ็กต์ใหม่

ค่าคงที่ Enum ใหม่

เพิ่มรายการต่อไปนี้ในคําจํากัดความของ XrObjectType

  • XR_OBJECT_TYPE_PASSTHROUGH_LAYER_ANDROID

เพิ่มรายการต่อไปนี้ในอนุกรม XrStructureType

  • XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_ANDROID
  • XR_TYPE_PASSTHROUGH_LAYER_MESH_ANDROID
  • XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_ANDROID
  • XR_TYPE_SYSTEM_PASSTHROUGH_LAYER_PROPERTIES_ANDROID

การแจกแจงค่า XrResult ขยายให้มีรายการต่อไปนี้

  • XR_ERROR_MESH_DATA_LIMIT_EXCEEDED_ANDROID

Enum ใหม่

โครงสร้างใหม่

ฟังก์ชันใหม่

ปัญหา

ประวัติเวอร์ชัน

  • การแก้ไข 1, 11-09-2024 (Levana Chen)
    • คำอธิบายส่วนขยายเริ่มต้น