กลิ้งกราฟฉากของฉันเอง


23

สวัสดีการพัฒนาเกม SE!

ฉันคลานผ่าน OpenGL ด้วยความหวังในการสร้างเอ็นจิ้นเกมที่เรียบง่ายและมีน้ำหนักเบามาก ฉันมองว่าโครงการนี้เป็นประสบการณ์การเรียนรู้ที่อาจสร้างรายได้เพียงเล็กน้อยในตอนท้าย แต่จะสนุกด้วยวิธีใดวิธีหนึ่ง

จนถึงตอนนี้ฉันใช้ GLFW เพื่อรับ I / O พื้นฐาน, หน้าต่าง (ด้วยคีย์เต็มหน้าจอ F11 ที่สวยงามมาก) และแน่นอนว่าเป็นบริบทของ OpenGL ฉันยังใช้ GLEW เพื่อแสดงส่วนขยาย OpenGL ที่เหลือเนื่องจากฉันใช้ Windows และฉันต้องการใช้ OpenGL 3.0 ขึ้นไปทั้งหมด

ซึ่งพาฉันไปที่กราฟของฉาก ในระยะสั้นฉันต้องการที่จะม้วนของตัวเอง การตัดสินใจครั้งนี้เกิดขึ้นหลังจากได้ดู OSG และอ่านบทความสองสามฉบับเกี่ยวกับวิธีที่แนวคิดของกราฟฉากกลายเป็นบิดงอและหัก หนึ่งบทความดังกล่าวอธิบายว่ากราฟฉากได้พัฒนาเป็น ...

จากนั้นเราเพิ่มสิ่งพิเศษทั้งหมดนี้เข้าไปเช่นเครื่องประดับที่แขวนอยู่บนต้นคริสต์มาสยกเว้นว่าเครื่องประดับบางชิ้นเป็นสเต็กที่ชุ่มฉ่ำและบางส่วนก็เป็นวัวที่ยังมีชีวิตอยู่

ตามการเปรียบเทียบฉันต้องการสเต็กเนื้อของกราฟฉากควรเป็นอะไรโดยไม่ต้องใส่สายรหัสพิเศษหรือวัวทั้งหมด

ดังนั้นในใจฉันพบว่าตัวเองสงสัยว่ากราฟซีนควรเป็นอะไรและควรใช้กราฟฉากง่าย ๆ อย่างไร? นี่คือสิ่งที่ฉันมี ...

ผู้ปกครองหนึ่งคนต้นไม้ n-children หรือ DAG ซึ่ง ...

  • ควรติดตามการเปลี่ยนแปลงวัตถุเกม (ตำแหน่งการหมุนขนาด)
  • ควรพักสถานะการเรนเดอร์เพื่อเพิ่มประสิทธิภาพ
  • ควรจัดให้มีวิธีการคัดวัตถุที่ไม่ได้อยู่ในมุมมอง frustum

ด้วยคุณสมบัติดังต่อไปนี้ ...

  • โหนดทั้งหมดควรถือว่าสามารถใช้งานได้ (แม้ว่าพวกเขาจะไม่ได้แสดงผล) ซึ่งหมายความว่าพวกเขา ...

    • ทุกคนควรมีการคัด (), รัฐ () และวิธีการวาด () (กลับ 0 ถ้ามองไม่เห็น)
    • cull () เรียก cull () ซ้ำ ๆ บนเด็กทุกคนดังนั้นจึงสร้างตาข่ายที่สมบูรณ์สำหรับโหนดทั้งหมดและลูกทั้งหมด อีกวิธีหนึ่ง hasChanged () อาจทำให้ตาข่ายแบบคงที่ที่เรียกว่าไม่จำเป็นต้องมีการคำนวณเรขาคณิตของพวกเขาในการคำนวณแต่ละเฟรม สิ่งนี้จะทำงานเช่นนั้นหากโหนดใด ๆ ในทรีย่อยมีการเปลี่ยนแปลงรูปทรงเรขาคณิตทั้งหมดลงไปที่รูทจะถูกสร้างใหม่
  • สถานะการแสดงผลจะถูกเก็บไว้ในการแจงนับอย่างง่ายแต่ละโหนดจะเลือกจากการแจงนับชุดสถานะ OpenGL ที่มันต้องการและสถานะนั้นจะถูกตั้งค่าก่อนที่จะดึง () เรียกว่าบนโหนดนั้น สิ่งนี้อนุญาตให้ทำการแบตช์โหนดทั้งหมดของชุดสถานะที่กำหนดจะถูกเรนเดอร์ด้วยกันจากนั้นชุดสถานะถัดไปจะถูกตั้งค่าและอื่น ๆ

  • ไม่มีโหนดใดควรถือข้อมูล geometry / shader / texture โดยตรงแทนที่จะใช้ node ควรชี้ไปยังวัตถุที่ใช้ร่วมกัน (อาจถูกจัดการโดยวัตถุ singleton บางตัวเช่นตัวจัดการทรัพยากร)

  • กราฟทิวทัศน์ควรสามารถอ้างอิงกราฟฉากอื่น ๆ (อาจใช้โหนดพร็อกซี) เพื่ออนุญาตสถานการณ์เช่นนี้จึงอนุญาตให้คัดลอกแบบจำลอง / วัตถุหลายตาข่ายที่ซับซ้อนเพื่อคัดลอกไปรอบ ๆ กราฟฉากโดยไม่ต้องเพิ่มข้อมูลมากมาย

ฉันหวังว่าจะได้รับคำติชมที่มีค่าเกี่ยวกับการออกแบบปัจจุบันของฉัน ฟังก์ชั่นขาดหายไปหรือไม่? มีวิธี / รูปแบบการออกแบบที่ดีขึ้นอย่างมากมายหรือไม่? ฉันขาดคอนเซ็ปต์ที่ใหญ่กว่าซึ่งจำเป็นต้องมีในการออกแบบนี้สำหรับเกม 3D ที่ค่อนข้างง่ายหรือไม่? เป็นต้น

ขอบคุณ - โคดี้

คำตอบ:


15

แนวคิด

โดยพื้นฐานแล้วกราฟฉากไม่มีอะไรมากไปกว่ากราฟอะไซโคลแบบสองทิศทางซึ่งทำหน้าที่เป็นตัวแทนของชุดของความสัมพันธ์เชิงพื้นที่

เอนจิ้นในป่ามีแนวโน้มที่จะรวมสารพัดอื่น ๆ ลงในกราฟฉากตามที่ระบุไว้ ไม่ว่าคุณจะเห็นว่าในขณะที่เนื้อหรือวัวนั้นอาจขึ้นอยู่กับประสบการณ์ของคุณกับเครื่องยนต์และห้องสมุด

น้ำหนักเบา

ฉันชอบสไตล์ Unity3D ที่มีโหนดกราฟฉากของคุณ (ซึ่งหัวใจของมันคือโทโพโลยีมากกว่าโครงสร้างเชิงพื้นที่ / ภูมิประเทศ) โดยเนื้อแท้จะมีพารามิเตอร์เชิงพื้นที่และฟังก์ชันการทำงาน ในเอ็นจิ้นของฉันโหนดของฉันมีน้ำหนักเบากว่า Unity3D ซึ่งพวกมันสืบทอดสมาชิกขยะจำนวนมากที่ไม่จำเป็นจากซูเปอร์คลาส / อินเตอร์เฟสที่ใช้งาน: นี่คือสิ่งที่ฉันมี - เบาพอ ๆ กับที่คุณจะได้รับ:

  • สมาชิกตัวชี้พาเรนต์ / ลูก
  • pre-transform สมาชิกพารามิเตอร์ spatial: ตำแหน่ง xyz, pitch, yaw และ roll
  • เมทริกซ์การแปลง เมทริกซ์ในห่วงโซ่แบบลำดับชั้นสามารถอย่างรวดเร็วและง่ายดายคูณด้วยการเดินขึ้น / ลงต้นไม้ซ้ำ ๆ เพื่อให้การแปลงเชิงพื้นที่แบบลำดับชั้นซึ่งเป็นคุณสมบัติหลักของกราฟฉาก
  • updateLocal()วิธีการที่ปรับปรุงเพียงแค่นี้โหนดเป็นแปลงเมทริกซ์
  • updateAll()วิธีการที่ปรับปรุงนี้และลูกหลานโหนดเปลี่ยนเมทริกซ์

... ฉันยังรวมถึงสมการของตรรกะการเคลื่อนไหวและทำให้สมาชิกความเร็ว / การเร่ง (เชิงเส้นและเชิงมุม) ในชั้นโหนดของฉัน คุณสามารถนำมาใช้และจัดการกับมันในตัวควบคุมหลักของคุณแทนหากคุณต้องการ แต่นั่นคือ - น้ำหนักเบามากอย่างแน่นอน จำไว้ว่าคุณสามารถมีสิ่งเหล่านี้ได้ในเอนทิตีหลายพันรายการ ดังนั้นตามที่คุณแนะนำไว้ให้เบา

การสร้างลำดับชั้น

สิ่งที่คุณพูดเกี่ยวกับกราฟฉากอ้างอิงกราฟฉากอื่น ๆ ... ฉันกำลังรอหมัดเด็ด? แน่นอนพวกเขาทำ นั่นคือการใช้งานหลักของพวกเขา คุณสามารถเพิ่มโหนดใด ๆ ไปยังโหนดอื่นและการแปลงควรเกิดขึ้นโดยอัตโนมัติภายในพื้นที่ภายในของการแปลงใหม่ สิ่งที่คุณกำลังทำคือการเปลี่ยนตัวชี้ไม่ใช่ว่าคุณกำลังคัดลอกข้อมูลอยู่! โดยการเปลี่ยนตัวชี้คุณจะมีกราฟฉากที่ลึกกว่า หากใช้พร็อกซี่ทำให้สิ่งต่าง ๆ มีประสิทธิภาพมากขึ้นโดยทั้งหมด แต่ฉันไม่เคยเห็นความต้องการ

หลีกเลี่ยงลอจิกที่เกี่ยวข้องกับ Render

ลืมเกี่ยวกับการเรนเดอร์ขณะที่คุณเขียนคลาสโหนดกราฟของฉากหรือคุณจะทำให้คุณสับสน สิ่งที่สำคัญคือคุณมีโมเดลข้อมูลไม่ว่าจะเป็นกราฟฉากหรือไม่สำคัญและนักแสดงบางคนจะตรวจสอบโมเดลข้อมูลและแสดงวัตถุในโลกตามลำดับไม่ว่าจะเป็น 1, 2 , 3 หรือ 7 ส่วนข้อมูล จุดที่ฉันทำคือ: อย่าปนเปื้อนกราฟฉากของคุณด้วยตรรกะการแสดงผล กราฟฉากเป็นเรื่องเกี่ยวกับโทโพโลยีและภูมิประเทศ - เช่นการเชื่อมต่อและลักษณะเชิงพื้นที่ สิ่งเหล่านี้เป็นสถานะที่แท้จริงของการจำลองและมีอยู่แม้ในกรณีที่ไม่มีการเรนเดอร์ (ซึ่งสามารถใช้รูปแบบใด ๆ ภายใต้ดวงอาทิตย์จากมุมมองบุคคลที่หนึ่งไปยังกราฟสถิติไปยัง โหนดไม่ได้ชี้ไปที่วัตถุที่เกี่ยวข้องกับการเรนเดอร์ - อย่างไรก็ตามการย้อนกลับอาจเป็นจริงได้ พิจารณาสิ่งนี้ด้วย: ไม่ใช่กราฟกราฟฉากในต้นไม้ทั้งหมดของคุณที่จะแสดงผลได้ หลายคนจะเป็นเพียงภาชนะบรรจุ ดังนั้นทำไมถึงต้องจัดสรรหน่วยความจำสำหรับตัวชี้ไปยังวัตถุ? แม้แต่สมาชิกตัวชี้ที่ไม่เคยใช้ยังคงใช้หน่วยความจำ ดังนั้นย้อนกลับทิศทางตัวชี้: อินสแตนซ์ที่เกี่ยวข้องกับการแสดงผลอ้างอิงแบบจำลองข้อมูล (ซึ่งอาจจะเป็นหรือรวมถึงโหนดกราฟฉากของคุณ) ไม่ใช่ในทางกลับกัน และถ้าคุณต้องการวิธีง่ายๆในการเรียกใช้ผ่านรายการคอนโทรลเลอร์ของคุณ แต่ยังสามารถเข้าถึงมุมมองที่เกี่ยวข้องได้ให้ใช้พจนานุกรม / hashtable ซึ่งใช้เวลา O (1) ในการอ่าน ด้วยวิธีนี้ไม่มีสิ่งเจือปนและตรรกะการจำลองของคุณไม่สนใจสิ่งที่แสดงอยู่ในสถานที่ซึ่งทำให้วันและคืนของการเข้ารหัสของคุณ ดังนั้นทำไมถึงต้องจัดสรรหน่วยความจำสำหรับตัวชี้ไปยังวัตถุ? แม้แต่สมาชิกตัวชี้ที่ไม่เคยใช้ยังคงใช้หน่วยความจำ ดังนั้นย้อนกลับทิศทางตัวชี้: อินสแตนซ์ที่เกี่ยวข้องกับการแสดงผลอ้างอิงแบบจำลองข้อมูล (ซึ่งอาจจะเป็นหรือรวมถึงโหนดกราฟฉากของคุณ) ไม่ใช่ในทางกลับกัน และถ้าคุณต้องการวิธีง่ายๆในการเรียกใช้ผ่านรายการคอนโทรลเลอร์ของคุณ แต่ยังสามารถเข้าถึงมุมมองที่เกี่ยวข้องได้ให้ใช้พจนานุกรม / hashtable ซึ่งใช้เวลา O (1) ในการอ่าน ด้วยวิธีนี้ไม่มีสิ่งเจือปนและตรรกะการจำลองของคุณไม่สนใจสิ่งที่แสดงอยู่ในสถานที่ซึ่งทำให้วันและคืนของการเข้ารหัสของคุณ ดังนั้นทำไมถึงต้องจัดสรรหน่วยความจำสำหรับตัวชี้ไปยังวัตถุ? แม้แต่สมาชิกตัวชี้ที่ไม่เคยใช้ยังคงใช้หน่วยความจำ ดังนั้นย้อนกลับทิศทางตัวชี้: อินสแตนซ์ที่เกี่ยวข้องกับการแสดงผลอ้างอิงแบบจำลองข้อมูล (ซึ่งอาจจะเป็นหรือรวมถึงโหนดกราฟฉากของคุณ) ไม่ใช่ในทางกลับกัน และถ้าคุณต้องการวิธีง่ายๆในการเรียกใช้ผ่านรายการคอนโทรลเลอร์ของคุณ แต่ยังสามารถเข้าถึงมุมมองที่เกี่ยวข้องได้ให้ใช้พจนานุกรม / hashtable ซึ่งใช้เวลา O (1) ในการอ่าน ด้วยวิธีนี้ไม่มีสิ่งเจือปนและตรรกะการจำลองของคุณไม่สนใจสิ่งที่แสดงอยู่ในสถานที่ซึ่งทำให้วันและคืนของการเข้ารหัสของคุณ และถ้าคุณต้องการวิธีง่ายๆในการเรียกใช้ผ่านรายการคอนโทรลเลอร์ของคุณ แต่ยังสามารถเข้าถึงมุมมองที่เกี่ยวข้องได้ให้ใช้พจนานุกรม / hashtable ซึ่งใช้เวลา O (1) ในการอ่าน ด้วยวิธีนี้ไม่มีสิ่งเจือปนและตรรกะการจำลองของคุณไม่สนใจสิ่งที่แสดงอยู่ในสถานที่ซึ่งทำให้วันและคืนของการเข้ารหัสของคุณ และถ้าคุณต้องการวิธีง่ายๆในการเรียกใช้ผ่านรายการคอนโทรลเลอร์ของคุณ แต่ยังสามารถเข้าถึงมุมมองที่เกี่ยวข้องได้ให้ใช้พจนานุกรม / hashtable ซึ่งใช้เวลา O (1) ในการอ่าน ด้วยวิธีนี้ไม่มีสิ่งเจือปนและตรรกะการจำลองของคุณไม่สนใจสิ่งที่แสดงอยู่ในสถานที่ซึ่งทำให้วันและคืนของการเข้ารหัสของคุณโลกง่ายขึ้น

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

หมายเหตุสุดท้าย ...

ฉันรู้สึกว่าคุณมาจากพื้นหลัง Flash (โดยเฉพาะ AS3) โดยให้รายละเอียดทั้งหมดเกี่ยวกับการแสดงผลที่นี่ ใช่กระบวนงานของ Flash Stage / DisplayObject รวมตรรกะการแสดงผลทั้งหมดไว้เป็นส่วนหนึ่งของ Scenegraph แต่ Flash สร้างข้อสันนิษฐานมากมายที่คุณไม่ต้องการ สำหรับเครื่องยนต์เกมเต็มเปี่ยมมันจะดีกว่าที่จะไม่ผสมสองสำหรับเหตุผลของการทำงาน, ความสะดวกสบายและการควบคุมความซับซ้อนรหัสผ่านที่เหมาะสมSoC


1
ขอบคุณนิค จริงๆแล้วฉันเป็นอนิเมเตอร์ 3 มิติ (ไม่ใช่ 3D จริง ๆ ) จึงกลายเป็นโปรแกรมเมอร์ดังนั้นฉันมักจะคิดในแง่ของกราฟิก ถ้านั่นไม่เลวร้ายพอฉันเริ่มต้นใน Java และสอดแนมตัวเองจากความคิด "ทุกอย่างต้องเป็นวัตถุ" ที่ปลูกฝังในภาษานั้น คุณเชื่อฉันว่ากราฟฉากควรแยกออกจากการเรนเดอร์และการเลือกรหัสตอนนี้เกียร์ของฉันหมุนไปตามวิธีการที่จะทำให้สำเร็จ ฉันคิดว่าการรักษา renderer เหมือนมันเป็นระบบที่แตกต่างกันของตัวเองที่อ้างอิงภาพกราฟสำหรับแปลงข้อมูล ฯลฯ
โคดี้สมิ ธ

1
@CodySmith ดีใจที่ได้ช่วย ปลั๊กไร้ยางอาย แต่ฉันรักษากรอบซึ่งเป็นเรื่องเกี่ยวกับ SoC / MVC ในการทำเช่นนี้ฉันได้มากับค่ายแบบดั้งเดิมในอุตสาหกรรมที่ยืนยันว่าทุกสิ่งควรอยู่ในวัตถุที่เป็นศูนย์กลาง แต่แม้พวกเขาจะบอกคุณโดยทั่วไป - ให้แยกการแสดงผลของคุณจากกราฟฉากของคุณ SoC / SRP เป็นสิ่งที่ฉันไม่สามารถเน้นได้มากพอ - ไม่เคยผสมตรรกะเข้ากับคลาสเดียวมากกว่าที่คุณต้องการ ฉันยังจะสนับสนุนโซ่การสืบทอด OO ที่ซับซ้อนเกี่ยวกับตรรกะผสมในระดับเดียวกันถ้าคุณเอาปืนใส่หัวของฉัน!
วิศวกร

ไม่ฉันชอบแนวคิด และสิทธิของคุณนี่คือการกล่าวถึงครั้งแรกของ SoC ที่ฉันได้เห็นทุก ๆ ปีในการอ่านเกี่ยวกับการออกแบบเกม ขอบคุณอีกครั้ง.
Cody Smith

@CodySmith คิดอย่างรวดเร็วขณะเรียกดูข้อมูลนี้อีก โดยทั่วไปแล้วมันเป็นเรื่องดีที่จะเก็บสิ่งที่แยกออก หลากหลายชนิดของวัตถุแบบควบคุมใน codebase ของคุณที่ได้รับการแสดงผล แต่มันเป็นที่ดีสำหรับคุณเพื่อให้คอลเลกชันของRenderables (ซึ่งเป็นอินเตอร์เฟซหรือระดับนามธรรม) ภายในให้กับผู้หลักวัตถุแบบควบคุม ตัวอย่างที่ดีของสิ่งนี้คือเอนทิตีหรือองค์ประกอบ UI ดังนั้นคุณสามารถเข้าถึงเฉพาะเรนเดอร์เหล่านั้นที่เกี่ยวข้องกับออบเจ็กต์หลักนั้นโดยไม่ต้องมีการใช้งานเฉพาะซึ่งจะปนเปื้อนคลาสเอนทิตีดังนั้นการใช้อินเทอร์เฟซ
วิศวกร

@CodySmith ผลประโยชน์ชัดเจนกับเอนทิตีซึ่งอาจเช่น มีตัวแทนทั้งในวิวพอร์ตของโลกและในแผนที่ย่อ ดังนั้นการสะสม อีกทางหนึ่งคุณสามารถอนุญาตให้มีสล็อตตัวแสดงผลเพียงอันเดียวสำหรับวัตถุแต่ละรุ่นของคอนโทรลเลอร์ภายในวัตถุนั้น แต่ให้อินเทอร์เฟซทั่วไป! ไม่มีรายละเอียด - Rendererเพียงแค่
วิศวกร
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.