Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> การเขียนโปรแกรม BASH

การผูก OpenGL สำหรับ Bash

ในบทความก่อนหน้าของฉันที่อธิบายการออกแบบ Perl 5 และความเหมาะสมของมันเป็น "ภาษากาว" ฉันกล่าวว่าฉันเคยเขียนการผูก OpenGL สำหรับ Bash นี่อาจเป็นเรื่องที่ไม่น่าเชื่อเกินกว่าจะพูดโดยไม่มีการพิสูจน์ ดังนั้นฉันจึงกลับไปที่มุมที่เต็มไปด้วยฝุ่นของฮาร์ดไดรฟ์ ขุดออกมา ปรับปรุงมันเล็กน้อย ปรับปรุงการรองรับฟอนต์ เขียนเอกสาร และเผยแพร่บน ไซต์ของฉันและบน GitHub (คุณจะต้องใช้ระบบที่รองรับทั้ง Bash และ OpenGL เพื่อสัมผัสประสบการณ์โดยตรง แต่นี่คือวิดีโอ)

คำสารภาพของฉัน:กราฟิก Perl ในแดชบอร์ด DeLorean ที่ฉันอธิบายไว้ใน My DeLorean เรียกใช้ Perl  แบ่งปันประวัติกับโครงการ OpenGL for Bash ของฉัน ด้วยความสนุกสนานและน่าขัน ตอนแรกฉันเริ่มโครงการนี้เมื่อ 13 ปีที่แล้วหลังจากที่ได้เห็น Frozen Bubble และความอ่อนไหวทางเทคนิคของฉันทำให้ขุ่นเคืองใจที่มีคนเขียนวิดีโอเกมแบบเรียลไทม์ใน Perl ย้อนกลับไปตอนนั้น ภาษาหลักของฉันคือ C++ และฉันกำลังศึกษา OpenGL เพื่อวัตถุประสงค์ในวิดีโอเกม ฉันประกาศกับเพื่อนของฉันว่าสิ่งเดียวที่แย่กว่านั้นคือถ้ามันเป็น 3D และเขียนด้วย Bash เมื่อพูดแนวคิดนี้ออกมาดัง ๆ มันยังคงกระตุ้นฉัน และในที่สุดฉันก็ตัดสินใจที่จะลองใช้ "ความเลวร้าย" ของการใช้ Perl สำหรับกราฟิกแบบเรียลไทม์

ขยาย Bash

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

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

ในที่สุด ฉันก็ตกลงกับการออกแบบที่ฉันจะมีกระบวนการ "OpenGL Interpreter" ที่จะอ่านคำสั่ง OpenGL ใน standard-in และเขียนเหตุการณ์อินพุตของผู้ใช้ไปยัง standard-out จากนั้นสคริปต์ Bash สามารถเริ่มตัวแปลนี้ซึ่งเชื่อมต่อกับไพพ์ และคำสั่ง OpenGL แต่ละคำสั่งอาจเป็นฟังก์ชัน Bash ที่เขียนไปยังไพพ์ ในขณะที่ฉันอยู่ที่นั่น ฉันตัดสินใจที่จะโยนกลอุบายประสิทธิภาพทั้งหมดของฉันและเขียนล่ามในภาษา C ธรรมดาด้วยตารางแฮชที่คอมไพล์แบบสแตติกและต้นไม้สีแดงดำ

โหมดทันที OpenGL

รายละเอียด OpenGL คือจุดที่โปรเจ็กต์นี้เริ่มตัดกับโปรเจ็กต์แดชบอร์ด DeLorean ก่อนอื่น ฉันจะย้อนกลับไปและสรุป OpenGL API

OpenGL นั้นเกี่ยวกับการเขียนโปรแกรมที่วางแผนกราฟิกในแง่ของพิกัดและพื้นผิว 3 มิติ จากนั้นส่งข้อมูลนั้นไปยังการ์ดกราฟิกเพื่อแสดงผลเป็นหน้าจอ 2 มิติ เพื่อให้เข้าใจง่ายจริง ๆ มีชุดคณิตศาสตร์ที่คุณใช้อธิบายขอบเขตของหน้าจอที่กำลังทาสี และชุดคณิตศาสตร์เพื่ออธิบายสีของแต่ละพิกเซลในพื้นที่นั้น

การดำเนินการที่พบบ่อยที่สุดคือการอธิบายสามมุมของรูปสามเหลี่ยมในพื้นที่ 3 มิติเสมือนจริง ให้ OpenGL หาตำแหน่งที่ลงจอดบนหน้าจอ 2 มิติ จากนั้นบอกให้ขยายภาพ 2 มิติไปทั่วพื้นที่นั้น อาจรวมกับภาพอื่นหรือดัดแปลง โดยการคำนวณความสว่างบางอย่าง ลูปหลักของโปรแกรมสร้างเฟรมวิดีโอหนึ่งเฟรมโดยเช็ดบัฟเฟอร์ วาดทุกรูปหลายเหลี่ยมที่มองเห็นได้ และส่งไปที่หน้าจอ หากคุณเลิกใช้การแสดงความสามารถทั้งหมดนี้ภายใน 16 มิลลิวินาทีหรือน้อยกว่า คุณจะสามารถรักษา 60 เฟรมต่อวินาทีและมีกราฟิกที่ลื่นไหลได้ดี

ฉันไม่สามารถพูดกับผู้มีอำนาจเกี่ยวกับที่มาของ OpenGL API ได้ แต่ดูเหมือนค่อนข้างชัดเจนว่าสร้างขึ้นจากแนวคิดของการสตรีม ซึ่งอาจเข้ากันได้กับโปรโตคอลการแสดงผล X11 แต่ก็เพียงเพราะเป็นความคิดที่ดี ดังนั้น ฟังก์ชัน OpenGL ส่วนใหญ่จึงไม่มีค่าส่งคืน ซึ่งต่างจาก API อื่นๆ ที่การเรียกใช้ฟังก์ชันแต่ละครั้งจะส่งคืนสถานะที่แจ้งผลลัพธ์ของการดำเนินการให้คุณทราบ หากคุณเห็นภาพฟังก์ชัน OpenGL เช่น glVertex3f(1,2,3) เป็นคำสั่งพิมพ์ที่เขียนตัวเลขสามตัวบนไพพ์ คุณมีความคิดที่ดีทีเดียวว่ามันทำงานอย่างไรเบื้องหลัง อันที่จริงแล้วสำหรับการผูก Bash ฉันเขียน glVertex 1 2 3 . อย่างแท้จริง เหนือท่อเมื่อ glVertex 1 2 3 ถูกดำเนินการ สคริปต์ Bash ทำงานแบบ blind โดยไม่รู้ว่าคำสั่งกราฟิกของมันกำลังทำอะไรตามที่ตั้งใจหรือไม่

มีการแก้ไขครั้งใหญ่หลายครั้งใน OpenGL API ในช่วงหลายปีที่ผ่านมา และผู้คนเขียนทั้งบทในหนังสือของพวกเขาเกี่ยวกับโหมด "คงอยู่" กับ "ทันที" แต่ทั้งหมดนี้สรุปได้เป็นสองแนวคิด:

  • การส่งข้อมูลทั้งหมดซ้ำบนไพพ์ในแต่ละเฟรมนั้นช้า ดังนั้น เรามาแคชข้อมูลบางส่วนกันที่อีกด้านหนึ่ง
  • เราไม่สามารถตอบสนองความต้องการของทุกคนได้ด้วยคณิตศาสตร์ในตัว ให้คนอื่นใช้ภาษาอธิบายคณิตศาสตร์ที่พวกเขากำหนดเอง

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

ดังนั้น แม้ว่าการผูก Bash OpenGL จะจัดการกับ API ที่ "เลิกใช้แล้ว" เท่านั้น แต่ฉันก็ยังสนับสนุนให้ผู้คนมองมันเพื่อการศึกษาและการแก้ไข

แสดงรายการ

โชคดีที่ OpenGL API ดั้งเดิมมีกลไกการแคชและใช้งานง่าย พวกมันทำงานโดยประมาณตามลำดับของ:

"สวัสดี OpenGL ฉันต้องการให้คุณสร้างวัตถุ 37 ที่ปลายทางระยะไกล"

"นี่คือข้อมูลบางส่วนที่อธิบายวัตถุ 37"

"ใช้วัตถุ 37 ในขั้นตอนการแสดงผลถัดไป"

เพื่อให้ง่ายยิ่งขึ้น การผูก Bash ให้คุณใช้ชื่อแทนตัวเลขได้

วัตถุประเภทแรกหลักคือพื้นผิวที่คุณโหลดภาพ 2D ลงในการ์ดกราฟิกแล้ว "ระบายสี" รูปหลายเหลี่ยมด้วย อย่างที่สองคือ "แสดงรายการ" ซึ่งคุณบันทึกลำดับของคำสั่ง OpenGL จากนั้นเล่นเสมือนเป็นคำสั่ง OpenGL เดียว

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

สำหรับตัวอย่างของพาวเวอร์นี้ ให้ดู Robot.sh ในไดเร็กทอรี Examples มันสร้างรายการที่แสดงหนึ่งรายการสำหรับแต่ละส่วนของร่างกายของหุ่นยนต์เมื่อเริ่มต้น และในขณะที่ทำงาน จะแสดงข้อความเพียง 58 บรรทัดต่อเฟรมเพื่อแสดงหุ่นยนต์ Bash สามารถสร้างข้อความ 58 บรรทัดได้อย่างง่ายดายใน 16 มิลลิวินาที (แม้เมื่อ 12 ปีที่แล้ว) ดังนั้นการสาธิตจึงสามารถทำงานด้วยความเร็วเต็มที่บนฮาร์ดแวร์ทั่วไป

รายการที่แสดงเป็นเคล็ดลับหลักที่ฉันนำไปใช้กับกราฟิก Perl ที่ฉันใช้ในซอฟต์แวร์แดชบอร์ด DeLorean การเรียกใช้ฟังก์ชัน Perl นั้นค่อนข้างแพงเมื่อเทียบกับ C โดยเฉพาะอย่างยิ่งสำหรับ API ที่มีฟังก์ชันหนัก เช่น OpenGL 1.4 แต่ด้วยการรวมสิ่งต่าง ๆ ลงในรายการที่แสดง Perl ไม่มีงานให้ทำมากนักต่อเฟรมวิดีโอ ถ้าฉันไม่ได้เรียนรู้เคล็ดลับนี้สำหรับโปรเจ็กต์ Bash โปรเจ็กต์ Perl ก็คงไม่ประสบความสำเร็จเกือบเท่า

ทำไมไม่เผยแพร่เมื่อ 12 ปีที่แล้ว

ในขณะที่ฉันสามารถสร้างการสาธิตแอนิเมชั่นแฟนซีใน Bash ได้ เป้าหมายที่แท้จริงของฉันคือการสร้างเกมที่สมบูรณ์ด้วยมัน ฉันกำลังเล็งไปที่โคลนของเกมจำลองการบินเก่าอย่าง Terminal Velocity และฉันไปถึงยานอวกาศที่สามารถบินผ่านทุ่งลูกบาศก์ได้ (ดู Flight.sh ในตัวอย่าง) แต่ปัญหาต่อไปคือการตรวจจับการชน primitives ที่มีอยู่ใน Bash คือ "associative array" ทั่วโลกของชื่อตัวแปรและตัวแปรอาร์เรย์ (แม้ว่าเวอร์ชัน 4 ในตอนนี้จะมีตัวแปรเชื่อมโยงอาร์เรย์) และคณิตศาสตร์ทั้งหมดเป็นจำนวนเต็ม แม้ว่าฉันจะสามารถดึงการหมุนเมทริกซ์ 3 มิติในคณิตศาสตร์จำนวนเต็มจุดคงที่ได้ แต่การใช้การตรวจจับการชนกันนั้นดูเหมือนสิ่งกีดขวางที่ใหญ่เกินไป ฉันไม่พอใจกับฟอนต์ API ของฉันด้วย ขณะไตร่ตรองวิธีแก้ปัญหาเหล่านี้ โครงการก็ค่อยๆ หายไปจากรายชื่อของฉัน

นี่คือที่ที่ฉันสรุป (ในขณะที่ฉันเขียน) "Bash เป็นภาษากาวที่น่ากลัว" ในขณะที่โครงการนี้เริ่มต้นและจบลงด้วยเรื่องตลก (หรือเครื่องมือการศึกษา) รูปแบบโปรแกรมเดียวกันใน Perl กลับกลายเป็นว่ามีประโยชน์มากสำหรับการใช้งานจริง ถ้าฉันพิจารณา Frozen Bubble อย่างจริงจังมากขึ้นเมื่อ 13 ปีที่แล้ว ฉันอาจจะเริ่มใช้ Perl ซึ่งเป็นภาษาที่ฉันชอบในตอนนี้ได้

ฉันไม่มีแผนที่จะปรับปรุงโครงการนี้นอกเหนือจากการแก้ไขข้อบกพร่อง แต่ฉันคิดว่าอย่างน้อยก็อาจเป็นประโยชน์กับผู้ที่ต้องการเรียนรู้แนวคิดของ OpenGL หรือผู้ที่มีเวลาว่างและความปรารถนาอย่างแรงกล้าที่จะเขียน Doom โคลนใน M4

สนุก! และสนุกกับการส่งต่อลิงก์นี้ มิฉะนั้นจะไม่มีใครเชื่อคุณ