ผ่านมาหลายบท ตอนนี้สามารถทำให้วัตถุเคลื่อนที่ได้แล้ว แต่ถ้าวัตถุแค่เคลื่อนที่ไปเรื่อยๆเฉยๆมันก็ดูแข็งทื่อ ดังนั้นบทนี้มารู้วิธีการทำให้วัตถุหมุน
การหมุนสามารถทำได้หลายวิธีด้วยกัน วิธีหนึ่งคือการปรับแกนดังที่พูดถึงไปแล้วใน บทที่ ๘
แต่วิธีนั้นใช้ได้กับเฉพาะวัตถุที่สร้างมาจากฟังก์ชันสร้างรูปทรงและยังเก็บ ประวัติการสร้างไว้อยู่เท่านั้น ในบทนี้จะพูดถึงวิธีที่ใช้ได้ทั่วไปกว่านั้น คือการปรับองค์ประกอบมุมการหมุนที่ตัวโหนดหลักของวัตถุ
ค่าองค์ประกอบที่กำหนดทิศทางการหันของวัตถุทั่วไปคือ rx (rotateX), ry (rotateY) และ rz (rotateZ)
โดยการใช้ฟังก์ชัน getAttr() ปรับค่า สามารถทำให้หมุนไปในทิศทางไหนก็ได้ เช่น ลองสร้างแท่งสี่เหลี่ยมยาวๆมาอันนึง
mc.polyCube(w=1,h=20,d=1)
แล้วตั้งให้หมุนในแกน x
mc.setAttr('.rx',30)
จากนั้นลองให้หมุนในแกน y ดู
mc.setAttr('.ry',45)
จากนั้นลองให้หมุนในแกน z ดู
mc.setAttr('.rz',10)
ก็จะเห็นว่าวัตถุมีการหมุนไปเรื่อยๆ
ค่ามุมหมุนของ ๓ แกนอาจปรับไปพร้อมกันได้ เช่น
mc.setAttr('.r',30,45,10)
แต่ว่าการปรับค่าด้วยวิธีนี้ต้องพิจารณาเรื่องลำดับการหมุนด้วย ทำให้อาจเข้าใจยากหน่อย
ลำดับการหมุนกำหนดโดยค่าองค์ประกอบ ro (rotateOrder)
ro = 0 เป็น xyz
ro = 1 เป็น yzx
ro = 2 เป็น zxy
ro = 3 เป็น xzy
ro = 4 เป็น yxz
ro = 5 เป็น zyx
โดยค่าเริ่มต้นมักตั้งเป็น 0 นั่นคือ xyz
ดังนั้นถ้าเราเริ่มหมุนจาก x แล้วค่อยหมุน y สุดท้ายก็หมุน z ก็จะไม่มีปัญหาอะไร เข้าใจได้ง่าย
แต่ถ้าปรับค่า z แล้วค่อยไปปรับค่า y ก็อาจทำให้ได้ค่าที่แปลกไปจากที่ต้องการ
ในกรณีที่ต้องการแบบนั้นมีวิธีการหมุนที่ดีกว่า คือใช้ฟังก์ชัน rotate()
ฟังก์ชันนี้มีไว้ใช้สำหรับหมุนวัตถุ โดยอาร์กิวเมนต์ ๓ ตัวคือพิกัดการหมุนในแกน x y z ตามลำดับ และอาจใส่อาร์กิวเมนต์ตัวที่ ๔ คือชื่อของวัตถุที่ต้องการหมุน สำหรับในกรณีที่ไม่ได้เลือกวัตถุ แต่ถ้าไม่ใส่ก็จะหมุนวัตถุที่ถูกเลือกอยู่
กรณีที่ไม่ใส่แฟล็กอะไร การใช้ rotate นี้ก็มีค่าเหมือนกับการใช้ setAttr เช่น
mc.rotate(30,45,10) # มีผลเท่ากับ mc.setAttr('.r',30,45,10)
แต่ถ้าใส่แฟล็ก r (relate) ก็จะเป็นการหมุนแบบสัมพัทธ์ คือเทียบกับมุมที่หันอยู่ในตอนนี้ เช่น เริ่มจากลองสร้างวัตถุแล้วให้หมุนไปในมุมแบบตอนแรก
mc.polyCube(w=1,h=20,d=1)
mc.setAttr('.r',30,45,10)
จากนั้นลองหมุนในแกน x แบบสัมพัทธ์
mc.rotate(-30,0,0,r=1)
จะพบว่ามันหมุน ๓๐ องศาตามแกน x จริงๆ แต่พอลองพิมพ์
mc.getAttr('.r')
จะพบว่าค่าที่ได้ไม่ใช่ [0,45,10] แต่เป็น [-12, 42, -19] ทั้งๆที่ตอนแรก x เป็น 30 ถ้าหมุนกลับ -30 ดังนั้น x ก็น่าจะเป็น 0 แต่นี่ไม่ใช่ แถมแกนอื่นยังเปลี่ยนค่าไปด้วย เพราะอะไร?
เพราะการหมุนแบบสัมพัทธ์ นี้จะหมุนตามภาพที่เห็นโดยไม่ได้สนลำดับการหมุน ดังนั้นถ้าใช้วิธีนี้หมุนในแกน x จะเป็นการปรับค่ามุมเพื่อที่จะให้เห็นว่ามีการหมุนในแกน x ไปตามค่าเท่านั้น เพื่อการนั้นอาจกระทบต่อค่ามุมหมุนของแกนอื่นไปด้วย
แต่ถ้าหากหมุนแกน z ซึ่งเป็นแกนที่มีลำดับการหมุนอยู่ลำดับสุดท้ายอยู่แล้ว เช่นพิมพ์ต่อไปว่า
mc.rotate(0,0,19,r=1)
เมื่อดูค่ามุมหมุนจะพบว่ามีการเปลี่ยนแปลงแค่ในแกน z ไม่ได้กระทบต่อแกนอื่นไปด้วย
แฟล็กของ rotate() มีลักษณะคล้าย move() นั่นคือมีแฟล็กสำหรับหมุนเฉพาะบางแกน
x (rotateX)
y (rotateY)
z (rotateZ)
xy (rotateXY)
xz (rotateXZ)
yz (rotateYZ)
วิธีการใช้คล้ายกับของ move() ดังนั้นไม่กล่าวซ้ำ
นอกจากนี้แล้วสิ่งสำคัญที่ต้องพูดถึงก็คือเรื่องของจุดพีว็อต (ピボット, pivot) ซึ่งเป็นจุดแกนกลางในการหมุน
โดยทั่วไปพีว็อตจะถูกตั้งมาให้เริ่มต้นอยู่ที่จุดศูนย์กลางของวัตถุ แต่ก็ไม่เสมอไป ตำแหน่งของพีว็อตสามารถย้ายได้
จุดพีว็อตนั้นมี ๒ จุดแยกกัน คือจุดพีว็อตของการหมุน กับจุดพีว็อตของมาตราส่วน ในที่นี้ขอพูดถึงพีว็อตของการหมุนก่อน
การย้ายจุดพีว็อตสามารถทำได้โดยคำสั่ง move() เหมือนกับวัตถุทั่วไป
เช่น ลองสร้างวัตถุแบบเดิมขึ้นมาใหม่แล้วย้ายพีว็อต
chue = mc.polyCube(w=1,h=20,d=1)
mc.select(chue[0]+'.rotatePivot')
mc.move(10,10,10)
หรืออาจกดเลือกที่ตัววัตถุแล้วพิมพ์แค่ .rotatePivot ดังนั้นอาจพิมพ์เป็นแบบนี้ได้เลย
chue = mc.polyCube(w=1,h=20,d=1)
mc.move(10,10,10,'.rotatePivot')
จุดพีว็อตไม่สามารถมองเห็นได้ถ้าไม่ตั้งให้มันแสดงผล สามารถให้แสดงได้โดยพิมพ์
mc.setAttr(chue[0]+'.displayRotatePivot',1)
หรือใช้ชื่อย่อเป็น
mc.setAttr(chue[0]+'.drp',1)
เพื่อให้แน่ใจว่าย้ายไปแล้วจริงๆสามารถพิมพ์
mc.getAttr('.rotatePivot')
ก็จะได้ตำแหน่งของจุดพีว็อต
พอย้ายจุดไปแบบนี้แล้ว พอลองพิมพ์
mc.rotate(0,120,0,chue[0])
จะพบว่าวัตถุถูกหมุนแล้วย้ายตำแหน่งไปไกล โดยแกนกลางการหมุนอยู่ที่พีว็อต
ปกติแล้วเวลาที่ใช้คำสั่ง move เพื่อย้ายวัตถุไป จุดพีว็อตจะถูกย้ายไปด้วย ดังนั้นไม่ว่าจะย้ายไปไหนวัตถุก็จะยังหมุนรอบจุดศูนย์กลาง
ดังนั้นหากต้องการให้วัตถุอยู่ห่างจากจุดพีว็อตก็ต้องมาทำการกำหนดตำแหน่งพีว็อตอีกที
ด้วยการย้ายพีว็อต เราอาจสามารถสร้างวัตถุที่มีสมมาตรแนวหมุนขึ้นมาได้อย่างง่าย เช่น
for i in range(36):
mc.polyCylinder(r=1,h=2) # สร้างทั้งหมด 36 ชิ้น
mc.move(10,0,0) # ทุกอันถูกย้ายไปในตำแหน่งนี้หมด
mc.rotate(0,10*i,0,p=[0,0,0]) # แต่ถูกหมุนด้วยมุมที่ต่างกัน
หรือซับซ้อนกว่านั้น เช่น
for j in range(18):
for i in range(36):
mc.polyCylinder(r=1,h=2)
mc.move(10,0,0)
mc.move(0,0,0,'.rotatePivot')
mc.rotate(0,10*i,10*j)
ที่จริงแล้วมีวิธีที่ง่ายกว่านั้นไปอีก โดยที่ไม่ต้องไปยุ่งอะไรกับพีว็อตเลย คือใช้แฟล็ก p (pivot) ในฟังก์ชัน rotate เพื่อกำหนดจุดศูนย์กลางในการหมุน โดยไม่จำเป็นต้องย้ายตำแหน่งพีว็อตก่อนเลย
ดังนั้นตัวอย่างนี้อาจเขียนใหม่ได้เป็น
for j in range(18):
for i in range(36):
mc.polyCylinder(r=1,h=2)
mc.move(10,0,0)
mc.rotate(0,10*i,10*j,p=[0,0,0])
สามารถทำภาพเคลื่อนไหวให้วัตถุหมุนไปมาได้โดยใช้ expression() หรือ setKeyframe()
ตัวอย่างการใช้เอ็กซ์เพรชชัน ลองจำลองการหมุนไปส่ายไป คล้ายลูกข่าง
mc.polyCone(r=4,h=20,ax=[0,-1,0],n='thaeng')
mc.expression(o='thaeng',s='rx = 60+15*cos(time*10)')
mc.expression(o='thaeng',s='ry = time*45')
ตอนต่อไปจะพูดถึงเรื่องมาตราส่วน ซึ่งเป็นเรื่องที่มีความใกล้เคียงกัน และมีความเกี่ยวข้องกันอยู่
อ้างอิง