วิธีใช้ LUT (ตารางค้นหา) ในวิดีโอเกม
(blog.frost.kiwi)- LUT (ตารางค้นหา) คือวิธีอ้างอิงค่าที่คำนวณไว้ล่วงหน้าในลักษณะคล้ายตาราง และถูกใช้อย่างกว้างขวางตั้งแต่การทำภาพความร้อนขาวดำให้เป็นสี ไปจนถึงการแปลงรูปวัตถุในเกมและการเกรดสีวิดีโอ
- ตัวอย่าง WebGL แสดงลำดับการทำงานที่นำเฟรมวิดีโอขึ้นสู่ GPU เป็น เท็กซ์เจอร์ 2D แล้วใช้ tinting, 1D LUT และ 3D LUT ใน Fragment Shader ที่กำหนดสีของแต่ละพิกเซล
- 1D LUT ใช้ค่าความสว่าง
[0.0 - 1.0]เป็นพิกัดของอาร์เรย์สีเพื่อแปลงอินพุตขาวดำเป็น RGB และอาศัยการกรองแบบ bilinear ของ GPU เพื่ออินเตอร์โพเลตค่าระหว่างกลางให้เนียนแม้ LUT จะมีขนาดเล็ก - เช่นเดียวกับกรณีของ Left 4 Dead จาก Valve, tinting และ LUT ถูกใช้เพื่อสร้างการเปลี่ยนสีของรถยนต์ ผิวซอมบี้ และเสื้อผ้า ภายใต้ข้อจำกัดของหน่วยความจำเท็กซ์เจอร์
- LUT เพิ่มต้นทุนของการอ่านเท็กซ์เจอร์อีกครั้ง แต่เป็นเครื่องมือที่ใช้งานได้จริงสำหรับการเก็บผลคำนวณแพง ๆ อย่างการแกมมาคอร์เรกชันไว้ล่วงหน้า หรือดึงเวิร์กโฟลว์การเกรดสีจากภายนอกมาใช้กับกราฟิกแบบเรียลไทม์
LUT ทำอะไรในงานเขียนโปรแกรมกราฟิก
- Lookup table (LUT) คือวิธีเก็บค่าที่คำนวณไว้ล่วงหน้าในแถวหรือตาราง แล้วอ้างอิงเมื่อจำเป็น
- ในงานเขียนโปรแกรมกราฟิก โครงสร้างที่เรียบง่ายนี้ต่อยอดไปสู่เอฟเฟกต์ภาพได้หลายแบบ
- เปลี่ยนภาพขาวดำให้เป็นสี
- ใช้การแก้สีและการจัดสไตล์
- สร้างการแปลงวัตถุในวิดีโอเกมอย่างมีประสิทธิภาพ
- ตัวอย่างใช้ WebGL แต่เทคนิคเดียวกันนี้ก็ใช้ได้กับ DirectX, OpenGL, Vulkan, Unity และการแสดงผลข้อมูลเชิงวิทยาศาสตร์
- วิดีโอเดโมเป็นภาพที่บันทึกจาก Panasonic GH6 และกล้องภาพความร้อน TESTO 890 และกระบวนการประมวลผล ทำบน GPU ภายในเครื่อง โดยข้อมูลไม่ถูกส่งออกนอกอุปกรณ์
ไปป์ไลน์ของ WebGL และ tinting
- เอาต์พุตจากกล้องภาพความร้อนเป็น วิดีโอขาวดำ และแต่ละเฟรมจะถูกส่งขึ้น GPU เป็นเท็กซ์เจอร์ 2D ผ่าน WebGL
- Fragment Shader คือโค้ดที่กำหนดสีสุดท้ายของแต่ละ fragment ในเอาต์พุต
- ในตัวอย่าง จะอ่านสีวิดีโอที่ตำแหน่งปัจจุบันด้วย
texture2D(video, tex).rgb - เอาต์พุตสุดท้ายของ WebGL 1.0 จะถูกเขียนเป็น RGBA ลงใน
gl_FragColor
- ในตัวอย่าง จะอ่านสีวิดีโอที่ตำแหน่งปัจจุบันด้วย
- tinting คือการคูณสีของเท็กซ์เจอร์ด้วยสีที่กำหนด เพื่อเติมโทนสีลงไป
- ในตัวอย่าง ใช้
videoColor * vec3(1.0, 0.5, 0.0)เพื่อคูณด้วยสีส้ม - สีขาวจะกลายเป็นสีส้ม ส่วนสีดำยังคงเป็นสีดำเพราะคูณด้วย 0
- ในตัวอย่าง ใช้
- ในบริบทนี้ ต้นทุนของการคูณเพื่อทำ tinting อาจวัดได้ยาก
- ต้นทุนของการดึงเท็กซ์เจอร์จากหน่วยความจำสูงกว่าการคูณมาก
- เมื่อหลายเธรดทำงานแบบขนาน ระหว่างที่พิกเซลหนึ่งรอการอ่านเท็กซ์เจอร์ ก็อาจมีการคูณของพิกเซลอื่นเกิดขึ้นได้
- นี่เป็นคำอธิบายถึงความแตกต่างที่ tinting สร้างขึ้น ไม่ได้หมายความว่าการปรับจูนประสิทธิภาพโดยรวมเสร็จสมบูรณ์แล้ว
การใช้ tinting ของ Valve
- Valve Software ใช้ tinting ใน Left 4 Dead เพื่อสร้างความหลากหลายให้รถยนต์
- ถ้าต้องมีเท็กซ์เจอร์แยกสำหรับรถแต่ละชนิดและแต่ละสี ก็อาจเกินงบประมาณหน่วยความจำของเท็กซ์เจอร์ได้
- Valve ใช้ mask texture เพิ่มเติม เพื่อทำ tinting เฉพาะบริเวณสีรถให้มีสีแตกต่างกันในแต่ละอินสแตนซ์
- เท็กซ์เจอร์สีหนึ่งชุดถูกแชร์ระหว่างรถ 3 รุ่น
- ด้วยต้นทุนของเท็กซ์เจอร์ 2 ชุด สามารถสร้างรถ 4 รุ่นและความหลากหลายของสีได้แทบไม่จำกัด
- ใน Source Engine ไม่ได้มีแค่รถเท่านั้น แต่แทบทุกอย่างสามารถทำ tinting ได้
แปลงค่าขาวดำเป็นสีด้วย 1D LUT
- 1D LUT คืออาร์เรย์ของตัวเลข และถ้าเป็นภาพ RGB ก็จะเป็นอาร์เรย์หนึ่งมิติของสี
- ใช้ค่าความสว่างของภาพขาวดำเป็นพิกัดบนแกน X ของ LUT เพื่อดึงสีออกมา
- ค่าความสว่างของวิดีโออยู่ในช่วง
[0.0 - 1.0] - สีดำ
0.0จะถูกแมปไปยังสีฝั่งซ้ายของ LUT และสีขาว1.0ไปยังสีฝั่งขวา - ค่าระหว่างกลางจะถูกแมปไปยังสีตามตำแหน่งที่สอดคล้องกัน
- ค่าความสว่างของวิดีโออยู่ในช่วง
- WebGL 1.0 ไม่มี 1D texture จึงใช้ เท็กซ์เจอร์ 2D ที่มีความสูง 1px แทน
- โค้ดตัวอย่างอยู่ในรูป
texture2D(lut, vec2(videoColor, 0.5)) - เนื่องจากอินพุตเป็นค่า 1D และเอาต์พุตเป็น RGB จึงเป็นโครงสร้างแบบ “1D vector in, 3D vector out”
- โค้ดตัวอย่างอยู่ในรูป
- การกรองแบบ bilinear ของ GPU จะอินเตอร์โพเลตค่าระหว่างกลางให้อัตโนมัติขณะอ่านเท็กซ์เจอร์
- วิดีโอขาวดำ 8 บิตมีระดับความสว่าง 256 ระดับ
- แม้ 1D LUT จะกว้างเพียง 32 พิกเซล การเข้าถึงระหว่างพิกเซลก็ยังถูกอินเตอร์โพเลตแบบเชิงเส้น
- แม้มีข้อมูลเพียง 8 พิกเซล ก็ยังให้ผลลัพธ์ที่ใกล้เคียงกับกราเดียนต์หลากสีความกว้าง 256 พิกเซลได้
การเลือก colormap และความสม่ำเสมอเชิงการรับรู้
- ตัวอย่างมีรายการ colormap ที่ matplotlib รองรับ และสามารถส่งออกเป็น 1D LUT ได้
- หากข้อมูลไม่มีโครงสร้างเฉพาะ การใช้ colormap ที่สม่ำเสมอเชิงการรับรู้ หรือกำหนดสีโดยอิงจากแนวคิดนี้ถือว่าเหมาะสม
- ตระกูล viridis เป็นตัวอย่างที่เด่น
- colormap ที่สม่ำเสมอเชิงการรับรู้ยังคงทำให้ส่วนที่เย็นดูมืดและส่วนที่ร้อนดูสว่าง แม้นำไปแสดงเป็นขาวดำ
- colormap อย่าง jet ที่เปลี่ยนหลัก ๆ แค่เฉดสี (hue) และละเลยความสว่างเชิงการรับรู้ ไม่ได้รับประกันคุณสมบัตินี้
- ความสามารถในการทำให้ผู้มีความบกพร่องในการมองเห็นสีตีความข้อมูลได้ถูกต้อง ก็เป็นเกณฑ์สำคัญในการเลือก colormap
ประสิทธิภาพของ 1D LUT และการประมาณด้วยพหุนาม
- ต้นทุนของ 1D LUT ขนาดเล็กโดยทั่วไปอาจต่ำ แต่ก็มีประเด็นให้พิจารณามากกว่า tinting
- ความกังวลด้านประสิทธิภาพหลักคือ dependent texture read
- ใช้ผลจากการอ่านเท็กซ์เจอร์ครั้งแรกเพื่อกำหนดพิกัดการอ่านเท็กซ์เจอร์ครั้งที่สอง
- ในงานกราฟิก นี่เป็นแพตเทิร์นที่อาจทำให้เส้นทางการปรับแต่งบางส่วนใช้ไม่ได้
- GPU มี texture cache และ LUT ขนาดเล็กอาจอยู่ในแคชได้ ทำให้ต้นทุนของการอ่าน LUT ต่ำมาก
- หากจะประเมินประสิทธิภาพอย่างละเอียด จำเป็นต้องใช้เครื่องมือวิเคราะห์ตามแพลตฟอร์ม
- Nvidia NSight ให้การวิเคราะห์ประสิทธิภาพแยกตามขั้นของเชดเดอร์ แต่ไม่รองรับ OpenGL
- ถ้าใช้ การประมาณด้วยพหุนาม เพื่อสร้าง colormap ก็ไม่จำเป็นต้องจัดการกับเท็กซ์เจอร์ LUT
- การประมาณ viridis บน ShaderToy ของ Matt Zucker เขียนในรูป Horner’s method
- คำนวณสีด้วยการดำเนินการแบบ multiply-add ในรูป
c0+t*(c1+t*(c2+t*(c3+t*(c4+t*(c5+t*c6))))) - จะเร็วกว่า LUT จริงหรือไม่นั้นยากจะตัดสินหากไม่มีการวิเคราะห์ตามแพลตฟอร์ม
ความหลากหลายของซอมบี้ใน Left 4 Dead 2
- Left 4 Dead 2 ใช้ LUT กับการเปลี่ยนสีผิวและเสื้อผ้าที่ tinting แบบง่ายอย่างเดียวไม่เพียงพอ
- tinting แบบง่ายอาจให้ความหลากหลายของความสว่างในสีไม่เพียงพอ
- สำหรับผิวและเสื้อผ้า มีการสุ่มเลือก LUT จากหลายชุดเพื่อสร้างความหลากหลายของสี
- ศิลปินจะเลือก color ramp ที่เหมาะสมเพื่อนำเข้าเกมสุดท้าย
- จากเท็กซ์เจอร์เดียว สามารถสร้างทั้งชุดสูทสีอ่อนและชุดสูทสีเข้มได้
- ดูงานนำเสนอฉบับเต็มที่เกี่ยวข้องได้ใน GDC: Shading a Bigger Better Sequel
- “Exclusive Masking” คือวิธีใส่ช่วงของเท็กซ์เจอร์ 2 ชุดไว้ในแชนเนลเดียว
- Texture 1 ใช้ช่วง 0-128
- Texture 2 ใช้ช่วง 128-256
- ต้นทุนคือความละเอียดของสีที่ลดลง
1D LUT สำหรับเก็บผลคำนวณล่วงหน้า
- 1D LUT ยังใช้เป็น แคชของการคำนวณราคาแพง ในงานกราฟิกได้ด้วย
- Gamma correction เป็นตัวอย่างเด่น
- ถ้าไม่ใช้การประมาณ ก็ต้องใช้ฟังก์ชัน
pow() - โดยเฉพาะบน GPU รุ่นเก่า
pow()อาจเป็นคำสั่งที่มีต้นทุนสูง - ถ้าใช้เส้นโค้งแบบแบ่งช่วงของ sRGB มาตรฐาน ก็จะมีเส้นทางแบบมีการแตกแขนงเพิ่มขึ้น
- ถ้าไม่ใช้การประมาณ ก็ต้องใช้ฟังก์ชัน
- หากคำนวณการแปลงแกมมาไว้ล่วงหน้าใน 1D LUT ก็สามารถข้ามการคำนวณรายพิกเซลได้
- ในกรณีนี้จะเป็นโครงสร้างแบบ “1D vector in, 1D vector out”
- 1D LUT สามารถส่งออกช่องสีได้สูงสุด 4 แชนเนล
- Redshift เป็นตัวอย่างซอฟต์แวร์ที่ลดอาการล้าตาด้วยการทำให้จอภาพติดโทนส้มในเวลากลางคืน
- มันเปลี่ยน Gamma Ramp ของช่อง Red, Green และ Blue ของจอ
- มีการคำนวณ Kelvin Warmth → RGB และการคำนวณแกมมาเพิ่มเติมไว้ล่วงหน้าใน 3 ชุดของ 1D LUT
- ดูการทำงานที่เกี่ยวข้องได้ใน ซอร์สโค้ดของ Redshift
- วิธีนี้ไม่มีผลด้านประสิทธิภาพ เพราะการ remap เกิดที่จอภาพไม่ใช่การ์ดจอ แต่การรองรับอินเทอร์เฟซฮาร์ดแวร์ในปัจจุบันมักไม่เสถียรหรือแตกหักไปแล้ว
- มีกรณีที่กราฟิกสแตกของ Raspberry Pi สูญเสียการรองรับนี้ไปในอัปเดตใหม่
- Microsoft ก็เตือนเกี่ยวกับการใช้ SetDeviceGammaRamp
3D LUT: รีแมปพื้นที่ RGB ทั้งหมด
- 3D LUT แทนพื้นที่ RGB ทั้งหมดเป็นคิวบ์เดียว และทำการรีแมปทุกสีที่เป็นไปได้
- เพราะมันแปลงเวกเตอร์ RGB 3 มิติอินพุตเป็นเวกเตอร์ RGB 3 มิติเอาต์พุต จึงเป็นโครงสร้างแบบ “3D vector in, 3D vector out”
- ถ้าใช้ 1D LUT แยกกับ Red, Green และ Blue ก็สามารถเปลี่ยนสมดุลสีได้
- แต่ 3D LUT จำเป็นสำหรับการแปลงที่ต้องอาศัยการผสมกันของค่า RGB อินพุต
- การเปลี่ยนความอิ่มสี
- การเปลี่ยนเฉดสี (hue)
- การปรับสีเฉพาะจุด
- การแยกสี
- โดยปกติ 3D LUT จะอยู่ในรูปคิวบ์ ส่วนในเกมมักเก็บเป็น strip หรือ square และในเครื่องมือตัดต่อวิดีโอจะใช้ไฟล์
.cubeแบบ “Iridas/Adobe”
การทำ 3D LUT ใน WebGL 1.0
- วิดีโอในตัวอย่างถ่ายด้วย Panasonic GH6 โดยใช้โปรไฟล์สี Panasonic V-Log
- V-Log เป็นโปรไฟล์ log ที่เก็บช่วงไดนามิกได้มากขึ้น และมีนิยาม Gamut กับ Gamma ที่ชัดเจน
- WebGL 1.0 ไม่รองรับ 3D texture จึงจำลองการอ่าน 3D texture ด้วยการอ่าน 2D texture สองครั้งและอินเตอร์โพเลชัน
- แนวทางนี้อ้างอิงจาก งานนำเสนอ Google I/O 2011 ของ Gregg Tavares และ คำอธิบายบน webglfundamentals.org
- โค้ดตัวอย่างเดิมเคยมีข้อผิดพลาดในการคำนวณแกน Z ของคิวบ์ ทำให้สีเพี้ยนไปทางน้ำเงิน และถูกแก้ไขในปี 2019
- หากต้องการให้ยังเข้ากันได้กับ WebGL 1.0, OpenGLES 2 และ OpenGL 2.1 โดยไม่มี
OES_texture_3Dควรใช้โค้ด sample 3D texture เวอร์ชันใหม่ล่าสุด
นำเวิร์กโฟลว์เกรดสีเข้ามาด้วย 3D LUT
- การปรับแก้ที่ใช้กับ 3D LUT จะถูกนำไปใช้ตรง ๆ กับวิดีโอหรือฉากกราฟิกที่ผ่าน LUT นั้น
- ในตัวอย่าง มีการนำวิดีโอ V-Log และ LUT เข้าไปประมวลผลใน DaVinci Resolve
- ใช้ V-Log to V-709 3D-LUT ของ Panasonic
- ปรับคอนทราสต์และ white point เพื่อให้สีขาวสว่างเต็มที่
- จากนั้นส่งออก LUT ที่ปรับแล้วอีกครั้ง
- ตัววิดีโอจริงยังคงเป็นต้นฉบับ และการเกรดสีถูกนำไปใช้แบบเรียลไทม์ผ่าน LUT ใน WebGL
- LUT ที่อัปโหลดต้องมีขนาดเท่าเดิม
- ข้อจำกัดในตัวอย่างคือ 1024px × 32px
- ต้องคงรูปแบบคิวบ์ขนาด 32³px ไว้
วิธีใช้ 3D LUT ในอุตสาหกรรมเกม
- การใช้ 3D LUT เพื่อจัดสไตล์สีของเกมจากเครื่องมือภายนอก เป็นเวิร์กโฟลว์มาตรฐานที่รู้จักกันดีในอุตสาหกรรมวิดีโอเกม
- ขั้นตอนทั่วไปมีดังนี้
- จับภาพหน้าจอของฉากที่ต้องการเกรดสี
- เปิดภาพหน้าจอและ 3D LUT ที่ถูก initialize ไว้แล้วพร้อมกันในเครื่องมืออย่าง Photoshop
- ใช้การเกรดสีแบบเดียวกันกับทั้งภาพหน้าจอและ LUT
- ครอปเฉพาะส่วน 3D LUT แล้วส่งออก
- Left 4 Dead ก็ใช้วิธีเดียวกัน
- แม้จะใช้เครื่องมือแก้สีของ Photoshop ได้อย่างอิสระ แต่ไม่สามารถใช้ฟิลเตอร์ที่เปลี่ยนความสัมพันธ์ระหว่างหลายพิกเซลได้
- ฟิลเตอร์สาย convolution อย่าง blur, sharpen หรือ emboss อาจทำให้สีที่ remap แล้วเบลอ และให้ผลลัพธ์ไม่คาดคิด
อบการเกรดสีซับซ้อนให้เป็น LUT เดียว
- เครื่องมือเกรดสีอย่าง DaVinci Resolve สามารถสร้างการแปลงสีและ color grade ที่ซับซ้อน แล้วส่งออกเป็น 3D LUT ได้
- ตัวอย่างใช้ LUT Kodak 2383 เพื่อสร้างลุคแบบฟิล์มพิมพ์
- แปลงวิดีโอ gamma แบบ V-Log ไปเป็น Cineon Film Log
- แปลง color space ไปเป็น Rec.709
- ใช้การจำลองฟิล์ม แล้วแปลง gamma กลับเป็น Rec.709
- สุดท้ายปรับ white point
- รายละเอียดการแปลงที่ซับซ้อนไม่จำเป็นต้องเขียนเองทั้งหมด เพราะสามารถอบรวมเป็น LUT เดียวแล้วนำเข้าแอปกราฟิกได้
- วิดีโอตัวอย่างใช้ฟอร์แมต 8 บิตแบบบีบอัดสูงเพื่อให้เข้ากับบทความ แต่โดยทั่วไปงานลักษณะนี้จะทำกับฟุตเทจ 10 บิต
- ขนาด LUT ที่ใช้งานจริงมักเล็กกว่าที่คิด
- 3D-LUT อย่างเป็นทางการของ Panasonic สำหรับ V-Log to V-709 มีขนาด 33³px
- LUT สำหรับการมอนิเตอร์ในกล้องของ Panasonic ใช้ขนาด 17³px
- แม้แต่กล้องภาพยนตร์ของ Panasonic ระดับราคาหลายหมื่นดอลลาร์ก็ยังใช้ 17³px
ตัวอย่าง LUT นอกงานกราฟิก
- LUT ไม่ได้ใช้แค่ในงานเขียนโปรแกรมกราฟิก
- LUT ยังถูกใช้ในกรณีพอร์ต Tomb Raider ไปยัง Game Boy Advance
- พอร์ตเอนจินโอเพนซอร์ส OpenLara ทำงานหลายส่วนด้วยซอฟต์แวร์ เพราะ Game Boy Advance ไม่มีฟังก์ชัน 3D
- หนึ่งในนั้นคือ LUT สำหรับทำ integer division
- LUT นี้ถูกวางไว้ที่จุดเริ่มต้นของ address space ใน ROM เพื่อหลีกเลี่ยงการใช้ load instruction
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ถ้าไม่มี lookup table ก็คงทำเอฟเฟกต์นี้ไม่ได้เลย: https://twitter.com/zeta0134/status/1756988843851383181
ประเด็นสำคัญคือใช้ lookup table สองชุด ตารางขนาดใหญ่เก็บข้อมูลแสงแบบวงกลมภายในรัศมีที่กำหนดค่าได้รอบตัวผู้เล่น และมีตารางทั้งชุดหนึ่งชุดต่อหนึ่งรัศมี ส่วนตารางที่สองเก็บ ลำดับแบบสุ่มเทียม ของแถวฉากหลัง ทุกครั้งที่เรียกรูทีนแสงจากคบเพลิง จะมีเวลาอัปเดตได้แค่ 1/20 ของหน้าจอ แต่ถ้าทำให้ลำดับสุ่มขึ้นเล็กน้อย ขอบจะดูนุ่มขึ้นและซ่อน raster scan ที่เดิมทีจะเห็นได้ ลำดับนี้เป็น grab bag เพื่อไม่ให้แถวใดอดการอัปเดต และเพราะการคำนวณแบบเรียลไทม์ช้าเกินไปจึงใช้ตาราง
เอฟเฟกต์จาก lookup table ที่ทำให้ประทับใจจริง ๆ ครั้งแรกคือวิธีที่ใช้สร้าง texture tunnel
มี lookup table สำหรับแต่ละพิกเซลบนหน้าจอที่บอกมุมและระยะจากจุดศูนย์กลางหน้าจอ แล้วใช้มันเลือกว่าจะวาง texel ใดในตำแหน่งพิกเซลแต่ละจุด มันดูเหมือนกำลังเคลื่อนที่อยู่ในอุโมงค์เรขาคณิต 3D แต่ต้นทุนต่ำมากจนทำได้แม้บน pico: https://www.lexaloffle.com/bbs/?pid=63818
ตอนแรกคิดว่า Stardust น่าจะใช้เอฟเฟกต์นี้ แต่เมื่อกี้ลองค้นดูแล้ว จริง ๆ แค่เล่น แอนิเมชัน 6 เฟรม ที่วนซ้ำเป็นพื้นหลังเท่านั้น: https://codetapper.com/amiga/sprite-tricks/stardust/
https://web.engr.oregonstate.edu/~mjb/cs557/Projects/Papers/Parallax_Occlusion_Mapping.pdf
มีวิดีโอเกี่ยวกับวิธีที่ Wind Waker ใช้ LUT หลายชุดเพื่อสร้างลุคที่เป็นเอกลักษณ์ BoTW และ ToTK ก็ใช้เทคนิคเดียวกัน
https://www.youtube.com/watch?v=mnxs6CR6Zrk
ผมเป็นผู้เขียนบทความ ถ้ามีคำถามก็ตอบได้
แต่ผมแปลกใจนิดหน่อยกับวิธีที่บทความแนะนำ color grading ด้วย LUT ในบทความดูเหมือนเป็นทางออกเฉพาะทางสุดเท่ที่ L4D2 ใช้ แต่จริง ๆ แล้วมันเป็นมาตรฐานอุตสาหกรรมมานานแล้ว และใช้ในทุกเกมที่ผมเคยทำ ตั้งแต่เกม AAA อย่าง NFS (2015) ไปจนถึงเกมอินดี้ขนาดใหญ่อย่าง Lost in Random
[1] https://www.copetti.org/writings/consoles/game-boy-advance/#operating-system
“Here is every single colormap that matlibplot supports,...”
แม้แต่ในแวดวง กระบวนการทางธุรกิจ ที่น่าเบื่อ เรื่องนี้ก็มีประโยชน์อย่างน่าทึ่ง
บ่อยครั้งเราสามารถลดความซับซ้อนของโค้ดเบสที่เต็มไปด้วยเงื่อนไขให้กลายเป็น lookup table ที่สะอาดตาได้ สิ่งที่ดูเรียบง่ายก็อาจกลายเป็น lookup table 50,000 แถวได้ คนเลยอาจไม่ได้นึกถึงเสมอ สำหรับผู้ใช้ปลายทางอาจดูเยอะ แต่คอมพิวเตอร์ไม่ค่อยใส่ใจนัก แถม lookup table ยังมีลักษณะซ้ำ ๆ จึงมักจัดการได้ง่าย และแม้ในกรณีที่ไม่ง่ายก็ยังมีคุณค่า ผู้ใช้ปลายทางยังตั้งค่าได้โดยไม่ต้องแก้โค้ดด้วย โดยรวมแล้วเป็นแนวคิดที่มีประโยชน์เป็นพิเศษกับหลายสถานการณ์ที่โผล่ขึ้นมาตลอดเวลาตอนเขียนโค้ด business logic
เกมเรโทรใช้ตารางกันเยอะมากจริง ๆ ตอนนั้นความเร็วหน่วยความจำเร็วมากและโปรเซสเซอร์ช้า ดังนั้นการยัดการคำนวณให้ไปอยู่ในตารางให้มากที่สุดเท่าที่ทำได้จึงสมเหตุสมผล ยิ่งทำได้ฉลาดเท่าไร ก็ยิ่งสร้างเกมที่อลังการได้มากขึ้นเท่านั้น
ชอบช่องนั้นนะ เขาปรับแก้โค้ด Mario 64 ทั้งหมดเพื่อให้ม็อดของตัวเองรันได้เร็วขึ้น จนได้ 60FPS ที่เสถียร [0]
[0] https://www.youtube.com/watch?v=t_rzYnXEQlE
ถ้าต้องจัดการกับ LUT เยอะ ๆ ผมกำลังทำแอป Mac สำหรับงาน วิทยาศาสตร์สี ขั้นสูงและการแปลงต่าง ๆ อยู่: https://videovillage.com/lattice
เมื่อก่อนเคยขุดคุ้ยวงการ NES homebrew อยู่บ้าง และได้เห็นเอฟเฟกต์ฟิสิกส์สุดน่าทึ่งในเกมชื่อ Bobl ที่ดูเกินกว่าระบบจะคำนวณได้มาก ปรากฏว่ามันคือ lookup table และทำให้ตระหนักได้ว่าเครื่องมือง่าย ๆ ก็สามารถทำให้ดูเหมือนกระบวนการที่ซับซ้อนมากได้
https://morphcatgames.itch.io/bobl
A Podcast Of Unnecessary Detail ออกตอนที่พูดถึง การพอร์ต Doom ลง SNES และวิธีใช้ LUT กับฟังก์ชันตรีโกณมิติ บริบทคือ SNES ไม่มีกราฟิกโปรเซสเซอร์
https://festivalofthespokennerd.com/podcast/series-3-episode-4/
https://github.com/RandalLinden/DOOM-FX
มันยังหมุนและสเกลพื้นหลังได้ด้วย นั่นคือ Mode 7 ที่ให้นึกถึง Mario Kart และยังรองรับความโปร่งใสด้วยฮาร์ดแวร์ที่เห็นได้ในหลายเกมด้วย ยิ่งกว่านั้น กรณีอย่าง Doom และ Starfox ยังมีชิป Super FX อยู่ในตลับเพื่อจัดการการคำนวณ 3D ดังนั้นในเกมเฉพาะเหล่านั้น เรียกได้ว่าแทบจะกำลังจัดการกราฟิกโปรเซสเซอร์อยู่สองตัว
มีซีรีส์ Retro Game Mechanics Explained ที่อธิบายฮาร์ดแวร์ SNES ได้ยอดเยี่ยมและละเอียดจนเจ็บปวด:
https://www.youtube.com/watch?v=57ibhDU2SAI&list=PLHQ0utQyFw5KCcj1ljIhExH_lvGwfn6GV&index=1
การใช้งาน LUT ที่ผมเคยทำและนึกออกคือ การกระเจิงในชั้นบรรยากาศ, การลงสีสไปรต์, กล้องเล็ง night vision, กล้องเล็ง FLIR, เอฟเฟกต์ “วิดีโอฟีด” ขาวดำ, เอฟเฟกต์ glitch, การทำ shading ของ heightmap, ค่าสัมประสิทธิ์จุดอัลฟาของ plume ไอเสียยานอวกาศ, heatmap การพักเมาส์ของผู้เยี่ยมชมเว็บไซต์, เอฟเฟกต์ผลึก และสุดท้ายคือการทำสี post-processing ใน color space ดิบ
LUT คือการทำให้เห็นภาพของอาร์เรย์ค่าที่รู้อยู่แล้ว และมันมีประโยชน์อย่างน่าทึ่ง
http://www.effectgames.com/demos/canvascycle/
Xbox รุ่นแรกทำเรื่องนี้ได้ไม่ดีนัก และ Photoshop ก็ไม่รองรับ เลยทำให้ความนิยมซาลง แต่ฮาร์ดแวร์สมัยใหม่จัดการ palette swap ที่ทำจาก AESprite ได้สบาย