φυβλαςのβλογ
บล็อกของ phyblas



maya python เบื้องต้น บทที่ ๔๐: การสำเนาวัตถุ
เขียนเมื่อ 2016/03/19 13:38
แก้ไขล่าสุด 2021/09/28 16:42
บางครั้งเราอาจต้องการสร้างวัตถุที่มีลักษณะเหมือนเดิมซ้ำๆหรือคล้ายจากเดิมหลายอัน

โดยปกติเราสามารถใช้การวนซ้ำ for หรือ while เพื่อสร้างวัตถุที่ต้องการขึ้นมากี่อันก็ได้ตามที่ต้องการอยู่แล้ว

แต่ว่าบางครั้งการซ้ำกระบวนการสร้างเดิมอยู่หลายๆครั้งนั้นเป็นอะไรที่ต้องใช้ เวลา ยิ่งวัตถุมีรูปร่างซับซ้อน กว่าจะทำออกมาได้อันหนึ่งก็ยิ่งนาน

กรณีที่มีวัตถุที่ต้องการวัตถุที่ซ้ำๆกันหรือสามารถแปลงรูปจากรูปร่างที่มีอยู่ ได้โดยง่าย เราสามารถใช้วิธีการทำสำเนาของวัตถุได้ โดยฟังก์ชันที่ใช้ก็คือ duplicate()

การใช้งานนั้นง่ายมาก แค่กดเลือกที่วัตถุที่ต้องการทำการสำเนาแล้วก็พิมพ์ mc.duplicate() เท่านี้ก็ได้วัตถุชิ้นเดิมอีกอันซึ่งอยู่ในตำแหน่งเดียวกัน จากนั้นก็กดย้ายมันไปไว้ในตำแหน่งอื่นตามที่ต้องการ เช่น
mc.polySphere(r=1)
for i in range(10):
    mc.duplicate()
    mc.move(i*2,i*2,0)



(หมายเหตุ ภาพในบทนี้มีการปรับแสงไฟโดยใช้ไฟสามสีจากบทที่แล้ว หากไม่มีแสงวัตถุจะเป็นสีเทาตามปกติ)

หรือถ้าใส่ชื่อของวัตถุที่ต้องการทำสำเนาลงไปเป็นอาร์กิวเมนต์ก็สามารถสำเนาวัตถุได้แม้จะไม่ได้เลือกอยู่

วัตถุที่ถูกทำสำเนาขึ้นมาใหม่สามารถตั้งชื่อได้เช่นกันโดยใส่แฟล้ก n (name) ถ้าไม่ตั้งจะถูกตั้งให้โดยอัตโนมัติให้สัมพันธ์กับวัตถุต้นฉบับ



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

วิธีใช้
import time # ประกาศนำเข้าชุดคำสั่ง
t0 = time.time() # เวลาเริ่มต้น
<กลุ่มคำสั่งที่ต้องการจับเวลา>
print(time.time() - t0) # พิมพ์เวลาสุดท้ายลบด้วยเวลาเริ่มต้น

เราลองทดสอบโดยการใช้จับเวลาเปรียบเทียบระหว่างใช้การสำเนากับใช้การวนซ้ำเพื่อสร้างใหม่

ลองสร้างวัตถุทรงกลมที่รวมกันเป็นกลุ่ม ๓๘ ลูก โดยเริ่มแรกจับเวลาที่ใช้สร้างด้วยวิธีสร้างซ้ำแล้วก็พิมพ์เวลาออกมา จากนั้นก็สร้างเหมือนเดิมอีกด้วยวิธีการทำสำเนา แล้วก็พิมพ์เวลาออกมาอีก จากนั้นลองเทียบกันดู
import time
k = [1,4,8,12,8,4,1]
# ใช้วิธีสร้างซ้ำ
t0 = time.time()
g = [] # สร้างลิสต์ที่เก็บชื่อของวัตถุ
for j in range(7):
    for i in range(k[j]):
        g += mc.polySphere(r=1,ch=0) # สร้างทรงกลมใหม่ พร้อมเพิ่มชื่อเข้าลิสต์
        mc.move(0,2,0) # ย้ายไปไว้ตำแหน่งขั้วเหนือ
        mc.rotate(j*30,360/k[j]*i,0,p=[0,0,0]) # หมุนตามแนวละติจูดและลองจิจูด
mc.group(g) # รวมกลุ่ม
print(time.time() - t0) # พิมพ์เวลาที่ใช้
# ใช้วิธีทำสำเนาไปเรื่อยๆ
t0 = time.time()    
g = mc.polySphere(r=1,ch=0) # สร้างทรงกลมลูกแรก พร้อมเก็บชื่อลิสต์
mc.move(0,2,0)
for j in range(1,7):
    for i in range(k[j]):
        g += mc.duplicate() # ทำสำเนา พร้อมเพิ่มชื่อเข้าลิสต์
        mc.rotate(j*30,360/k[j]*i,0,p=[0,0,0])
mc.group(g) # รวมกลุ่ม
print(time.time() - t0) # พิมพ์เวลาที่ใช้



จะได้ตัวเลขเวลาออกมาสองค่า จะเห็นว่าเลขตัวแรกจะมากกว่า นั่นคือวิธีการทำสำเนานั้นใช้เวลาน้อยกว่า ดังนั้นจึงช่วยประหยัดเวลาในการสร้างได้ แม้ว่าผลลัพธ์สุดท้ายจะเหมือนกันก็ตาม



การสำเนานั้นไม่เพียงทำกับตัววัตถุทีละชิ้นเท่านั้น ยังสามารถสำเนาวัตถุพรุ้อมกันหลายชิ้น หรืออาจสำเนากลุ่มของวัตถุก็ได้

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

ลองเทียบอีกตัวอย่างหนึ่งที่ซับซ้อนกว่าเดิม คราวนี้ลองเอากลุ่มทรงกลมที่ได้ออกมานั้นมานั้นมาสร้างใหม่ซ้ำๆแล้วรวมเป็นก ลุ่มที่ใหญ่ขึ้นไปอีก
import time
k = [1,4,8,12,8,4,1]
# ใช้วิธีสร้างซ้ำ
t1 = time.time()
gg = [] # สร้างลิสต์ที่เก็บชื่อของกลุ่มทรงกลม
for n in range(7): # วงใหญ่ (วนซ้ำเพื่อสร้างกลุ่มของทรงกลมที่ถูกสร้างในวงย่อย)
    for m in range(k[n]):
        g = [] # สร้างลิสต์ที่เก็บชื่อของทรงกลมย่อย
        for j in range(7): # วงย่อย (สร้างทรงกลมย่อย)
            for i in range(k[j]):
                g += mc.polySphere(r=1,ch=0) # สร้างทรงกลมย่อยพร้อมเก็บชื่อเข้าลิสต์
                mc.move(0,2,0)
                mc.rotate(j*30,360/k[j]*i,0,p=[0,0,0])
        gg += [mc.group(g)] # รวมทรงกลมย่อยเป็นกลุ่มพร้อมเพิ่มชื่อเข้าลิสต์
        mc.move(0,6,0)
        mc.rotate(n*30,360/k[n]*m,0,p=[0,0,0])
mc.group(gg) # รวมกลุ่มทรงกลมเป็นใหญ่
print(time.time() - t1) # พิมพ์เวลาที่ใช้
# ใช้วิธีทำสำเนาไปเรื่อยๆ
t1 = time.time()
g = mc.polySphere(r=1,ch=0) # สร้างทรงกลมย่อยลูกแรก
mc.move(0,2,0)
for j in range(1,7):
    for i in range(k[j]):
        g += mc.duplicate() # สำเนาทรงกลมย่อย
        mc.rotate(j*30,360/k[j]*i,0,p=[0,0,0])
gg = [mc.group(g)] # รวมกลุ่มเป็นกลุ่มทรงกลมกลุ่มแรก พร้อมเก็บชื่อเข้าลิสต์ที่เก็บชื่อกลุ่มทรงกลม
mc.move(0,6,0)
for j in range(1,7):
    for i in range(k[j]):
        gg += [mc.duplicate()[0]] # สำเนากลุ่มทรงกลม พร้อมเก็บชื่อเข้าลิสต์ โดย [0] ในที่นี้หมายถึงเอาเฉพาะชื่อของกลุ่มซึ่งเป็นชื่อแรกที่ฟังก์ชันคืนกลับมา
        mc.rotate(j*30,360/k[j]*i,0,p=[0,0,0])
mc.group(gg) # รวมกลุ่มทรงกลมเป็นกลุ่มใหญ่
print(time.time() - t1) # พิมพ์เวลาที่ใช้

จะเห็นว่าใช้การทำสำเนานั้นให้ผลเป็นเวลาที่เร็วกว่า อีกทั้งโค้ดดูง่ายกว่า ไม่ต้องสร้างวงวนซ้ำซ้อนกัน





อนึ่ง หากลองไปดูที่ชื่อของกลุ่มที่ถูกสำเนาขึ้นมาจะเห็นว่าชื่อเหมือนกันหมดทุก กลุ่ม เช่นในกลุ่ม group40 ถึง group 77 จะมีวัตถุชื่อ pSphere1445 ถึง  pSphere1482 อยู่เหมือนกันหมด

หากมีวัตถุชื่อซ้ำกันจะมีปัญหาเวลาที่ อ้างอิงถึงวัตถุนั้น ถ้าหากพิมพ์แค่ชื่อวัตถุนั้นลงไปเช่น mc.select('pSphere1445') ก็จะพบว่าโปรแกรมขัดข้องเพราะไม่รู้ว่าหมายถึงชิ้นไหน

แต่สำหรับวัตถุที่แม้จะชื่อซ้ำกันแต่อยู่สังกัดคนละกลุ่มกันก็สามารถแยกแยะได้โดย พิมพ์ชื่อกลุ่มที่สังกัดนำหน้าไว้แล้วตามด้วย | แล้วค่อยตามด้วยชื่อวัตถุนั้น เช่นในกรณีนี้พิมพ์เป็น
mc.select('group40|pSphere1445')

ก็จะเป็นการเลือกวัตถุ pSphere1445 ที่อยู่ในกลุ่ม group40 ไม่ใช่ที่อยู่ในกลุ่มอื่น สามารถแยกแยะกันได้ชัดเจนไม่มีปัญหาอะไร



ดังนั้นโดยทั่วไปอาจไม่ต้องคิดมากเรื่องที่ชื่อซ้ำ ถือเป็นเรื่องปกติและยังทำให้สะดวกในการอ้างอิงด้วย

อย่างไรก็ตามตอนที่สำเนาหากต้องการเปลี่ยนชื่อวัตถุที่อยู่ในกลุ่มให้ไม่ซ้ำกันก็ สามารถทำได้โดยเพิ่มแฟล็ก rc (renameChildren) เป็น rc=1 แล้วชื่อวัตถุก็จะถูกเปลี่ยนให้ไม่ซ้ำกัน

ลองสร้างใหม่โดยใช้โค้ด ตัวอย่างที่แล้ว โดยแค่เพิ่มแฟล็ก rc=1 ลงในฟังก์ชัน duplicate() เป็น mc.duplicate(rc=1) ทั้งสองที่ จะได้ผลเหมือนเดิมแต่ต่างกันแค่ชื่อของวัตถุ





นอกจากนี้การสำเนาไม่ได้ทำได้เพียงแค่วัตถุที่จับต้องได้เท่านั้น ยังสามารถใช้กับโหนดอย่างอื่นด้วย เช่นเท็กซ์เจอร์หรือวัสดุ ฯลฯ ได้ด้วยเช่นกัน

duplicate() เป็นคำสั่งที่มีประโยชน์มากมาย น่าจะได้ใช้กันต่อไปอีกเยอะ



อ้างอิง

<< บทที่แล้ว      บทถัดไป >>
หน้าสารบัญ


-----------------------------------------

囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧囧

ดูสถิติของหน้านี้

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> python >> mayapython
-- คอมพิวเตอร์ >> 3D >> maya

ไม่อนุญาตให้นำเนื้อหาของบทความไปลงที่อื่นโดยไม่ได้ขออนุญาตโดยเด็ดขาด หากต้องการนำบางส่วนไปลงสามารถทำได้โดยต้องไม่ใช่การก๊อปแปะแต่ให้เปลี่ยนคำพูดเป็นของตัวเอง หรือไม่ก็เขียนในลักษณะการยกข้อความอ้างอิง และไม่ว่ากรณีไหนก็ตาม ต้องให้เครดิตพร้อมใส่ลิงก์ของทุกบทความที่มีการใช้เนื้อหาเสมอ

สารบัญ

รวมคำแปลวลีเด็ดจากญี่ปุ่น
มอดูลต่างๆ
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
การเรียนรู้ของเครื่อง
-- โครงข่าย
     ประสาทเทียม
ภาษา javascript
ภาษา mongol
ภาษาศาสตร์
maya
ความน่าจะเป็น
บันทึกในญี่ปุ่น
บันทึกในจีน
-- บันทึกในปักกิ่ง
-- บันทึกในฮ่องกง
-- บันทึกในมาเก๊า
บันทึกในไต้หวัน
บันทึกในยุโรปเหนือ
บันทึกในประเทศอื่นๆ
qiita
บทความอื่นๆ

บทความแบ่งตามหมวด



ติดตามอัปเดตของบล็อกได้ที่แฟนเพจ

  ค้นหาบทความ

  บทความแนะนำ

ตัวอักษรกรีกและเปรียบเทียบการใช้งานในภาษากรีกโบราณและกรีกสมัยใหม่
ที่มาของอักษรไทยและความเกี่ยวพันกับอักษรอื่นๆในตระกูลอักษรพราหมี
การสร้างแบบจำลองสามมิติเป็นไฟล์ .obj วิธีการอย่างง่ายที่ไม่ว่าใครก็ลองทำได้ทันที
รวมรายชื่อนักร้องเพลงกวางตุ้ง
ภาษาจีนแบ่งเป็นสำเนียงอะไรบ้าง มีความแตกต่างกันมากแค่ไหน
ทำความเข้าใจระบอบประชาธิปไตยจากประวัติศาสตร์ความเป็นมา
เรียนรู้วิธีการใช้ regular expression (regex)
การใช้ unix shell เบื้องต้น ใน linux และ mac
g ในภาษาญี่ปุ่นออกเสียง "ก" หรือ "ง" กันแน่
ทำความรู้จักกับปัญญาประดิษฐ์และการเรียนรู้ของเครื่อง
ค้นพบระบบดาวเคราะห์ ๘ ดวง เบื้องหลังความสำเร็จคือปัญญาประดิษฐ์ (AI)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

บทความแต่ละเดือน

2024年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2023年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2022年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2021年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

2020年

1月 2月 3月 4月
5月 6月 7月 8月
9月 10月 11月 12月

ค้นบทความเก่ากว่านั้น

ไทย

日本語

中文