นิยามปริภูมิแฝงเชิงท่าทางที่ตีความได้ (Interpretable Pose Latent: IPL 1.1.2)
ทีมวิจัยเทคโนโลยีที่ทุกคนเข้าถึงและสิ่งอำนวยความสะดวก (AAT)
กลุ่มนวัตกรรมแพลตฟอร์มดิจิทัลสุขภาพการแพทย์ (DHCB)
สำนักงานพัฒนาวิทยาศาสตร์และเทคโนโลยีแห่งชาติ (NSTDA)
1.1.
เอกสารนี้นิยาม ปริภูมิแฝงเชิงท่าทางที่ตีความได้ (Interpretable Pose Latent: IPL) รุ่น 1.1.2 อันเป็นเวกเตอร์พารามิเตอร์แบบแบน (flat vector) ที่ทุกมิติมีชื่อกำกับ มีค่าที่ทำให้เป็นบรรทัดฐาน (normalize) และไม่ผูกกับโครงกระดูกของโมเดลใดโมเดลหนึ่ง (rig-agnostic) สำหรับแทนท่าทางภาษามือของร่างกายท่อนบน — มือ แขน ศีรษะ ลำตัว ใบหน้า และปาก — ณ ขณะเวลาหนึ่ง (หนึ่งคีย์เฟรม)
1.2.
IPL เป็นมาตรฐานการแทนข้อมูล (representation standard) มิใช่อัลกอริทึม — เอกสารนี้กำหนดว่าเวกเตอร์มีความหมายอย่างไร มิได้กำหนดวิธีการภายในของโปรแกรมที่สร้างหรืออ่านเวกเตอร์
1.3.
หลักการออกแบบ: (ก) กำหนดขึ้นโดยเจตนา (designed) — แกนของปริภูมิแฝงถูกนิยามด้วยภาษามนุษย์และตรึงไว้โดยเอกสารนี้ มิใช่แกนที่ได้จากการเรียนรู้ของแบบจำลอง (ข) ตีความได้ — แต่ละมิติตรงกับมโนทัศน์การเคลื่อนไหวหนึ่งเรื่องที่มนุษย์อ่าน เข้าใจ และแก้ไขค่าด้วยมือได้ (ค) ไม่ผูกกับโมเดล — ค่าถูกทำให้เป็นบรรทัดฐานและเป็นอิสระจากโครงกระดูก โปรแกรมแสดงผลที่สอดคล้องกับนิยามย่อมถอดรหัสเวกเตอร์เดียวกันไปยังโมเดลรูปทรงมนุษย์ของตนได้
1.4.
การอ้างอิงของทุกมิติผูกกับอวัยวะของโมเดลตามนิยามที่มนุษย์เข้าใจ — เช่น มือ ศอก ข้อมือ นิ้ว คิ้ว เปลือกตา ริมฝีปาก — มิใช่แกนเชิงนามธรรมหรือดัชนีกระดูกภายในของโมเดลใดโมเดลหนึ่ง ชื่อและความหมายของพารามิเตอร์จึงอ่านเข้าใจได้ตรงตามสรีระ และนำไปผูกกับโครงกระดูกของโมเดลรูปทรงมนุษย์ใดก็ได้ที่มีอวัยวะครบตามนิยาม
1.5.
คำว่า "ต้อง" "ห้าม" "ควร" และ "อาจ" ในเอกสารนี้ ให้ตีความตามแนวทาง RFC 2119
2.1.
- เวกเตอร์ IPL — เวกเตอร์พารามิเตอร์ครบชุดตามลำดับที่เอกสารนี้กำหนด ใช้สัญลักษณ์ P (อักษรโรมันตัวพิมพ์ใหญ่ตัวตรงตัวหนา)
- มิติ / พารามิเตอร์ — ค่าสเกลาร์หนึ่งตัวของเวกเตอร์ที่มีชื่อกำกับ
- กลุ่ม — การแบ่งส่วนของมิติตามข้อ 3.1
- องศาอิสระ (DOF) — จำนวนแกนการเคลื่อนไหวที่พารามิเตอร์หรือกลุ่มหนึ่งให้
- ท่าหลัก (pose) — ชั้นการเคลื่อนไหวพื้นฐาน: ร่างกายกำลังทำท่าอะไร
- การแสดงออก (expression) — ชั้นค่าส่วนเพิ่ม (additive) บนกลุ่มที่ใช้ใน latent อารมณ์ได้: ท่านั้นถูกแต่งอารมณ์อย่างไร (ข้อ 3.3)
- เงื่อนไขเสริม (hyper condition) — ช่องสัญญาณเชิงเงื่อนไขที่กำกับการถอดรหัส เดินทางคู่กับเวกเตอร์ แต่มิใช่มิติของปริภูมิแฝง ได้แก่ จุดมองสายตา รูปปากตามเสียง การสัมผัส และจุดยึดแขน (ข้อ 3.4)
- จุดบนร่างกาย (body site) — จุดอ้างอิงที่มีชื่อบนร่างกายที่ถอดรหัสแล้ว ใช้เป็นโดเมนของเงื่อนไขการสัมผัสและจุดยึดแขน (ข้อ 3.4)
- การปรับปรุงผลลัพธ์ (post-processing) — ขั้นสุดท้ายของการถอดรหัส กระทำบนท่าที่ถอดรหัสสมบูรณ์แล้ว (ท่าหลักรวมการแสดงออก ถอดรหัสลงโครงกระดูก) หลังการถอดรหัสปริภูมิแฝงทั้งหมด (ข้อ 3.4)
- การประกอบ (composition) — สคริปต์ข้อความบรรทัดเดียวที่วางชุดคีย์เฟรมของเวกเตอร์ IPL ที่จัดเก็บไว้ลงบนเส้นเวลา (ข้อ 7)
- ผู้ผลิต (producer) — โปรแกรมใดๆ ที่สร้างเวกเตอร์ IPL ไม่ว่าจากแบบจำลองหรือจากการแก้ไขโดยมนุษย์
- ผู้บริโภค (consumer) — โปรแกรมใดๆ ที่อ่านเวกเตอร์ IPL เช่น โปรแกรมแสดงผล โปรแกรมส่งออก หรือโปรแกรมวิเคราะห์
3.1.
เวกเตอร์ IPL แบ่งเป็นกลุ่มต่อเนื่อง 7 กลุ่ม รวม 71 มิติ ดังนี้
| รหัส |
กลุ่ม |
บทบาท |
จำนวนมิติ |
| a |
แขน (arm) |
การเคลื่อนไหว (articulation) |
8 (4 × ซ้าย/ขวา) |
| w |
การหันฝ่ามือ (palm facing) |
การเคลื่อนไหว |
6 (3 × ซ้าย/ขวา) |
| g |
นิ้วมือ (fingers) |
การเคลื่อนไหว |
32 (16 × ซ้าย/ขวา) |
| h |
ศีรษะ (head) |
การเคลื่อนไหว + การแสดงออก |
3 |
| b |
ลำตัว (body) |
การเคลื่อนไหว + การแสดงออก |
3 |
| f |
ใบหน้า (face) |
การเคลื่อนไหว + การแสดงออก |
8 |
| m |
ปาก (mouth) |
การเคลื่อนไหว + การแสดงออก |
11 |
กลุ่มที่เป็นการเคลื่อนไหวล้วน (a, w, g) ห้ามรับค่าส่วนเพิ่มของการแสดงออก — กลุ่มที่ใช้ใน latent อารมณ์ได้มีเฉพาะ h, b, f, m เท่านั้น (ข้อ 3.3) นอกจากกลุ่มต่อเนื่องแล้ว เวกเตอร์ยังมีเงื่อนไขเสริมเดินทางคู่กันตามข้อ 3.4
3.2.1.
ทุกมิติต่อเนื่องถูกทำให้เป็นบรรทัดฐานในช่วงปิด [−1, 1] ผู้บริโภคต้องตัดค่า (clamp) ที่เกินช่วงให้อยู่ใน [−1, 1]
3.2.2.
ค่าเชิงกายภาพของมิติกู้คืนได้จากค่าบรรทัดฐาน n ตามโหมดของมิตินั้น: แบบสองขั้ว (bipolar ค่าปริยาย) real = n × max, แบบขั้วเดียว (unipolar) real = (n+1)/2 × max สำหรับแกนที่ไม่มีความหมายเชิงลบ และแบบวนรอบ (circular) เก็บองศาโดยตรงและวนรอบที่ max — การแปลงนี้เป็นเพียงความสะดวกฝั่งถอดรหัส ค่าที่รับส่งจริงคือค่าบรรทัดฐานเสมอ
3.2.3.
กรอบอ้างอิงเชิงความหมายของท่าคือกรอบลำตัวยึดคอเป็นศูนย์กลาง (neck-centric) แบบมือขวา: +x = ขวาของร่างกาย, +y = ขึ้น, +z = เข้าหาผู้ชม — ตำแหน่งแขนใช้หน่วยแกนที่คาลิเบรตแล้วตามข้อ 4.1 และค่าในเวกเตอร์เป็นค่าบรรทัดฐาน มิใช่ระยะดิบ
3.2.4.
ความเป็นข้างซ้าย/ขวามีนัยสำคัญทางภาษา ห้ามสลับข้างโดยพลการ มิติที่มีข้างปรากฏเป็นคู่ท้ายชื่อ _l/_r ที่ใช้นิยามร่วมกัน — ค่าบรรทัดฐานเท่ากันทั้งสองข้างหมายถึงท่าสมมาตร โดยแกนแนวราบ (x-like) ถูกกลับเครื่องหมายให้ข้างขวาโดยอัตโนมัติในขั้นถอดรหัส
3.3.
ชั้นท่าหลักและการแสดงออก — เวกเตอร์ IPL ซ้อนกันสองชั้นตามสูตร effective = clamp( pose + alpha × expression ) โดย pose คือเวกเตอร์พื้นฐานครบทั้ง 7 กลุ่ม, expression คือค่าส่วนเพิ่มเฉพาะกลุ่ม h, b, f, m และ alpha คือตัวคูณความเข้มในช่วง [0, 1] — การแสดงออกไม่เพิ่มมิติใหม่ให้ทะเบียน และผู้บริโภคที่ไม่รองรับการแสดงออกต้องยังแสดงผล pose ได้ถูกต้อง
3.4.
เงื่อนไขเสริมและการปรับปรุงผลลัพธ์ (post-processing)
3.4.1.
เงื่อนไขเสริมเป็นช่องสัญญาณเชิงเงื่อนไขที่กำหนดขึ้นโดยเจตนา (มิใช่การเรียนรู้) ไม่ครองตำแหน่งในทะเบียนพารามิเตอร์ ไม่ประมาณค่าระหว่างคีย์เฟรมแบบสเกลาร์ และเมื่อถอดเงื่อนไขเสริมออก การถอดรหัสท่าหลักจากเวกเตอร์ต้องยังคงถูกต้อง ค่าอื่นทั้งหมดยังเป็นปริภูมิแฝงเช่นเดิม
3.4.2.
ลำดับการถอดรหัสเต็ม: เวกเตอร์ (pose + alpha × expression) → ถอดรหัสเป็นท่าโครงกระดูก (จุดมองสายตาและรูปปากตามเสียงถูกใช้ในขั้นนี้) → การปรับปรุงผลลัพธ์ (การสัมผัสและจุดยึดแขนถูกแก้ในขั้นนี้) → ร่างกายที่แสดงผล
3.4.3.
เงื่อนไขเสริมมี 4 ชนิด: จุดมองสายตา (eye look-at) และรูปปากตามเสียง (viseme) เป็นเงื่อนไขขั้นถอดรหัส ส่วนการสัมผัส (contact) และจุดยึดแขน (anchor) เป็นเงื่อนไขขั้นการปรับปรุงผลลัพธ์ — การสัมผัสระบุเป็นคู่ (จุดเคลื่อน, จุดเป้าหมาย) บนจุดบนร่างกาย หมายถึง "จุดเคลื่อนแตะจุดเป้าหมาย" โดยแก้บนร่างกายที่ถอดรหัสสมบูรณ์แล้ว ด้วยการขยับเฉพาะสายโซ่แขนฝั่งจุดเคลื่อนให้จุดทั้งสองประจบกัน — ฝั่งเป้าหมายและลำตัวห้ามเคลื่อน เป้าหมายที่เกินระยะเอื้อมให้ตัดที่จุดใกล้สุดที่เอื้อมถึง และแต่ละคีย์เฟรมมีการสัมผัสได้ไม่เกินหนึ่งรายการ
3.4.4.
จุดยึดแขน (anchor) ระบุแยกต่อข้างแขนในรูป {l?: {site}, r?: {site}} บนจุดบนร่างกาย หมายถึง "ตำแหน่งแขนข้างนี้ (a_hand_*) วัดจากจุดนี้แทนคอ" — แต่ละรายการอยู่บนคีย์เฟรมของแขนข้างตนเอง แขนที่คีย์เฟรมไม่มีจุดยึดต้องไม่ถูกขยับ (ยังวัดจากคอเช่นเดิม) การแก้ทำบนร่างกายที่ถอดรหัสสมบูรณ์แล้ว โดยเลื่อนเป้าหมายของแขนข้างที่มีจุดยึดด้วยผลต่างพิกัดโลก (จุดยึด − คอ) บนโมเดลที่วางท่าแล้ว แล้วแก้การเคลื่อนไหวผกผัน (IK) ใหม่ ลำตัวห้ามเคลื่อน (จุดยึด neck จึงไม่มีผลโดยโครงสร้าง) จุดที่ใช้ได้มีเฉพาะ forehead, mouth, navel, shoulder_l, shoulder_r และ neck (ค่าปริยาย ไม่มีผล) จุดบนมือใช้ไม่ได้ — ลำดับความสำคัญ: การสัมผัสเหนือจุดยึดแขน กล่าวคือฝั่งที่การสัมผัสทำงาน จุดยึดของฝั่งนั้นถูกละเลย ส่วนอีกฝั่งยังใช้จุดยึดตามปกติ และโมเดลที่ถอดจุดไม่ได้ให้ถอยกลับไปวัดจากคอ (ไม่ถือเป็นข้อผิดพลาด) ด้วยเหตุนี้เวกเตอร์เดียวกันจึงให้ตำแหน่งถูกต้องบนทุกโมเดล
3.4.5.
จุดบนร่างกายเป็นชุดคำศัพท์ตายตัว 32 ชื่อ ได้แก่ คอ สะดือ หน้าผาก ปาก และรายข้าง (ซ้าย/ขวา) ไหล่ ศอก ข้อมือ ฝ่ามือ กับโคนนิ้วและปลายนิ้วของนิ้วทั้งห้า — จุดหนึ่งแปลงเป็นพิกัดโลกด้วยกระดูกหลักบวกระยะเยื้องท้องถิ่นของกระดูก ซึ่งปรับเทียบรายโมเดลและถือเป็นสถานะของโปรแกรมแสดงผล มิใช่ส่วนหนึ่งของเวกเตอร์ ข้อจำกัดของการสัมผัส: จุดเคลื่อนต้องเป็นจุดบนมือเท่านั้น และจุดเป้าหมายห้ามอยู่บนมือเดียวกันกับจุดเคลื่อนหรือเป็นศอกฝั่งเดียวกัน
4.
ทะเบียนพารามิเตอร์
ทะเบียนนี้เป็นรายการมิติทั้งหมดที่มีผลบังคับ หนึ่งแถวคือหนึ่งมิติ (มิติที่มีข้างปรากฏเป็นคู่ _l/_r ใช้นิยามร่วมกัน) รหัสมิติ (id) เป็นตัวระบุถาวร ห้ามนำกลับมาใช้ซ้ำหรือนิยามใหม่ภายในรุ่นกระบวนทัศน์ (X) เดียวกัน (ข้อ 8) ค่าปริยายของทุกมิติคือค่าบรรทัดฐานของท่ากลางเริ่มต้น ซึ่งเป็น 0 ยกเว้น a_hand_x 0.333, a_hand_y −0.933, a_hand_z 0.35, a_spread 0.4, w_qx 0.885, w_qy −0.093 และ w_qz −0.429 (ทั้งข้างซ้ายและขวา)
4.1.
กลุ่มแขน (a) — ตำแหน่งมือในกรอบยึดคอ ค่าจริงสูงสุด 1.5 เท่าของหน่วยแกนที่คาลิเบรตแล้ว และการกางศอกแบบขั้วเดียว (ค่าจริงสูงสุด 1) — แต่ละแกนของตำแหน่งมือมีหน่วยความยาวที่คาลิเบรตแยกกันจากระยะอ้างอิง d บนจุดบนร่างกาย ดังนี้ แกน X อิงความยาวมือ (ข้อมือถึงปลายนิ้วกลาง ขณะมือกางในท่าอ้างอิง) แกน Y อิงความยาวช่วงตัว (คอถึงสะดือ ขณะลำตัวอยู่ในท่าอ้างอิง) และแกน Z อิงความยาวแขน (ไหล่ถึงข้อมือ ขณะเหยียดแขนเต็มที่โดยคงทิศข้อมือเดิม) โดยหน่วยแกนเป็นไปตามข้อ 4.1.2
| รหัส |
ข้าง |
ความหมาย |
−1 … +1 |
| a_hand_x |
ซ/ข |
ตำแหน่งมือด้านข้าง ในหน่วยแกน X = 2 · r · ความยาวมือ (ข้อมือถึงปลายนิ้วกลาง) ที่คาลิเบรตแล้ว |
−1 = ข้ามไปฝั่งตรงข้าม · +1 = เลยไหล่ตนเองออกไป |
| a_hand_y |
ซ/ข |
ความสูงของมือ ในหน่วยแกน Y = 2 · r · ความยาวช่วงตัว (คอถึงสะดือ) ที่คาลิเบรตแล้ว |
−1 = ต่ำระดับสะโพก · +1 = ชูเหนือศีรษะ |
| a_hand_z |
ซ/ข |
ระยะยื่นไปข้างหน้า ในหน่วยแกน Z = 2 · r · ความยาวแขน (ไหล่ถึงข้อมือเมื่อเหยียดเต็มที่) ที่คาลิเบรตแล้ว |
−1 = ชิดลำตัว · +1 = ยื่นสุดแขน |
| a_spread |
ซ/ข |
การกางศอก |
0 = แนบซี่โครง · +1 = กางออก |
4.1.1.
ระยะอ้างอิงต้องวัดระหว่างจุดบนร่างกายที่คาลิเบรตแล้ว (รวมระยะเยื้องท้องถิ่นของกระดูก) ในท่าอ้างอิงคงที่ ห้ามวัดใหม่จากท่าขณะเคลื่อนไหว — การงอศอก การงอนิ้ว หรือการหมุนลำตัวต้องไม่เปลี่ยนหน่วย ระยะอ้างอิงของข้างขวากำหนดหน่วยร่วมของแขนทั้งสองข้าง โดยเครื่องหมายซ้าย/ขวายังเป็นไปตามข้อ 3.2.4 และเมื่อจุดที่คาลิเบรตหรือรูปทรงมือจริงเปลี่ยน ต้องคำนวณระยะอ้างอิงที่ได้รับผลใหม่
4.1.2.
หน่วยของแต่ละแกนคือ L = 2 · r · d โดย d คือระยะอ้างอิงที่คาลิเบรตของแกนนั้น และ r คืออัตราส่วนอ้างอิงคงที่ต่อแกนซึ่งนิยามโดยโมเดลอ้างอิงทางการ (based) เพื่อคงขนาดตัวเลขของค่าบรรทัดฐานเดิมไว้ ได้แก่ หน่วยแกน X = 2 · r · ความยาวมือ (ข้อมือถึงปลายนิ้วกลาง) หน่วยแกน Y = 2 · r · ความยาวช่วงตัว (คอถึงสะดือ) และหน่วยแกน Z = 2 · r · ความยาวแขน (ไหล่ถึงข้อมือ ขณะเหยียดแขน) ไม่มีแกนใดใช้ความยาวนั้นโดยตรงเป็นหน่วย พิกัดแขนบรรทัดฐาน n ให้ระยะเลื่อน n × max × หน่วยแกน ตามแกนในกรอบร่างกาย ก่อนการแก้จุดยึดแขนและการสัมผัส ความกว้างไหล่เพียงอย่างเดียวจึงไม่กำหนดตำแหน่งแขนข้ามโมเดลอีกต่อไป ทั้งนี้รหัส ค่าสูงสุด และค่าปริยายในทะเบียนไม่เปลี่ยน
4.1.3.
ผู้บริโภคที่ไม่มีระยะอ้างอิงที่ใช้ได้ ควรใช้หน่วยความกว้างไหล่แบบเดิมสำหรับแกนนั้นและรายงานว่าขาดการคาลิเบรต — การถอยกลับนี้ไม่ถือว่าโมเดลนั้นสอดคล้องกับข้อกำหนดหน่วยแกนที่คาลิเบรตแล้ว
4.2.
กลุ่มการหันฝ่ามือ (w) — ทิศทางข้อมือแทนด้วยควอเทอร์เนียน (quaternion) ซึ่งโดยสมบูรณ์มี 4 องค์ประกอบ (w, qx, qy, qz) แต่ IPL จัดเก็บเฉพาะส่วนเวกเตอร์ 3 องค์ประกอบ (qx, qy, qz) — เมื่อนำไปคำนวณจริง ผู้บริโภคต้องคำนวณองค์ประกอบ w คืนจากเงื่อนไขความยาวหนึ่งหน่วย w = √(1 − (qx² + qy² + qz²)) เพื่อให้ควอเทอร์เนียนมีความยาว (length) เท่ากับ 1 เสมอ โดยหากผลรวมกำลังสองของส่วนเวกเตอร์เกิน 1 ต้องย่อสเกลส่วนเวกเตอร์ลงให้ความยาวไม่เกิน 1 ก่อนคำนวณ (และควรจำกัดไว้ต่ำกว่า 1 เล็กน้อย เช่น 0.98 เพื่อเลี่ยงภาวะเอกฐานใกล้ w = 0) การกำหนดให้ w ≥ 0 เสมอเช่นนี้ยังทำให้การแทนการหมุนไม่กำกวม (ควอเทอร์เนียน q และ −q คือการหมุนเดียวกัน) ทิศทางอ้างอิงในกรอบลำตัว — เหตุที่เลือกใช้ควอเทอร์เนียนแทนมุมออยเลอร์ คือ (ก) หลีกเลี่ยงปัญหามุมอับ (gimbal lock) เมื่อนำการหมุนไปประกอบร่วมกับกรอบอ้างอิงอื่น และ (ข) การประมาณค่าระหว่างคีย์เฟรม (interpolation) ของควอเทอร์เนียนให้เส้นทางการหมุนที่ราบรื่นและเป็นธรรมชาติกว่า — เอกลักษณ์ (0,0,0) = ฝ่ามือหันหน้า นิ้วชี้ขึ้น ข้างขวาสะท้อนผ่านระนาบกลางลำตัว
| รหัส |
ข้าง |
ความหมาย |
−1 … +1 |
| w_qx |
ซ/ข |
องค์ประกอบ qx (แกนก้ม/เงยฝ่ามือ) |
−1 … +1 |
| w_qy |
ซ/ข |
องค์ประกอบ qy (แกนคว่ำ/หงาย) |
−1 … +1 |
| w_qz |
ซ/ข |
องค์ประกอบ qz (แกนเอียงข้าง) |
−1 … +1 |
4.3.
กลุ่มนิ้วมือ (g) — รวม 16 มิติต่อข้าง ทุกมิติสองขั้ว ค่าจริงสูงสุด 1 แยกเป็นนิ้วทั้งสี่ (นิ้วละ 3 องศาอิสระ) และนิ้วหัวแม่มือซึ่งมีความอิสระของการเคลื่อนไหวมากกว่า (4 องศาอิสระ) ดังนี้
4.3.1.
นิ้วชี้ (index) นิ้วกลาง (middle) นิ้วนาง (ring) และนิ้วก้อย (pinky) — นิ้วละ 3 องศาอิสระ (งอปลาย / งอโคน / กาง)
| รหัส |
ข้าง |
ความหมาย |
−1 … +1 |
| g_{index,middle,ring,pinky}_curl |
ซ/ข |
การงอปลายนิ้ว (ข้อกลาง/ข้อปลายเข้าหาฝ่ามือ) |
−1 = กรีดนิ้ว (แอ่นไปด้านหลัง) · 0 = เหยียดตรง · +1 = งอสุด |
| g_{index,middle,ring,pinky}_fold |
ซ/ข |
การงอโคนนิ้ว (ข้อโคน) |
−1 = พับไปด้านหลัง (ทางตรงข้าม) · 0 = เหยียดตรง · +1 = พับเข้าหาฝ่ามือ |
| g_{index,middle,ring,pinky}_side |
ซ/ข |
การกางนิ้ว |
−1 = เอียงหาหัวแม่มือ · +1 = เอียงหาก้อย |
4.3.2.
นิ้วหัวแม่มือ — 4 องศาอิสระ เนื่องจากนิ้วหัวแม่มือยึดกระดูกเอียงจากนิ้วอื่นราว 90° การงอโคน (fold) จึงหมายถึงการกวาดข้ามฝ่ามือ (opposition) และการกาง (side) หมายถึงการกางเข้า/ออกจากระนาบฝ่ามือ — ผู้ผลิตที่ประเมินค่า g_thumb_roll ไม่ได้ ต้องส่งค่า 0
| รหัส |
ข้าง |
ความหมาย |
−1 … +1 |
| g_thumb_curl |
ซ/ข |
การงอปลายนิ้วหัวแม่มือ |
−1 = กรีดนิ้ว (แอ่นไปด้านหลัง) · 0 = เหยียดตรง · +1 = งอสุด |
| g_thumb_fold |
ซ/ข |
การกวาดข้ามฝ่ามือ (opposition) |
−1 = ออกห่าง · +1 = ข้ามฝ่ามือ |
| g_thumb_side |
ซ/ข |
การกางเข้า/ออกจากระนาบฝ่ามือ (abduction) |
−1 = หุบเข้า · +1 = กางออก |
| g_thumb_roll |
ซ/ข |
การหมุนนิ้วหัวแม่มือ (pronation) |
−1 = หันออก · +1 = หันเข้า |
4.4.
กลุ่มศีรษะ (h) — เก็บค่าบรรทัดฐาน −1 ถึง 1 เช่นเดียวกับทุกกลุ่ม โดยแปลผลที่ปรากฏเป็นมุมองศา ใช้ใน latent อารมณ์ได้
| รหัส |
ความหมาย |
−1 … +1 |
| h_yaw |
หันซ้าย/ขวา |
−1 = −80° · +1 = +80° |
| h_pitch |
ก้ม/เงย |
−1 = −60° · +1 = +60° |
| h_roll |
เอียงศีรษะ |
−1 = −50° · +1 = +50° |
4.5.
กลุ่มลำตัว (b) — เก็บค่าบรรทัดฐาน −1 ถึง 1 โดยแปลผลที่ปรากฏเป็นมุมองศา กระจายการเคลื่อนไหวตามแนวกระดูกสันหลัง ใช้ใน latent อารมณ์ได้
| รหัส |
ความหมาย |
−1 … +1 |
| b_twist |
บิดลำตัวซ้าย/ขวา |
−1 = −60° · +1 = +60° |
| b_bend |
โน้มหน้า/แอ่นหลัง |
−1 = −50° · +1 = +50° |
| b_lean |
เอียงข้าง |
−1 = −40° · +1 = +40° |
4.6.
กลุ่มใบหน้า (f) — มิติการแสดงออกบนใบหน้า แต่ละมิติขับช่องสัญญาณการเปลี่ยนรูปใบหน้า (blendshape) มาตรฐานที่ใช้กันแพร่หลายหนึ่งช่องขึ้นไปต่อทิศทาง ทุกมิติค่าจริงสูงสุด 1 ใช้ใน latent อารมณ์ได้
| รหัส |
ข้าง |
ความหมาย |
−1 … +1 |
| f_brow_inner |
- |
หัวคิ้วด้านใน |
−1 = ขมวด · +1 = เลิก |
| f_brow |
ซ/ข |
คิ้วด้านนอก |
−1 = ลด · +1 = ยก |
| f_eye |
ซ/ข |
เปลือกตา |
−1 = หลับ · +1 = เบิกกว้าง |
| f_squint |
ซ/ข |
การหยีตา |
0 = ปกติ · +1 = หยี (ขั้วบวกเท่านั้น) |
| f_nose |
- |
การย่นจมูก |
0 = ปกติ · +1 = ย่น (ขั้วบวกเท่านั้น) |
4.7.
กลุ่มปาก (m) — รูปทรงปากและอวัยวะช่องปาก (รวมแก้ม ลิ้น ฟัน) แต่ละมิติขับช่องสัญญาณการเปลี่ยนรูปหลายช่องต่อทิศทางเพื่อให้ถึงรูปทรงสุดขั้ว ทุกมิติค่าจริงสูงสุด 1 ใช้ใน latent อารมณ์ได้
| รหัส |
ข้าง |
ความหมาย |
−1 … +1 |
| m_mouth |
ซ/ข |
มุมปาก |
−1 = เศร้า · +1 = ยิ้ม |
| m_jaw |
- |
ขากรรไกร |
−1 = ขบแน่น · +1 = อ้า (ถึงหาว) |
| m_lips |
- |
การห่อริมฝีปาก |
−1 = ห่อกรวย · +1 = จู๋ปาก |
| m_wide |
- |
ความกว้างปาก |
−1 = แคบ · +1 = กว้าง |
| m_roll |
- |
การม้วนริมฝีปาก |
−1 = ล่างทับบน · +1 = บนทับล่าง |
| m_press |
- |
การเม้มริมฝีปาก |
−1 = ผ่อนแยก · +1 = เม้มแน่น |
| m_fwd |
- |
การยื่นปาก/ขากรรไกร |
0 = ปกติ · +1 = ยื่นไปหน้า (ขั้วบวกเท่านั้น) |
| m_cheek |
- |
แก้ม |
−1 = ดูดเข้า · +1 = พองออก |
| m_tongue |
- |
การแลบลิ้น |
0 = อยู่ใน · +1 = แลบออก (ขั้วบวกเท่านั้น) |
| m_teeth |
- |
การแยกเขี้ยว (ริมฝีปากรั้งเปิดเห็นฟัน) |
0 = ปกติ · +1 = เห็นฟัน (ขั้วบวกเท่านั้น) |
เมื่อรูปปากตามเสียง (viseme) ทำงาน ช่องสัญญาณรูปปากตามเสียงของโมเดลยังเป็นรูปหลัก และมิติ m_* เป็นค่าส่วนต่างที่มีขอบเขตจากรูปนั้น — ส่วนผสมรูปปากตามเสียงที่ทำให้เป็นบรรทัดฐานแล้วให้ค่าฐาน b ตามน้ำหนัก และในขั้นถอดรหัสจะส่งเฉพาะ clamp(b + ค่าที่กำหนด, −1, 1) − b ไปยังช่องสัญญาณปาก ค่าที่กำหนดเป็นศูนย์จึงไม่เปลี่ยนรูปปากของโมเดล การปรับในทิศเดียวกันใช้ได้เฉพาะช่วงที่เหลือ และการปรับในทิศตรงข้ามหักล้างกันได้ ตารางค่าฐานเริ่มต้นแบบระมัดระวังคือ viseme_aa → m_jaw +0.7 และ viseme_PP → m_jaw −0.7, m_press +0.7 ส่วนคู่อื่นมีค่าฐานเป็นศูนย์จนกว่าจะปรับจูน
4.8.
เงื่อนไขเสริม — ช่องสัญญาณเชิงเงื่อนไขเดินทางคู่กับเวกเตอร์ตามข้อ 3.4
| รหัส |
โดเมน |
ขั้นที่ใช้ |
ความหมาย |
| eye_lookat |
ค่าแจงนับ (enum) |
ถอดรหัส |
จุดมองสายตา: มองหน้าตรง / มองมือซ้าย / มองมือขวา / ชำเลืองซ้าย ขวา บน ล่าง |
| viseme |
แมปกระจาย (sparse map) viseme_* → สัดส่วน 0…1 |
ถอดรหัส |
รูปปากตามเสียง: แมปกระจายจากรหัสรูปปาก viseme_* (aa, E, I, O, U, PP, FF, TH, DD, kk, CH, SS, nn, RR) ไปยังสัดส่วนของรูปนั้น เช่น {viseme_PP: 0.7, viseme_aa: 0.3} — รหัสที่ไม่ปรากฏมีค่า 0, {} คือไม่ขยับปาก และผลรวมของสัดส่วนต้องไม่เกิน 1 รูปปากหลายรูปทำงานพร้อมกันได้ (แต่ละรหัสกำหนดค่าลงช่องสัญญาณของตนโดยตรง) และเพราะค่าต่อเนื่อง คีย์ปากสองคีย์จึงไล่ข้ามกัน (crossfade) ระหว่างคีย์เฟรมแทนการกระโดด แมปที่เกินเพดานให้ตัดค่าทีละรายการไม่ให้เกิน 1 แล้วหารลงให้ผลรวมเป็น 1 |
| contact |
จุดเคลื่อน → จุดเป้าหมาย |
การปรับปรุงผลลัพธ์ |
จุดบนมือฝั่งเคลื่อนแตะจุดเป้าหมายบนร่างกายที่ถอดรหัสแล้ว ฝั่งเป้าหมายไม่เคลื่อน (ข้อ 3.4.3, 3.4.5) |
| anchor |
จุดบนร่างกายแยกต่อข้างแขน |
การปรับปรุงผลลัพธ์ |
แขนข้างที่มีจุดยึดวัดตำแหน่งจากจุดของตนแทนคอ แขนที่คีย์เฟรมไม่มีจุดยึดไม่เคลื่อน ฝั่งที่การสัมผัสทำงานให้การสัมผัสมีผลเหนือกว่า (ข้อ 3.4.4–3.4.5) |
5.1.
ลำดับของทะเบียน (ข้อ 4) เป็นลำดับการจัดเรียงข้อมูลมาตรฐาน การเข้ารหัสแบบ JSON ที่สอดคล้องกับนิยามใช้การจับคู่ รหัสมิติ → ค่า โดยผู้บริโภคต้องเพิกเฉยต่อรหัสที่ไม่รู้จัก (เพื่อความเข้ากันได้ไปข้างหน้า) และควรบันทึกไว้ในระบบบันทึกเหตุการณ์
5.2.
ระหว่างคีย์เฟรม มิติต่อเนื่องประมาณค่า (interpolate) เป็นอิสระต่อกัน ส่วนเงื่อนไขเสริมไม่ประมาณค่าเป็นตัวเลข (ใช้ค่าที่ใกล้ที่สุดหรือคงค่าเดิม) — ผู้บริโภคควรเข้า/ออกจากการแก้การสัมผัสอย่างนุ่มนวลด้วยการลาดน้ำหนักการแก้ (ramp) แม้ตัวเงื่อนไขจะเป็นค่าไม่ต่อเนื่อง
5.3.
ผู้ผลิตอาจละมิติที่ประเมินไม่ได้ ผู้บริโภคต้องแทนด้วยค่าปริยายในทะเบียน (ข้อ 4)
6.
ความสอดคล้องกับนิยาม (Conformance)
6.1.
ผู้ผลิตที่สอดคล้อง ต้องส่งเฉพาะรหัสที่ขึ้นทะเบียน ค่าอยู่ในช่วง และการกำหนดข้างซ้าย/ขวากับกลุ่มถูกต้อง
6.2.
ผู้บริโภคที่สอดคล้อง ต้องตัดค่าเข้าช่วง [−1, 1] ใช้ค่าปริยายในทะเบียน (ข้อ 4) แทนมิติที่ขาด แสดงผลท่าหลักได้ถูกต้องแม้เพิกเฉยต่อการแสดงออก และหากรองรับการแสดงออก ต้องใช้สูตร clamp(pose + alpha × expression) เฉพาะกลุ่มที่ใช้ใน latent อารมณ์ได้เท่านั้น — สำหรับการวางตำแหน่งแขนที่คาลิเบรตแล้ว ต้องใช้นิยามแกนจากท่าอ้างอิงคงที่และการทำให้เป็นบรรทัดฐานตามข้อ 4.1
6.3.
ผู้บริโภคอาจเพิกเฉยต่อเงื่อนไขเสริมทั้งหมดได้ โดยการถอดรหัสท่าหลักต้องยังถูกต้อง ผู้บริโภคที่รองรับการสัมผัสต้องแก้ในขั้นการปรับปรุงผลลัพธ์บนร่างกายที่ถอดรหัสสมบูรณ์แล้ว ห้ามเคลื่อนฝั่งเป้าหมายหรือลำตัว และห้ามแก้ไขค่าในเวกเตอร์
6.4.
ผู้บริโภคที่รองรับจุดยึดแขนต้องแก้ในขั้นการปรับปรุงผลลัพธ์แยกต่อข้างแขน (เฉพาะข้างที่มีจุดยึดเท่านั้นที่เคลื่อน ลำตัวไม่เคลื่อน) ต้องให้การสัมผัสมีผลเหนือกว่าบนฝั่งจุดเคลื่อนของการสัมผัส และห้ามแก้ไขค่าในเวกเตอร์ จุดที่ถอดไม่ได้ให้ถอยกลับไปวัดจากคอ
6.5.
การระบุความสอดคล้องต้องระบุเทียบกับรุ่นเฉพาะ เช่น "สอดคล้องกับ IPL 1.1.2"
7.
ไวยากรณ์การประกอบ (Composition Syntax)
การประกอบ (composition) คือสคริปต์ข้อความบรรทัดเดียวที่วางชุดคีย์เฟรมของเวกเตอร์ IPL ที่จัดเก็บไว้ — กลอส (gloss) คือท่ามือที่มีชื่อในคลังคำ และการแสดงออก (expression) คือค่าส่วนเพิ่มทางอารมณ์ที่มีชื่อ (ข้อ 3.3) — ลงบนเส้นเวลาเดียว ข้อนี้นิยามภาษาสคริปต์ดังกล่าว แต่ละโครงสร้างระบุ "ตั้งแต่รุ่น" ซึ่งบอกระดับที่โครงสร้างนั้นเข้าสู่ไวยากรณ์ (1.1.0 พื้นฐาน, 1.1.1 ฟังก์ชันพิเศษและตัวดำเนินการ, 1.1.2 ฟังก์ชันผู้ใช้) ทั้งสามระดับเป็นส่วนหนึ่งของเอกสารรุ่นนี้ มิใช่รุ่นที่เผยแพร่แยกต่างหาก
7.1.1.
ทุกโครงสร้างทำได้เพียงวาง ปรับสเกลเวลา เลื่อนค่า สะท้อนซ้าย/ขวา คงค่าหรือเติมค่า หรืออ้างอิงคีย์เฟรมของเวกเตอร์ที่มีอยู่และเงื่อนไขเสริม (ข้อ 3.4) เท่านั้น ห้ามมีโครงสร้างใดเพิ่มมิติของปริภูมิแฝง เปลี่ยนทะเบียน (ข้อ 4) หรือนิยามมิติใหม่
7.1.2.
การประกอบเกิดขึ้น ณ เวลาประกอบ (compose-time) สคริปต์ถูกประเมินครั้งเดียวเป็นคีย์เฟรมธรรมดา (รวมการอ้างอิงการแสดงออก) และผลลัพธ์ถอดรหัสเหมือนเวกเตอร์อื่นทุกประการ ผู้บริโภคที่ถอดรหัสเวกเตอร์เพียงอย่างเดียวไม่จำเป็นต้องแจงสคริปต์ ส่วนผู้ผลิตควรจัดเก็บสคริปต์คู่กับผลการประกอบ เพื่อประกอบใหม่ได้เมื่อกลอสหรือฟังก์ชันต้นทางเปลี่ยน
7.1.3.
คำที่ใช้ในข้อนี้
- คลังคำ (lexicon) — ที่จัดเก็บกลอส การแสดงออก และฟังก์ชันผู้ใช้ที่มีชื่อของผู้ผลิต
- กลอส (gloss) — ชุดคีย์เฟรมของเวกเตอร์ที่มีชื่อ (หนึ่งท่ามือ) ความยาวต้นฉบับคือดัชนีคีย์เฟรมสุดท้าย (เป็น 1 หากดัชนีนั้นเป็น 0)
- กลุ่มย่อย (subgroup) — กลุ่มที่แยกตามข้างสำหรับกลุ่มที่มีข้าง ได้แก่ a_l a_r w_l w_r g_l g_r h b f m กลอสขับกลุ่มย่อยเมื่อมีคีย์เฟรมบนกลุ่มย่อยนั้นอย่างน้อยหนึ่งคีย์
- แฟล็กของกลอส — draft (ยังไม่เสร็จ), spelling (ตัวอักษรสะกดนิ้วมือ), fixed_position (ยึดกับร่างกาย ไม่ถูกเลื่อนหรือยึดจุด), left_dominant (มือซ้ายเป็นมือหลัก)
- ท่าพัก (neutral pose) — ท่าพักที่ตั้งค่าไว้สำหรับการประกอบ หากไม่ได้ตั้งค่าให้ใช้ค่าปริยายในทะเบียน
- เฟรม (frame) — หนึ่งขั้นของเส้นเวลาการประกอบ ค่าการหยุด ช่องว่าง และการไล่ระดับทั้งหมดมีหน่วยเป็นเฟรม
7.2.
ข้อตกลงเชิงศัพท์ (ตั้งแต่รุ่น 1.1.0)
7.2.1.
สคริปต์เป็นลำดับของโทเคนคั่นด้วย | หรือ || ช่องว่างหน้าและหลังของทุกโทเคนถูกละเว้น และโทเคนว่างถูกข้าม ตัวคั่น | แบ่งเฉพาะที่ความลึกของวงเล็บเหลี่ยม [ ] และวงเล็บปีกกา { } เป็น 0 ส่วนตัวดำเนินการ ; แบ่งเฉพาะที่ความลึกของวงเล็บทุกชนิดเป็น 0
7.2.2.
อักขระสงวน ได้แก่ | ; ( ) { } [ ] # ! $ @ % โดย $ ขึ้นต้นฟังก์ชันในตัว, @ ขึ้นต้นเครื่องหมายการแสดงออก, % ขึ้นต้นการเรียกฟังก์ชันผู้ใช้, # คั่นชื่อรูปแปร (variation), ! ปิดท้ายโทเคนกลอส และ ; เป็นตัวดำเนินการท่าผสม — ชื่อกลอส ชื่อการแสดงออก และป้ายกำกับ (label) ห้ามมี | ; ( ) { } [ ] และห้ามขึ้นต้นด้วย $ @ หรือ % ชื่อกลอสห้ามลงท้ายด้วย ! ห้ามมี % ที่ตำแหน่งใด และมี # ได้ไม่เกินหนึ่งตัวโดยต้องไม่เป็นอักขระแรกหรืออักขระสุดท้าย
7.2.3.
ไม่มีไวยากรณ์หมายเหตุ (comment) และไม่มีการหลีกอักขระหรือการครอบเครื่องหมายคำพูด ตัวเลขต้องเขียนเป็นทศนิยมธรรมดา (เครื่องหมายบวก/ลบได้ ตัวเลข และเศษทศนิยมได้) ผู้บริโภคอาจยอมรับรูปอื่น และค่าที่ไม่ใช่ตัวเลขในช่องตัวเลขถือเป็นข้อผิดพลาด
7.2.4.
อาร์กิวเมนต์เรียงตามตำแหน่ง คั่นด้วยจุลภาคภายในวงเล็บคู่เดียวซึ่งห้ามซ้อนกัน ทุกอาร์กิวเมนต์ละได้ — ช่องว่างหรือช่องที่ขาดใช้ค่าปริยาย การละวงเล็บหมายถึงใช้ค่าปริยายทั้งหมด และช่อง label ท้ายสุดรับข้อความอาร์กิวเมนต์ที่เหลือทั้งหมด ป้ายกำกับจึงมีจุลภาคได้
7.2.5.
ชื่อกลอส ชื่อการแสดงออก (รวม none และ break) ชื่อฟังก์ชันผู้ใช้ และชื่อจุดยึด เทียบแบบไม่สนตัวพิมพ์เล็ก/ใหญ่ ส่วนคำสำคัญของฟังก์ชันในตัว ($pause, $shift, $reset, $spell, $anchor, $mirror, $buoy, $compound, $viseme) เป็นตัวพิมพ์เล็กและแยกตัวพิมพ์
7.3.
การแปลงชื่อ (ตั้งแต่รุ่น 1.1.0) — ชื่อในโทเคนกลอส (หลังตัด ! ท้ายและอาร์กิวเมนต์ออก) ถูกค้นในคลังคำแบบไม่สนตัวพิมพ์ตามลำดับดังนี้
7.3.1.
ตรงทุกตัวอักษร — หากมีรายการเดียวที่ชื่อนี้ให้ใช้รายการนั้น (รายการ draft ใช้ได้เมื่อเป็นรายการเดียวที่ตรง) หากมีมากกว่าหนึ่งรายการ รวมกรณีรายการสมบูรณ์ชนกับ draft ถือเป็นข้อผิดพลาด ambiguous gloss name
7.3.2.
รูปแปรที่ระบุชัด NAME#var — หากไม่มีรายการชื่อ NAME#var ตรงทุกตัว โทเคนถอยไปใช้รายการชื่อ NAME (ด้วยกฎตรงทุกตัวเดียวกัน) และไม่สุ่มไปยังรูปแปรอื่น หากไม่มีทั้งสองถือว่าไม่รู้จักชื่อ
7.3.3.
ตระกูลรูปแปรแบบไม่ระบุ — ชื่อที่ไม่มี # ซึ่งไม่ตรงรายการใดแต่เป็นหัวของรายการชื่อ NAME#… ให้สุ่มเลือกสมาชิกหนึ่งตัวแบบสม่ำเสมอจากสมาชิกที่สมบูรณ์ (ไม่ใช่ draft) หากมี มิฉะนั้นจากสมาชิกทั้งหมด การสุ่มเกิดใหม่ทุกครั้งที่ประกอบ และผู้ผลิตที่เขียนสคริปต์กลับต้องคงชื่อ NAME แบบไม่ระบุไว้ — นอกจากกรณีข้างต้นถือว่าไม่รู้จักชื่อ (unknown gloss) ซึ่งเป็นข้อผิดพลาด
7.3.4.
ชื่อการแสดงออก (@name) ค้นด้วยวิธีเดียวกันโดยไม่มีรูปแปร: ตรงหนึ่งรายการใช้รายการนั้น ไม่ตรงเลยคือ unknown expression และตรงมากกว่าหนึ่งคือ ambiguous expression name
7.3.5.
นามแฝง (alias) แปลงไปยังกลอสหลักหนึ่งขั้นและใช้คีย์เฟรมของกลอสหลักนั้น ส่วนกลอสประกอบ (composed gloss) จัดเก็บสคริปต์และคีย์เฟรมที่ประกอบจากสคริปต์นั้น และถูกวางในลำดับเหมือนกลอสทั่วไป — สคริปต์ของกลอสประกอบห้ามอ้างอิงกลอสประกอบอื่น (ไม่มีลูกโซ่ จึงไม่มีวงวน) และห้ามใช้ตระกูลรูปแปรแบบไม่ระบุ เมื่อประกอบกลอสประกอบ คีย์ถูกเลื่อนฐานให้คีย์เฟรมแรกอยู่ที่เฟรม 0 (ไม่มีช่วงนำเข้าและช่วงปิดท้าย) เครื่องหมายการแสดงออกถูกอบ (bake) ลงในคีย์เฟรมของกลุ่ม h, b, f, m เป็น clamp(pose + Σ alphaᵢ × expressionᵢ) และ NAME! เติมค่าจากค่าปริยายในทะเบียน สคริปต์ที่ไม่วางอะไรเลยเป็นข้อผิดพลาด
7.4.
เส้นเวลาและช่องว่างอัตโนมัติ (ตั้งแต่รุ่น 1.1.0)
7.4.1.
รายการถูกวางตามลำดับ รายการที่มีเวลา (กลอส บล็อก $viseme และ $pause) กินเฟรม ส่วนเครื่องหมาย ($shift, $reset และเครื่องหมายการแสดงออก) ไม่กินเฟรมและไม่มีผลต่อการคำนวณช่องว่าง กลอสที่ความเร็ว s กิน L = max(1, round(native / s)) เฟรม จากเฟรมเริ่ม t ถึง t + L
7.4.2.
ระหว่างรายการที่มีเวลาที่ติดกัน ก่อนรายการแรก (ช่วงนำเข้า) และหลังรายการสุดท้าย (ช่วงปิดท้าย) ตัวประกอบแทรกช่องว่าง gap = min( max(15, m), m + round(4 × d) ) เฟรม โดย m = max(1, round(minGap)) และ minGap คือช่องว่างต่ำสุดของการประกอบ (ค่าปริยาย 2) — d คือระยะยุคลิดบนค่าบรรทัดฐานระหว่างท่าขาออก (คีย์เฟรมสุดท้ายของรายการก่อนหน้า) กับท่าขาเข้า (คีย์เฟรมแรกของรายการถัดไป) โดยทิศทางข้อมือเทียบกันเป็นการหมุน (ระยะคอร์ดของควอเทอร์เนียนที่ไม่ขึ้นกับเครื่องหมาย) วัดรวมการเลื่อนที่มีผลกับรายการนั้น ส่วนกลอส fixed_position การหยุด และขอบช่วงนำเข้า/ปิดท้ายวัดแบบไม่เลื่อน และขอบหรือการหยุดใช้ท่าค่าปริยายในทะเบียน
7.4.3.
ช่องว่างถูกแทนที่ตามลำดับความสำคัญ: ช่องว่างคงที่ของสมาชิกกลุ่ม [ ] (ข้อ 7.5.2), m สำหรับรายการที่เชื่อมด้วย || (ข้อ 7.6) และ 3 เฟรมระหว่างกลอสที่มีแฟล็ก spelling สองตัวติดกัน ความยาวเส้นเวลาคือ max(2, end + 1) โดย end คือเฟรมหลังช่วงปิดท้าย
7.5.
โครงสร้างพื้นฐาน (ตั้งแต่รุ่น 1.1.0)
| รหัส |
ไวยากรณ์ |
ความหมาย |
ค่าปริยาย / ขีดจำกัด |
ตั้งแต่รุ่น |
| sequence |
A | B |
วางรายการตามลำดับบนเส้นเวลาเดียว คั่นด้วยช่องว่างอัตโนมัติ (ข้อ 7.4) |
- |
1.1.0 |
| gloss |
NAME, NAME(speed), NAME(speed,label) |
วางกลอสที่แปลงชื่อแล้ว (ข้อ 7.3) ความเร็ว 2 เล่นในครึ่งหนึ่งของความยาวต้นฉบับ label เป็นคำบรรยายสำหรับแสดงผล ไม่มีผลต่อเวกเตอร์ |
speed มากกว่า 0 ค่าปริยาย 1 · label ห้ามมี ; |
1.1.0 |
| variation |
NAME#var, ตระกูล NAME แบบไม่ระบุ |
เลือกรูปแปรที่ระบุ หรือสุ่มสมาชิกของตระกูล (ข้อ 7.3.2–7.3.3) |
สุ่มใหม่ทุกครั้งที่ประกอบ |
1.1.0 |
| alias-composed |
ชื่อนามแฝง / ชื่อกลอสประกอบ |
แปลงชื่อนามแฝงไปยังกลอสหลัก และวางกลอสประกอบเหมือนกลอสทั่วไป (ข้อ 7.3.5) |
ไม่มีลูกโซ่ของกลอสประกอบ |
1.1.0 |
| auto-gap |
โดยนัย |
ช่องว่างเปลี่ยนผ่านระหว่างรายการ ช่วงนำเข้า และช่วงปิดท้าย ตามระยะห่างของท่า (ข้อ 7.4) |
minGap 2 · เพดาน 15 |
1.1.0 |
| pause |
$pause, $pause(N) |
คงท่าพักไว้ N เฟรม (ปัดเศษ) เป็นรายการที่มีเวลา มีช่องว่างอัตโนมัติทั้งสองข้างและไม่มีคีย์เฟรม |
N ≥ 1 · ค่าปริยาย 15 |
1.1.0 |
| shift |
$shift(x,y,z,twist), $reset |
เครื่องหมายแบบมีสถานะที่เลื่อนค่ากลอสทุกตัวที่ตามมา จนถึง $shift หรือ $reset ถัดไป หรือจบบล็อก $spell (ข้อ 7.5.1) |
ทุกแกนค่าปริยาย 0 · $shift เปล่าเท่ากับ $reset |
1.1.0 |
| group |
[A | B](speed,gap,label) |
วางสมาชิกเป็นหน่วยเดียว เชื่อมด้วยช่องว่างคงที่แทนช่องว่างอัตโนมัติ (ข้อ 7.5.2) |
speed มากกว่า 0 ค่าปริยาย 1 · gap ≥ 0 ค่าปริยาย 3 · ห้ามซ้อน |
1.1.0 |
| spell |
$spell(x,y,z,twist,label){A | B | …} |
ชุดสะกดนิ้วมือที่มีขั้นบันไดการเลื่อนของตนเอง (ข้อ 7.5.3) |
การเลื่อนค่าปริยาย (0.1, 0, 0, 0) · บล็อกว่างเป็นข้อผิดพลาด |
1.1.0 |
| expression |
@name(alpha,rampIn,rampOut), @none, @break |
เปิด/ปิดช่วงการแสดงออกแบบอ้างอิงบนช่องอ้างอิง (lane) (ข้อ 7.5.4) |
alpha มากกว่า 0 ไม่เกิน 1 ค่าปริยาย 1 · ramp ≥ 0 ค่าปริยาย 6 เฟรม · ไม่เกิน 3 ช่อง |
1.1.0 |
7.5.1.
การเลื่อน — สำหรับแต่ละคีย์เฟรมที่กลอสเขียนไว้เอง: a_hand_x_l += x และ a_hand_x_r −= x (x สะท้อนซ้าย/ขวา ค่า x บวกจึงพามือทั้งสองไปทางเดียวกันของลำตัว), a_hand_y_l/r += y, a_hand_z_l/r += z และ b_twist += twist แล้วตัดค่าแต่ละค่าให้อยู่ใน [−1, 1] มิติที่กลอสไม่ได้เขียนไว้ต้องไม่ถูกสร้างขึ้น กลอส fixed_position ไม่ถูกเลื่อน และการเลื่อนกระทำกับคีย์เฟรมที่วางเท่านั้น นิยามของเวกเตอร์ไม่เปลี่ยน
7.5.2.
กลุ่ม — speed ใช้กับสมาชิกที่ความเร็วของตนเป็น 1 (ความเร็วของสมาชิกเองมาก่อน) gap ถูกปัดเศษ และสมาชิกถัดไปเริ่ม max(1, gap) เฟรมหลังเฟรมสุดท้ายของสมาชิกก่อนหน้า สมาชิกต้องเป็นกลอสหรือชุด $spell โดยชุด $spell ถูกขยายเป็นตัวอักษรพร้อมอบขั้นบันไดการเลื่อนลงในตัวอักษร โดยไม่เปลี่ยนสถานะการเลื่อนภายนอกกลุ่ม กลุ่มว่าง กลุ่มซ้อน หรือสมาชิกชนิดอื่นเป็นข้อผิดพลาด และกลุ่มเป็นหน่วยเดียวสำหรับคำบรรยาย (label หรือชื่อสมาชิก)
7.5.3.
ชุดสะกดนิ้วมือ — สมาชิกเป็นกลอสหรือกลุ่ม [ ] โดยกลุ่มนับเป็นตัวอักษรหนึ่งตัว สำหรับตัวอักษรที่ i จาก N (เริ่มที่ 0) การเลื่อนที่มีผลคือการเลื่อนตั้งต้นคูณ (N − 1 − i)/(N − 1) ตัวแรกจึงเลื่อนเต็มและตัวสุดท้ายเป็นศูนย์ ตัวอักษรเดียวคงการเลื่อนเต็ม หลังบล็อกสถานะการเลื่อนเป็นศูนย์ ($shift ก่อนหน้าไม่ถูกคืน) และเมื่อมี label ทั้งชุดเป็นหน่วยเดียวสำหรับคำบรรยาย
7.5.4.
การแสดงออก — @name เปิดช่วงบนช่องอ้างอิงที่ว่างช่องแรกจาก 3 ช่อง เริ่มที่จุดเริ่มของรายการที่มีเวลาถัดไป alpha คืออัตราขยายสูงสุด rampIn/rampOut เป็นจำนวนเฟรม (ปัดเศษ) หากละไว้ใช้ช่วงไล่ระดับของผู้บริโภค (6 เฟรมหากไม่ได้ตั้งค่า) การแสดงออกพร้อมกันตัวที่สี่เป็นข้อผิดพลาด @break ปิดช่วงที่เปิดล่าสุด และ @none ปิดทุกช่วง ณ จุดเริ่มของรายการที่มีเวลาถัดไป ช่วงที่ค้างเปิดสิ้นสุดที่ปลายรายการสุดท้ายที่ช่วงนั้นครอบ (ไม่ใช่ที่ช่วงปิดท้าย) ช่วงที่ไม่ครอบเฟรมใดถูกทิ้ง และช่องที่ถูกปล่อยแล้วเปิดใหม่ในเฟรมเดียวกันเริ่มช้าไปหนึ่งเฟรม — ในลำดับ ช่วงเหล่านี้เป็นการอ้างอิง ค่าส่วนเพิ่มถูกใช้ตอนถอดรหัสเป็น clamp(pose + Σ alphaᵢ × expressionᵢ) บนกลุ่ม h, b, f, m (ข้อ 3.3) และไม่ถูกเขียนลงในคีย์เฟรมท่าหลัก (ยกเว้นกลอสประกอบซึ่งอบลงไปตามข้อ 7.3.5)
7.6.
ฟังก์ชันพิเศษและตัวดำเนินการ (ตั้งแต่รุ่น 1.1.1) — โครงสร้างที่รับเนื้อบล็อก { } มีเนื้อเป็นกลอสและกลุ่ม [ ] เท่านั้น หากไม่ระบุเป็นอื่น เครื่องหมาย ($…, @…) ในเนื้อบล็อก เนื้อบล็อกว่าง หรือ || ในเนื้อบล็อกเป็นข้อผิดพลาด (บล็อกกำหนดช่องว่างระหว่างสมาชิกเอง)
| รหัส |
ไวยากรณ์ |
ความหมาย |
ค่าปริยาย / ขีดจำกัด |
ตั้งแต่รุ่น |
| anchor |
$anchor(site){A | B} |
วัดตำแหน่งแขนของกลอสที่ครอบจากจุดบนร่างกายแทนคอ โดยประทับเงื่อนไขเสริมจุดยึดแขนลงบนคีย์เฟรมแขน (ข้อ 7.6.1) |
site: neck forehead mouth navel shoulder_l shoulder_r |
1.1.1 |
| mirror |
$mirror(speed,label){A | B} |
เล่นชุดแบบสลับข้างซ้าย/ขวา (ข้อ 7.6.2) |
speed มากกว่า 0 ค่าปริยาย 1 · เนื้อบล็อกเดียว |
1.1.1 |
| buoy |
$buoy(speed,label){P}{S} |
ชุดหลักเล่นตามที่เขียน ชุดรองเล่นแบบสะท้อนพร้อมคงค่าท่าสุดท้ายของชุดหลัก (ข้อ 7.6.3) |
speed มากกว่า 0 ค่าปริยาย 1 · เนื้อทั้งสองห้ามว่าง |
1.1.1 |
| compound |
$compound(speed,label){P}{S}, P ; S |
ท่าผสมสองมือพร้อมกันเป็นรายการเดียวจากตัวหลัก P และตัวรอง S (ข้อ 7.6.4–7.6.5) |
speed มากกว่า 0 ค่าปริยาย 1 · ซ้อนได้ไม่เกิน 32 ระดับ |
1.1.1 |
| viseme |
$viseme(word), $viseme(word,speed) |
รายการเฉพาะปากที่สร้างจากอักษรไทยหรือไทยถอดอักษรโรมัน (ข้อ 7.6.6) |
speed มากกว่า 0 ค่าปริยาย 1 · ไม่เกิน 512 code point และ 128 พยางค์ |
1.1.1 |
| min-gap-join |
A || B |
เชื่อม B กับ A ด้วยช่องว่างต่ำสุด m ของการประกอบ (ข้อ 7.6.7) |
B ต้องเป็นกลอสหรือโครงสร้างบล็อก |
1.1.1 |
| neutral-fill |
NAME! |
เติมท่าพักให้ทุกกลุ่มย่อยที่กลอสไม่ได้ขับ (ข้อ 7.6.8) |
ช่วงไล่ระดับท่าพักค่าปริยาย 6 เฟรมทั้งสองข้าง |
1.1.1 |
7.6.1.
บล็อกจุดยึด — ประทับเงื่อนไขเสริมจุดยึดแขน (ข้อ 3.4.4, 4.8) ลงบนคีย์เฟรมแขนแต่ละคีย์ที่กลอสเขียนไว้: คีย์ a_l ได้ {l: {site}} และคีย์ a_r ได้ {r: {site}} แขนที่กลอสไม่ได้ขับไม่ได้รับสิ่งใด site นอกรายการเป็นข้อผิดพลาด และ neck ไม่ประทับสิ่งใด (จุดกำเนิดค่าปริยาย) คีย์เฟรมที่มีจุดยึดของข้างนั้นอยู่แล้วคงค่าเดิม กลอส fixed_position และกลุ่มย่อยที่ถูกเติมโดย ! ไม่ถูกประทับ บล็อกนี้ใช้ร่วมกับการสัมผัสได้ โดยการสัมผัสยังมีผลเหนือกว่า และการย้ายจุดกำเนิดจริงเกิดในขั้นการปรับปรุงผลลัพธ์ตอนถอดรหัส แยกต่อโมเดล
7.6.2.
บล็อกสะท้อน — แทร็กกลุ่มย่อยและมิติ _l/_r สลับข้างกัน h_yaw, h_roll, b_twist, b_lean กลับเครื่องหมาย และจุดมองสายตา จุดของการสัมผัส และจุดยึดแขนสลับข้าง การสะท้อนสองครั้งได้ค่าเดิม speed ใช้กับสมาชิกที่ความเร็วของตนเป็น 1 เมื่อมี label ทั้งชุดเป็นหน่วยเดียวสำหรับคำบรรยาย และเนื้อ { } ที่สองเป็นข้อผิดพลาด
7.6.3.
ทุ่น (buoy) — ชุดหลักเล่นตามที่เขียนโดยสมาชิกหลักทุกตัวประกอบเหมือนมีเครื่องหมาย ! (ข้อ 7.6.8) จากนั้นชุดรองเล่นแบบสะท้อนทั้งหมด (เหมือน $mirror) และบนทุกกลุ่มย่อยที่สมาชิกรองไม่ได้ขับ ค่าคีย์เฟรมสุดท้ายของชุดหลักถูกคงไว้ตลอดสมาชิกนั้น สมาชิกรองที่มี ! ใช้การเติมท่าพักแทนการคงค่า speed ใช้กับสมาชิกที่ความเร็วของตนเป็น 1 และทุ่นทั้งชุดเป็นหน่วยเดียวสำหรับคำบรรยาย
7.6.4.
ท่าผสม — ตัวถูกดำเนินการแต่ละตัวต้องแจงได้เป็นรายการที่สร้างท่ามือเพียงหนึ่งรายการ (กลอส กลุ่ม $spell $anchor $mirror $buoy $compound หรือ $viseme) มิฉะนั้นเป็นข้อผิดพลาด รูปย่อ P ; S ไม่มีอาร์กิวเมนต์และรับตัวถูกดำเนินการสองตัวพอดี (; ระดับบนสุดตัวที่สองหรือข้างที่ว่างเป็นข้อผิดพลาด) — มือเป้าหมายคือข้างหลักของ P (ซ้ายหากมีแฟล็ก left_dominant มิฉะนั้นขวา) หรือข้างตรงข้ามเมื่อ S เป็นบล็อก $mirror และ S ถูกสะท้อนเมื่อข้างหลักของ S ต่างจากมือเป้าหมาย แทร็กนิ้วของ S บนมือเป้าหมายแทนที่ของ P ส่วนกลุ่มย่อยอื่นของ S ใช้เฉพาะเมื่อ P ไม่ได้ขับกลุ่มย่อยนั้น ทั้งสองถูกปรับสเกลเวลาให้เท่าตัวที่ยาวกว่า (อย่างน้อย 1 เฟรม) ! บนตัวถูกดำเนินการที่เป็นกลอสมีผลกับท่าผสมทั้งชุด และตัวรองที่ไม่เพิ่มกลุ่มย่อยใดให้ข้อวินิจฉัย compound-noop
7.6.5.
ท่าผสมกับรูปปาก — เมื่อตัวถูกดำเนินการเพียงตัวเดียวเป็น $viseme ท่ามือเป็นผู้กำหนดความยาวไม่ว่าจะอยู่ลำดับใด หากท่ามือเป็นตัวหลักและขับปากอยู่แล้ว รูปปากไม่เพิ่มสิ่งใด (compound-noop) ชุดปากที่ยาวกว่าท่ามือถูกบีบให้เท่าความยาวท่ามือ หากท่ามือยาวอย่างน้อยหนึ่งเฟรมต่อพยางค์บวกช่วงกันชน 3 เฟรมทั้งสองข้าง มิฉะนั้นเป็นข้อผิดพลาด viseme-too-short ส่วนชุดที่สั้นกว่าถูกคงไว้ที่ไม่มีการขยับปากจนท่ามือจบ
7.6.6.
รูปปาก — สร้างคีย์เฟรมบนกลุ่มย่อยปากที่มีเพียงเงื่อนไขเสริมรูปปากตามเสียง (ข้อ 4.8) คำถูกแบ่งเป็นท่อนที่ช่องว่างและ - ท่อนที่มีอักขระไทยอ่านเป็นอักษรไทย มิฉะนั้นอ่านเป็นอักษรโรมัน วรรณยุกต์ถูกละเว้น และ ๆ ซ้ำทั้งท่อนก่อนหน้า ข้อความเกิน 512 code point หรือเกิน 128 พยางค์ (หลังซ้ำ ๆ) เป็นข้อผิดพลาด viseme-limit คำที่ไม่มีพยางค์ใดอ่านได้เป็นข้อผิดพลาด และอาร์กิวเมนต์มากกว่าสองตัวเป็นข้อผิดพลาด พยางค์ที่อ่านไม่ได้ถูกทิ้งพร้อมข้อวินิจฉัย viseme-incomplete มิฉะนั้นการอ่านแบบอาศัยฮิวริสติกให้ viseme-guessed (เมื่อเข้าเงื่อนไขทั้งคู่ให้แจ้งเพียง viseme-incomplete) จังหวะเวลาต่อพยางค์เป็นการตั้งค่าของผู้บริโภค
7.6.7.
การเชื่อมด้วยช่องว่างต่ำสุด — B เชื่อมกับ A ด้วยช่องว่าง m (ข้อ 7.4.2) โดยข้ามการปรับตามระยะและกฎสะกดนิ้วมือ และ B ยังเป็นรายการของตนเอง สำหรับบล็อก การเชื่อมมีผลกับกลอสแรกที่ถูกวาง || หน้าการหยุดหรือเครื่องหมาย ที่ต้นหรือท้ายสคริปต์ หรือในเนื้อบล็อก เป็นข้อผิดพลาด และโทเคนว่างที่คั่นอยู่ไม่ยกเลิกการเชื่อม
7.6.8.
การเติมท่าพัก — ทุกกลุ่มย่อยที่กลอสไม่ได้ขับถูกใส่คีย์ท่าพักที่เฟรมแรกและเฟรมสุดท้ายของกลอส (หนึ่งคีย์หากเป็นเฟรมเดียวกัน) และใส่คีย์ท่าพักอีกหนึ่งคีย์ก่อนเฟรมแรก rampIn เฟรมและหลังเฟรมสุดท้าย rampOut เฟรม (ปัดเศษ ไม่ต่ำกว่า 0) เฉพาะเมื่อเฟรมนั้นอยู่ในหน่วยคำบรรยายเดียวกัน ไม่มีคีย์อยู่บนเฟรมนั้นแล้ว และไม่มีคีย์อื่นอยู่ระหว่างเฟรมนั้นกับกลอส $shift และ $anchor ข้ามกลุ่มย่อยที่ถูกเติม ! เป็นอักขระสุดท้ายของโทเคนกลอส (หลัง #variation และอาร์กิวเมนต์) และใช้หลัง ] หรือ } ไม่ได้
7.7.
ฟังก์ชันผู้ใช้ (ตั้งแต่รุ่น 1.1.2) — รายการในคลังคำ {name, arity, rules} ที่เขียนการเรียกใหม่เป็นข้อความสคริปต์ การขยายเป็นขั้นข้อความล่วงหน้า (text pre-pass) ที่ทำก่อนแบ่งโทเคน (ข้อ 7.2) หลังขยายแล้วสคริปต์จึงไม่มีการเรียก % เหลืออยู่
| รหัส |
ไวยากรณ์ |
ความหมาย |
ค่าปริยาย / ขีดจำกัด |
ตั้งแต่รุ่น |
| user-function |
%name(args) |
แทนการเรียกด้วยเทมเพลตของกฎแรกที่ตรงกับอาร์กิวเมนต์ |
กฎ 1–200 · 32 รอบ · 500 ครั้งต่อสคริปต์ |
1.1.2 |
7.7.1.
การเรียกคือ % ตามด้วยชื่อและข้อความอาร์กิวเมนต์ในวงเล็บที่ไม่มีวงเล็บซ้อน เนมสเปซ % แยกจาก $ (%pause และ $pause มีพร้อมกันได้) ชื่อต้องตรงกับ [A-Za-z_][A-Za-z0-9_]* ยาวไม่เกิน 64 อักขระ (ที่จัดเก็บอาจตัดชื่อที่ยาวกว่า) และไม่ซ้ำกันแบบไม่สนตัวพิมพ์ การเรียกค้นชื่อแบบไม่สนตัวพิมพ์
7.7.2.
กฎเป็นรายการเรียงลำดับของคู่ {pattern, template} จำนวน 1 ถึง 200 คู่ ข้อความอาร์กิวเมนต์ถูกแบ่งที่จุลภาค ตัดช่องว่างหัวท้ายของแต่ละอาร์กิวเมนต์ แล้วต่อกลับด้วยจุลภาค กฎถูกลองตามลำดับ และกฎแรกที่แพตเทิร์นตรงที่ตำแหน่งใดก็ได้ในสตริงนั้นชนะ (แพตเทิร์นไม่ผูกตำแหน่งเว้นแต่เขียน ^ หรือ $) แล้วการเรียกถูกแทนด้วยเทมเพลตของกฎนั้น — ในเทมเพลต \1–\9 แทรกกลุ่มที่จับได้ \{1}–\{9} ใช้เมื่อตามด้วยตัวเลข และ \\ คือแบ็กสแลชตามตัวอักษร การอ้างกลุ่มที่แพตเทิร์นไม่ได้นิยามถูกปฏิเสธตอนบันทึก และกลุ่มทางเลือกที่ไม่ตรงแทรกข้อความว่าง arity (0–9) เป็นเพียงข้อมูลประกอบ ไม่ใช้กั้นการจับคู่
7.7.3.
หนึ่งรอบการขยายแทนทุกการเรียกในข้อความปัจจุบันจากซ้ายไปขวา ข้อความที่รอบหนึ่งสร้างขึ้นถูกสแกนในรอบถัดไปเท่านั้น ทำได้สูงสุด 32 รอบ (การเรียกที่เหลือเป็นข้อผิดพลาด expansion too deep) และแทนได้สูงสุด 500 ครั้งต่อสคริปต์ (เกินเป็นข้อผิดพลาด expanded too many items)
7.7.4.
ชุดย่อยนิพจน์ปรกติที่พกพาได้ — แพตเทิร์นต้องยาวไม่เกิน 2000 อักขระและเทมเพลตไม่เกิน 4000 อักขระ (ที่จัดเก็บอาจตัดค่าที่ยาวกว่า) แพตเทิร์นจับคู่บน Unicode code point โดย \d, \w, \s หมายถึงคลาส ASCII ห้ามใช้การอ้างกลับ (\1–\9, \k) lookahead หรือ lookbehind กลุ่มที่มีชื่อ หรือรูป (? อื่นใด ยกเว้นกลุ่มไม่จับ (?: และนอกคลาสอักขระ แบ็กสแลชหลีกได้เฉพาะ d D w W s S b B n r t f v 0 x u \ ^ $ . | ? * + ( ) [ ] { } / ฟังก์ชันที่ฝ่าฝืนถูกปฏิเสธตอนบันทึก
7.7.5.
ฟังก์ชันที่ไม่รู้จัก การเรียกที่ไม่มีกฎใดตรง และแพตเทิร์นที่คอมไพล์ไม่ได้เป็นข้อผิดพลาด การเรียกที่ล้มเหลวถูกลบออกจากข้อความและรายงานพร้อมข้อผิดพลาดอื่นของสคริปต์
7.8.
ข้อผิดพลาดและข้อวินิจฉัย
7.8.1.
ข้อผิดพลาดที่ปิดกั้น (blocking error) หยุดการประกอบ — สคริปต์ไม่ให้คีย์เฟรมจนกว่าจะแก้ ส่วนข้อวินิจฉัย (diagnostic) ไม่ปิดกั้น การประกอบดำเนินต่อ และผู้ผลิตควรแสดงให้ผู้สร้างเห็น
| ประเภท |
เงื่อนไข |
เกิดเมื่อ |
| ปิดกั้น |
unknown gloss, ambiguous gloss name, unknown expression, ambiguous expression name |
ชื่อแปลงไม่ได้ หรือตรงมากกว่าหนึ่งรายการ (ข้อ 7.3) |
| ปิดกั้น |
bad gloss speed, bad group args, bad group gap, bad spell args, bad pause, bad shift, bad mirror speed, bad buoy speed, bad compound speed, bad viseme args, bad viseme speed, bad expression alpha, bad expression ramp |
อาร์กิวเมนต์ไม่ใช่ตัวเลขหรืออยู่นอกช่วง |
| ปิดกั้น |
reserved label |
ป้ายกำกับมี ; |
| ปิดกั้น |
bad group, empty group, no nested groups, group member |
กลุ่มผิดรูป หรือมีสมาชิกที่ไม่ใช่กลอสหรือ $spell |
| ปิดกั้น |
empty block, block member, block arity |
เนื้อบล็อกว่าง มีเครื่องหมายในเนื้อบล็อก หรือจำนวนเนื้อบล็อกผิด |
| ปิดกั้น |
unknown anchor site |
จุดนอกรายการของ $anchor (ข้อ 7.6.1) |
| ปิดกั้น |
expression lanes |
การแสดงออกพร้อมกันตัวที่สี่ |
| ปิดกั้น |
compound operand, compound shorthand, compound-limit |
ตัวถูกดำเนินการไม่ใช่รายการสร้างท่ามือหนึ่งรายการ, ; ที่ไม่มีตัวถูกดำเนินการสองตัวพอดี, ท่าผสมซ้อนลึกเกิน 32 |
| ปิดกั้น |
viseme-limit, viseme unreadable, viseme-too-short |
เกินขีดจำกัด 512 / 128, ไม่มีพยางค์ที่อ่านได้, ท่ามือสั้นเกินสำหรับชุดปากในท่าผสม |
| ปิดกั้น |
misplaced join |
|| วางผิดที่ (ข้อ 7.6.7) |
| ปิดกั้น |
unknown function |
ฟังก์ชันในตัว $ ที่ไม่รู้จัก |
| ปิดกั้น |
unknown user function, no rule matches, bad pattern, expansion too deep, expanded too many items |
การขยายฟังก์ชันผู้ใช้ (ข้อ 7.7) |
| ปิดกั้น |
nothing to place, variation family in composed gloss, composed gloss chain |
กฎของกลอสประกอบ (ข้อ 7.3.5) |
| วินิจฉัย |
viseme-guessed, viseme-incomplete, compound-noop |
การอ่านพยางค์แบบอาศัยฮิวริสติก, บางพยางค์อ่านไม่ได้และถูกทิ้ง, ตัวรองไม่เพิ่มสิ่งใด |
7.8.2.
ชื่อที่มีขีดกลาง (compound-limit, viseme-limit, viseme-too-short, viseme-guessed, viseme-incomplete, compound-noop) เป็นชนิดข้อวินิจฉัยที่เครื่องอ่านได้ รายการอื่นเป็นชื่อของเงื่อนไข ส่วนถ้อยคำของข้อความแจ้งไม่เป็นข้อบังคับ
7.9.
ตัวอย่าง (เพื่อให้ข้อมูล ชื่อกลอสและการแสดงออกเป็นเพียงตัวอย่าง)
- รุ่น 1.1.0 — $shift(0.3,0,0,0.2) | HELLO | MY NAME(0.75) | @smile(0.5) | $spell{ก | ข} | @none | $pause(15) | $reset
- รุ่น 1.1.1 — $anchor(mouth){EAT} || WATER! | $compound(1,caption){A}{B} | SIGN ; $viseme(sa-wat-dee)
- รุ่น 1.1.2 — %num(123) | YEAR
8.1.
นิยามนี้ใช้หมายเลขรุ่นแบบ X.Y.Z แต่ละหลักบอกระดับของสิ่งที่เปลี่ยนในรุ่นนั้น และเมื่อหลักใดเพิ่มขึ้น หลักที่อยู่ทางขวาจะกลับเป็น 0
8.2.
X — การเปลี่ยนกระบวนทัศน์ (paradigm shift) เมื่อแบบจำลองการแทนข้อมูลเปลี่ยนไปหรือเวกเตอร์เดิมใช้ไม่ได้อีก ได้แก่ เวกเตอร์ที่ถูกแทนที่หรือแบ่งกลุ่มใหม่ (แบบจำลองกลุ่มตามข้อ 3 เปลี่ยน ข้อตกลงช่วง [−1, 1] เปลี่ยน หรือเวกเตอร์ IPL มิใช่การแทนข้อมูลหลักอีกต่อไป) และการแก้ทะเบียนแบบไม่เข้ากันทุกกรณี (ข้อ 4) คือ การถอดมิติ การนำรหัสกลับมาใช้ซ้ำ หรือการนิยามความหมายหรือช่วงค่าของมิติใหม่ — รุ่น X ใหม่เริ่มสายเวกเตอร์ใหม่ เวกเตอร์ โปรแกรมถอดรหัส และสคริปต์ของรุ่น X ก่อนหน้าไม่ถือว่าใช้ต่อได้โดยไม่แปลง และรุ่นนั้นต้องบันทึกว่าไม่เข้ากัน (breaking) พร้อมแนวทางย้ายข้อมูล
8.3.
Y — การเปลี่ยนแปลงหลัก (major change) เมื่อเอกสารได้ความสามารถเชิงบังคับเพิ่มภายในกระบวนทัศน์เดิมโดยเวกเตอร์ที่มีอยู่ทุกตัวยังใช้ได้ ได้แก่ การเพิ่มมิติหนึ่งตัวขึ้นไปในทะเบียน (ข้อ 4) พร้อมค่าปริยายที่เป็นกลาง ซึ่งเวกเตอร์เดิมยังถอดรหัสได้โดยมิติใหม่ใช้ค่าปริยาย และหัวข้อบังคับใหม่ที่มีข้อกำหนดระดับ "ต้อง" (ไวยากรณ์การประกอบ ข้อ 7 เข้ามาในรุ่น 1.1.0) — รุ่น Y เป็นแบบเพิ่มเติม (additive)
8.4.
Z — การเปลี่ยนแปลงย่อย (minor change) สำหรับทุกสิ่งที่ไม่แตะต้องเวกเตอร์และการถอดรหัสท่าหลักจากเวกเตอร์ ได้แก่ การชี้แจง การแก้ถ้อยคำที่ไม่กระทบความหมาย การเพิ่มเงื่อนไขเสริม (ข้อ 3.4) และการปรับโดเมนของเงื่อนไขเสริมที่รูปแบบเดิมยังใช้ได้ (จุดยึดแขนในรุ่น 1.0.1 และแมปรูปปากตามเสียงในรุ่น 1.1.1) โครงสร้างไวยากรณ์ที่เพิ่มเข้าในข้อ 7 โดยสคริปต์เดิมทุกตัวยังใช้ได้ (รุ่น 1.1.1 และ 1.1.2) และการปรับการถอดรหัสที่คงรูปแบบเวกเตอร์ รหัส ช่วงค่า และค่าปริยาย (การปรับปรุงนิยามแกนแขนตามข้อ 4.1 ในรุ่น 1.1.2) — การเปลี่ยนแปลงย่อยอาจทำให้รูปทรงที่แสดงผลต่างไปบนบางโมเดล ความเข้ากันได้ของข้อมูลที่จัดเก็บมิได้หมายความว่ารูปทรงจะเหมือนเดิม และบันทึกการเปลี่ยนแปลงต้องระบุผลเช่นนั้น
8.5.
ภายในรุ่น X เดียวกัน ห้ามนำรหัสกลับมาใช้ซ้ำในความหมายอื่น ห้ามถอดหรือนิยามมิติใหม่ และลำดับทะเบียนของรหัสที่มีอยู่ไม่เปลี่ยน — เนื่องจากผู้บริโภคต้องเพิกเฉยต่อรหัสที่ไม่รู้จัก (ข้อ 5.1) เวกเตอร์ที่เขียนภายใต้รุ่น Y หรือ Z ที่ใหม่กว่าในรุ่น X เดียวกันจึงถอดรหัสภายใต้รุ่นเก่ากว่าได้โดยทิ้งมิติใหม่ และเวกเตอร์ที่เขียนภายใต้รุ่นเก่ากว่าถอดรหัสภายใต้รุ่นใหม่กว่าได้โดยแทนด้วยค่าปริยาย แต่ละรุ่นต้องบันทึกรุ่นที่แทนที่และระดับความเข้ากันได้ (ฉบับตั้งต้น / เพิ่มเติม / ไม่เข้ากัน) และป้าย "ตั้งแต่รุ่น" ในข้อ 7 ระบุระดับที่โครงสร้างเข้ามา มิใช่รุ่นที่เผยแพร่แยกต่างหาก — ผู้พัฒนาควรระบุรุ่นที่รองรับให้ชัดเจน และการเผยแพร่รวมถึงหมายเลขของรุ่นเป็นสิ่งที่เจ้าของนิยามประกาศ
8.6.
เอกสารฉบับนี้คือรุ่น IPL 1.1.2 (เผยแพร่ 15 ต.ค. 2569) แทนที่รุ่น IPL 1.1.1
8.7.
สัญญาอนุญาต — ข้อกำหนด IPL เป็นข้อกำหนดแบบเปิด ทุกคนสามารถนำไปพัฒนา เข้ารหัส ถอดรหัส หรือแลกเปลี่ยนข้อมูล IPL ได้โดยไม่ต้องขออนุญาตและไม่มีค่าธรรมเนียม ส่วนเนื้อความของเอกสารนี้ เว็บไซต์ ipl.signthai.com และฉบับ .docx เป็นลิขสิทธิ์ © 2026 ทีมวิจัยเทคโนโลยีที่ทุกคนเข้าถึงและสิ่งอำนวยความสะดวก (AAT) กลุ่มนวัตกรรมแพลตฟอร์มดิจิทัลสุขภาพการแพทย์ (DHCB) สำนักงานพัฒนาวิทยาศาสตร์และเทคโนโลยีแห่งชาติ (สวทช.) สงวนลิขสิทธิ์ทั้งหมด การทำซ้ำหรือเผยแพร่ต่อซึ่งเอกสารนี้ต้องได้รับอนุญาตเป็นลายลักษณ์อักษร
8.8.
ตัวระบุ — คำในเนื้อความคือ IPL (Interpretable Pose Latent) ซึ่งต้องขยายตัวย่อเมื่อกล่าวถึงครั้งแรกในทุกเอกสาร สัญลักษณ์ทางคณิตศาสตร์คือ P เนมสเปซและ URI ฐานคือ signthai.com/ipl ชนิดสื่อ (media type) คือ application/vnd.ipl+json (เสนอ — ยืนยันเมื่อลงทะเบียน) และสตริงรุ่นคือ IPL 1.1.2
9.
บันทึกการเปลี่ยนแปลง (Change Log)
9.1.
รุ่น 1.0.0 (มิ.ย. 2569) — ฉบับเผยแพร่ครั้งแรก: แบบจำลองกลุ่มต่อเนื่อง 7 กลุ่ม (a, w, g, h, b, f, m) รวม 71 มิติ ข้อตกลงค่าบรรทัดฐาน [−1, 1] กรอบลำตัวยึดคอ ชั้นการแสดงออกแบบส่วนเพิ่มบนกลุ่ม h, b, f, m เงื่อนไขเสริม 3 ชนิด (จุดมองสายตา รูปปากตามเสียง และการสัมผัสบนจุดบนร่างกาย 32 ชื่อ) ทะเบียนพารามิเตอร์ ข้อตกลงการเข้ารหัส ความสอดคล้อง และนโยบายการกำหนดรุ่นสามหลัก — แทนที่: ไม่มี ความเข้ากันได้: ฉบับตั้งต้น (baseline)
9.2.
รุ่น 1.0.1 (16 ก.ค. 2569) — การเปลี่ยนแปลงย่อย: เพิ่มเงื่อนไขเสริมจุดยึดแขน (anchor) ขั้นการปรับปรุงผลลัพธ์แยกต่อข้างแขน ให้ตำแหน่งแขนวัดจากจุดบนร่างกายที่เลือกแทนคอ โดยการสัมผัสมีผลเหนือกว่า (ข้อ 3.4.4) พร้อมข้อกำหนดความสอดคล้องของผู้บริโภค (ข้อ 6.4) และระบุว่าการเพิ่มเงื่อนไขเสริมเพิ่มเฉพาะหลักขวาสุดของหมายเลขรุ่น — แทนที่: 1.0.0 ความเข้ากันได้: เพิ่มเติม (additive) เวกเตอร์ไม่เปลี่ยน
9.3.
รุ่น 1.1.0 (1 ต.ค. 2569) — การเปลี่ยนแปลงหลัก: เพิ่มไวยากรณ์การประกอบเป็นหัวข้อบังคับใหม่ (ข้อ 7) ได้แก่ หลักการและคำศัพท์ ข้อตกลงเชิงศัพท์ การแปลงชื่อพร้อมนามแฝงและกลอสประกอบ เส้นเวลาและช่องว่างอัตโนมัติ โครงสร้างพื้นฐาน (ลำดับ กลอส การหยุด การเลื่อน กลุ่ม การสะกดนิ้วมือ และการแสดงออกแบบอ้างอิง) และข้อผิดพลาดและข้อวินิจฉัย — แทนที่: 1.0.1 ความเข้ากันได้: เพิ่มเติม (additive) เวกเตอร์และเงื่อนไขเสริมไม่เปลี่ยน หลัก Y เพิ่มขึ้นเพราะเอกสารได้ความสามารถเชิงบังคับใหม่ (ข้อ 8.3)
9.4.
รุ่น 1.1.1 (8 ต.ค. 2569) — การเปลี่ยนแปลงย่อย: เพิ่มฟังก์ชันพิเศษและตัวดำเนินการในไวยากรณ์การประกอบ (ข้อ 7.6) ได้แก่ $anchor $mirror $buoy $compound $viseme ตัวเชื่อม || และการเติมท่าพัก NAME! พร้อมอักขระสงวนและข้อวินิจฉัยที่เกี่ยวข้อง และเปลี่ยนโดเมนของรูปปากตามเสียงเป็นแมปกระจายที่ผสมหลายรูปปากได้ โดยให้ m_* เป็นค่าส่วนต่างจากรูปปากนั้น (ข้อ 4.8) — แทนที่: 1.1.0 ความเข้ากันได้: เพิ่มเติม (additive) เวกเตอร์ไม่เปลี่ยน สคริปต์และรูปปากรายการเดียวของรุ่น 1.1.0 ให้ผลเหมือนเดิม
9.5.
รุ่น 1.1.2 (15 ต.ค. 2569) — การเปลี่ยนแปลงย่อย: เพิ่มฟังก์ชันผู้ใช้ %name(args) ที่ขยายเป็นข้อความก่อนแบ่งโทเคน (ข้อ 7.7) ปรับปรุงนิยามแกนแขน — แกน X อิงความยาวมือ แกน Y อิงความยาวช่วงตัว (คอถึงสะดือ) และแกน Z อิงความยาวแขน โดยหน่วยแกน L = 2 · r · d (ข้อ 4.1) พร้อมข้อกำหนดความสอดคล้องที่เกี่ยวข้อง กำหนดนโยบายการกำหนดรุ่นใหม่เป็น X.Y.Z (ข้อ 8) ใช้ชื่อมาตรฐาน IPL — Interpretable Pose Latent และสัญลักษณ์ P แทนอักษรกรีก Π (ข้อ 8.8) และสัญญาอนุญาตสองส่วน (ข้อ 8.7) ชี้แจงขั้วการงอนิ้ว (ข้อ 4.3) และค่าของจุดมองสายตา (ข้อ 4.8) — แทนที่: 1.1.1 ความเข้ากันได้: เพิ่มเติม (additive) รูปแบบเวกเตอร์และเงื่อนไขเสริมไม่เปลี่ยน แต่ตำแหน่งแขนที่แสดงผลอาจต่างไปบนบางโมเดล สคริปต์ของรุ่น 1.1.1 ให้ผลเหมือนเดิม และ % เป็นอักขระสงวน