2 คะแนน โดย GN⁺ 2024-03-01 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • 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 สองครั้งและอินเตอร์โพเลชัน
  • โค้ดตัวอย่างเดิมเคยมีข้อผิดพลาดในการคำนวณแกน 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 ความคิดเห็น

 
GN⁺ 2024-03-01
ความคิดเห็นบน Hacker News
  • ถ้าไม่มี lookup table ก็คงทำเอฟเฟกต์นี้ไม่ได้เลย: https://twitter.com/zeta0134/status/1756988843851383181
    ประเด็นสำคัญคือใช้ lookup table สองชุด ตารางขนาดใหญ่เก็บข้อมูลแสงแบบวงกลมภายในรัศมีที่กำหนดค่าได้รอบตัวผู้เล่น และมีตารางทั้งชุดหนึ่งชุดต่อหนึ่งรัศมี ส่วนตารางที่สองเก็บ ลำดับแบบสุ่มเทียม ของแถวฉากหลัง ทุกครั้งที่เรียกรูทีนแสงจากคบเพลิง จะมีเวลาอัปเดตได้แค่ 1/20 ของหน้าจอ แต่ถ้าทำให้ลำดับสุ่มขึ้นเล็กน้อย ขอบจะดูนุ่มขึ้นและซ่อน raster scan ที่เดิมทีจะเห็นได้ ลำดับนี้เป็น grab bag เพื่อไม่ให้แถวใดอดการอัปเดต และเพราะการคำนวณแบบเรียลไทม์ช้าเกินไปจึงใช้ตาราง

    • ดูเจ๋งมาก และกราฟิกดีกว่า เกม NES ไหน ๆ ที่จำได้มาก จนดูเหมือนกราฟิกระดับ SNES น่าจะรันบนอีมูเลเตอร์อยู่ เลยสงสัยว่าอีมูเลเตอร์นั้นจำกัดประสิทธิภาพให้อยู่ระดับ NES หรือเปล่า
    • ดูเป็นเกมที่เจ๋งจริง ๆ สงสัยว่าได้แรงบันดาลใจจาก Crypt of the Necrodancer ไหม เป็นหนึ่งในเกมโปรดของผม เคยคิดว่าถ้ากลไกแบบนั้นถูกคิดค้นขึ้นในยุคนั้น NES หรือคอนโซลเก่าอื่น ๆ จะรับมือได้แค่ไหน และนี่ดูเหมือนจะแสดงให้เห็นว่าเป็นไปได้
    • การ อัปเดต 1/20 ใช้ได้ดีเพราะทำให้เกิดภาพลวงตาว่าไทล์ค่อย ๆ เผยออกมาอย่างเป็นธรรมชาติเมื่อโคมไฟเคลื่อนที่ เจ๋งที่เอฟเฟกต์แบบนี้ทำให้หลอกตาได้
    • น่าสนใจเสมอที่เกมบนคอนโซลเดียวกันค่อย ๆ ดูสวยขึ้นมากเมื่อผู้คนเรียนรู้วิธีเขียนโค้ด เช่น Mario 1 กับ 3 หรือเกม Zelda สองภาคบน N64
    • คีย์เวิร์ดสำหรับค้นหาส่วนที่ว่า “เก็บลำดับแบบสุ่มเป็น grab bag เพื่อไม่ให้แถวอดการอัปเดต” น่าจะเป็น quasirandom
  • เอฟเฟกต์จาก 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/

    • ถ้ามอง พาเลตสี เป็น lookup table การวนพาเลตก็พบได้บ่อยมากและดูเกี่ยวข้องกันทีเดียว
    • การใช้หลักการนี้ในแบบขั้นสูงคือ parallax occlusion mapping (POM) ทำเงาตัวเองได้ด้วย
      https://web.engr.oregonstate.edu/~mjb/cs557/Projects/Papers/Parallax_Occlusion_Mapping.pdf
    • ถ้าอยากดูว่ามันทำงานอย่างไร ใต้เดโมมีปุ่ม Code ▽ เล็ก ๆ อยู่
    • เมื่อดู สมมาตร ในบางกรณี ก็อาจพบวิธีแก้ที่สะดวกได้
  • มีวิดีโอเกี่ยวกับวิธีที่ Wind Waker ใช้ LUT หลายชุดเพื่อสร้างลุคที่เป็นเอกลักษณ์ BoTW และ ToTK ก็ใช้เทคนิคเดียวกัน
    https://www.youtube.com/watch?v=mnxs6CR6Zrk

  • ผมเป็นผู้เขียนบทความ ถ้ามีคำถามก็ตอบได้

    • ตัวอย่างการใช้ LUT ดีมาก และดีใจที่มีบทความอธิบายเรื่องแบบนี้ได้อย่างกระชับ ชอบด้วยที่ใช้ WebGL และให้ลองอัปโหลดข้อมูลเองได้
      แต่ผมแปลกใจนิดหน่อยกับวิธีที่บทความแนะนำ color grading ด้วย LUT ในบทความดูเหมือนเป็นทางออกเฉพาะทางสุดเท่ที่ L4D2 ใช้ แต่จริง ๆ แล้วมันเป็นมาตรฐานอุตสาหกรรมมานานแล้ว และใช้ในทุกเกมที่ผมเคยทำ ตั้งแต่เกม AAA อย่าง NFS (2015) ไปจนถึงเกมอินดี้ขนาดใหญ่อย่าง Lost in Random
    • บทความดี และอยากเสริมส่วนท้ายเล็กน้อย Game Boy Advance รองรับการหารจำนวนเต็มได้ระดับหนึ่ง แต่ไม่ใช่แบบเร่งด้วยฮาร์ดแวร์ [1] โมเดล LUT น่าจะเป็นเพราะเหตุผลด้านประสิทธิภาพ และการตัดสินใจนั้นก็ดูสมเหตุสมผล
      [1] https://www.copetti.org/writings/consoles/game-boy-advance/#operating-system
    • สับสนอยู่นานเพราะพิมพ์ผิด นึกว่ามีไลบรารี plotting อีกตัวหนึ่ง
      “Here is every single colormap that matlibplot supports,...”
    • GIF แอนิเมชันเยอะเกินไป น่ารำคาญและทำให้เสียสมาธิ มีมบูมเมอร์ฝืด ๆ สไตล์ยุค 2010 ก็ไม่จำเป็น GIF สีฉูดฉาดเด้งขึ้นมาตลอด ทำให้อ่านบทความลำบาก
  • แม้แต่ในแวดวง กระบวนการทางธุรกิจ ที่น่าเบื่อ เรื่องนี้ก็มีประโยชน์อย่างน่าทึ่ง
    บ่อยครั้งเราสามารถลดความซับซ้อนของโค้ดเบสที่เต็มไปด้วยเงื่อนไขให้กลายเป็น lookup table ที่สะอาดตาได้ สิ่งที่ดูเรียบง่ายก็อาจกลายเป็น lookup table 50,000 แถวได้ คนเลยอาจไม่ได้นึกถึงเสมอ สำหรับผู้ใช้ปลายทางอาจดูเยอะ แต่คอมพิวเตอร์ไม่ค่อยใส่ใจนัก แถม lookup table ยังมีลักษณะซ้ำ ๆ จึงมักจัดการได้ง่าย และแม้ในกรณีที่ไม่ง่ายก็ยังมีคุณค่า ผู้ใช้ปลายทางยังตั้งค่าได้โดยไม่ต้องแก้โค้ดด้วย โดยรวมแล้วเป็นแนวคิดที่มีประโยชน์เป็นพิเศษกับหลายสถานการณ์ที่โผล่ขึ้นมาตลอดเวลาตอนเขียนโค้ด business logic

    • แล้วสุดท้ายก็ได้ DSL ขึ้นมา
    • lookup table แบบ double-buffered เนี่ยนะ!
  • เกมเรโทรใช้ตารางกันเยอะมากจริง ๆ ตอนนั้นความเร็วหน่วยความจำเร็วมากและโปรเซสเซอร์ช้า ดังนั้นการยัดการคำนวณให้ไปอยู่ในตารางให้มากที่สุดเท่าที่ทำได้จึงสมเหตุสมผล ยิ่งทำได้ฉลาดเท่าไร ก็ยิ่งสร้างเกมที่อลังการได้มากขึ้นเท่านั้น

    • ก็ไม่ใช่เสมอไป และคงขึ้นอยู่กับว่า เรโทร หมายถึงแพลตฟอร์มไหน Kaze Emanuar บน YouTube ทำงานพัฒนา N64 เยอะมาก และราวครึ่งหนึ่งของเรื่องการปรับแต่งประสิทธิภาพคือบัสหน่วยความจำส่งผลต่อการ optimize สารพัดอย่างอย่างไร ใน Mario 64 เขาเปลี่ยน lookup table เดิมสำหรับฟังก์ชันไซน์เป็นสูตรประมาณค่า เพราะสูตรประมาณค่านั้นเร็วกว่าและแม่นยำพอแล้ว พูดให้ตรงคือเป็นสูตรประมาณค่า 2 แบบสำหรับวัตถุประสงค์ต่างกัน
      ชอบช่องนั้นนะ เขาปรับแก้โค้ด Mario 64 ทั้งหมดเพื่อให้ม็อดของตัวเองรันได้เร็วขึ้น จนได้ 60FPS ที่เสถียร [0]
      [0] https://www.youtube.com/watch?v=t_rzYnXEQlE
    • จำยุคที่จำกัดความละเอียดของการหมุนไว้ที่หน่วย 360/256 องศา เพื่อให้ใส่ได้ในหนึ่งไบต์ แล้วใช้ค่านั้นเป็นดัชนีใน lookup table ของฟังก์ชันตรีโกณมิติได้เลย :)
  • ถ้าต้องจัดการกับ LUT เยอะ ๆ ผมกำลังทำแอป Mac สำหรับงาน วิทยาศาสตร์สี ขั้นสูงและการแปลงต่าง ๆ อยู่: https://videovillage.com/lattice

  • เมื่อก่อนเคยขุดคุ้ยวงการ NES homebrew อยู่บ้าง และได้เห็นเอฟเฟกต์ฟิสิกส์สุดน่าทึ่งในเกมชื่อ Bobl ที่ดูเกินกว่าระบบจะคำนวณได้มาก ปรากฏว่ามันคือ lookup table และทำให้ตระหนักได้ว่าเครื่องมือง่าย ๆ ก็สามารถทำให้ดูเหมือนกระบวนการที่ซับซ้อนมากได้
    https://morphcatgames.itch.io/bobl

    • ไม่ปฏิเสธว่าเอฟเฟกต์นั้นน่าประทับใจ แต่ถ้าสิ่งที่พูดถึงคือระลอกบนผิวน้ำหรือ คลื่นแคพิลารี ก็สงสัยว่า NES จะคำนวณ cellular automaton 1 มิติแบบเรียลไทม์ได้ยากขนาดนั้นจริงหรือไม่
  • A Podcast Of Unnecessary Detail ออกตอนที่พูดถึง การพอร์ต Doom ลง SNES และวิธีใช้ LUT กับฟังก์ชันตรีโกณมิติ บริบทคือ SNES ไม่มีกราฟิกโปรเซสเซอร์
    https://festivalofthespokennerd.com/podcast/series-3-episode-4/
    https://github.com/RandalLinden/DOOM-FX

    • คำว่า “SNES ไม่มีกราฟิกโปรเซสเซอร์” นั้นผิดถนัด แม้แต่ NES ก็ยังมี นอกจาก CPU ของ SNES ซึ่งเป็น Motorola 65c816 โคลนแล้ว PPU (picture processing unit) ยังเป็นชิปคัสตอมที่ให้เลย์เอาต์หลายแบบสำหรับส่งพื้นหลังแบบไทล์และสไปรต์ออกไปขณะที่ทีวี CRT วาดแต่ละ scanline ทางกายภาพ
      มันยังหมุนและสเกลพื้นหลังได้ด้วย นั่นคือ 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 คือการทำให้เห็นภาพของอาร์เรย์ค่าที่รู้อยู่แล้ว และมันมีประโยชน์อย่างน่าทึ่ง

    • “การลงสีสไปรต์” นี่ เด็กสมัยนี้ลืม สไปรต์แบบอิงพาเล็ต กันหมดแล้วสินะ! คำว่า “palette swap” คิดว่ามาจากไหนกันล่ะ? ;)
      http://www.effectgames.com/demos/canvascycle/
      Xbox รุ่นแรกทำเรื่องนี้ได้ไม่ดีนัก และ Photoshop ก็ไม่รองรับ เลยทำให้ความนิยมซาลง แต่ฮาร์ดแวร์สมัยใหม่จัดการ palette swap ที่ทำจาก AESprite ได้สบาย