-
พื้นผิวสามารถประหยัดเวลาของ CPU ได้อย่างมาก ฮ่าฮ่า แต่ส่วนนี้ใช้เวลานานมาก: (
เนื่องจากมีการใช้ไลบรารีเสริม OpenGL จึงมีเพียงไม่กี่คนที่ใช้ฟังก์ชันของไลบรารีนี้ แต่ฉันก็ยังพบมัน ต้องขอบคุณ zdcnow (Magnetic Effect) เขาจึงมอบไลบรารี่เสริมเวอร์ชัน Delphi นี้ให้ฉัน ก่อนที่จะศึกษาหัวข้อนี้ โปรดดาวน์โหลดไฟล์ gaux.dll และ Glaux.pas ออนไลน์ และเพิ่มลงในโปรเจ็กต์
โอเค เรามาเดินทางต่อไปยัง OPENGL กันต่อ
ก่อนอื่น เราต้องเพิ่มหน่วย SysUtils เนื่องจากเราจะใช้การทำงานของไฟล์ในส่วนนี้ และเราจำเป็นต้องเพิ่มหน่วย Glaux ด้วย
จากนั้นเราจะเพิ่มตัวแปรหลายตัว ได้แก่ xrot, yrot และ zrot ตามบทเรียนแรก ตัวแปรเหล่านี้ใช้เพื่อหมุนลูกบาศก์รอบแกน X, Y และ Z texture[] จัดสรรพื้นที่เก็บข้อมูลสำหรับพื้นผิว หากคุณต้องการมากกว่าหนึ่งพื้นผิว คุณควรเปลี่ยนหมายเลข 1 เป็นจำนวนที่คุณต้องการ
-
วีเออาร์
h_RC: HGLRC; // บริบทการแสดงผล (ตารางคำอธิบายการแรเงา)
h_DC: HDC; // บริบทอุปกรณ์ (ตารางคำอธิบายอุปกรณ์)
h_Wnd: HWND; // ที่จับหน้าต่าง
h_Instance: HINST; // อินสแตนซ์ของโปรแกรม (อินสแตนซ์)
ปุ่ม : Array[0..255] ของ Boolean; // Array สำหรับรูทีนของคีย์บอร์ด
xrot, // จำนวนการหมุน X (ใหม่)
yrot // จำนวนการหมุน Y (ใหม่)
zrot : GLfloat; // จำนวนการหมุน Z (ใหม่)
พื้นผิว : Array[0..1] Of GLuint; // เก็บพื้นผิว (ใหม่)
{จากนั้นโหลดทั้งสองกระบวนการใน opengl32.dll เราจำเป็นต้องใช้มัน}
PROcedure glGenTextures (n: GLsizei; พื้นผิว Var: GLuint); stdcall ภายนอก
opengl32;
ขั้นตอน glBindTexture (เป้าหมาย: GLenum; texture: GLuint); stdcall ภายนอก
opengl32;
{ต่อไป เราจำเป็นต้องเพิ่มฟังก์ชันใหม่เพื่อป้อนรูปภาพอีกครั้ง ประเภทการส่งคืนของฟังก์ชันนี้ถูกกำหนดไว้ใน Glaux.pas ดังนี้:
TAUX_RGBImageRec= บันทึก
sizeX, sizeY: แวววาว;
ข้อมูล: ตัวชี้;
จบ;
PTAUX_RGBImageRec= ^TAUX_RGBImageRec;
ความหมายเฉพาะจะถูกนำมาใช้ในภายหลัง}
ฟังก์ชั่น LoadBmp (ชื่อไฟล์: pchar): PTAUX_RGBImageRec;
วาร์
BitmapFile : Thandle; // ตัวจัดการไฟล์
เริ่ม
//ต่อไปตรวจสอบว่าได้ระบุชื่อไฟล์แล้วหรือไม่
ถ้า Filename = '' จากนั้น // ตรวจสอบให้แน่ใจว่าได้ระบุชื่อไฟล์แล้ว
ผลลัพธ์ := ไม่มี; // ถ้าไม่ระบุ ให้คืนค่า NULL
//จากนั้นตรวจสอบว่ามีไฟล์อยู่หรือไม่
BitmapFile := FileOpen(ชื่อไฟล์, fmOpenWrite); //ลองเปิดไฟล์
//ถ้าเราเปิดไฟล์ได้ แสดงว่ามีไฟล์อยู่แน่นอน
ถ้า BitmapFile > 0 แล้ว // มีไฟล์อยู่หรือไม่?
เริ่ม
//ปิดไฟล์.
FileClose(BitmapFile); //ปิดที่จับ
//auxDIBImageLoad(Filename) อ่านข้อมูลรูปภาพและส่งกลับ
ผลลัพธ์ := auxDIBImageLoadA(ชื่อไฟล์); //โหลดบิตแมปและส่งคืนตัวชี้
จบ
อื่น
//หากเราไม่สามารถเปิดไฟล์ได้ เราจะคืน NiL
ผลลัพธ์ := Nil; // หากการโหลดล้มเหลว ให้ส่งคืน NiL
จบ;
//ถัดไปสร้างฟังก์ชันใหม่เพื่อโหลดแผนที่พื้นผิว
ฟังก์ชั่น LoadTexture: บูลีน;
//ตัวแปรสถานะ เราใช้สิ่งนี้เพื่อติดตามว่าสามารถโหลดบิตแมปได้หรือไม่และสามารถสร้างพื้นผิวได้หรือไม่
// สถานะถูกตั้งค่าเป็น FALSE ตามค่าเริ่มต้น (แสดงว่าไม่มีการโหลดหรือสร้างอะไรเลย)
//ตัวแปร TextureImage ประเภท PTAUX_RGBImageRec จัดเก็บบันทึกภาพของบิตแมป
//บันทึกนี้ประกอบด้วยความกว้าง ความสูง และข้อมูลของบิตแมป
วาร์
สถานะ: บูลีน;
TextureImage : Array[0..1] ของ PTAUX_RGBImageRec;
เริ่ม
สถานะ := เท็จ;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // ตั้งค่าตัวชี้เป็น NULL
TextureImage[0] := LoadBMP('Texture.bmp');
ถ้า TextureImage[0] <> ไม่มีเลย
เริ่ม
สถานะ := TRUE; // ตั้งค่าสถานะเป็น TRUE
//ตอนนี้ใช้ข้อมูลใน TextureImage[0] เพื่อสร้างพื้นผิว
//glGenTextures(1, texture[0]) บอก OpenGL ว่าเราต้องการสร้างชื่อพื้นผิว
//(หากต้องการโหลดหลายพื้นผิว ให้เพิ่มจำนวน)
//glBindTexture(GL_TEXTURE_2D, texture[0]) บอกให้ OpenGL ผูกชื่อพื้นผิว texture[0] กับเป้าหมายพื้นผิว
//พื้นผิว 2D มีเพียงความสูง (บนแกน Y) และความกว้าง (บนแกน X)
//ฟังก์ชั่นหลักกำหนดชื่อพื้นผิวให้กับข้อมูลพื้นผิว
//ในตัวอย่างนี้ เราบอก OpenGL ว่าหน่วยความจำที่ &texture[0] พร้อมใช้งาน
//พื้นผิวที่เราสร้างจะถูกจัดเก็บไว้ในพื้นที่หน่วยความจำที่ &texture[0] ชี้ไป
glGenTextures(1, texture[0]); // สร้างพื้นผิว
glBindTexture(GL_TEXTURE_2D, texture[0]); //ใช้พื้นผิวทั่วไปที่สร้างจากข้อมูลบิตแมป
//ด้านล่างเราสร้างพื้นผิวที่แท้จริง
//บรรทัดต่อไปนี้บอก OpenGL ว่าพื้นผิวนี้เป็นพื้นผิว 2D (GL_TEXTURE_2D)
//เลขศูนย์แสดงถึงระดับรายละเอียดของรูปภาพ ซึ่งโดยปกติจะเหลือไว้ที่ศูนย์
//หมายเลขสามคือจำนวนส่วนประกอบของข้อมูล เนื่องจากรูปภาพประกอบด้วยสามองค์ประกอบ: ข้อมูลสีแดง ข้อมูลสีเขียว และข้อมูลสีน้ำเงิน
//TextureImage[0].sizeX คือความกว้างของพื้นผิว
//ถ้าคุณทราบความกว้าง คุณสามารถกรอกได้ที่นี่ แต่คอมพิวเตอร์สามารถหาค่านี้ให้คุณได้อย่างง่ายดาย
// TextureImage[0].sizey คือความสูงของพื้นผิว
//เลขศูนย์คือค่าของเส้นขอบ ซึ่งปกติจะเป็นศูนย์
// GL_RGB บอก OpenGL ว่าข้อมูลรูปภาพประกอบด้วยข้อมูลสีแดง เขียว และน้ำเงิน
//GL_UNSIGNED_BYTE หมายความว่าข้อมูลที่ประกอบเป็นรูปภาพนั้นเป็นประเภทไบต์ที่ไม่ได้ลงนาม
//ในที่สุด... TextureImage[0].data จะบอก OpenGL ถึงแหล่งที่มาของข้อมูลพื้นผิว
//ตัวอย่างนี้ชี้ไปที่ข้อมูลที่จัดเก็บไว้ในบันทึก TextureImage[0]
// สร้างพื้นผิว
glTexImage2D(GL_TEXTURE_2D, 0, 3, พื้นผิวรูปภาพ[0].sizeX,
พื้นผิวรูปภาพ[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
พื้นผิวรูปภาพ[0].ข้อมูล);
// สองบรรทัดต่อไปนี้บอก OpenGL เมื่อแสดงรูปภาพ
//เมื่อมีขนาดใหญ่กว่าพื้นผิวดั้งเดิมที่ขยาย (GL_TEXTURE_MAG_FILTER)
//หรือวิธีการกรองที่ใช้โดย OpenGL เมื่อพื้นผิวถูกลดขนาดให้เล็กกว่าพื้นผิวดั้งเดิม (GL_TEXTURE_MIN_FILTER)
//ปกติแล้วฉันใช้ GL_LINEAR ในทั้งสองกรณี ช่วยให้พื้นผิวปรากฏได้อย่างราบรื่นจากระยะไกลไปจนถึงใกล้กับหน้าจอมาก
//การใช้ GL_LINEAR ต้องใช้ CPU และการ์ดกราฟิกเพื่อดำเนินการเพิ่มเติม
//หากเครื่องของคุณช้า คุณควรใช้ GL_NEAREST
//เมื่อขยายพื้นผิวที่กรอง จะมีลักษณะเป็นโมเสก (โมเสก)
//คุณยังสามารถรวมวิธีการกรองทั้งสองวิธีนี้เข้าด้วยกันได้ ใช้ GL_LINEAR เมื่ออยู่ใกล้ และ GL_NEAREST เมื่ออยู่ไกล
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // การกรองเชิงเส้น
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // การกรองเชิงเส้น
จบ;
//ตอนนี้เราปล่อยหน่วยความจำที่เคยใช้ในการจัดเก็บข้อมูลบิตแมปแล้ว
// ก่อนอื่นเราตรวจสอบก่อนว่าข้อมูลบิตแมปถูกเก็บไว้หรือไม่
//หากเป็นเช่นนั้น ให้ตรวจสอบว่าข้อมูลถูกเก็บไว้หรือไม่
//หากเก็บไว้แล้วให้ลบออก
//จากนั้นปล่อยโครงสร้างภาพ TextureImage[0] เพื่อให้แน่ใจว่าหน่วยความจำทั้งหมดจะถูกปล่อยออกมา
หากกำหนด (TextureImage[0]) จากนั้น // ไม่ว่าจะมีพื้นผิวอยู่หรือไม่
หากกำหนด (TextureImage[0].data) จากนั้น // ไม่ว่าจะมีรูปภาพพื้นผิวอยู่หรือไม่
TextureImage[0].data := Nil; // ปล่อยหน่วยความจำที่ครอบครองโดยภาพพื้นผิว
TextureImage[0] := Nil; // ปล่อยโครงสร้างภาพ
//ในที่สุดก็ส่งคืนตัวแปรสถานะ หากทุกอย่างเรียบร้อยดี ตัวแปร Status จะมีค่าเป็น TRUE มิฉะนั้นเป็นเท็จ
ผลลัพธ์ := สถานะ; // สถานะการกลับมา
จบ;