เทคนิคการทำเงาในวิดีโอเกม 3D ยุคคลาสสิก
(30fps.net)- เงาในเกม 3D ไม่ได้เกิดขึ้นโดยอัตโนมัติเหมือนในโลกจริง แต่เป็นเอฟเฟกต์ภาพที่ถูก ออกแบบให้ดูสมจริงพอ ภายใต้ข้อจำกัดด้านประสิทธิภาพ
- เกม 3D ยุคแรกจัดการเงาด้วยเทคนิคที่เรียบง่ายแต่รวดเร็ว เช่น ภาพ 2D, blob shadow ใต้เท้า, เท็กซ์เจอร์เงาที่สร้างตอนรันไทม์ และเรขาคณิตที่ฉายลงบนระนาบ
- เมื่อฉากซับซ้อนขึ้น ก็มีการใช้ projected texture, shadow map และ stencil shadow แต่ก็มาพร้อมข้อจำกัด เช่น อาร์ติแฟกต์จากความละเอียด การฉายลงบนพื้นผิวผิดตำแหน่ง และต้นทุนการรันที่คาดเดายาก
- แสงของเลเวลแบบคงที่ใช้ vertex color และ lightmap เพื่อเก็บเงาขนาดใหญ่ และเกมสมัยใหม่ก็ยังใช้รูปแบบดัดแปลงของเทคนิคดั้งเดิมอย่าง Cascaded Shadow Maps, light probes และ capsule shadows ต่อไป
- เงาแบบเรย์เทรซิงเป็นทิศทางที่เป็นธรรมชาติกว่า แต่ในฉากซับซ้อนอย่าง Alan Wake 2 ก็ยังต้องพึ่งพาการสุ่มตัวอย่างและ denoiser ทำให้ trade-off ยังคงกำหนดลักษณะของภาพบนหน้าจอ
เงาในเกมถูกสร้างต่างจากโลกจริง
- ในโลกจริง เงาเป็นผลจากแสงที่ถูกบัง และเมื่อมีแหล่งกำเนิดแสงเดียวอยู่ไกลออกไป เงาหลายเงาที่ซ้อนกันจะไม่ทำให้มืดลงกว่าเดิม
- ในวิดีโอเกม 3D เงาไม่ได้มีอยู่เองตามธรรมชาติ นักพัฒนาจึงต้องออกแบบเองระหว่าง ประสิทธิภาพ กับ ความน่าเชื่อถือทางภาพ
- ในเกม เงาอาจถูกแสดงให้ยิ่งซ้อนกันยิ่งมืดลงได้ เช่น blob shadow ใน Metal Gear Solid
เงา 2D ที่วาดลงบนหน้าจอโดยตรง
- วิธีที่เรียบง่ายที่สุดคือวาด ภาพเงา 2D ลงบนหน้าจอก่อนวาดตัวละคร
- Winter Gold และ MDK ใช้ภาพเงา 2D แบบแอนิเมชันที่ไม่มีการสเกล
- ในฉากที่ตัวละครอยู่ข้างหน้าทุกสิ่ง วิธีง่าย ๆ นี้ก็ทำงานได้ดี
Blob shadow: วงมืดใต้เท้า
- แนวทางที่เรียบง่ายที่สุดใน 3D คือการวาด แผ่นวงกลมสีมืด ไว้ใต้ตัวละคร
- Super Mario 64 ใช้ blob shadow กับตัวละคร และใช้ฟีเจอร์ decal ของฮาร์ดแวร์ Nintendo 64 เพื่อทำให้เงาแสดงเฉพาะบนระนาบพื้นได้ในทางปฏิบัติ เสมือนเป็นการ clipping
- blob shadow สามารถทำแอนิเมชันให้เข้ากับสถานการณ์ได้
- ใน Super Mario 64 เงาจะเล็กลงเมื่อตัวละครกระโดด
- ใน Metal Gear Solid รูปร่างของเงาจะเปลี่ยนไป
- ปัญหาเงาเลยออกไปนอกหน้าผาสามารถจัดการได้ด้วยการฉาย blob quad แบบเดียวกับ decal
เงาระนาบจาก render texture
- หาก blob เป็นเพียงเท็กซ์เจอร์ธรรมดา ก็สามารถเรนเดอร์ตัวละครจากด้านบนตอนรันไทม์เพื่อใช้เป็น เท็กซ์เจอร์เงา ได้
- Crash Bandicoot: Warped ให้ผลลัพธ์ที่ดีด้วยเท็กซ์เจอร์เงาแบบรันไทม์
- Soldier of Fortune ก็ใช้วิธีเดียวกัน แต่ความละเอียดของเงาต่ำ ทำให้ผลลัพธ์ด้อยกว่า
- วิธีนี้ต่างจาก shadow mapping ที่สร้าง depth map จากมุมมองของแสง
- ในที่นี้ใช้ภาพขาว/ดำเป็นเท็กซ์เจอร์
- แนวคิดใกล้เคียงกับ shadow map แบบ 1 บิต
เงาระนาบที่สร้างด้วยเรขาคณิต
- วิธีที่เข้าใจง่ายคือ ฉายวัตถุที่ทอดเงาให้แบนลงบนระนาบ ไปตามทิศตรงข้ามกับแสง แล้วเรนเดอร์วัตถุเดียวกันอีกครั้งด้วยสีดำ
- เงานี้มักคงไว้แบบทึบเพื่อซ่อนปัญหาที่บางส่วนของวัตถุถูกวาดซ้อนทับกัน
- บนพื้นราบจะเข้ากันได้ดี แต่บนภูมิประเทศซับซ้อนความแม่นยำจะลดลง
- F-19 Stealth Fighter วาดเงาเครื่องบินบนรันเวย์
- ในเกมที่ใช้ GLQuake ก็พบเงาระนาบได้เช่นกัน
- Kingpin: Life of Crime ใช้เงาระนาบสีดำได้อย่างใช้ได้
- Half-Life alpha 0.52 เผยให้เห็นปัญหาเรื่องความโปร่งใส
เงาระนาบบนภูมิประเทศ
- Virus ของ David Braben ทำให้ยานอวกาศทอดเงาแบบมองจากด้านบนลงบนภูมิประเทศ
- Interstate ’76 เอียงและยืด เงาระนาบ ให้เข้ากับความลาดชันของพื้น
- บางครั้งเงาทะลุผ่านพื้น
- โดยรวมแล้วดูน่าเชื่อถือพอสมควร
- ในภาพจากซอฟต์แวร์เรนเดอริงจะเห็นเงาโปร่งใสเล็กน้อย ส่วนในภาพที่ใช้ฮาร์ดแวร์เร่งความเร็วจะเป็นเงาดำสนิท
- Interstate ’76 ยังพยายามฉายเงาของวัตถุขนาดใหญ่อย่างสะพานด้วย แต่ผลลัพธ์ยังไม่สำเร็จสมบูรณ์
เงาตกกระทบแบบ projected texture
- วิธี projected texture คือการฉายเท็กซ์เจอร์เงาที่สร้างไว้ข้างต้นลงบน พื้นผิวหลายรูปแบบ ไม่ใช่แค่ระนาบ
- ในเชิงแนวคิด คล้ายกับการยิง Bat-Signal จากท้องฟ้าลงมาด้านล่าง
- Toy Story 3: The Video Game เป็นตัวอย่างของวิธีนี้ และเมื่อเงาซ้อนกับเงาอื่นก็จะมืดขึ้น
- สามารถสร้างเงาที่คมชัดมากได้ แต่ไวต่อเงื่อนไขของพื้นผิว
- อาจดูแปลกบนพื้นผิวแนวตั้ง
- ในบางกรณีอาจปรากฏบนเพดานด้วย
- สามารถเห็นตัวอย่างแบบนี้ได้ในวิดีโอเกมเพลย์ของ Sonic Adventure 2: Battle
- เนื่องจากอาจมองทะลุวัตถุได้ จึงเหมาะกับ กรณีพิเศษ มากกว่า
- ใช้กับเงาของต้นไม้ได้ดีเช่นกัน
Shadow map: วิธีมาตรฐานโดยพฤตินัย
- shadow map คือวิธีที่เกมวาดภาพความลึกจากมุมมองของแสง แล้วอ่านภาพนั้นระหว่างเรนเดอร์โลกเพื่อตัดสินว่าเป็นเงาหรือไม่
- ค่อนข้างติดตั้งได้ง่าย เพราะสามารถใช้โค้ดเรนเดอริงทั่วไปซ้ำได้
- ความละเอียดที่จำกัดก่อให้เกิดอาร์ติแฟกต์ที่รู้จักกันดี เช่น “Peter Panning” และ “shadow acne”
- มีการเสนอเทคนิคหลายแบบเพื่อจัดสรรพื้นที่ของ shadow map ให้กับพื้นผิวใกล้กล้องมากขึ้น
- หากต้องการผลลัพธ์ที่ดูดี โดยทั่วไปต้องมีการ จูน
Stencil shadow: คมชัดแต่มีต้นทุนสูง
- stencil shadow สามารถวาดเงาคมชัดบนพื้นผิวใดก็ได้ และสร้างบรรยากาศแบบ film-noir ที่เลียนแบบด้วย shadow map ได้ยาก
- ตัวอย่างที่เด่นคือ Doom 3 ซึ่งขึ้นชื่อเรื่องห้องมืด
- วิธีนี้แบ่งโลกออกเป็นพื้นที่ที่แสงส่องถึงและพื้นที่เงาด้วย shadow volume ซึ่งเป็นเรขาคณิตที่มองไม่เห็น
- เกมจะใช้แสงเฉพาะกับพิกเซลที่ไม่ได้อยู่ภายใน shadow volume เท่านั้น
- การทำงานต้องวาดโลกหลายครั้ง
- ก่อนอื่นวาดทั้งโลกด้วย ambient lighting
- สำหรับแต่ละ light ให้วาด shadow volume จากนั้นวาดโลกอีกครั้ง โดยให้เฉพาะพิกเซลนอกเงาได้รับผลกระทบ
- ตั้งค่า stencil operation ที่ต่างกันสำหรับ front face และ back face
- หนึ่งในตัวอย่างเชิงพาณิชย์แรกสุดที่เป็นไปได้คือ Severance: Blade of Darkness ซึ่งแสดงเงาที่ดีในปี 2001
- เหตุผลหนึ่งที่ทุกวันนี้ไม่ค่อยใช้กันมาก คือ ต้นทุนการรันคาดเดาได้ยาก
- ต้นทุนเปลี่ยนไปมากตามขนาดที่ shadow volume ปรากฏบนหน้าจอ
- อัลกอริทึมที่ปรับแต่งแล้วบางส่วนเคยมีสิทธิบัตร
- มีลิงก์ที่เกี่ยวข้องซึ่งดูเหมือนว่า Id Software ได้บรรลุข้อตกลงบางอย่างเกี่ยวกับ Doom 3
Stencil shadow แบบนุ่ม
- stencil shadow ไม่จำเป็นต้องคมเสมอไป
- Silent Hill 2 ใช้ stencil shadow บน PlayStation 2 แล้วเบลอภายหลังเพื่อสร้าง เงานุ่ม
- ผลลัพธ์บนคอนโซลดูแทบจะสมบูรณ์แบบ
เงาตัวละครแบบเรียบง่าย
- สามารถให้โมเดลที่ง่ายกว่าโมเดลที่แสดงบนหน้าจอเป็นตัวทอดเงาได้
- ใน Zelda บน Nintendo 64 มีเพียงเท้าของ Link เท่านั้นที่ทอดเงา ส่วนอื่นไม่ทอดเงา
- Hyperblade ใช้วิธีที่โดดเด่น โดยให้ผู้เล่นทอดเงาระนาบในรูปทรงแอนิเมชันแบบง่ายบนสนามฮอกกี้ล้ำยุค
เงาในแสงของเลเวลแบบคงที่
- vertex color และ lightmap เป็นเทคนิคสำหรับเก็บแสงของเลเวลในเกม และในหลายเกมเคยเป็นวิธีเดียวที่ใช้แสดงเงาขนาดใหญ่
-
Vertex color
- Ico แสดงให้เห็นว่าแม้ใช้แค่ per-vertex lighting แบบเก่า ก็สามารถสร้างเงาที่ประณีตได้
- ในแผนที่ low-poly เงาคมก็สามารถแสดงด้วย vertex color ได้
- Tony Hawk Pro Skater 2 ให้ผลลัพธ์ที่น่าประทับใจแม้ใช้วิธีง่าย ๆ นี้
-
Lightmap
- lightmap เป็นวิธีคลาสสิกในการเก็บแสงและเงาของเลเวล
- แทนที่จะเก็บสีไว้ในแต่ละ vertex จะใช้ชุดเท็กซ์เจอร์ชุดที่สองเพื่อแสดงเฉพาะแสง
- สามารถกำหนดความละเอียดต่างกันในแต่ละพื้นที่ได้ จึงทำให้เงาแม่นยำขึ้นในจุดที่จำเป็น
- ใช้หน่วยความจำมากกว่า vertex color
- Quake ถือเป็นเกมที่ทำให้ lightmap แพร่หลาย
เทคนิคดั้งเดิมที่ยังใช้ต่อในเกมสมัยใหม่
- เกมสมัยใหม่ก็ยังใช้เทคนิคเงาแบบดั้งเดิมต่อไปตามสถานการณ์
- Cascaded Shadow Maps ซึ่งเป็นรูปแบบดัดแปลงของ shadow mapping ใช้เพื่อครอบคลุมพื้นที่กว้างอย่างรวดเร็ว
- lightmap สามารถใช้ร่วมกับเทคนิคอื่น เช่น light probes ได้
- Call of Duty ก็ใช้ lightmap
- ตัวอย่างที่เกี่ยวข้องอยู่ในสไลด์ Hemispherical Lighting Insights
- แนวคิดการใช้โมเดลตัวละครแบบเรียบง่ายยังคงสืบต่อมา
- The Last of Us ใช้ทรงกลมที่ยืดออกเพื่อสร้างเงาตัวละครแบบนุ่ม
- Unreal Engine รองรับ capsule shadows สำหรับตัวละคร
- เงาแบบฉายก็ยังคงใช้อยู่
- Hot Wheels Track Attack เรนเดอร์ shadow mesh เป็นเท็กซ์เจอร์ แล้วฉายลงบนสนามแข่ง
- สามารถดูได้จากคำอธิบายในบล็อกของนักพัฒนาและวิดีโอเกมเพลย์
เงาแบบเรย์เทรซิงก็ไม่ได้สมบูรณ์แบบ
- ในเกมที่พยายามจำลองแสงให้ถูกต้องตามฟิสิกส์ เงาจะปรากฏขึ้นเองตามธรรมชาติในจุดที่ไม่มีแสง
- ต่างจาก shadow map รายละเอียดเรขาคณิตขนาดเล็กก็สามารถทอดเงาได้อย่างถูกต้อง
- โคมไฟขนาดใหญ่สร้างเงานุ่มได้อย่างเป็นธรรมชาติ และแสงทางอ้อมสามารถทำให้มุมมืดสว่างขึ้นได้
- เพื่อทำให้เป้าหมายนี้เป็นจริง มีการลงทุนเวลาและต้นทุนจำนวนมากในอัลกอริทึมและฮาร์ดแวร์เรย์เทรซิง
- ฉากในเกมสมัยใหม่จริง ๆ ซับซ้อนมาก จึงต้อง ประมาณค่า การจำลอง
- ใน ray-traced shadows ของ Alan Wake 2 แต่ละพิกเซลจะรับแสงจาก light เพียงดวงเดียวที่ถูกเลือกแบบสุ่ม
- ผลลัพธ์จะถูกส่งต่อไปยัง denoiser เพื่อทำให้ภาพที่มี noise นุ่มลงอย่างชาญฉลาด
- เงาแบบเรย์เทรซิงก็ไม่สมบูรณ์แบบเช่นกัน และจะมีรูปลักษณ์เฉพาะตัวตาม trade-off ที่เลือก
ทางเลือกที่ไม่มีเงา
- บางเกมอาจให้ความสำคัญกับองค์ประกอบอื่นมากกว่าเงา
- การไม่ทำเงาก็อาจเป็นตัวเลือกที่ตั้งใจไว้ได้
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
ไม่ใช่ภาพลวงตาหรือบรรยากาศเชิงศิลป์ แต่เพราะท้องฟ้าเป็นสีฟ้า และในวันที่ท้องฟ้าแจ่มใส เงาจะถูกส่องด้วยแสงที่สะท้อนมาจากท้องฟ้า จึงดูเป็นสีน้ำเงิน
ถ้ามองใต้รถ จะเห็นว่าในส่วนที่มองเห็นท้องฟ้ามีเงาสีน้ำเงินชัดเจน และยิ่งเข้าไปตรงที่ตัวรถบังแม้แต่แสงจากท้องฟ้า ก็จะยิ่งใกล้เคียงสีดำจริง ๆ
ถ้านำเงาจากดวงอาทิตย์สีน้ำเงินสดนี้ไปผสมกับ เงาท้องฟ้า AO ที่นุ่มและมืด ก็จะสร้างเงาที่ดูสวยพอสมควรได้ด้วยต้นทุนต่ำ
เอนจินเรนเดอร์กราฟิกที่ดีควรทำแบบนี้ เงาควรมีเฉดสีอ่อน ๆ ของสีท้องฟ้า
นั่นเลยเป็นเหตุผลที่ภาพสกรีนช็อตเก่า ๆ บางภาพของ No Man's Sky ทำให้รู้สึกขัดตา เหมือนเคยเห็นฉากที่ท้องฟ้าเป็นสีเขียวแต่เงาเป็นสีม่วง
มันช่วยให้กะได้ว่าจะลงพื้นตรงไหนหลังจากกระโดด เหมือนเงาก้อนแบบคลาสสิก แต่ยังรักษาคุณภาพภาพของเงาที่ถูกต้องได้
ถ้าจำไม่ผิด ในสภาพแวดล้อมที่มืด เขายังทำให้เงาสว่างกว่าพื้นเพื่อให้ยังมองเห็นได้ด้วย
ถ้าเป็นแบบนั้น เงาก็จะโผล่ขึ้นและหายไปตอนโมเดลผู้เล่นถูกโหลดและยกเลิกโหลด จึงทำให้ไม่สามารถเห็นเงาได้เว้นแต่จะเห็นตัวผู้เล่นด้วย
Valorant ตั้งใจทำการเรนเดอร์ให้เรียบง่ายสุด ๆ เพื่อให้ได้เฟรมเรตสูงมากแม้บนฮาร์ดแวร์ระดับล่าง ไม่เพียงไม่มีเงาแบบไดนามิก แต่ยังไม่มี แสงแบบไดนามิก เลย และไม่มีความโปร่งใสแบบ alpha ที่ไหนทั้งนั้น
แม้แต่ควันซึ่งปกติจะวาดแบบโปร่งใส ก็ถูกออกแบบเชิงสไตล์ให้วาดเป็นทึบแสงทั้งหมดได้ เพราะมันเร็วกว่า ต่อให้ไม่เกี่ยวกับการโกง เงาแบบไดนามิกก็น่าจะถูกตัดออกอยู่ดีด้วยเหตุผลด้านประสิทธิภาพ
เมื่อเทคนิค ray tracing ถูกนำมาใช้ ผมคิดว่า area light และเงานุ่มจะกลายเป็นมาตรฐาน ถ้าฮาร์ดแวร์ไหว ลองดู Quake 2 RTX ก็พอจะเห็นว่าอนาคตจะหน้าตาเป็นอย่างไร
สุดท้าย ผมเพิ่มบล็อกนี้เข้าไปในรายการทรัพยากรกราฟิกของผมแล้ว: https://github.com/aaron9000/c-game-resources
https://www.youtube.com/watch?v=7BvtML5dIuI
PowerVR PCX1 รองรับ shadow volume ในฮาร์ดแวร์ และมีการใช้งานที่มีประสิทธิภาพกว่าสเตนซิลชาโดว์มาตรฐาน แทนที่จะวาดฉากหลายรอบ โดยพื้นฐานแล้วมันทำ depth-only pre-pass ในฮาร์ดแวร์ลงใน depth/stencil buffer แบบ on-chip เพื่อกำหนดพิกเซลที่มองเห็น ตรวจสอบ shadow volume เพื่อดูว่าพิกเซลใดอยู่ในเงา แล้วจึงทำ texture sampling และ shading
ความสว่างของแสงถูกปรับตามผลของ shadow volume และเนื่องจาก shade เฉพาะพิกเซลที่มองเห็น overdraw จึงไม่ทำให้เปลืองแบนด์วิดท์ texture fetch โดยไม่จำเป็น
Dreamcast ซึ่งอิงจากรุ่นต่อจาก PCX1 ก็มีเกมจำนวนมากที่ใช้ shadow volume การใช้งานบน Dreamcast ยืดหยุ่นกว่า โดย volume สามารถเปลี่ยนได้ไม่ใช่แค่แสง แต่รวมถึงเท็กซ์เจอร์ที่จะใช้, UV mapping และแม้แต่สมการ blending ของโพลีกอนโปร่งใส
เคยทำเงานุ่มบน DC ด้วย (https://imgur.com/a/DyaqzZD ช่วงท้าย) แต่เนื่องจากย้อนกลับไปใช้วิธี stencil ที่มาตรฐานกว่าและต้องวาดเงาซ้ำหลายรอบ ภาระด้าน fill rate จึงค่อนข้างหนัก
ถ้ามีโคมไฟสองดวงส่องคนสามคน ก็จะเกิดเงา 6 เงา จุดที่เงาทั้งหกซ้อนกันทั้งหมดจะกลายเป็น “สีดำ” หรือได้รับเพียงแสงรอบข้าง
ในจุดอื่นที่เงาซ้อนกันน้อยกว่า จะเกิด ไล่ระดับความสว่าง
ถ้าอยู่ในเงาของแหล่งกำเนิดแสง A และอยู่ในเงาของแหล่งกำเนิดแสง B แล้วจะรับแสงจากที่ไหน? ก็มีแต่แสงรอบข้าง และถ้าไม่มีแสงนั้นก็เป็นสีดำ
มีเงื่อนไขกำกับอยู่ว่า “เพราะมีแหล่งกำเนิดแสงเพียงแหล่งเดียวและอยู่ค่อนข้างไกล เงาจึงเป็นเพียงการไม่มีแสง”
เงานั้นเป็นองค์ประกอบเล็ก ๆ อีกอย่างที่ทำให้เกมนี้ให้ความรู้สึกเร็วอย่างมหาศาล
https://imgur.com/a/hOgxr7a
https://www.mobygames.com/game/6233/f29-retaliator/
ช่วงเวลาที่ยังจำได้คือกลางคืนในตรอกด้านหลัง ตอนกำลังขโมยรถ ทันทีที่ตัวละครผู้เล่นกำลังขึ้นรถ ตำรวจก็โผล่พ้นหัวมุมมา “เห็น” การขโมยรถและชักปืน ในจังหวะเดียวกับที่ไฟหน้ารถเปิดขึ้น เงาขนาดใหญ่ของตำรวจที่กำลังเคลื่อนไหวก็ทอดลงบนกำแพงใกล้ ๆ
การซ้อนกันของเงาใน MGS ไม่ได้ผิดทั้งหมด เพราะมีแสงรอบข้าง การกระเจิง และปรากฏการณ์ global illumination อื่น ๆ
คำว่า “Mirror’s Edge (2008, PC) โดยพื้นฐานแล้วคือ Lightmaps: The Game” ตลกแต่ก็ถูก เกมนี้น่าประทับใจตั้งแต่ตอนนั้น และมาดูตอนนี้ก็ยังเป็นแบบนั้น
ตอนนั้นผมคิดว่ามันถูกประเมินต่ำเกินไปอย่างไม่เป็นธรรม อาจเป็นเพราะมันสั้นกว่าคู่แข่งก็ได้