-
ยินดีต้อนรับสู่บทเรียนที่เก้า ถึงตอนนี้ คุณควรจะมีความเข้าใจเกี่ยวกับ OpenGL เป็นอย่างดี
"CKER: ถ้าไม่ใช่ คงเป็นความผิดของนักแปลของฉันเอง..."
(มายลิ่งกล่าวเสริม: บาปของฉันยิ่งกว่านั้นอีก 555)
คุณได้เรียนรู้ทุกรายละเอียดของการตั้งค่าหน้าต่าง OpenGL แล้ว
เรียนรู้การทำแผนที่และเพิ่มการผสมแสงและสี (ความโปร่งใส) ให้กับวัตถุที่กำลังหมุน
บทเรียนนี้ควรถือเป็นบทช่วยสอนระดับกลาง
คุณจะได้เรียนรู้วิธีย้ายบิตแมปไปรอบๆ ฉาก 3 มิติ และลบพิกเซลสีดำออกจากบิตแมป (โดยใช้การผสมสี)
จากนั้น ระบายสีพื้นผิวขาวดำ และสุดท้ายคุณจะได้เรียนรู้การสร้างสีสันที่หลากหลาย
และผสมพื้นผิวที่มีสีต่างกันเข้าด้วยกันเพื่อให้ได้เอฟเฟกต์แอนิเมชั่นง่ายๆ
เราจะทำการแก้ไขตามโค้ดจากบทเรียนแรก ขั้นแรกให้เพิ่มตัวแปรสองสามตัวที่จุดเริ่มต้นของซอร์สโค้ดโปรแกรม
ฉันเขียนโค้ดใหม่ทั้งหมดเพื่อความชัดเจน
-
วาร์
h_RC: HGLRC; // บริบทการแสดงผล (ตารางคำอธิบายการแรเงา)
h_DC: HDC; // บริบทอุปกรณ์ (ตารางคำอธิบายอุปกรณ์)
h_Wnd: HWND; // ที่จับหน้าต่าง
h_Instance: HINST; // อินสแตนซ์ของโปรแกรม (อินสแตนซ์)
ปุ่ม : Array[0..255] ของ Boolean; // Array สำหรับรูทีนของคีย์บอร์ด
{บรรทัดต่อไปนี้ถูกเพิ่มใหม่
Twinkle และ tp เป็นตัวแปรบูลีน ซึ่งหมายความว่าสามารถตั้งค่าเป็น TRUE หรือ FALSE เท่านั้น
Twinkle ใช้เพื่อติดตามว่าเปิดใช้งานเอฟเฟกต์การสั่นไหวหรือไม่
tp ใช้เพื่อตรวจสอบว่ามีการกดหรือปล่อยปุ่ม 'T' หรือไม่
(tp=TRUE เมื่อกด, tp=FALSE เมื่อปล่อย)}
กระพริบตา : บูลีน; // กระพริบตาดาว (ใหม่)
tp : Boolean; // กด 'T' หรือไม่ (ใหม่)
{ตอนนี้เรามาสร้างโครงสร้างกันดีกว่า
โครงสร้างคำฟังดูน่ากลัว แต่ก็ไม่เป็นเช่นนั้น (นี่คือประเภทบันทึกของ Delphi)
โครงสร้างใช้ชุดของประเภทข้อมูลอย่างง่าย (และตัวแปร ฯลฯ) เพื่อแสดงชุดข้อมูลที่คล้ายคลึงกันที่มีขนาดใหญ่กว่า
เรารู้ว่าเรากำลังติดตามดวงดาว
คุณสามารถมองเห็นดวงดาวด้านล่าง
ดาวแต่ละดวงมีค่าสีจำนวนเต็มสามค่า สีแดงหนึ่งอัน (r) หนึ่งสีเขียว (g) และสีน้ำเงินหนึ่งอัน (b)
นอกจากนี้ ดาวแต่ละดวงยังอยู่ห่างจากศูนย์กลางหน้าจอต่างกัน
และสามารถเป็นมุมใดก็ได้ใน 360 องศา โดยมีศูนย์กลางของหน้าจอเป็นจุดเริ่มต้น
จำนวนจุดลอยตัวของ dist เพื่อติดตามระยะทาง
จำนวนจุดลอยตัวของมุมจะติดตามค่ามุมของดาวฤกษ์
ดังนั้นเราจึงใช้ชุดข้อมูลเพื่ออธิบายสี ระยะทาง และมุมของดวงดาวบนหน้าจอ
ขออภัย เรากำลังติดตามดาวมากกว่าหนึ่งดวง
แต่ไม่จำเป็นต้องสร้างค่าสีแดง 50 ค่า สีเขียว 50 ค่า สีน้ำเงิน 50 ค่า ระยะทาง 50 ค่า
และค่ามุม 50 ค่า และเพียงสร้างดาวอาร์เรย์ -
พิมพ์
stars = Record //สร้างโครงสร้างดาว ตั้งชื่อโครงสร้างดาว
r, g, b: จำนวนเต็ม; // สีของดวงดาว
dist: GLfloat; // ระยะห่างของดาวฤกษ์จากจุดศูนย์กลาง
มุม: GLfloat; // มุมของดาวปัจจุบัน
จบ;
วาร์
star : Array[0..49] Of stars; // ใช้โครงสร้าง 'stars' เพื่อสร้างอาร์เรย์ 'star' ที่มี 50 องค์ประกอบ
{ต่อไป เราจะตั้งค่าตัวแปรการติดตามหลายรายการ:
ตัวแปรระยะห่าง (การซูม) ของดาวฤกษ์จากผู้สังเกต
มุม (เอียง) ที่เราเห็นดวงดาว
และการหมุนแบบแปรผันที่ทำให้ดาวระยิบระยับหมุนรอบแกน Z
ตัวแปรวนซ้ำใช้ในการวาดดาว 50 ดวง
texture[1] ใช้เพื่อจัดเก็บพื้นผิวขาวดำ
หากคุณต้องการพื้นผิวเพิ่มเติม
คุณควรเพิ่มขนาดของอาร์เรย์พื้นผิวตามจำนวนพื้นผิวที่คุณตัดสินใจใช้
-
Zoom : GLfloat = -15.0; // ระยะห่างของดาวฤกษ์จากผู้สังเกต
เอียง : GLfloat = 90.0; // ความเอียงของดาว
spin : GLfloat; // การหมุนของดาวระยิบระยับ
วนซ้ำ : GLuint; // ตัวแปร Global l วนซ้ำ
texture : Array[0..1] ของ GLuint; // เก็บพื้นผิว
PROcedure glGenTextures (n: GLsizei; พื้นผิว Var: GLuint); stdcall ภายนอก
opengl32;
ขั้นตอน glBindTexture (เป้าหมาย: GLenum; texture: GLuint); stdcall ภายนอก
opengl32;
-
โค้ดด้านบนสุดคือโค้ดที่เราใช้ในการโหลดพื้นผิว
ฉันจะไม่อธิบายรหัสนี้โดยละเอียด
นี่เป็นโค้ดเดียวกับที่เราใช้ในบทที่ 6, 7 และ 8
บิตแมปที่โหลดในครั้งนี้เรียกว่า star.bmp
ที่นี่เราใช้ glGenTextures(1, &texture[0])
เพื่อสร้างพื้นผิว พื้นผิวใช้การกรองเชิงเส้น
-
ฟังก์ชั่น LoadTexture: boolean; // โหลดบิตแมปและแปลงเป็นพื้นผิว
วาร์
สถานะ : บูลีน; // ตัวบ่งชี้สถานะ
TextureImage : Array[0..1] ของ PTAUX_RGBImageRec; // สร้างพื้นที่เก็บข้อมูลพื้นผิว
เริ่ม
สถานะ := เท็จ;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // ตั้งค่าตัวชี้เป็น NULL
TextureImage[0] := LoadBMP('Star.bmp');
ถ้า TextureImage[0] <> ไม่มีเลย
เริ่ม
สถานะ := TRUE; // ตั้งค่าสถานะเป็น TRUE
glGenTextures(1, texture[0]); // สร้างพื้นผิว
// สร้างแผนผังตัวกรองที่ใกล้ที่สุด
glBindTexture(GL_TEXTURE_2D, พื้นผิว[0]);
// สร้างพื้นผิว
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, 3, พื้นผิวรูปภาพ[0].sizeX,
พื้นผิวรูปภาพ[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
พื้นผิวรูปภาพ[0].ข้อมูล);
จบ;
หากกำหนด (TextureImage[0]) จากนั้น // ไม่ว่าจะมีพื้นผิวอยู่หรือไม่
หากกำหนด (TextureImage[0].data) จากนั้น // ไม่ว่าจะมีรูปภาพพื้นผิวอยู่หรือไม่
TextureImage[0].data := Nil; // ปล่อยหน่วยความจำที่ครอบครองโดยภาพพื้นผิว
TextureImage[0] := Nil; // ปล่อยโครงสร้างภาพ
ผลลัพธ์ := สถานะ; // สถานะการกลับมา
จบ;
-ตั้งค่าโหมดการเรนเดอร์ OpenGL ใน glInit() เราจะไม่ใช้การทดสอบเชิงลึกที่นี่
หากคุณใช้โค้ดจากบทที่ 1
โปรดยืนยันว่าได้ลบ glDepthFunc(GL_LEQUAL) และ glEnable(GL_DEPTH_TEST) แล้วหรือไม่
ไม่เช่นนั้นผลลัพธ์ที่คุณจะเห็นจะเละเทะ
ที่นี่เราใช้การทำแผนที่พื้นผิว
ดังนั้นโปรดตรวจสอบให้แน่ใจว่าคุณได้เพิ่มโค้ดที่ไม่ได้รวมอยู่ในบทเรียนแรก
คุณจะสังเกตเห็นว่าเราเปิดใช้งานการแมปพื้นผิวด้วยการผสมสี
-
ขั้นตอน glInit();
เริ่ม
ถ้า (ไม่ใช่ LoadTexture) จากนั้น // เรียกรูทีนย่อยการโหลดพื้นผิว (ใหม่)
exit; // หากโหลดไม่สำเร็จ ให้ออก (ใหม่)
glEnable(GL_TEXTURE_2D); // เปิดใช้งานการแมปพื้นผิว
glShadeModel(GL_SMOOTH); // เปิดใช้งานการปรับเงาให้เรียบ
glClearColor(0.0, 0.0, 0.0, 0.5); // พื้นหลังสีดำ
glClearDepth(1.0); //ตั้งค่าบัฟเฟอร์ความลึก
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // การแก้ไขเปอร์สเปคทีฟที่ดีจริงๆ
glBlendFunc(GL_SRC_ALPHA, GL_ONE); // ตั้งค่าฟังก์ชันการผสมสีเพื่อให้ได้เอฟเฟกต์โปร่งแสง
glEnable(GL_BLEND); // เปิดใช้งานการผสมสี
{ต่อไปนี้เป็นรหัสใหม่
มีการตั้งค่ามุมเริ่มต้น ระยะทาง และสีของดาวแต่ละดวง
คุณจะสังเกตได้ว่าการปรับเปลี่ยนคุณสมบัติของโครงสร้างนั้นง่ายเพียงใด
ดาวทั้ง 50 ดวงจะหมุนเวียนผ่านไป
หากต้องการเปลี่ยนมุมของ star[1] สิ่งที่เราต้องทำคือ star[1].angle=a ค่าที่แน่นอน
มันง่ายมาก! -
For loop := 0 To 49 Do // สร้าง loop เพื่อตั้งดาวทั้งหมด
เริ่ม
star[loop].angle := 0.0; // ดาวทั้งหมดเริ่มจากมุมศูนย์
{ระยะห่างของดาวดวงที่ 2 จากจุดศูนย์กลางหารด้วยค่าของวงด้วยจำนวนดาวทั้งหมด แล้วคูณด้วย 5.0
โดยพื้นฐานแล้ว สิ่งนี้จะทำให้ดาวดวงหลังอยู่ห่างจากจุดศูนย์กลางมากกว่าดาวดวงก่อนเล็กน้อย
ด้วยวิธีนี้ เมื่อลูปอยู่ที่ 50 (ดาวดวงสุดท้าย) ลูปที่หารด้วย num จะเท่ากับ 1.0 พอดี
สาเหตุที่เราต้องคูณ 5.0 ก็เพราะ 1.0*5.0 คือ 5.0
『CKER: ไร้สาระ ไร้สาระ! ทำไมฝรั่งคนนี้หน้าตาเหมือนกงอี้จี! -
5.0 อยู่ใกล้กับขอบหน้าจอมากแล้ว ฉันไม่ต้องการให้ดวงดาวลอยไปนอกจอ ดังนั้น 5.0 จึงเป็นตัวเลือกที่ดีที่สุด
แน่นอน หากคุณจัดฉากให้ลึกเข้าไปในหน้าจอมากขึ้น
บางทีคุณอาจใช้ค่าที่มากกว่า 5.0 แต่ดวงดาวจะดูเล็กลง (ทั้งหมดเป็นเพราะเปอร์สเปคทีฟ)
คุณจะสังเกตเห็นว่าสีของดาวแต่ละดวงเป็นตัวเลขสุ่มตั้งแต่ 0 ถึง 255
คุณอาจสงสัยว่าเหตุใดช่วงค่าสีที่นี่จึงไม่ใช่ช่วงปกติของ OpenGL ที่ 0.0 ถึง 1.0
ฟังก์ชั่นการตั้งค่าสีที่เราใช้ที่นี่คือ glColor4ub แทนที่จะเป็น glColor4f ก่อนหน้า
ub หมายความว่าพารามิเตอร์เป็นประเภท Unsigned Byte
ช่วงค่าของไบต์คือ 0~255
ดูเหมือนว่าการใช้ค่าไบต์เพื่อรับจำนวนเต็มแบบสุ่มจะง่ายกว่าการรับตัวเลขสุ่มทศนิยม
-
star[loop].dist := (Trunc(loop) / 50) * 5.0; // คำนวณระยะทางของดาวจากจุดศูนย์กลาง
star[loop].r := Random(256); // ตั้งค่าองค์ประกอบสีแดงแบบสุ่มสำหรับ star[loop]
star[loop].g := Random(256); // ตั้งค่าองค์ประกอบสีแดงแบบสุ่มสำหรับ star[loop]
star[loop].b := Random(256); // ตั้งค่าองค์ประกอบสีแดงแบบสุ่มสำหรับ star[loop]
จบ;
จบ;
-
ตอนนี้เรามาดูโค้ดการวาด glDraw()
หากคุณใช้โค้ดจากบทที่ 1 ให้ลบโค้ด DrawGLScene เก่าแล้วคัดลอกโค้ดด้านล่าง
จริงๆ แล้ว โค้ดสำหรับบทเรียนแรกมีเพียงสองบรรทัดเท่านั้น ดังนั้นจึงไม่ต้องตัดอะไรมากมาย
-
ขั้นตอน glDraw();
เริ่ม
glClear(GL_COLOR_BUFFER_BIT หรือ GL_DEPTH_BUFFER_BIT); // ล้างหน้าจอและบัฟเฟอร์ความลึก
glBindTexture(GL_TEXTURE_2D, พื้นผิว [0]); // เลือกพื้นผิว
สำหรับการวนซ้ำ := 0 ถึง 49 Do // วนซ้ำเพื่อตั้งดาวทั้งหมด
เริ่ม
glLoadIdentity(); // ก่อนที่จะวาดดาวแต่ละดวง ให้รีเซ็ตเมทริกซ์การสังเกตแบบจำลอง
glTranslatef(0.0, 0.0, ซูม); // เจาะลึกเข้าไปในหน้าจอ (ใช้ค่า 'ซูม')
glRotatef(tilt, 1.0, 0.0, 0.0); // มุมมองการเอียง (ใช้ค่า 'tilt')
-
ตอนนี้ขอย้ายดาว
ดาวเริ่มต้นที่กึ่งกลางหน้าจอ
สิ่งแรกที่เราต้องทำคือหมุนฉากไปตามแกน Y
ถ้าเราหมุนมัน 90 องศา แกน X จะไม่จากซ้ายไปขวาอีกต่อไป มันจะออกจากหน้าจอจากด้านในออก
เพื่อให้ชัดเจนยิ่งขึ้น เรามายกตัวอย่างกัน ลองนึกภาพคุณกำลังยืนอยู่กลางบ้าน
ลองจินตนาการว่ากำแพงทางด้านซ้ายของคุณเขียนว่า -x และกำแพงข้างหน้าคุณเขียนว่า -z
ผนังทางขวาคือ +x และผนังด้านหลังคุณคือ +z
หากบ้านทั้งหลังหันไปทางขวา 90 องศา แต่คุณไม่ขยับ ผนังด้านหน้าจะเป็น -x แทนที่จะเป็น -z
กำแพงอื่นๆ ทั้งหมดก็เคลื่อนไหวเช่นกัน -z ปรากฏทางด้านขวา +z ปรากฏทางด้านซ้าย และ +x ปรากฏด้านหลังคุณ
คุณเสียสติไปแล้วเหรอ? ด้วยการหมุนฉาก เราจะเปลี่ยนการวางแนวของระนาบ x และ z
โค้ดบรรทัดที่สองจะย้ายค่าบวกไปตามแกน x
โดยปกติค่าบวกบนแกน x หมายถึงการเคลื่อนที่ไปทางด้านขวาของหน้าจอ (นั่นคือ ทิศทางบวกตามปกติของแกน x)
แต่ตรงนี้เนื่องจากเราหมุนระบบพิกัดรอบแกน y ทิศทางบวกของแกน x จึงสามารถเป็นไปในทิศทางใดก็ได้
ถ้าเราหมุนได้ 180 องศา ด้านซ้ายและขวาของหน้าจอจะสะท้อน
เมื่อเราเคลื่อนไปตามแกน x บวก มันอาจเป็นซ้าย ขวา ข้างหน้า หรือข้างหลังก็ได้
-
glRotatef(star[loop].angle, 0.0, 1.0, 0.0); // หมุนไปที่มุมของดาวที่วาดอยู่ในปัจจุบัน
glTranslatef(star[loop].dist, 0.0, 0.0); // เลื่อนไปข้างหน้าตามแกน X
-
รหัสต่อไปนี้มีเคล็ดลับเล็กน้อย
จริงๆแล้วดวงดาวนั้นมีพื้นผิวเรียบๆ
ตอนนี้คุณวาดรูปสี่เหลี่ยมแบนๆ ตรงกลางหน้าจอแล้วใช้พื้นผิว และมันก็ดูดี
ทุกอย่างเป็นไปตามที่คุณจินตนาการ แต่เมื่อคุณหมุน 90 องศาไปตามแกน y
พื้นผิวเพียงสองด้านบนหน้าจอที่หันเข้าหาคุณคือด้านขวาและด้านซ้าย มันดูเหมือนเป็นเส้นบางๆ
นี่ไม่ใช่สิ่งที่เราต้องการ เราต้องการให้ดวงดาวหันเข้าหาเราตลอดเวลา ไม่ว่าหน้าจอจะหมุนหรือเอียงอย่างไรก็ตาม
เราทำสิ่งนี้ได้โดยยกเลิกการหมุนรอบดาวก่อนที่จะวาดมัน
คุณสามารถกลับการหมุนเพื่อต่อต้านการหมุนได้ เมื่อเราเอียงหน้าจอ เราจะหมุนดาวตามมุมปัจจุบัน
ด้วยการกลับลำดับ เราจะ "ต่อต้านการหมุน" ดาวฤกษ์ในมุมปัจจุบัน นั่นคือดาวหมุนด้วยค่าลบของมุมปัจจุบัน
นั่นคือ
ถ้าเราหมุนดาว 10 องศา เราจะหมุนดาว -10 องศา เพื่อให้ดาวหันหน้าไปทางหน้าจออีกครั้งบนแกนนั้น
บรรทัดแรกด้านล่างจะยกเลิกการหมุนตามแกน y จากนั้น เรายังต้องชดเชยการเอียงหน้าจอตามแกน x ด้วย
ในการทำเช่นนี้เราเพียงแค่ต้องหมุนหน้าจออีกครั้ง -เอียง
หลังจากยกเลิกการหมุนบนแกน x และ y แล้ว ดาวก็กลับมาหันหน้าเข้าหาเราอีกครั้งโดยสมบูรณ์
-
glRotatef(-star[loop].angle, 0.0, 1.0, 0.0); // ยกเลิกมุมของดาวปัจจุบัน
glRotatef(-tilt, 1.0, 0.0, 0.0); // ยกเลิกการเอียงหน้าจอ
{หากกระพริบตาเป็น TRUE เราจะวาดดาวที่ไม่หมุนบนหน้าจอก่อน:
ลบจำนวนดาวปัจจุบัน (วนซ้ำ) ออกจากจำนวนดาวทั้งหมด (num) แล้วลบ 1
เพื่อแยกสีที่แตกต่างกันของดาวแต่ละดวง (ซึ่งทำได้เนื่องจากช่วงลูปอยู่ระหว่าง 0 ถึง num-1)
เช่น เมื่อผลลัพธ์เป็น 10 เราก็ใช้สีของดาวหมายเลข 10
ด้วยวิธีนี้สีของดาวฤกษ์ที่อยู่ติดกันจึงแตกต่างกันเสมอ ไม่ใช่ความคิดที่ดีแต่ได้ผล
ค่าสุดท้ายคือส่วนประกอบช่องอัลฟา ยิ่งค่าน้อย ดาวก็ยิ่งหรี่ลง
เนื่องจากเปิดใช้งาน Twinkle ดาวแต่ละดวงจะถูกสุ่มสองครั้ง
โปรแกรมจะทำงานช้าลง ขึ้นอยู่กับประสิทธิภาพของเครื่องของคุณ
แต่สีของดวงดาวที่วาดในสองรอบผสมผสานกันและให้เอฟเฟกต์ที่ยอดเยี่ยม
ในเวลาเดียวกัน เนื่องจากดวงดาวในการผ่านครั้งแรกไม่หมุน ดาวหลังจากเปิดใช้งานการกระพริบตาจึงดูเหมือนเอฟเฟกต์ภาพเคลื่อนไหว
(ถ้าคุณไม่เข้าใจตรงนี้ ก็แค่ไปดูผลการทำงานของโปรแกรมด้วยตัวเอง)
เป็นที่น่าสังเกตว่าการระบายสีพื้นผิวเป็นเรื่องง่าย
แม้ว่าพื้นผิวจะเป็นสีขาวดำ แต่พื้นผิวจะเปลี่ยนเป็นสีใดก็ได้ที่เราเลือกก่อนที่จะทาสี
นอกจากนี้ยังเป็นที่น่าสังเกตว่าค่าสีที่เราใช้ที่นี่เป็นประเภทไบต์
แทนที่จะเป็นเลขทศนิยมปกติ แม้แต่องค์ประกอบช่องอัลฟ่าก็ยังเป็นแบบนี้ -
ถ้า (กระพริบตา) จากนั้น // เปิดใช้งานเอฟเฟกต์กระพริบตา
เริ่ม
//ระบุสีโดยใช้ค่าไบต์
glColor4ub(ดาว[(50 - วนซ้ำ) - 1].r, ดาว[(50 - วนซ้ำ) - 1].g,
ดาว[(50 - วนซ้ำ) - 1].b, 255);
glBegin(GL_QUADS); // เริ่มวาดรูปสี่เหลี่ยมที่แมปพื้นผิว
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // สิ้นสุดรูปสี่เหลี่ยม
จบ;
-
ตอนนี้วาดดวงดาวดวงที่สอง
ข้อแตกต่างเพียงอย่างเดียวจากโค้ดก่อนหน้านี้คือดวงดาวในครั้งนี้จะถูกวาดอย่างแน่นอน และคราวนี้ดวงดาวจะหมุนรอบแกน z
-
glRotatef(spin, 0.0, 0.0, 1.0); // หมุนดาวรอบแกน z
//ระบุสีโดยใช้ค่าไบต์
glColor4ub(ดาว[ลูป].r, ดาว[ลูป].g, ดาว[ลูป].b, 255);
glBegin(GL_QUADS); // เริ่มวาดรูปสี่เหลี่ยมที่แมปพื้นผิว
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 0.0);
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 0.0);
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 0.0);
glEnd(); // สิ้นสุดรูปสี่เหลี่ยม
{รหัสด้านล่างแสดงถึงการเคลื่อนที่ของดวงดาว
เราเพิ่มค่าการหมุนเพื่อหมุนดาวทั้งหมด (รอบ)
จากนั้นเพิ่มมุมการหมุนของดาวฤกษ์แต่ละดวงขึ้นเป็นวง/ตัวเลข
ส่งผลให้ดวงดาวที่อยู่ไกลจากศูนย์กลางหมุนเร็วขึ้น ในที่สุดก็ลดระยะห่างของดาวแต่ละดวงจากกึ่งกลางหน้าจอ
ดูเหมือนว่าดวงดาวจะถูกดูดเข้าไปตรงกลางหน้าจออยู่ตลอดเวลา -
หมุน := หมุน + 0.01; // การปฏิวัติของดวงดาว
star[loop].angle := star[loop].angle + Trunc(loop) / 50; // เปลี่ยนมุมการหมุนของดาว
star[loop].dist := star[loop].dist - 0.01; // เปลี่ยนระยะห่างของดาวจากศูนย์กลาง
{บรรทัดถัดมาตรวจสอบว่าดาวแตะตรงกลางหน้าจอแล้วหรือไม่
เมื่อดาวตกถึงกึ่งกลางหน้าจอ เราจะเพิ่มสีใหม่และย้ายดาวออกไปด้านนอก 5 หน่วย
ดาวดวงนี้จะเริ่มเดินทางกลับไปยังจุดศูนย์กลางของหน้าจอ -
ถ้า (star[loop].dist < 0.0) แล้ว // ดาวถึงจุดศูนย์กลางแล้วหรือยัง?
เริ่ม
star[loop].dist := star[loop].dist + 5.0; // ย้าย 5 หน่วยออกไปด้านนอก
star[loop].r := Random(256); // กำหนดองค์ประกอบสีแดงใหม่
star[loop].g := Random(256); // กำหนดองค์ประกอบสีเขียวใหม่
star[loop].b := Random(256); // กำหนดองค์ประกอบสีน้ำเงินใหม่
จบ;
จบ;
จบ;
-
ตอนนี้เราเพิ่มโค้ดเพื่อตรวจสอบคีย์บอร์ด
เลื่อนลงไปที่ WinMain() ค้นหาบรรทัด SwapBuffers(hDC)
เราจะเพิ่มโค้ดตรวจสอบแป้นพิมพ์หลังบรรทัดนี้
รหัสจะตรวจสอบว่ามีการกดปุ่ม T หรือไม่
หากกดปุ่ม T แล้วปล่อย โค้ดในบล็อก if จะถูกดำเนินการ
ถ้ากระพริบตาเป็นเท็จ มันจะกลายเป็นจริง
ในทางกลับกัน ตราบใดที่กดปุ่ม T tp จะกลายเป็น TRUE
วิธีนี้จะป้องกันไม่ให้โค้ดภายในบล็อกถูกดำเนินการซ้ำๆ หากคุณกดปุ่ม T ต่อไป
-
ถ้า (keys[ord('T')] และไม่ใช่ tp) จากนั้น // ไม่ว่าจะกดปุ่ม T และค่า tp เป็น FALSE
เริ่ม
tp := TRUE; // ถ้าใช่ ให้ตั้งค่า tp เป็น TRUE
กระพริบตา := ไม่กระพริบตา; // พลิกค่าของกระพริบตา
จบ;
-
รหัสด้านล่างตรวจสอบว่าได้ปล่อยปุ่ม T แล้วหรือไม่
หากเป็นเช่นนั้น ให้ตั้งค่า tp=FALSE
เว้นแต่ว่าค่าของ tp จะเป็น FALSE
มิฉะนั้นจะไม่มีอะไรเกิดขึ้นในขณะที่กดปุ่ม T ค้างไว้ ดังนั้นโค้ดบรรทัดนี้จึงมีความสำคัญ
-
ถ้า (ไม่ใช่คีย์[Ord('T')]) แล้ว // มีการปล่อยคีย์ T หรือไม่?
เริ่ม
tp := FALSE; // ถ้าใช่ tp จะเป็น FALSE
จบ;
{รหัสที่เหลือจะตรวจสอบว่ามีการกดปุ่มลูกศรขึ้นและลง ปุ่มเลื่อนหน้าขึ้น หรือปุ่มเลื่อนหน้าลง -
ถ้า (คีย์ [VK_UP]) จากนั้น // กดปุ่มลูกศรขึ้นหรือไม่?
เอียง := เอียง - 0.5; // เอียงหน้าจอขึ้น
ถ้า (ปุ่ม [VK_DOWN]) จากนั้น // กดปุ่มลูกศรลงหรือไม่?
เอียง := เอียง + 0.5; // เอียงหน้าจอลง
ถ้า (keys[VK_PRIOR]) จากนั้น // กดปุ่ม page up หรือไม่?
ซูม := ซูม - 0.2; // ซูมออก
ถ้า (ปุ่ม [VK_NEXT]) จากนั้น // กดปุ่มเลื่อนหน้าลงหรือไม่?
ซูม := ซูม + 0.2; // ซูมเข้า
-
ในบทเรียนนี้ ฉันพยายามอย่างเต็มที่เพื่ออธิบายวิธีการโหลดพื้นผิวบิตแมประดับสีเทา
หลังจากลบสีพื้นหลังออก (โดยใช้สีผสม) ให้ระบายสีอีกครั้ง และสุดท้ายทำให้เคลื่อนไหวในฉาก 3D
ฉันได้แสดงให้คุณเห็นถึงวิธีการสร้างเอฟเฟกต์สีและภาพเคลื่อนไหวที่สวยงามแล้ว
หลักการดำเนินการคือการซ้อนทับสำเนาบิตแมปบนบิตแมปต้นฉบับ
จนถึงบัดนี้ตราบเท่าที่ท่านเข้าใจทุกสิ่งที่เราสอนท่านเป็นอย่างดี
คุณควรจะสามารถสร้างการสาธิต 3D ของคุณเองได้โดยไม่มีปัญหาใดๆ
ครอบคลุมพื้นฐานทั้งหมดแล้ว! -
//========ฉันลิง:
//แปลบทที่ 1-9 แล้ว ดังที่ กพพ. กล่าวไว้ ความรู้พื้นฐานได้ถูกอธิบายไว้แล้ว
//ผมดูบทช่วยสอนต่อไปนี้แล้ว และดูเหมือนว่าจะมีคนอื่นเขียนไว้ หากมีตัวอย่างที่ดี ผมก็จะคัดเลือกทำตาม
//ต่อใหม่ เหนื่อยมาก งีบหลับซะ :) ไว้เจอกันใหม่ตอนหน้า