ผลต่างระหว่างรุ่นของ "418341 ภาคต้น 2552: การบ้าน 2"
Cardcaptor (คุย | มีส่วนร่วม) |
Cardcaptor (คุย | มีส่วนร่วม) |
||
แถว 134: | แถว 134: | ||
โดยจะใช้คำสั่งแรกหรือคำสั่งที่สองขึ้นอยู่กับว่าขณะนั้นคุณคอมไพล์โปรแกรมแบบ Debug (มีข้อมูลเกี่ยวกับการดีบัก ทำให้โค้ดช้า) หรือ Release (ดีบักไม่ได้ แต่เร็ว) | โดยจะใช้คำสั่งแรกหรือคำสั่งที่สองขึ้นอยู่กับว่าขณะนั้นคุณคอมไพล์โปรแกรมแบบ Debug (มีข้อมูลเกี่ยวกับการดีบัก ทำให้โค้ดช้า) หรือ Release (ดีบักไม่ได้ แต่เร็ว) | ||
+ | |||
+ | == ตัวอย่างผลลัพธ์ที่ถูกต้อง == | ||
+ | <table align="center"> | ||
+ | <tr> | ||
+ | <td align="center">[[Image:Problem_4_bunny.JPG|256px]]</td> | ||
+ | <td align="center">[[Image:Problem_4_garg.JPG|256px]]</td> | ||
+ | <td align="center">[[Image:Problem_4_torus.JPG|256px]]</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td align="center">Release\problem4_test data\bunny.obj</td> | ||
+ | <td align="center">Release\problem4_test data\garg.obj</td> | ||
+ | <td align="center">Release\problem4_test data\torus.obj</td> | ||
+ | </tr> | ||
+ | </table> | ||
+ | |||
+ | == คำแนะนำ == | ||
+ | ในไฟล์ <tt>include\cglib\string.h</tt> จะมีฟังก์ชัน | ||
+ | <geshi lang="C"> | ||
+ | std::vector<std::string> split(const std::string &s, char delim); | ||
+ | </geshi> | ||
+ | ซึ่งคุณสามารถป้อนสตริง <tt>s</tt> และตัวอักษร <tt>delim</tt> แล้วมันจะคืน vector ของสตริงหลายตัวที่เิิกิดจากการตัด <tt>s</tt> เป็นท่อนๆ แต่ละท่อนขั้นด้วยตัวอักษร <tt>delim</tt> เช่นถ้าเรียก | ||
+ | <geshi lang="C"> | ||
+ | std::vector<std::string> parts = split("v 0.5 0.3 0.7", ' '); | ||
+ | </geshi> | ||
+ | คุณจะได้ว่า <tt>parts[0] = "v"</tt>, <tt>parts[1] = "0.5"</tt>, <tt>parts[2] = "0.3"</tt>, และ <tt>parts[3] = "0.7"</tt> | ||
== ข้อ 5: แสดงผล MeshNode == | == ข้อ 5: แสดงผล MeshNode == |
รุ่นแก้ไขเมื่อ 17:03, 7 กันยายน 2552
คำเืตือน: การบ้านนี้เป็นการบ้านที่ต้องเขียนโปรแกรมมาก และมีเวลาทำน้อย นอกจากนี้ยังต้องมีความรู้ภาษา C++ เป็นอย่างดี
ุถ้าคุณไม่มั่นใจว่าคุณมีความรู้ภาษา C++ ดีพอ คุณสามารถไปหาข้อมูลเพิ่มเติมได้จาก
นอกจากนี้ โค้ดที่ให้ไปในการบ้านนี้มีจำนวนมาก ผมได้อธิบายรายละิเอียดของโ้ด้ดพวกนี้ไปบางส่วนแล้วในเลคเชอร์วันที่ 19 และ 21 สิงหาคม การดู สไลด์ ประกอบการสอนจะช่วยคุณได้มาก
เนื้อหา
ดาวน์โหลดโค้ด
ขั้นแรกให้ดาวน์โหลดโค้ดจากงลิงนี้ก่อน: homework-02.zip หลัีงจากนั้นให้ขยายไฟล์แล้วเปิดไฟล์ด้วย homework-02.sln ด้วย Microsoft Visual Studio 2008 Express
ข้อ 1: Matrix
เมื่อเปิดไฟล์ homework-02.sln แล้วให้ปิด project ทั้งหมดแล้วเหลือ project เหล่านี้เอาไว้
- gtest
- problem0
- problem1
- problem1_test
โดยการปิดโปรเจคใ้้ห้ทำโดยคลิกขวาที่ชื่อโปรเจคแล้วเลือก Unload Project
หลังจากนั้นให้เปิด problem1.cpp ในโปรเจค problem1 แล้วเติมฟังก์ชันเหล่านี้ให้สมบูรณ์
Matrix4x4 Matrix4x4::identity()
- คืน identity matrix ขนาด 4 คูณ 4
Matrix4x4 Matrix4x4::translate(float x, float y, float z)
- คืน matrix ของการเลื่อนแกนขนานไปตามแกน x เท่ากับอาร์กิวเมนต์ x, ไปตามแกน y เท่ากับอาร์กิวเมนต์ y, และไปตามแกน z เท่ากับอาร์กิวเมนต์ z
Matrix4x4 Matrix4x4::translate_x(float x)
- คืน matrix ของการเลื่อนแกนขนานไปตามแกน x เท่ากับอาร์กิวเมนต์ x
Matrix4x4 Matrix4x4::translate_y(float y)
- คืน matrix ของการเลื่อนแกนขนานไปตามแกน y เท่ากับอาร์กิวเมนต์ y
Matrix4x4 Matrix4x4::translate_z(float z)
- คืน matrix ของการเลื่อนแกนขนานไปตามแกน z เท่ากับอาร์กิวเมนต์ z
Matrix4x4 Matrix4x4::scale(float x, float y, float z)
- คืน matrix ของการย่อขยายขนาดตามแกน x เท่ากับอาร์กิวเมนต์ x เท่า, ตามแกน y เท่ากับอาร์กิวเมนต์ y เท่า, และตามแกน z เท่ากับอาร์กิวเมนต์ z เท่า
Matrix4x4 Matrix4x4::scale_x(float x)
- คืน matrix ของการย่อขยายขนาดตามแกน x เท่ากับอาร์กิวเมนต์ x เท่า
Matrix4x4 Matrix4x4::scale_y(float y)
- คืน matrix ของการย่อขยายขนาดตามแกน y เท่ากับอาร์กิวเมนต์ y เท่า
Matrix4x4 Matrix4x4::scale_z(float z)
- คืน matrix ของการย่อขยายขนาดตามแกน z เท่ากับอาร์กิวเมนต์ z เท่า
Matrix4x4 Matrix4x4::rotate(float degrees, Vector3 axis)
- คืน matrix ของการหมุนเป็นมุม degrees องศา รอบแกน axis
Matrix4x4 Matrix4x4::rotate_x(float degrees)
- คืน matrix ของการหมุนเป็นมุม degrees องศา รอบแกน x
Matrix4x4 Matrix4x4::rotate_y(float degrees)
- คืน matrix ของการหมุนเป็นมุม degrees องศา รอบแกน y
Matrix4x4 Matrix4x4::rotate_z(float degrees)
- คืน matrix ของการหมุนเป็นมุม degrees องศา รอบแกน z
เมื่อเติมเสร็จเรียบร้อยแล้วให้ทดลอง compile ด้วยการกด F7
ถ้าคอมไพล์ผ่านให้เลือกโปรเจค problem1_test เป็น Startup Project โดยคลิกขวาที่ชื่อโปรเจค problem1_test แล้วเลือก Set as Startup Project หลังจากนั้นจึงลองรันมันด้วยการกด Ctrl+F5 ถ้าโปรแกรมคุณทำงานได้ถูกต้อง คุณจะผ่านการทดสอบที่เขียนไว้ใน problem1_test.cpp
ข้อ 2: Transform
หลังจากทำข้อ 1 เสร็จแล้ว ให้เปิดโปรเจค problem2 และ problem2_test ด้วยการคลิกขวาที่ชื่อโปรเจคแล้วเลือก Load Project
ในข้อ 2 นี้เราจะทำการ implement ฟังก์ชันสำหรับสร้าง instance ของคลาส Transform ซึ่งใช้แทน affine transformation ที่สำคัญใน computer graphics
คลาส Transform มีส่วนประกอบเป็น matrix ขนาด 4 คูณ 4 สาม matrix ได้แก่
- m เป็น matrix ของ transform
- mi เป็น inverse ของ m
- mit เป็น inverse transform ของ m (กล่าวคือเป็น transpose ของ mi)
ฟังก์ชันที่ต้ัองเติมให้สมบูรณ์อยู่ในไฟล์ชื่อ problem2.cpp ในโปรเจค problem2 มีดังต่อไปนี้
Transform Transform::identity()
- คืน Transform ที่แทน identity transformation
Transform Transform::translate(float x, float y, float z)
- คืน Transform ที่แทนการเลื่อนแกนขนานไปตามแกน x เท่ากับอาร์กิวเมนต์ x, ไปตามแกน y เท่ากับอาร์กิวเมนต์ y, และไปตามแกน z เท่ากับอาร์กิวเมนต์ z
Transform Transform::translate_x(float x)
- คืน Transform ที่แทนการเลื่อนแกนขนานไปตามแกน x เท่ากับอาร์กิวเมนต์ x
Transform Transform::translate_y(float y)
- คืน Transform ที่แทนการเลื่อนแกนขนานไปตามแกน y เท่ากับอาร์กิวเมนต์ y
Transform Transform::translate_z(float z)
- คืน Transform ที่แทนการเลื่อนแกนขนานไปตามแกน z เท่ากับอาร์กิวเมนต์ z
Transform Transform::scale(float x, float y, float z)
- คืน Transform ที่แทนการย่อขยายขนาดตามแกน x เท่ากับอาร์กิวเมนต์ x เท่า, ตามแกน y เท่ากับอาร์กิวเมนต์ y เท่า, และตามแกน z เท่ากับอาร์กิวเมนต์ z เท่า
Transform Transform::scale_x(float x)
- คืน Transform ที่แทนการย่อขยายขนาดตามแกน x เท่ากับอาร์กิวเมนต์ x เท่า
Transform Transform::scale_y(float y)
- คืน Transform ที่แทนการย่อขยายขนาดตามแกน y เท่ากับอาร์กิวเมนต์ y เท่า
Transform Transform::scale_z(float z)
- คืน Transform ที่แทนการย่อขยายขนาดตามแกน z เท่ากับอาร์กิวเมนต์ z เท่า
Transform Transform::rotate(float degrees, Vector3 axis)
- คืน Transform ที่แทนการหมุนเป็นมุม degrees องศา รอบแกน axis
Transform Transform::rotate_x(float degrees)
- คืน Transform ที่แทนการหมุนเป็นมุม degrees องศา รอบแกน x
Transform Transform::rotate_y(float degrees)
- คืน Transform ที่แทนการหมุนเป็นมุม degrees องศา รอบแกน y
Transform Transform::rotate_z(float degrees)
- คืน Transform ที่แทนการหมุนเป็นมุม degrees องศา รอบแกน z
เมื่อเติมเสร็จเรียบร้อยแล้วให้ทดลอง compile ด้วยการกด F7
ถ้าคอมไพล์ผ่านให้เลือกโปรเจค problem2_test เป็น Startup Project โดยคลิกขวาที่ชื่อโปรเจค problem1_test แล้วเลือก Set as Startup Project หลังจากนั้นจึงลองรันมันด้วยการกด Ctrl+F5 ถ้าโปรแกรมคุณทำงานได้ถูกต้อง คุณจะผ่านการทดสอบที่เขียนไว้ใน problem2_test.cpp
หมายเหตุ: เพื่อให้ข้อนี้ไม่ง่ายเกินไป ผมได้ลบฟังก์ชัน inverse ออกไปจาก matrix4x4.h คุณจะต้องหาทางหา inverse ของวัตถุต่างๆ เอาเอง
ข้อ 3: Mesh
เมื่อทำข้อ 3 เสร็จแล้วให้เปิดโปรเจค problem3 และ problem3_test
ในข้อนี้เราจะทำการ implement คลาส Mesh คุณสามารถดูรายละเอียดของคลาสนี้ได้จาก สไลด์
คุณสามารถแ้ก้ไข declaration ของคลาส Mesh ได้ในไฟล์ problem3.h แต่คุณไม่ควรแก้ลบ method ที่มีอยู่แล้วออกไปเนื่องจากโค้ดส่วนอื่นใช้ method เหล่านี้ อนึ่ง คลาส Mesh ที่ให้มาไม่มีฟีลด์ใดๆ อยู่เลย ฉะนั้นคุณจะต้องเพิ่มฟีลด์ที่เหมาะสมเข้าไปเอง
หลังจากแก้ไข declaration แล้วให้ไป implement method ต่างๆ ในไฟล์ problem3.cpp อย่าลืมว่าถ้าคุณเพิ่ม method ใดขึ้นมาคุณจะต้อง implement method นั้นด้วย
เมื่อคุณ implement คลาด Mesh เรียบร้อยแล้วให้ลองคอมไพล์ แล้วจึงเซต problem3_test เป็น Startup Project แล้วรัน ถ้าโปรแกรมคุณทำงานได้ถูกต้อง คุณจะผ่านการทดสอบที่เขียนไว้ใน problem3_test.cpp
ข้อ 4: อ่านไฟล์ .obj
ในข้อสี่ คุณจะทำการอ่านไฟล์ .obj เข้าใส่ในคลาส Mesh ที่เขียนไว้ในข้อ 3 อันดับแรกขอให้เปิดโปรเจคชื่อ problem4 และ problem4_test
คุณจะต้อง implement ฟังก์ชัน <geshi lang="c"> Mesh *parse_obj_file(const char *file_name) </geshi> ที่อยู่ในไฟล์ problem4/problem4.cpp
ฟังก์ชันนี้จะรับ string file_name ซึ่งบรรจุชื่อไฟล์ .obj เข้าไป คุณจะต้องเปิดอ่านไฟล์นี้ อ่านข้อมูลในไฟล์ .obj แล้ว allocate instance ของคลาส Mesh ขึ้นมาใหม่เพื่อเก็บข้อมูลจากไฟล์ เมื่อเสร็จแล้วให้คืน instance ที่ allocate ขึ้นมาใหม่กลับไปให้ผู้เรียกฟังก์ชัน
คุณสามารถอ่านรูปแบบของไฟล์ .obj ได้ในเวบไซต์นี้: http://www.royriggs.com/obj.html
คำสั่งในไฟล์ .obj ที่คุณจะต้องสามารถประมวลผลได้อย่างถูกต้องคือ
- v (ใช้เพิ่มตำแหน่ง)
- vn (ใช้เพิ่ม normal)
- vt (ใช้เพิ่ม texture coordinate)
- f (ใช้เพิ่ม face)
ส่วนคำสั่งอื่นถ้าอ่านเจอให้ข้ามไป ไม่ต้องเขียนโค้ดเพื่อประมวลผลคำสั่งเหล่านั้น
เมื่อคุณ implement ฟังก์ชันเสร็จแล้ว ให้ลองคอมไพล์โค้ดดู ถ้าคอมไพล์ได้ถูกต้องคุณจะสามารถรันโปรแกรม problem4_test ได้ คุณสามารถทดสอบว่าโปรแกรมของคุณทำงานได้ถูกต้องหรือไม่ได้โดยการรันคำสั่งต่อไปนี้ในไดเรคทอรีที่คุณขยายไฟล์ homework-02.zip เอาไว้
C:\Directory ที่ขยาย homework-02.zip> Debug\problem4_test <ชื่อไฟล์ .obj>
หรือ
C:\Directory ที่ขยาย homework-02.zip> Release\problem4_test <ชื่อไฟล์ .obj>
โดยจะใช้คำสั่งแรกหรือคำสั่งที่สองขึ้นอยู่กับว่าขณะนั้นคุณคอมไพล์โปรแกรมแบบ Debug (มีข้อมูลเกี่ยวกับการดีบัก ทำให้โค้ดช้า) หรือ Release (ดีบักไม่ได้ แต่เร็ว)
ตัวอย่างผลลัพธ์ที่ถูกต้อง
Release\problem4_test data\bunny.obj | Release\problem4_test data\garg.obj | Release\problem4_test data\torus.obj |
คำแนะนำ
ในไฟล์ include\cglib\string.h จะมีฟังก์ชัน <geshi lang="C"> std::vector<std::string> split(const std::string &s, char delim); </geshi> ซึ่งคุณสามารถป้อนสตริง s และตัวอักษร delim แล้วมันจะคืน vector ของสตริงหลายตัวที่เิิกิดจากการตัด s เป็นท่อนๆ แต่ละท่อนขั้นด้วยตัวอักษร delim เช่นถ้าเรียก <geshi lang="C"> std::vector<std::string> parts = split("v 0.5 0.3 0.7", ' '); </geshi> คุณจะได้ว่า parts[0] = "v", parts[1] = "0.5", parts[2] = "0.3", และ parts[3] = "0.7"