Skip to content
Tayakorn

คู่มือ Blender Animation

LEVEL 4 · ระดับเทพ

หนึ่งเฟรมถูกคำนวณยังไง

ทั้งเล่มปลูกคำถามไว้หลายข้อ บทนี้ไขพร้อมกันทั้งหมดด้วยคำตอบเดียว

ทุกครั้งที่เฟรมเปลี่ยน Blender ไม่ได้ "อัปเดตของที่เปลี่ยน" แบบสุ่ม มันมีแผนผังชื่อ dependency graph (depsgraph) ที่บอกว่าอะไรต้องคำนวณก่อนอะไร แล้วเดินตามแผนนั้นทุกเฟรม

ลูกศร = ทิศทางที่ค่าไหล · ปลายลูกศรคือคนที่ต้องรอเวลา (เลขเฟรม)ต้นทางที่ไม่รอใครF-Curveเขียนลง propertydriverอ่านจาก property อื่นรอค่านี้เมทริกซ์พ่อ → ลูกลูกอ่านของพ่อconstraint / IKทำงานบนผลลัพธ์Armature modifierอ่านกระดูกหลัง constraintวาดกฎข้อเดียวที่ตายตัวมีแค่ F-Curve ที่เขียนลงค่าที่คุณเก็บไว้ชั้นอื่นแตะไม่ได้เลยปิดมันแล้วของกลับที่เดิม
FIG 13.1 ลูกศรอ่านว่า "คนนี้รอค่าจากคนนั้น" — ใครมีลูกศรชี้เข้า คนนั้นถูกประเมินทีหลัง · ลำดับจึงเกิดจากวิธีที่คุณต่อของไม่ได้ถูกกำหนดมาก่อน · มีแค่ F-Curve ที่เขียนลง property จริง ที่เหลือทำงานบนผลลัพธ์

13.1 ดูทั้งสายพร้อมกัน

สร้างกล่องหนึ่งใบที่มีครบสามชั้นทับกันอยู่:

  1. keyframe บน location.x — วิ่งจาก 0 ไป 2 ระหว่างเฟรม 1 ถึง 41
  2. driver บน scale.z — อ่านจากตัวควบคุม ไม่เกี่ยวกับเวลา
  3. constraint Limit Location — ห้าม x เกิน 1.5

แล้วไล่ดูทีละเฟรม:

 frame |  F-Curve ให้ x |  property x |  x จริงหลังประเมิน |  scale.z
--------------------------------------------------------------------------
     1 |         0.0000 |      0.0000 |             0.0000 |    1.750
    11 |         0.3125 |      0.3125 |             0.3125 |    1.750
    21 |         1.0000 |      1.0000 |             1.0000 |    1.750
    31 |         1.6875 |      1.6875 |             1.5000 |    1.750
    41 |         2.0000 |      2.0000 |             1.5000 |    1.750

อ่านตารางนี้ทีละคอลัมน์ แล้วทั้งเล่มจะประกอบร่างพร้อมกัน:

  • คอลัมน์ 2 กับ 3 ตรงกันเสมอ — F-Curve เขียนลง property จริง นี่คือชั้นเดียวที่มีสิทธิ์แตะค่าที่คุณเก็บไว้
  • คอลัมน์ 4 แยกออกจากคอลัมน์ 3 ตั้งแต่เฟรม 31 — พอค่าเกิน 1.5 constraint เข้ามาตัด ค่าใน property ยังเป็น 1.6875 และ 2.0000 ครบถ้วน แต่ผลจริงถูกล็อกไว้ที่ 1.5
  • คอลัมน์ 5 ไม่เปลี่ยนเลยตลอด 41 เฟรม — เพราะ driver อ่านจากตัวควบคุมที่ไม่ได้ขยับ เวลาผ่านไปเท่าไหร่ก็ไม่เกี่ยว

13.2 ลำดับมาจากไหน — และทำไมมันไม่ใช่ท่อคงที่

ตรงนี้คือจุดที่คนอธิบายผิดกันบ่อยที่สุด รวมถึงคำอธิบายที่หาเจอทั่วไปบนอินเทอร์เน็ต

ความเข้าใจผิดคือคิดว่า Blender มี ท่อคงที่ — ทำอย่างนี้ก่อน แล้วอย่างนั้น เรียงเหมือนกันทุกครั้ง ถ้าเป็นแบบนั้นจริง คุณจะท่องลำดับได้ แต่คุณจะทำนายผิดทันทีที่เจอไฟล์ที่ต่อของกันคนละแบบ

ของจริง: depsgraph สร้างลำดับขึ้นใหม่จากคำถามเดียว — ใครอ่านค่าจากใคร

ไม่มีใครได้คิวเพราะเป็นชนิดนั้น ทุกคนได้คิวเพราะมีคนรอค่าของตัวเองอยู่

ลองพิสูจน์ด้วยตาเอง สามการทดลอง:

หนึ่ง — ให้ driver อ่านค่าที่ถูกคีย์

  frame  1: F-Curve ให้ Ctrl.x =  0.0000  ->  driver ได้ scale.z =  1.0000
  frame 13: F-Curve ให้ Ctrl.x =  5.0000  ->  driver ได้ scale.z =  6.0000
  frame 25: F-Curve ให้ Ctrl.x = 10.0000  ->  driver ได้ scale.z = 11.0000

driver เห็นค่าของเฟรมปัจจุบัน ไม่ใช่ค่าเฟรมก่อน ⇒ มันถูกประเมินหลัง F-Curve ที่ป้อนมัน เพราะมันรออยู่

สอง — ให้ constraint เล็งเป้าที่ถูก driver ขับ

  Target.x หลังประเมิน   = 7.0000   ← มาจาก driver ล้วน ไม่มี keyframe เลย
  Follower.x หลังประเมิน = 7.0000   ← constraint เห็นผลของ driver แล้ว

⇒ constraint ตัวนี้ถูกประเมินหลัง driver ตัวนั้น ด้วยเหตุผลเดียวกันเป๊ะ

สาม — constraint สองตัวเดิม สลับลำดับใน stack

  Limit(max 2) แล้วค่อย CopyLocation(9) -> x = 9.0000
  CopyLocation(9) แล้วค่อย Limit(max 2) -> x = 2.0000

ของสองชิ้นเดิม ค่าเดิม ได้คนละคำตอบ เพราะตัวล่างรับผลของตัวบนมาทำต่อ

13.3 กฎที่เชื่อได้ แทนลำดับที่ท่องไว้

จากสามการทดลองข้างบน สิ่งที่เชื่อได้จริงมีสามข้อ ไม่ใช่ลำดับ 1-2-3-4:

  1. มีที่เดียวที่เขียนลง property จริง คือ F-Curve — คอลัมน์ 2 กับ 3 ในตารางบทนี้ตรงกันทุกแถวเพราะเหตุนี้ ชั้นอื่นทั้งหมดทำงานบนผลลัพธ์ ไม่ใช่บนค่าที่คุณเก็บ
  2. ใครอ่านค่าจากใคร คนนั้นมาทีหลัง — ครอบทั้ง driver, constraint, พ่อ-ลูก และ modifier โดยไม่ต้องจำแยก
  3. ในกองเดียวกัน ลำดับบนลงล่างคือลำดับจริง — constraint stack และ modifier stack เรียงได้ เพราะลำดับมีความหมาย

ค่าที่คุณเก็บ กับค่าที่คุณเห็น เป็นคนละอย่าง และมีชั้นคั่นระหว่างมันเสมอ

💡 ที่พูดว่า "ไม่ใช่ท่อคงที่" ไม่ได้แปลว่ามันสุ่ม — ไฟล์ไหนที่ต่อของแบบเดียวกัน ก็ได้ลำดับเดิมทุกเฟรมแน่นอน สิ่งที่เปลี่ยนคือลำดับเกิดจากวิธีที่คุณต่อของ ไม่ได้ถูกกำหนดมาก่อน

13.4 ปริศนาทั้งเล่ม ไขพร้อมกัน

ทุกข้อใช้กฎข้อ 1 กับข้อ 2 ข้างบนตอบได้หมด:

  • ทำไมคีย์ไว้ (0,0,0) แล้วของไปอยู่ (7,3,2)? — constraint อ่านผลลัพธ์ของ property นั้นเพื่อทำงาน มันจึงมาทีหลัง (กฎ 2) และมันไม่มีสิทธิ์เขียนกลับ (กฎ 1) ค่าที่คุณคีย์จึงอยู่ครบ
  • ทำไม IK แก้มุมได้ 78.4 องศา แต่ค่าใน property ยัง 0? — IK คือ constraint ตัวหนึ่ง กฎ 1 ห้ามมันเขียนกลับเหมือนกันทุกตัว ไม่มีข้อยกเว้น
  • ทำไมหมุนพ่อแล้วลูกย้ายที่ทั้งที่ค่าลูกเป็นศูนย์? — ลูกอ่านเมทริกซ์ของพ่อ (กฎ 2) พ่อจึงเสร็จก่อนเสมอ และค่าที่เก็บของลูกไม่ต้องเปลี่ยนเลย
  • ทำไม weight ที่ดูถูกแล้วเนื้อยังบิด? — Armature modifier อ่านตำแหน่งกระดูกหลัง constraint ทำงานแล้ว ถ้ากระดูกไปผิดที่ก่อนหน้านั้น เนื้อก็บิดตามอย่างซื่อสัตย์ ปัญหาไม่ได้อยู่ที่ weight
  • ทำไม driver ที่อ้างวนกันถึงพัง? — นี่คือคำตอบที่ชัดที่สุดว่าทำไมมันเป็นกราฟไม่ใช่ท่อ: ถ้า A รอ B และ B รอ A ก็ไม่มีลำดับไหนที่ถูก ท่อคงที่จะไม่มีปัญหานี้เลย เพราะมันไม่เคยถามว่าใครรอใคร

13.5 วิธีไล่ปัญหาที่ใช้ได้จริงตั้งแต่วันนี้

เมื่อ "ของไม่เป็นอย่างที่คิด" ให้ไล่ถอยจากปลายทางกลับมาต้นทาง เพราะคนที่ได้คิวหลังคือคนที่ชนะ:

#ดูอะไรเปิดดูที่ไหน
1มี modifier อยู่ไหม (Armature, Lattice)แผงขวา แท็บรูปประแจ
2มี constraint อยู่ไหม และเรียงยังไงแผงขวา แท็บรูปโซ่ (กระดูกใช้แท็บโซ่ที่มีรูปกระดูก)
3วัตถุนี้มีพ่อหรือเปล่าแผงขวา แท็บสี่เหลี่ยมส้ม › Relations › Parent
4ค่าใน property คืออะไร ตรงกับที่คีย์ไหมกด N ในวิวพอร์ต แถบด้านขวาจะเด้งออกมา
5มี driver อยู่บนช่องนั้นไหมช่องที่มี driver จะเป็นสีม่วง — คีย์เฟรมเป็นสีเหลือง/เขียว

💡 จำสีให้แม่นแล้วประหยัดเวลาได้มาก: เขียว = มีคีย์เฟรมแต่ไม่ใช่เฟรมนี้ · เหลือง = มีคีย์ตรงเฟรมนี้พอดี · ม่วง = ถูก driver ขับอยู่ ไม่ใช่คีย์เฟรม สีบอกให้รู้ตั้งแต่ยังไม่ต้องคลิกว่าใครเป็นเจ้าของค่านั้น

เคล็ดลับ: ถ้าเปิดดูแล้วค่าในช่องถูกต้อง แต่ของไปอยู่ผิดที่ แปลว่าปัญหาไม่ได้อยู่ที่ข้อ 4–5 เลย ให้ไปดูข้อ 1–3 ทันที — ค่าถูกแต่ผลผิด คือนิยามของ "มีชั้นอื่นทำงานทับอยู่" ไม่ต้องเสียเวลาไล่ keyframe

Read the full book