φυβλαςのβλογ
phyblas的博客



maya python เบื้องต้น บทที่ ๓๔: การใส่ภาพบนพื้นผิว NURBS
เขียนเมื่อ 2016/03/14 01:34
แก้ไขล่าสุด 2021/09/28 16:42
ในบทที่ ๒๗ ที่ผ่านมาเราสามารถใส่สีสันให้กับวัตถุได้แล้ว แต่ว่าใสบางครั้งแค่สีเรียบๆธรรมดาก็อาจจะไม่เพียงพอ อาจต้องการสีสันอะไรมากกว่านั้น

ดังนั้นจึงอาจต้องมีการนำภาพจากไฟล์ภาพที่มีอยู่แล้วมาใช้เพื่อตกแต่ง

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

กระบวนการ ใส่ภาพบนพื้นผิว NURBS กับโพลิกอนจะแตกต่างกันอยู่เล็กน้อย ดังนั้นจะขอแยกอธิบาย โดยเริ่มจากพื้นผิว NURBS ซึ่งค่อนข้างเรียบง่ายกว่า



ขอเริ่มยกตัวอย่างโดยลองใส่ภาพนี้ลงบนกระดาษแผ่นหนึ่ง เป็นรูปสาวน้อยเวทมนตร์มาโดกะ



ภาพตัวอย่างนำมาจาก https://www.facebook.com/616507455065460

โดยมีการตัดขอบซ้ายขวาออกไปเพื่อให้ได้ภาพสัดส่วน 4:3

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

ภาพที่ใช้จะเซฟใส่ไว้ในโฟลเดอร์ไหนก็ได้ แล้วให้เปลี่ยนพาธของไฟล์ในโค้ดให้เป็นไปตามนั้น
เช่น 'C:/ชื่อโฟลเดอร์/madokatokyube.jpg' เป็นต้น (ใช้ \ หรือ / ก็ได้)

โค้ดส่วนนี้ยาวเล็กน้อย แต่จะค่อยๆอธิบายทีละขั้นอย่างละเอียด
mc.shadingNode('phong',asShader=1,n='phap_madoka') # สร้างโหนดวัสดุ
mc.shadingNode('file',at=1,n='file_madoka') # สร้างโหนดเท็กซ์เจอร์ไฟล์ภาพ
mc.connectAttr('file_madoka.oc','phap_madoka.c') # เชื่อมโหนดวัสดุเข้ากับโหนดไฟล์ภาพ
s = '<พาธและชื่อไฟล์ภาพ>' # กำหนดไฟล์ภาพ
mc.setAttr('file_madoka.ftn',s,typ='string') # ตั้งพาธไฟล์ให้โหนดไฟล์ภาพ
mc.nurbsPlane(w=2,n='phaenkradat') # สร้างแผ่นกระดาษ
mc.rotate(0,0,45,p=[-1,0,0]) # หมุนให้หันขึ้นมาหน่อย
mc.hyperShade(a='phap_madoka') # ใส่วัสดุให้แผ่นกระดาษ
mc.shadingNode('place2dTexture',au=1,n='uv_madoka') # สร้างโหนด place2dTexture สำหรับปรับแต่งเท็กซ์เจอร์
mc.defaultNavigation(ce=1,s='uv_madoka',d='file_madoka') # เชื่อมโหนด place2dTexture เข้ากับโหนดเท็กซ์เจอร์ไฟล์ภาพ

ผลที่ได้ควรจะออกมาเป็นแบบนี้



ต่อไปเป็นคำอธิบายโค้ดทีละขั้น

เริ่มต้นทำเหมือนกันกับการใส่สีคือใช้ฟังก์ชัน shadingNode() โดยใส่แฟล็กเป็น asShader=1 สร้างโหนดของวัสดุขึ้น

จากนั้นขั้นตอนต่อไปก็คือต้องใช้ฟังก์ชัน shadingNode() อีกครั้งเพื่อสร้างโหนดขึ้นมาอีกโหนด ซึ่งคราวนี้สร้างเป็นหมวดเท็กซ์เจอร์ชนิดรูปภาพ ซึ่งทำได้โดยใส่แฟล็กเป็น at=1 และใส่ชนิดเป็น file

ซึ่งก็คือ mc.shadingNode('file',at=1,n='ชื่อโหนด')

จากนั้นก็ทำการเชื่อมต่อโหนดของวัสดุเข้ากับโหนดของเท็กซ์เจอร์โดยใช้ฟังก์ชัน connectAttr() ฟังก์ชันนี้มีไว้สำหรับเชื่อมโหนด ๒ โหนดเข้าด้วยกัน โดยการเชื่อมต่อนั้นจะเชื่อมที่ตัวองค์ประกอบของโหนดทั้ง ๒

ในที่นี้คือเชื่อมองค์ประกอบชื่อ oc (outColor) ของโหนดไฟล์ภาพเข้ากับองค์ประกอบ c (color) ของโหนดวัสดุภาพ ซึ่งจะมีความหมายว่า สีของไฟล์ภาพจะออกมากลายเป็นสีของวัสดุ

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

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

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

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

โหนดที่จะต้องสร้างขึ้นมาใหม่นั้นคือโหนดชนิด place2dTexture อยู่ในหมวด ยูทิลิตี (utility) สามารถสร้างขึ้นมาได้โดยใช้ฟังก์ชัน shadingNode() เช่นเดียวกันกับโหนดไฟล์ภาพ โดยเขียนเป็น mc.shadingNode('place2dTexture',au=1,n='ชื่อโหนด')

จากนั้นก็เชื่อมต่อโหนดนี้เข้ากับโหนดไฟล์ภาพ แต่คราวนี้ฟังก์ชันที่ต้องใช้คือ defaultNavigation()

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

การใช้ให้ใส่ชื่อของ ๒ โหนดที่ต้องการเชื่อมต่อกันไว้ในแฟล็ก s (source) และ d (destination) แล้วใส่แฟล็ก ce (connectToExisting) เป็น ce=1

ในที่นี้ใส่ s เป็นโหนดของ place2dTexture ส่วน d เป็นโหนดของไฟล์ภาพ

จากนั้นทั้ง ๒ โหนดนี้ก็จะเชื่อมต่อกันเรียบร้อย

ลองไปดูที่ไฮเพอร์เชด (วิธีเปิดดูในบทที่ ๒๗) แล้วคลิกขวาค้างที่โหนดวัสดุ แล้วเลือก Graph Network (グラフネットワーク) จะเป็นการแสดงกราฟเน็ตเวิร์ก



ก็จะพบความว่ามีกรอบวางเรียงรายกันอยู่ ๔ อัน ซึ่งแต่ละอันก็คือโหนดต่างๆ โดยมีเส้นเชื่อมกันอยู่ แสดงความสัมพันธ์

โหนดอันซ้ายสุดคือโหนด place2dTexture ส่วนถัดมาคือโหนดไฟล์ภาพ



สามารถคลี่ออกเพื่อดูรายละเอียดได้โดยกดปุ่มที่มุมขวาบน

คลี่ออกมาจะเห็นเส้นต่างๆมากมาย ทั้งหมดนี้คือสิ่งที่ฟังก์ชัน defaultNavigation() ได้ทำการเชื่อมโยงให้อัตโนมัติ



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

ลองพิมพ์
s = mc.listConnections('uv_madoka',c=1,p=1)
for i in range(0,len(s),2):
    print(s[i]+' \t '+s[i+1])

ก็จะได้รายชื่อขององค์ประกอบที่เชื่อมโยงกันทั้งหมด

ทั้งหมดนี้เป็นองค์ประกอบที่จำเป็นต้องเชื่อมเพื่อให้ค่าที่ปรับในโหนด place2dTexture มีผลต่อการแสดงผลของโหนดไฟล์ภาพ

หากจะเชื่อมทั้งหมดนี้เองโดยใช้ฟังก์ชัน connectAttr() ก็ได้เช่นกัน โดยการพิมพ์
mc.connectAttr('uv_madoka.outUV','file_madoka.uvCoord')
mc.connectAttr('uv_madoka.outUvFilterSize','file_madoka.uvFilterSize')
mc.connectAttr('uv_madoka.coverage','file_madoka.coverage')
mc.connectAttr('uv_madoka.translateFrame','file_madoka.translateFrame')
mc.connectAttr('uv_madoka.rotateFrame','file_madoka.rotateFrame')
mc.connectAttr('uv_madoka.mirrorU','file_madoka.mirrorU')
mc.connectAttr('uv_madoka.mirrorV','file_madoka.mirrorV')
mc.connectAttr('uv_madoka.stagger','file_madoka.stagger')
mc.connectAttr('uv_madoka.wrapU','file_madoka.wrapU')
mc.connectAttr('uv_madoka.wrapV','file_madoka.wrapV')
mc.connectAttr('uv_madoka.repeatUV','file_madoka.repeatUV')
mc.connectAttr('uv_madoka.vertexUvOne','file_madoka.vertexUvOne')
mc.connectAttr('uv_madoka.vertexUvTwo','file_madoka.vertexUvTwo')
mc.connectAttr('uv_madoka.vertexUvThree','file_madoka.vertexUvThree')
mc.connectAttr('uv_madoka.vertexCameraOne','file_madoka.vertexCameraOne')
mc.connectAttr('uv_madoka.noiseUV','file_madoka.noiseUV')
mc.connectAttr('uv_madoka.offset','file_madoka.offset')
mc.connectAttr('uv_madoka.rotateUV','file_madoka.rotateUV')

ซึ่งเยอะและยาวกว่ามาก และอาจมีการตกหล่นได้ ดังนั้นโดยทั่วไปแล้วใช้ defaultNavigation() ทีเดียวเลยดีกว่า

อันที่จริงไม่มีความจำเป็นจะต้องเชื่อมองค์ประกอบทั้งหมด เชื่อมแค่ค่าที่ต้องการจะใช้เท่านั้นก็พอ



ตอนนี้การเตรียมการทุกอย่างก็พร้อมแล้ว ขั้นตอนต่อไปจะมาลองปรับค่าต่างๆภายในโหนด place2dTexture

สามารถกดเลือกโหนดนั้นได้โดยผ่านทางกราฟเน็ตเวิร์กในไฮเพอร์เชดเมื่อครู่ หรืออาจเข้าไปที่หมวด Utility (ユーティリティ) แล้วเลือก



หรืออาจใช้ฟังก์ชัน select() เพื่อเลือกก็ได้ ในที่นี้พิมพ์
mc.select('uv_madoka')

จากนั้นดูที่แอตทริบิวต์อีดิเตอร์ก็จะเห็นค่าอะไรต่างๆมากมายที่สามารถปรับได้ เช่น
c (coverage) 有効範囲 = ขอบเขตแสดงผล
แบ่งเป็นแนวแกน U และ V: cu (coverageU) และ cv (coverageV)
tf (translateFrame) フレームの移動 = การเคลื่อนย้ายเฟรม
แบ่งเป็นแนวแกน U และ V: tfu (translateFrameU) และ tfv (translateFrameV)
rf (rotateFrame) フレームの回転 = การหมุนเฟรม
mu (mirrorU) ミラーU = สะท้อน U
mv (mirrorV) ミラーV = สะท้อน V
s (stagger) スタッカー = สลับฟันปลา
re (repeatUV) 繰り返しUV = วนซ้ำ UV
แบ่งเป็นแนวแกน U และ V: reu (repeatU) และ rev (repeatV)
of (offset) オフセット = อ็อฟเซ็ต
แบ่งเป็นแนวแกน U และ V: ofu (offsetU) และ ofv (offsetV)
r (rotateUV) UVの回転 = การหมุน UV
n (noiseUV) ノイズUV = UV คลื่นรบกวน
แบ่งเป็นแนวแกน U และ V: nu (noiseU) และ nv (noiseV)

เริ่มแรกลองเริ่มจากทำให้ภาพแสดงผลเป็นสัดส่วนที่ถูกต้องก่อน สามารถทำได้หลายวิธี

เนื่องจากสัดส่วนเดิมของภาพเป็น 4:3 แต่ถูกบีบให้อยู่ในพื้นที่ 1:1 ทำให้ภาพแคบลง ดังนั้นต้องปรับด้านกว้างให้กว้างขึ้น หรือปรับด้านสูงให้แคบลง

ในที่นี้จะลองปรับด้านกว้างให้กว้างขึ้นโดยปรับขอบเขตของภาพ โดยปรับที่ค่า cu (coverageU) ซึ่งเป็นค่าความกว้างของขอบเขตภาพในหน่วยจำนวนเท่าของความกว้างพื้นผิว

พอ ทำแบบนี้แล้วก็จะได้ภาพที่ขยายออกไปเป็น 1.333 เท่า กลายเป็นตามสัดส่วนจริง แต่ว่าเนื่องจากภาพกว้างขึ้นจึงด้านออกไปทางด้านขวาจนตกขอบมองไม่เห็น

แก้ปัญหาด้วยการเลื่อนภาพไปทางซ้าย การเลื่อนตำแหน่งต้องปรับที่ค่า tf (translateFrame) ค่าตำแหน่งนี้ก็ใช้เป็นหน่วยจำนวนเท่าของความกว้างผิว
mc.setAttr('uv_madoka.tfu',-0.333)
mc.setAttr('uv_madoka.cu',1.333)



การหมุนภาพทำได้ด้วยการปรับค่า rf (rotateFrame)
mc.setAttr('uv_madoka.rf',-30)



แต่ถ้าแค่หมุนไปก็จะเห็นว่าภาพแหว่งหายไปไม่เต็มส่วน คราวนี้ลองขยายภาพเพิ่มแล้วก็เลื่อนตำแหน่งให้เห็นหัวพอดี
mc.setAttr('uv_madoka.c',4,3)
mc.setAttr('uv_madoka.tf',-2.6,-1.7)



อีกค่าที่อาจลองปรับดูก็คือ re (repeatUV) ซึ่งเป็นจำนวนของภาพที่ต้องการให้ซ้ำ ถ้าตั้งให้มากกว่า 1 ภาพก็จะเล็กลงแต่วนซ้ำทำให้จำนวนเพิ่มขึ้น

ลองปรับค่า ๓ อย่างแรก (rf, c, tf) ให้กลับเป็นค่าเริ่มต้นก่อนแล้วค่อยตั้งค่า re
mc.setAttr('uv_madoka.rf',0)
mc.setAttr('uv_madoka.c',1,1)
mc.setAttr('uv_madoka.tf',0,0)
mc.setAttr('uv_madoka.re',3,4)

จะได้ภาพเล็กๆออกมา ๑๒ ภาพ



ภาพ ที่วนซ้ำนี้สามารถทำให้กลับด้านไปมาได้โดยปรับ mu (mirrorU) และ mv (mirrorV) ซึ่งแรกเริ่มจะเป็น 0 คือไม่มีการกลับด้าน ถ้าปรับให้เป็น 1 ก็จะกลับด้าน
mc.setAttr('uv_madoka.mu',1)
mc.setAttr('uv_madoka.mv',1)



ถ้าปรับค่า s (stagger) การกลับด้านในแต่ละแถวก็จะสลับฟันปลา
mc.setAttr('uv_madoka.s',1)



ถ้าปรับค่า of (offset) ก็จะเป็นการเลื่อนตำแหน่ง แต่หน่วยในที่นี้คือจำนวนเท่าของความกว้างของภาพที่ย่อแล้ว
mc.setAttr('uv_madoka.of',0.6,0.2)



ส่วนค่า n (noiseUV) คือคลื่นรบกวน ถ้าปรับจะทำให้ภาพบิดเบี้ยวเหมือนมองผ่านผิวน้ำที่มีคลื่นซัดไปมา
mc.setAttr('uv_madoka.n',0.03,0.03)



นอกจากนี้ภาพจะเปลี่ยนไปตามพื้นผิวที่ถูกวาง หากมีการเปลี่ยนแปลงพื้นผิวดูก็จะพบว่าภาพถูกดึงตามไปด้วย เหมือนผืนผ้า

ลองปรับรูปแผ่นกระดาษดู
mc.setAttr('uv_madoka.n',0,0) # ลบคลื่นรบกวนออกไปก่อน
mc.setAttr('uv_madoka.re',1,1) # ปรับขนาดให้เท่าเดิม
mc.setAttr('uv_madoka.of',0,0) # ดึงภาพกลับมาตรงกลาง
for i in [0,3]:
    mc.scale(1,1,3,'phaenkradat.cv[%d][*]'%i) # ยืดส่วนขอบไปซ้ายขวา
for i in [1,2]:
    mc.scale(3,3,1,'phaenkradat.cv[%d][*]'%i) # ยืดส่วนกลางๆไปบนล่าง





ลองสร้างใหม่โดยนำภาพมาแปะบนทรงกระบอกก็ได้ (ก่อนสร้างให้เริ่มฉากใหม่ก่อน)
mc.shadingNode('phong',asShader=1,n='phap_madoka')
mc.shadingNode('file',at=1,n='file_madoka')
mc.connectAttr('file_madoka.oc','phap_madoka.c')
s = '<พาธและชื่อไฟล์ภาพ>'
mc.setAttr('file_madoka.ftn',s,typ='string')
mc.cylinder(r=1,hr=2*3.14159*4/3,n='krabok')
mc.hyperShade(a='phap_madoka')
mc.shadingNode('place2dTexture',au=1,n='uv_madoka')
mc.defaultNavigation(ce=1,s='uv_madoka',d='file_madoka')





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


(คลิกเพื่อดูภาพเต็ม)


ที่มาของภาพ จาก http://members2.jcom.home.ne.jp/planet.earth/four_seasons.html

ลองเอาภาพแผนที่โลกนี้มาแปะลงบนทรงกลมจะได้ภาพลูกโลกตามที่ควรเป็นพอดี
mc.shadingNode('phong',asShader=1,n='phap_lok')
mc.shadingNode('file',at=1,n='file_lok')
mc.connectAttr('file_lok.oc','phap_lok.c')
s = '<พาธและชื่อไฟล์ภาพ>'
mc.setAttr('file_lok.ftn',s,typ='string')
mc.sphere(r=200,n='luklok',nsp=36,s=36,ax=[0,1,0])
mc.hyperShade(a='phap_lok')
mc.shadingNode('place2dTexture',au=1,n='uv_lok')
mc.defaultNavigation(ce=1,s='uv_lok',d='file_lok')
mc.setAttr('uv_lok.rf',90)





สรุปขั้นตอนการใส่ภาพบนพื้นผิว NURBS
๑. mc.shadingNode('<ชนิดวัสดุ>',asShader=1,n='<ชื่อโหนดวัสดุ>') สร้างโหนดวัสดุที่ใช้เป็นภาพ
๒. mc.shadingNode('file',at=1,n='<ชื่อโหนดไฟล์ภาพ>') สร้างโหนดเท็กซ์เจอร์ชนิดไฟล์
๓. mc.connectAttr('<ชื่อโหนดไฟล์ภาพ>.oc','<ชื่อโหนดวัสดุ>.c') เชื่อมต่อโหนดไฟล์ภาพกับโหนดวัสดุ
๔. mc.setAttr('<ชื่อโหนดไฟล์ภาพ>.ftn',<พาธและชื่อไฟล์ภาพ>,typ='string') ระบุไฟล์ที่เก็บภาพ
๕. mc.shadingNode('place2dTexture',au=1,n='<ชื่อโหนด>') สร้างโหนดยูทิลิตีชนิด place2dTexture
๖. mc.defaultNavigation(ce=1,s='<ชื่อโหนด place2dTexture>',d='<ชื่อโหนดไฟล์ภาพ>') เชื่อมต่อโหนด place2dTexture เข้ากับโหนดไฟล์ภาพ
๗. mc.select('<ชื่อวัตถุหรือผิว>') เลือกวัตถุที่ต้องการแปะภาพ
๘. mc.hyperShade(a='<ชื่อโหนดไฟล์ภาพ>') เชื่อมต่อโหนดวัสดุภาพเข้ากับวัตถุหรือผิว
๙. ปรับค่าองค์ประกอบต่างๆในโหนด place2dTexture เพื่อให้ได้ภาพที่วางในตำแหน่งตามที่ต้องการ



อ้างอิง

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


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

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

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

หมวดหมู่

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

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

目录

从日本来的名言
模块
-- numpy
-- matplotlib

-- pandas
-- manim
-- opencv
-- pyqt
-- pytorch
机器学习
-- 神经网络
javascript
蒙古语
语言学
maya
概率论
与日本相关的日记
与中国相关的日记
-- 与北京相关的日记
-- 与香港相关的日记
-- 与澳门相关的日记
与台湾相关的日记
与北欧相关的日记
与其他国家相关的日记
qiita
其他日志

按类别分日志



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

  查看日志

  推荐日志

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