φυβλαςのβλογ
บล็อกของ 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)
หอดูดาวโบราณปักกิ่ง ตอนที่ ๑: แท่นสังเกตการณ์และสวนดอกไม้
พิพิธภัณฑ์สถาปัตยกรรมโบราณปักกิ่ง
เที่ยวเมืองตานตง ล่องเรือในน่านน้ำเกาหลีเหนือ
ตระเวนเที่ยวตามรอยฉากของอนิเมะในญี่ปุ่น
เที่ยวชมหอดูดาวที่ฐานสังเกตการณ์ซิงหลง
ทำไมจึงไม่ควรเขียนวรรณยุกต์เวลาทับศัพท์ภาษาต่างประเทศ

ไทย

日本語

中文