- เพื่อทำความเข้าใจหลักการทำงานภายในของ OpenGL·Vulkan·Metal·DirectX จึงสร้าง ซอฟต์แวร์เรนเดอเรอร์ ขึ้นมาเองตั้งแต่ต้นโดยไม่ใช้ไลบรารีกราฟิกภายนอก
- แปลง โมเดล 3D เป็นภาพ ที่ประกอบด้วยเมชสามเหลี่ยมและเท็กซ์เจอร์ โดยไม่ครอบคลุมการทำ GUI หรือแอปพลิเคชัน GPU
- โค้ดที่เสร็จสมบูรณ์มีประมาณ 500 บรรทัด และโดยทั่วไปนักเรียนจะเริ่มสร้างเรนเดอเรอร์ที่ใช้งานได้ภายใน 10~20 ชั่วโมง
- มีให้เพียง คลาสจัดการ TGA ที่รองรับ RGB·RGBA·grayscale และฟังก์ชันตั้งค่าพิกเซลเดี่ยว โดยการวาดเส้นและสามเหลี่ยมต้องลงมือเขียนเอง
- การเขียนด้วยตัวเองแทนการคัดลอกโค้ดที่เสร็จแล้วจะช่วยให้เข้าใจแนวคิดของการเรนเดอร์และการทำงานภายในของไลบรารี 3D
กระบวนการสร้างเรนเดอริงไปป์ไลน์ด้วยตัวเอง
- เรียนรู้หลักการทำงานของ เรนเดอริงไปป์ไลน์ โดยอิงโครงสร้างของไลบรารีกราฟิก 3D สมัยใหม่แบบหลวม ๆ
- แทนที่จะสอนวิธีเขียนแอปพลิเคชัน GPU จะจำลองการทำงานภายในด้วยซอฟต์แวร์เรนเดอเรอร์
- อินพุตคือโมเดล 3D ที่ประกอบด้วยเมชสามเหลี่ยมและเท็กซ์เจอร์ และเอาต์พุตคือภาพที่เรนเดอร์แล้ว
- โปรแกรมจะสร้างไฟล์ภาพโดยไม่ต้องมีกราฟิกอินเทอร์เฟซ
- เพื่อให้มี dependency ภายนอกน้อยที่สุด จึงใช้ TGA ซึ่งเป็นฟอร์แมตภาพอย่างง่าย
- ฟังก์ชันที่ให้มาตั้งต้นมีเพียงการโหลดภาพ·บันทึกภาพ และ ตั้งค่าสีของพิกเซลหนึ่งจุด
- ไม่มีฟังก์ชันในตัวสำหรับวาดเส้นหรือสามเหลี่ยม ดังนั้นต้องเขียนเองทั้งหมด
- ตัวอย่างเริ่มต้นจะสร้างเฟรมบัฟเฟอร์ RGB
64x64 ตั้งค่าพิกเซลตามพิกัดสามจุดให้เป็นสีขาว แล้วบันทึกเป็น framebuffer.tga
การบิลด์และรันโค้ด
git clone https://github.com/ssloy/tinyrenderer.git &&
cd tinyrenderer &&
cmake -Bbuild &&
cmake --build build -j &&
build/tinyrenderer obj/diablo3_pose/diablo3_pose.obj obj/floor.obj
- ผลลัพธ์จากการรันจะถูกบันทึกไว้ใน
framebuffer.tga
- แม้โค้ดที่เสร็จสมบูรณ์จะมีราว 500 บรรทัด แต่กระบวนการลงมือทำเองเป็นสิ่งสำคัญต่อความเข้าใจเชิงแนวคิด จึงไม่แนะนำให้ใช้โค้ดที่มีให้แบบตรง ๆ
1 ความคิดเห็น
ความเห็นจาก Hacker News
https://github.com/kshitijl/tinyrenderer-rs
ในรีโพมีสกรีนช็อตจำนวนมากที่บันทึกกระบวนการพัฒนาและบั๊กภาพตลก ๆ เอาไว้ นอกจากหลักการเรนเดอร์แล้ว ยังได้เรียนรู้อย่างมากด้วยว่า CPU สมัยใหม่เร็วมาก และแม้เป็น CPU renderer แบบเธรดเดียว ก็ยังรันเกม 3D แบบโต้ตอบที่มีเอฟเฟ็กต์พิเศษอลังการได้
เป็นช่วงก่อนมี LLM เลยใช้เวลาอย่างน้อยสองเดือน และเวลาส่วนใหญ่หมดไปกับการทำความเข้าใจคณิตศาสตร์คอมพิวเตอร์กราฟิกส์และตามแก้ segmentation fault ของ C
โน้ตการสอนใน GitHub นี้เหมาะกับการทบทวนแนวคิดมากกว่า แม้จะไม่ชอบสไตล์โค้ดในรีโพ และแรสเตอร์ไรเซอร์แบบเก่าก็เรียบง่ายกับไม่มีประสิทธิภาพเกินไป แต่ก็ยังอ่านง่ายกว่าหนังสือของ Foley
แต่ละฉบับพัฒนาภาษาที่ใช้จาก Pascal ไปเป็น C แล้วก็ C กับ C++ และฉบับล่าสุดยังมี C# เล็กน้อย แม้แนวคิดใหม่หลายอย่างจะหายไป แต่ก็ยังมี เนื้อหาที่มีคุณค่า อยู่อีกมาก
การ clipping กับ frustum จัดการได้ด้วยการเลือกจุดของ local tile ส่วนการประกอบ primitive จะง่ายกว่าถ้าจัดการสี่เหลี่ยม clipping ที่แปลงกลับแล้วในระบบพิกัด barycentric สามารถควบคุมความคลาดเคลื่อนจากการปัดเศษได้ด้วยเลขทศนิยมความแม่นยำคู่หรือ fixed-point และจุดยากหลักคือการสร้างค่า Z และ 1/Z ของจุดยอดใหม่ขึ้นมาอีกครั้ง ถ้าเป็นแรสเตอร์ไรเซอร์แบบ lazy attribute composition ที่เหลือก็จะไหลผ่าน pipeline ไปเองตามธรรมชาติ และดูตัวอย่างได้จาก implementation โอเพนซอร์สของ OpenSWR.org
กำแพงทางใจที่ใหญ่ที่สุดคือความไม่คุ้นกับปริภูมิฉายภาพและพิกัด homogeneous ระนาบทั้งหกของ clip space นั้นเรียบง่ายแค่
x = ±w,y = ±w,z = ±wเพียงวนไปตามแต่ละขอบของรูปหลายเหลี่ยม ตัดสินว่าจุดปลายทั้งสองอยู่ด้านในหรือด้านนอก แล้วแทรกเชิงเส้นตำแหน่งจุดตัดขอบเขตและคุณสมบัติของจุดยอด กระบวนการนี้เมื่อนำไปใช้กับทุกระนาบตามลำดับ สามเหลี่ยมจะกลายเป็นรูปหลายเหลี่ยมนูนที่มีจุดยอดได้สูงสุด 9 จุด และสามารถแบ่งเป็นสามเหลี่ยมใหม่ได้ง่าย ถ้าคำนวณ outcode ไว้ล่วงหน้า ก็ข้ามการ clipping ของสามเหลี่ยมที่อยู่ข้างในหรือข้างนอกทั้งหมดได้บทความ: https://dl.acm.org/doi/10.1145/360767.360802
ถ้ายังคงรูปแบบ fixed pipeline ไว้ ก็ใช้ฟังก์ชันวาดที่ค่อนข้างเรียบง่ายแต่จัดการสามเหลี่ยมได้มากอย่างน่าประหลาด