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



maya python เบื้องต้น บทที่ ๓๐: ทำความเข้าใจกับโครงสร้างโหนด
เขียนเมื่อ 2016/03/11 17:26
แก้ไขล่าสุด 2021/09/28 16:42
หากใครตามอ่านมาเรื่อยๆจนถึงบทนี้คิดว่าน่าจะพอเริ่มจับทางขึ้นมาได้บ้างแล้วเกี่ยวกับกลไกและโครงสร้างพื้นฐานของโปรแกรมมายา

นั่นคือจะเห็นได้ว่าภายในโปรแกรมนี้โดยหลักแล้วประกอบขึ้นจากหน่วยย่อยๆซึ่งเรียกว่าโหนด (node) ต่างๆมากมาย

ตั้งแต่บทที่ผ่านๆมาก็มีพูดถึงโหนดไปบ้างแล้ว แต่ว่ายังไม่ได้พูดขยายความละเอียด ในบทนี้จะมาเน้นเรื่องนี้สักหน่อย



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

เพื่อให้เห็นภาพขอเริ่มจากยกตัวอย่าง ลองสร้างวัตถุโพลิกอนขึ้นมาอันนึง
mc.polyCube()

ในที่นี้จะได้วัตถุชื่อ pCube1 เริ่มแรกดูในแอตทริบิวต์อีดิเตอร์ก็จะปรากฏ ๕ แถบ



pCube1, pCubeShape1, polyCube1, initialShadingGroup และ lambert1
(ระวังสับสน pCube1 กับ polyCube1 ชื่อคล้ายกันแต่เป็นคนละอันกัน)

ซึ่งแต่ละแถบก็แทน ๑ โหนด ซึ่งโหนดทางซ้ายสุดคือโหนดหลักของตัววัตถุ ส่วนโหนดถัดๆมาก็เป็นโหนดที่มีความเกี่ยวข้องเชื่อมโยงกับวัตถุนั้น

แต่ละโหนดนั้นยังประกอบด้วยค่าองค์ประกอบต่างๆ เช่นโหนด pCube1 กำหนดตำแหน่งและมุมหมุนของวัตถุ โหนด polyCube1 กำหนดความกว้างยาวสูงของวัตถุ โหนด lambert1 กำหนดลักษณะพื้นผิวและสี เป็นต้น

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

โหนดแบ่งออกเป็นชนิดต่างๆซึ่งมีหน้าที่แตกต่างกันไป

การจะหาว่าโหนดไหนเป็นชนิดไหนก็ทำได้โดยฟังก์ชัน nodeType()

ลองพิมพ์ตามนี้เพื่อหาชนิดของโหนดทั้งหมดที่เกี่ยวข้องกับ pCube1
for n in ['pCube1','pCubeShape1','polyCube1','initialShadingGroup','lambert1']:
    print(n+u' เป็นโหนดชนิด '+mc.nodeType(n))

จะได้ว่า
pCube1 เป็นโหนดชนิด transform
pCubeShape1 เป็นโหนดชนิด mesh
polyCube1 เป็นโหนดชนิด polyCube
initialShadingGroup เป็นโหนดชนิด shadingEngine
lambert1 เป็นโหนดชนิด lambert

อันแรกคือชนิด transform คือตัวกำหนดรูปร่างปรากฏขั้นสุดท้ายของวัตถุ เก็บค่าตำแหน่ง, มุมหมุน, สัดส่วน, ฯลฯ เป็นโหนดหลักของตัววัตถุที่เราเห็นเป็นรูปเป็นร่างปรากฏอยู่ในฉาก

ส่วน mesh นั้นก็เป็นโหนดที่กำหนดรูปแบบการแสดงผลของวัตถุ ถูกสร้างตามติดมากับวัตถุชนิดโพลิกอน

ส่วน polyCube คือโหนดเฉพาะของลูกบาศก์โพลิกอน เป็นโหนดที่เปลี่ยนไปตามชนิดของวัตถุ มีหน้าที่กำหนดรูปร่างพื้นฐานของวัตถุ เช่นความกว้างยาว และจำนวนโพลิกอน

เกี่ยวกับเรื่องนี้ได้อธิบายไปแล้วในบทที่ ๘

shadingEngine กับ lambert นั้นเกี่ยวข้องกับพื้นผิว โดยนี่เป็นสีที่กำหนดมาให้เป็นสีตั้งต้นถ้ายังไม่ได้มีการกำหนดสีใหม่

ในบทที่ ๒๗ ได้พูดถึงการใส่สีไปแล้ว และจะเห็นว่าเมื่อมีการกำหนดสีใหม่ให้กับวัตถุโหนดนี้จะเปลี่ยนเป็นโหนดของ วัสดุที่สร้างขึ้นมาใหม่

เช่นลองสร้างวัตถุใหม่แล้วใส่สีตามขั้นตอนเช่นเดียวกับที่ทำในบทที่ ๒๗
a = mc.shadingNode('blinn',asShader=1)
mc.setAttr(a+'.c',0.26,0.9,0.1,typ='double3')
mc.polySphere(r=1)
mc.hyperShade(a=a)

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



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

ยิ่งทำอะไรกับวัตถุมากก็จะมีโหนดที่เกี่ยวข้องกับตัววัตถุเพิ่มขึ้นมากตามมา คำสั่งที่จัดการกับโพลิกอนในแบบพิเศษเช่นการดึงผิวด้วย polyExtrudeFacet() (บทที่ ๒๔) หรือการปรับขอบโค้งมนด้วย polyBevel() (บทที่ ๒๕) ก็ทำให้เกิดโหนดใหม่เช่นกัน

ลอง
mc.polyPrism()
mc.polyBevel()
mc.polyExtrudeFacet()

จะได้วัตถุที่มีโหนดชื่อ polyExtrudeFace1 และ polyBevel1 อยู่





การดูโหนดทั้งหมดที่ปรากฏอยู่ในโปรแกรมตอนนี้สามารถทำได้โดยใช้ฟังก์ชัน ls()

ลองพิมพ์
print(mc.ls())

จะพบรายชื่อโหนดต่างๆโผล่มามากมายซึ่งมีชื่อแปลกๆที่ไม่คุ้นเคยเต็มไปหมด

ลองนับจำนวนโหนดดูได้ด้วย
print(len(mc.ls())

เพิ่งสร้างวัตถุมาแค่แค่นิดเดียวทำไมถึงมีโหนดอยู่เต็มไปหมดแบบนี้?

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

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



ที่เห็นเป็นรูปกล้องนั้นคือโหนดของกล้อง ซึ่แบ่งเป็นมุมต่างๆ ได้แก่ persp คือมุมกล้องที่ปรากฏอยู่บนหน้าจอที่เรามองนี่เอง แล้วก็ตามแนวแกน ๓ ทิศ top, front, side

ส่วนที่เหลือคือ defaultLightSet กับ defaultObjectSet

ของพวกนี้แม้กด delete ก็ไม่สามารถลบทิ้งได้เพราะเป็นสิ่งติดตัวที่จำเป็นต้องมี

สามารถจำเพาะโหนดที่จะเลือกดูได้โดยกำหนดแฟล็กในฟังก์ชัน ls ใช้แฟล็ก typ (type) ซึ่งใส่ค่าเป็นชนิดของโหนดที่ต้องการ เช่นหากจะหาโหนดชนิด transform
mc.ls(typ='transform')

ก็จะปรากฏรายชื่อแค่โหนด transform ซึ่งได้แก่โหนดของวัตถุโพลิกอนที่สร้างขึ้นมาแล้ว แล้วยังมีโหนดของกล้องมุมต่างๆด้วย กล้องพวกนี้ก็ประกอบด้วยโหนด transform เช่นเดียวกัน

หรือถ้าใส่แฟล็ก sl (selection) เป็น mc.ls(sl=1) ก็จะแสดงเฉพาะโหนดที่ถูกเลือกอยู่

ถ้าใส่แฟล็ก ca (cameras) เป็น mc.ls(ca=1) ก็จะแสดงเฉพาะโหนดที่เป็นกล้อง

และยังมีแฟล็กอีกหลายตัวที่ใช้จำกัดชนิดของโหนดที่จะเลือก

ถ้าต้องการรู้ชนิดของโหนดก็ให้ใส่แฟล็ก st (showType) ก็จะมีชนิดของโหนดวางเรียงอยู่ต่อจากชื่อโหนดนั้นๆ



นอกจากนี้มีอีกหลายกรณีที่เราสร้างโหนดขึ้นมาโดยไม่รู้ตัว เช่นเวลาที่ตั้งคีย์เฟรมให้กับค่าไหนก็จะมีโหนดเกิดขึ้นมาใหม่ด้วย โดยแต่ละค่าองค์ประกอบจะมีโหนดสำหรับเก็บค่าความเปลี่ยนแปลงแยกออกจากกัน เช่น
mc.polyCone(r=1)
mc.setKeyframe(at='rx',v=0,t=1)
mc.setKeyframe(at='ty',v=0,t=1)
mc.setKeyframe(at='tz',v=0,t=1)
mc.setKeyframe(at='rx',v=90,t=11)
mc.setKeyframe(at='ty',v=10,t=11)
mc.setKeyframe(at='tz',v=4,t=11)

ในนี้มีการตั้งคีย์เฟรมให้กับ rx, ty และ tz จึงมีโหนดใหม่เกิดขึ้นใหม่ ๓ โหนด ส่วนองค์ประกอบที่ไม่ได้ตั้งคีย์เฟรมจะยังไม่มีโหนดเกิดขึ้น

โหนดต่างๆนั้นมีความสัมพันธ์เชื่อมโยงอยู่ในลักษณะต่างๆ โยงกันโดยผ่านองค์ประกอบต่างๆ การจะดูว่าแต่ละโหนดมีความสัมพันธ์กันอยู่อย่างไรก็ทำได้โดยฟังก์ชัน listConnections()

เช่นลองกับวัตถุ pCone1 ที่เพิ่งตั้งคีย์เฟรมไปนี้
print(mc.listConnections('pCone1'))

จะได้
[u'pCone1_rotateX', u'pCone1_translateY', u'pCone1_translateZ']

ซึ่งจะเห็นว่าเชื่อมโยงอยู่กับโหนดชื่อ pCone1_rotateX, pCone1_translateY และ pCone1_translateZ

เมื่อลองดูชนิดของโหนดเหล่านี้ก็จะเห็นว่า pCone1_rotateX เป็นชนิด animCurveTA ส่วน pCone1_translateY และ pCone1_translateZ เป็นชนิด animCurveTL โหนดนี้จะเก็บลักษณะความเปลี่ยนแปลงที่เกิดขึ้นในแต่ละเฟรม

แต่ในนี้แสดงแค่ว่าเชื่อมต่อกันอยู่ แต่ไม่ได้บอกว่าเชื่อมกันที่องค์ประกอบไหน หากต้องการให้แสดงก็ทำได้โดยเพิ่มแฟล้ก p (plugs)
print(mc.listConnections('pCone1',p=1))

จะได้
[u'pCone1_rotateX.output', u'pCone1_translateY.output', u'pCone1_translateZ.output']

ก็จะเห็นว่าเชื่อมโยงกันอยู่ที่ค่าองค์ประกอบที่ชื่อ output ของแต่ละโหนดนั่นเอง

แต่ในนี้ก็ยังไม่ได้แสดงว่าเชื่อมต่ออยู่กับองค์ประกอบไหนของวัตถุ pCone1 หากจะให้แสดงก็ต้องเพิ่มอีกแฟล็กคือ c (connections)
print(mc.listConnections('pCone1',c=1,p=1))

ผลที่ได้คือ
[u'pCone1.rotateX', u'pCone1_rotateX.output', u'pCone1.translateY', u'pCone1_translateY.output', u'pCone1.translateZ', u'pCone1_translateZ.output']

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

จะเห็นว่าเชื่อมต่อกับองค์ประกอบ rotateX, translateY และ translateZ ตามลำดับ

ตรงนี้จะมีความหมายว่าโหนด pCone1_rotateX นั้นควบคุมองค์ประกอบ rotateX ของโหนด pCone1 อยู่นั่นเอง



เพื่อ ให้เห็นภาพความสัมพันธ์ระหว่างโหนดชัดเจนสามารถเข้าไปดูที่ไฮเพอร์กราฟแบบ เชื่อมโยงโดยกดเลือกที่ตัววัตถุแล้วเข้าไปที่แถบเมนูด้านบน เลือก Windows (ウィンドウ) แล้วเลือก Hypergraph: Connections (ハイパーグラフ: 接続)



กดเลือกที่ปุ่มตามรูปนี้ (入力と出力接続)



ก็จะเห็นว่าโหนด pCone1 เชื่อมต่ออยู่กับโหนด pCone1_rotateX, pCone1_translateY และ pCone1_translateZ แล้วก็ยังเห็นโหนดอื่นๆเช่น pConeShape1 กับ polyCone1 เชื่อมต่อกันอยู่ด้วย

แต่พอดูแล้วก็จะสงสัยว่าโหนด pCone1 กับ pConeShape1 หรือ polyCone1 ไม่ได้เชื่อมต่อกันอยู่หรือ ไม่เห็นมีลากเส้นในภาพนี้ แล้วก็ไม่มีรายชื่อขึ้นตอนใช้ฟังก์ชัน listConnections() ด้วย

ความจริงแล้วก็คือ pCone1 กับ pConeShape1 มีความสัมพันธ์ในลักษณะพ่อแม่ลูกกันอยู่ เช่นเดียวกับความสัมพันธ์ระหว่างวัตถุที่ถูกผูกติดกันซึ่งพูดถึงไปในบทที่ ๑๙ ซึ่งจะไม่แสดงให้เห็นในนี้

การจะหาความสัมพันธ์แบบพ่อแม่ลูกต้องใช้ฟังก์ชัน listRelatives() ซึ่งจะคืนค่าชื่อโหนดลูกของวัตถุที่เลือก
print(mc.listRelatives('pCone1'))

จะได้
[u'pConeShape1']

ในทางกลับกันจะให้แสดงโหนดพ่อแม่ต้องใส่แฟล็ก p (parent)
print(mc.listRelatives('pConeShape1',p=1))

จะได้
[u'pCone1']



จะเห็นได้ว่าวัตถุในมายาประกอบด้วยโหนดชนิดต่างๆมากมายซึ่งแต่ละโหนดก็เชื่อมโยงกันด้วยความสัมพันธ์ในลักษณะต่างๆ

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

เรื่องนี้เป็นพื้นฐานสำคัญ พอได้กล่าวถึงเรื่องนี้ในบทนี้ก็น่าจะทำให้เข้าใจภาพรวมของโปรแกรมมากขึ้น เป็นประโยชน์ในการศึกษารายละเอียดลึกต่อไป



อ้างอิง

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


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

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

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

หมวดหมู่

-- คอมพิวเตอร์ >> เขียนโปรแกรม >> 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月

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

ไทย

日本語

中文