เรื่องเลิปๆ

ในเกมหลายๆคนอาจจะใช้ฟังก์ชั่น Vector3.Lerp ไม่ก็ Mathf.Lerp กันเพื่อหาค่ากลางตรงไหนก็ได้ระหว่าง 2 ค่า…

เรื่องเลิปๆ

ในเกมหลายๆคนอาจจะใช้ฟังก์ชั่น Vector3.Lerp ไม่ก็ Mathf.Lerp กันเพื่อหาค่ากลางตรงไหนก็ได้ระหว่าง 2 ค่า แต่หารู้ไม่ว่ามันสามารถเร็วขึ้นได้อีก!

เกมผมก็ไม่ต่างกัน เรียกได้ว่าเฟรมนึงเรียกประมาณ​ 30 ครั้งขึ้นไปได้ ตอนนี้พยายามหาคอขวดอยู่ก็เลยมาถึงฟังก์ชั่นนี้ จากภาพข้างล่าง คือไอ้ตัวบนเส้นทุกตัวต้องถามว่าในความยาวเส้นทั้งหมดมันควรจะอยู่ตรงไหนในสามมิติ

อย่างแรกเลย LerpUnclamped เร็วกว่า Lerp

ใครอาจจะเห็นไอ้นี่ผ่านๆตาแล้ว ก็คือมันเป็น Lerp แบบเขตทะลุ 0 กับ 1 ได้ แล้วมันจะไปต่อตาม linear function เลย

Unity - Scripting API: Vector3.LerpUnclamped
Unity is the ultimate game development platform. Use Unity to build high-quality 3D and 2D games, deploy them across…docs.unity3d.com

ด้วยความที่รู้สึกว่าฟีเจอร์ “เด็ด” กว่า Lerp ธรรมดาก็เลยใช้แบบธรรมดาไป “ก็พอ” แต่หารู้ไม่ว่าแบบธรรมดานั่นแหละช้ากว่า

มาลองคิดดูดีๆก็จริง เพราะการ Clamp หมายถึงอาจจะต้องใช้ if เข้ามาช่วย ซึ่งถ้ากดดูใน Profiler ก็จะเห็นแบบนั้นจริง

เพื่อให้เชื่อว่าผมไม่ได้หลอกก็เลยไปทดลองเรียก Lerp แข่งกัน 50,000 ครั้งให้ดู อันนี้ผมทำ Lerp ไทยบ้านของตัวเองมาแข่งด้วยนะ (คิดว่าจะเร็วกว่าโปรแกรมเมอร์ที่ Unity ได้)

ผลการรันเทสหลายๆรอบโดยวัดหน่วยเป็น ticks จากคลาส Stopwatch คือ!

ของผม 150,000 ของ Unity Lerp 100,000 และ Unity LerpUnclamped แค่ ~67,000 !

สรุปคือ LerpUnclamped เร็วกว่าตั้ง 1.5 เท่า ถ้าเขตที่จะใช้ชัวร์อยู่แล้วว่าอยู่ในช่วงอะไรงี้ ก็ใช้เถอะ

Lerp ไทยบ้าน Lv.2 Lv.3

อย่าหวังว่าแค่นี้ผมจะยอมแพ้ ถึงผมจะไม่รู้ว่า Lerp ของ Unity มัน implement วิเศษยังไงให้เร็วกว่าของผมได้ก็ตาม แต่ผมได้ลองทำเพิ่มขึ้นมาอีก

เนื่องจากคิดว่า V1 เกิดการสร้าง Vector3 ขึ้นมาระหว่างทางแล้วมันเสียเวลาตรงนั้น คราวนี้เลยคิดเป็นฝอยๆเลย ส่วน V3 ก็คือ V2 แบบใช้ความรู้ ม.3 แจกแจงเข้าไป.. เพราะคิดว่าอยากจะใช้ . field ให้น้อยครั้งลง

ผลคือ!

V2
V3

จะเห็นว่าตอนนี้ผมสามารถชนะ Lerp ได้แล้ว เย้ แต่ยังแพ้ LerpUnclamped อยู่ ผมละงงจริงๆว่าเขาทำท่าไหน ส่วน V2 กับ V3 ผลไม่ได้แตกต่างกันอย่างมีนัยยะสำคัญ

Lerp ไทยบ้าน Lv.4 Lv.5

ในเมื่อคิดไม่ออกว่าเขาทำเร็วกว่าเราได้ไง เอาด้วยเล่ห์ไม่ได้ก็จะเอาด้วยกลแทน

ตอนนี้ใช้ ref มาช่วย อย่าลืมว่า Vector3 เป็น struct ดังนั้นการส่งเข้าออกเมธอดจะเกิดการก๊อปปี้ตัวเองขึ้น เราก็เลยกำหนดไว้ว่าให้ตัวแรกเป็นผลลัพธ์ที่จะเอา ละก็เปลี่ยนเป็น return void ซะเลย

ผลคือ!

V4
V5

ชนะแล้ว!! ในที่สุด Lerp OTOP ของผมก็ชนะ Unity ได้แล้วครับ.. ประมาณ 20%

อย่าลืมว่ามีจุดอ่อนคือต้องเรียงลำดับให้ถูกนะ! ตัวแรกต้องเป็นตัวที่จะเอา (เพราะมันใช้ += อยู่ข้างใน) แล้วก็ต้องน้อยกว่าตัวที่ 2 ขอให้มีวินัยเองเพื่อความเร็ว ของ Unity ทำมาให้ถูกนิยาม

บทเรียน

เตือนตัวเองเสมอว่าข้อมูลอะไรเป็น struct แล้วถ้าตรงนั้นเป็นคอขวด ref สามารถช่วยได้มาก โดยเฉพาะคนสาย functional programming ที่ชอบแบบโยนข้อมูลไปมา ก๊อปปี้บานเบอะ บางทีเพื่อความเร็วอาจจะต้องกัดฟันใช้ ref ในบางจุดครับ

สุดท้ายเผื่อคิดว่าผมโมเมขึ้นมาเอง โหลดโค้ดนี้ไปรันใน Test Runner ของ Unity ได้

ของแถม ทำ InverseLerp ให้เร็วกว่า Unity นิดนึงก็ได้ แต่ทีนี้มีจุดอ่อนที่ว่าค่าห้ามเกินขอบล่างขอบบนไม่งั้นผิด แล้วก็ขอบล่างต้องน้อยกว่าขอบบน มีวินัยเอาเองเพราะมันเร็วกว่าตรงนั้นแหละ