ทดลองทำ blur ปลอมด้วย pixel interpolation

ในเกมผมพอดีว่าจะใช้ blur มาช่วยเติมในส่วนที่ iPad จอทรงสูงกว่า iPhone เพราะอยากให้นักวาดรูปวาดอิงขนาด iPhone อย่างเดียวก็พอ

ทดลองทำ blur ปลอมด้วย pixel interpolation

ในเกมผมพอดีว่าจะใช้ blur มาช่วยเติมในส่วนที่ iPad จอทรงสูงกว่า iPhone เพราะอยากให้นักวาดรูปวาดอิงขนาด iPhone อย่างเดียวก็พอ

ซึ่งถ้าเราทำการ post-process ภาพให้กลายเป็น blur ใน runtime นี่พบว่ามัน lag มากครับ พยายาม optimize ให้ post-process แค่ frame เดียวแล้วเก็บภาพนั้นไว้ใช้ ก็ยังกระตุกอยู่ดีตอน frame เดียวนั้นแหละ

Blur ที่เห็นเป็นเอาภาพชัด (ที่ render ใส่ RenderTexture ไว้) ขนาดย่อครึ่งนึงจากขนาดจอเหลือ 568x320 เพื่อประหยัด RAM หน่อย แล้วมาผ่าน post-processing stack ของ Unity ที่เขาแจกไว้ใน Asset Store

เป็นระบบใหม่ แทนได้ทุก effects แต่จะเหมาะกับเกมคอมมากกว่า มือถือไม่น่าใส่เอฟเฟคอะไรไว้ที่กล้อง

Unity-Technologies/PostProcessing
PostProcessing — Post Processing Stackgithub.com

เอามาใช้แล้วจะสามารถเลือก effects ได้มากมายแบบนี้ ซึ่งในภาพที่เห็นลองเอา Depth Of Field กับ Color Grading มาทำให้มืดๆลง

คาดว่า depth of field มันคงมี algorithm ไฮโซอะไรซักอย่างอยู่ ถ้า blur ที่ simple สุดๆก็คงเป็น box blur ที่แบบเอา kernel (matrix ของตัวเลขกล่องนึง ที่มีสมาชิก n ตัว เลขทุกตัวจะมีค่า 1/n เพราะจะได้รวมกันกลับมาได้ 1) ขนาดเท่าที่ต้องการให้ฟุ้งมาสไลด์ผ่านทุก pixel ให้มันคิดค่าสีใหม่ (สไลด์แล้วคิดเลขคล้ายๆ fourier transform อะครับ) ไม่รู้ถ้าวิธี box blur นั้นมันจะเร็วขึ้นมั้ย แต่พอดีไม่ได้ลอง

มี solution ที่คิดออกคือ ทำเบลอไว้ก่อนแล้วเซฟเก็บไว้เป็นภาพรวมเข้าไปใน asset แต่แบบนั้นนอกจากจะกินที่เกมแล้วถ้าเปลี่ยนอะไรคงต้องมายุ่งยากอัพเดทแก้ทีหลัง

อีก solution นึงก็คือ ใช้ loading screen ทำการ blur คิดเก็บไว้ทั้งหมดก่อน แต่กลัวว่าเกมใหญ่ขึ้นแล้วพื้นที่ texture จะกิน RAM เยอะไปหน่อย อยากคำนวณ blur สดแล้วทิ้งรัวๆได้มากกว่า

ก็เลยได้อีกไอเดียนึงคือใช้สมบัติ resampling ของ texture ให้เป็นประโยชน์ ก็คือทำภาพเล็กมากๆมาแล้วเอามาขยายให้แตกระเบิด (ขยายตอนแสดงผล ไม่ใช่ขยายไฟล์ภาพจริงๆ) ถ้าภาพขนาดเล็กไม่มากอาจจะน่าเกลียด แต่ถ้าเล็กสุดๆอาจจะกลายเป็น blur ที่สวยงามได้

เพราะงั้นเรามาทดสอบสมมติฐานนั้นดูว่าจริงมั้ย

Prototype ใน Photoshop กันดูดีกว่า

จะบอกว่าเป็นสิ่งที่ได้จากการเรียน ป.โทก็ว่าได้ครับ คือจะทำอะไรก่อนอื่นหัวจะคิดหาวิธีลองที่เร็ว and dirty ที่สุดดูก่อน 555

ก่อนอื่นก็ลองย่อภาพให้เล็กก่อน

แล้วขยายกลับมา

ทดสอบดูแล้วขยายกลับมาก็ดู blur ใช้ได้เลย

อันนี้เป็นแบบ bilinear ส่วนตัวไม่ค่อยชอบเท่าไหร่เพราะเห็นเป็นดาวแฉกๆ แต่อาจจะเป็นเพราะภาพยังไม่เล็กพอก็ได้ จะ blur ก็ไม่ใช่ จะชัดก็ไม่ใช่

อันนี้ลองเปลี่ยนเป็น bicubic รู้สึกชอบ algorithm นี้เพราะเห็นเป็นกลมๆนัวๆ แต่ใน Unity มันไม่มีนะครับ ก็หวังว่า bilinear ของ Unity จะออกมาดูดี

ผลลัพธ์ใน Unity

จะเห็นว่าครั้งนี้เทียบกับภาพบนสุดของ blog post นี้ ภาพต้นแบบเล็กมากเหลือแค่ 23 x 13 เอง ซึ่งเซ็ต filter mode เป็น Bilinear ส่วน Trilinear ลองแล้วผลเหมือนกัน (สุดท้ายใช้ Unity มาหลายปีก็ไม่รู้ว่าต่างกันตรงไหน) แค่อย่าเป็น point mode ก็พอ (แต่ถ้าชอบเป็น pixelated ก็ลองก็ได้ครับ แต่มันก็จะไม่ blur)

ผลออกมาใช้ได้อย่างไม่น่าเชื่อเลยครับ! นอกจากจะไม่ต้อง lag กับ blur ของแท้แล้ว ขนาด texture ก็ประหยัด RAM ลงมากเลย

แต่เนื่องจาก blur ปลอมนี้เกิดจาก pixel interpolation แค่ไม่กี่สี (23 x 13 สี) ก็เลยจะเห็นเป็นดวงๆชัดเจนแบบนี้เลยว่าเดิมที pixel มันอยู่ตรงไหนในบางภาพ ที่เนียนน้อยกว่าภาพสีแดงนั่น

blur แท้ไม่มีปัญหานี้ ถ้าโชคร้ายไปโดน pixel สว่างๆเข้า (แต่รอบๆเป็นมืดหมดเลย) อาจจะเกิดผลที่ไม่ค่อยสวยได้ แต่เราก็สามารถใช้ Color ของ Raw Image พยายามย้อมสีให้มันเข้ากันๆได้ครับ

ถ้าปรับสีดำๆหน่อยก็จะจำลองเอฟเฟค Color Grading (มืดลงเท่านั้น เพราะขาวคือปกติ) ของ post-processing stack ได้ในตัวด้วย ไม่เหมือนเด๊ะเพราะมันดำแบบโง่ๆ (จริงๆอยากจะได้ดำแบบ overlay ของ Photoshop แต่กลัวเปลือง draw call) แต่ก็พอใช้ได้ครับ ลองบนมือถืออีกทีไม่ lag แล้วด้วย