Distance Field เทคนิควาด Font ให้คมในทุก Resolution ของ Valve แม้ขนาด Texture จะเล็ก
เมื่อวานนี้ผมได้ลงข่าวเรื่องที่ Text Mesh Pro ที่เป็น Plug-in สุดฮิตของ Unity ได้ถูก Unity ผนวกเข้าบริษัทแล้วกลายเป็นฟรีในที่สุด
เมื่อวานนี้ผมได้ลงข่าวเรื่องที่ Text Mesh Pro ที่เป็น Plug-in สุดฮิตของ Unity ได้ถูก Unity ผนวกเข้าบริษัทแล้วกลายเป็นฟรีในที่สุด
วันนี้ผมได้ลองโหลดมาใช้แล้วมาเทียบประชันกันกับ built-in ของ Unity นอกจากจะมีเอฟเฟคทำขอบทำ drop shadow ฯลฯ ได้อย่างง่ายดายแล้ว อย่างนึงที่เตะตาผมสุดๆคือ Font มันคมชัดไม่ว่าจะขยายใหญ่แค่ไหนก็ตาม!?
สำหรับคนที่ตอนนี้คิดว่า Font เป็น Vector ขยายแค่ไหนก็ต้องไม่แตกสิ จริงๆแล้วก่อนจะ Render ออกมา ยังไงก็ต้องกลายเป็น Raster ที่ไหนซักแห่งอยู่แล้วครับ ซึ่งใน interactive application อย่างเกมนี้ มาสร้าง texture สดๆตอนจะใช้งานนี่รับไม่ได้ครับเลยต้องทำเป็น texture แผ่นไว้ก่อน (จริงๆก็ได้นะ แต่มันจะมีปัญหาแบบนี้)
เปรียบเทียบ
การเทียบที่เห็นนี้ ผมให้ Texture สุดที่ขนาด 256x256 ทั้งคู่ (ต่อให้ด้วยซ้ำเพราะ Text Mesh Pro ผมเพิ่มตัวสัญลักษณ์เข้าไปเยอะกว่า กินที่เยอะกว่าอีก) ทางซ้ายคืออันเก่า ทางขวาคืออันใหม่ซึ่งใช้ Text Mesh Pro เสกขึ้นมา
เอ๊ะ! จะเห็นว่าของ Text Mesh Pro ดูใน texture ดูเบลอๆกว่าด้วยซ้ำแฮะ ทีนี้มาดูผลการวาด
ตัวเลขพวกนี้ผมใช้ 2 ที่คือเลข Combo ตรงกลางกับเลขคะแนนที่มุมขวาบน ทางซ้ายคืออันเดิม จะเห็นว่าเนื่องจากเลขคะแนนค่อนข้างเล็กกว่าขนาดที่ทำไว้ใน texture ก็เลยคม ส่วนเลข combo ใหญ่กว่านิดนึงก็จะเห็นว่าขอบตัวเลขเบลอเล็กน้อย (คลิกที่ภาพแล้วมันจะขยายให้ดู แล้วจะเห็นว่ามันเบลอ) แต่ไม่อยากทำให้คมไปกว่านี้เพราะกลัวว่า 512x512 จะกินที่เยอะไป
ทางขวาของ Text Mesh Pro จากตัวอักษรเบลอๆบน 256x256 แท้ๆทำไมออกมาคมกริบ?
ความลับอยู่ที่ Distance Field
Text Mesh Pro นี้ใช้ Shader ที่ชื่อ Distance Field ในการวาด Font ซึ่งมันต้องทำอะไรกับภาพเบลอๆนั่นเป็นแน่แท้ถึงได้ออกมาคมอย่างที่เห็นได้ ก็เลยไป Google ดูปรากฏว่าเป็นงานวิจัยของ Valve Improved Alpha-Tested Magnification for Vector Textures and Special Effects โดย Chris Green ซึ่งได้ปรากฏที่ SIGGRAPH 2007
ไปอ่านมาคร่าวๆก็เลยได้ความว่า ปกติถ้าอยากจะเรนเดอร์อะไรให้คมๆเวลาขยาย เราอาจจะใช้เทคนิค alpha test แทน alpha blend ได้ ก็คือ ถ้า blend ก็แปลว่าค่า alpha เท่าไหร่ก็จางลงเท่านั้น ส่วน test ก็คือมี threshold อยู่แล้วถ้าเกินก็เห็น ไม่เกินก็หายไปเลย แบบนี้เวลาขยายจะได้ยังดูขอบคมอยู่ไม่ใช่เบลอๆ (boolean)
แต่ปัญหาคือถ้าเอา alpha จากภาพขยายจนแตกแล้วมา test ผลก็จะออกมาเป็นขอบขยุยแบบภาพ (b)
แต่ปัญหานี้จะหมดไปเมื่อใช้วิธีของ Valve ซึ่งไม่ได้ test โดยภาพขยายโง่ๆ แต่เราจะไปทำภาพพิเศษที่เรียกว่า signed distance field ขึ้นมาก่อน ซึ่งก็คือไอ้ภาพเบลอๆที่ให้ดูนั่นแหละ
ซึ่งอันที่จริงแล้วมันไม่ใช่ภาพเบลอธรรมดาๆ แต่ว่าสีของ pixel สื่อถึง “distance” ต่างหาก ว่าห่างจากขอบที่แท้จริงไกลแค่ไหน (อ้างอิงจากภาพต้นแบบที่อยากจะวาดให้คมในทุกขนาด) ในสเกล 0 ถึง 1 ซึ่ง 0.5 ที่เป็นสีเทา แปลว่าตรงนั้นอยู่ตรงขอบพอดี ตรงไหนสีขาว 1 แปลว่าห่างจากขอบมากไปทางบวก สีดำสนิทก็ห่างมากไปทางลบ
และใช้ภาพนี้เป็น input เข้าไปใน shader distance field ที่ว่า ซึ่งมันทำไงต่อก็ไปอ่านตาม link เปเปอร์ที่ให้ละกันตรงนี้เอาคร่าวๆ
ผลพลอยได้คือ ใส่เงา ใส่ขอบ ก็ใช้ข้อมูลของ distance field นี้ทำให้คมตามๆกันไปด้วยครับ ซึ่งผมคิดว่า Text Mesh Pro ก็ใช้จุดนี้ด้วย ซึ่งเปเปอร์นี้ได้ใช้ในเกม Team Fortress 2
ข้อจำกัดของเทคนิคนี้คือภาพต้องมีสีเดียวเท่านั้น ซึ่งก็เหมาะกับ font เป็นที่สุดครับ
มี artifact นิดหน่อย
มีข้อเสียเล็กน้อย ซึ่งผมคิดว่าถ้าเพิ่มขนาดของ texture distance field น่าจะช่วยได้ ซึ่งก็คือตรงไหนที่เป็นมุมคมๆจะเสียความแม่นยำไปครับ แต่จริงๆมองไกลๆก็ไม่น่าจะเห็นเท่าไหร่ สำหรับใครที่ชอบมนๆแล้วยิ่งดีเลย
แต่จะมนยังไง ใช้ขนาด texture แค่ 256x256 ได้ขนาดนี้ก็สุดยอดละ! ถ้าเทคนิคปกตินี่ซูมแบบนี้แตกกระจุยไปแล้ว