前言
眾所周知Houdini是一款很強(qiáng)大的三維軟件根吁,在很多影視大片里都能見到它的身影。官方SideFX把它定位在3D Procedural Software for Film,TV,&Gamedev木人,其實Houdini本身的程序節(jié)點流與眾多集成的CV功能早已超出了電影、電視、游戲領(lǐng)域范疇,就如UE4一樣也不僅僅只是一款游戲制作工具扫倡。這一點官方SideFX已經(jīng)認(rèn)識到了,但是具體什么原因沒有果斷轉(zhuǎn)型升級竟纳,我們也不清楚撵溃。就個人觀點來看,如果SideFX再不拓展領(lǐng)域锥累,開放開源的話缘挑,很可能會被UE5、Blender甚至Nuke等軟件把流媒體桶略、科研教育语淘、AI等新興市場給瓜分掉,從而讓自己徹底淪落為一個插件公司际歼。
其實從Houdini17.5開始,PDG的Top流以及CSV和Python3的格式開放亏娜,包括最近18.5對實時動補(bǔ)的大力支持,這些看似對傳統(tǒng)特效制作沒什么大提升的功能蹬挺,其實是Houdini對新型市場的嘗試與跟進(jìn),也是如今的發(fā)展趨勢它掂。對我個人而言巴帮,Houdini是一個很好的三維數(shù)據(jù)模擬與生成工具,對三維數(shù)據(jù)分析與處理有非常大的幫助∨扒铮現(xiàn)在比較火的CV領(lǐng)域榕茧,有matplotlib和OpenCV,都是業(yè)界不成文的標(biāo)準(zhǔn)客给,雖然兩者都有三維計算效果用押,但是專業(yè)可視化的三維數(shù)據(jù)軟件全球還沒一個大的統(tǒng)一。當(dāng)然要成為這種軟件前提必須是開源開放的靶剑,Blender或者UE5可能有機(jī)會蜻拨,Houdini我不知道池充。(吐槽完畢)
為什么講節(jié)點分類
用過Houdini的朋友都知道,每當(dāng)Houdini跨0.5的版本升級后缎讼,都會有較大的改動收夸,大家也經(jīng)常吐槽Houdini每次更新后就得重學(xué)一遍。其實Houdini本身的設(shè)計架構(gòu)決定了它的每次新功能嵌入都將會是一次大換血血崭。因為Houdini所有模塊之間的數(shù)據(jù)都是相通的卧惜,而且是以節(jié)點流的形式相連,這就好比人的經(jīng)絡(luò)夹纫,數(shù)據(jù)就如血液一般在其中有序循環(huán)咽瓷,當(dāng)新增一項功能,打個比方要給人加上一對翅膀舰讹,你整個骨骼與經(jīng)絡(luò)都得重新?lián)Q一套茅姜,形成循環(huán)系統(tǒng),以保證大腦的血液能流入翅膀跺涤。而Maya,Max的功能主要以插件的形式來增加匈睁,相當(dāng)于給人穿衣服,每加一個功能就多穿一件衣服桶错,穿多穿少不會影響整個人的身材航唆,所以FumeFX里的數(shù)據(jù)不能直接作用在Yeti上。
Houdini這套循環(huán)閉合的經(jīng)絡(luò)系統(tǒng)院刁,它的好處就是數(shù)據(jù)流通性糯钙,壞處也正是因為它數(shù)據(jù)一體化不好區(qū)分,容易導(dǎo)致眉毛胡子一把抓退腥,不知從哪斷到哪任岸。Houdini是一個節(jié)點流軟件,要使用Houdini模擬三維數(shù)據(jù)之前狡刘,必須得了解它的功能模塊與節(jié)點構(gòu)成享潜。這是入門Houdini的第一步,很多人認(rèn)為Houdini難學(xué)嗅蔬,其實第一步就邁錯了方向剑按,導(dǎo)致后面越學(xué)越懵逼。
Houdini的模塊與節(jié)點類型
說到Houdini的模塊有哪些澜术,節(jié)點有哪些艺蝴,估計有很多人都回答上來,包括一些老手鸟废。因為隨著Houdini版本與功能的升級猜敢,它本身的模塊與節(jié)點類型也在發(fā)生變化,所以它并非一成不變的。
Houdini18.5的功能模塊
上圖就是Houdini的功能模塊缩擂,我發(fā)現(xiàn)有很多人經(jīng)常將模塊功能與節(jié)點類型鼠冕、節(jié)點功能混在一起來劃分和描述Houdini。其實這是不科學(xué)的撇叁,也是比較混亂的供鸠。舉個例子,SOP是干什么的陨闹,這個問題估計每個使用Houdini的人都會問到楞捂。然而在功能模塊里我們并沒看見SOP,甚至我們把Houdini所有節(jié)點找一遍趋厉,除了個叫Sop network的根本就沒看見Sop寨闹。從一些老師口中或者網(wǎng)上查尋得到的答案往往是surface operator,What?表面操作?那這又是什么意思?更加蒙蔽君账。所以說僅從字義功能上去描述Houdini繁堡,是根本描述不通的,就像用"魯棒性"去描述算法一樣乡数,不僅會讓人覺得懵逼甚至還略帶一絲好笑椭蹄。 那為什么直白的字義就無法描述Houdini各模塊功能呢?正是因為Houdini的功能在不斷拓展净赴,現(xiàn)有的功能已經(jīng)超出了最原先的含義绳矩。surface operator是Houdini很早很早之前的版本所使用的功能描述,當(dāng)時的功能估計也就停留在對物體的基本屬性玖翅、形狀上的一些操作翼馆,有點類似Maya物體的Shape,當(dāng)然這也是我的個人推斷金度,畢竟Houdini的那些老版本我也沒用過应媚。
Houdini官方是按節(jié)點類型而非模塊的方式來劃分描述的。在幫助首頁里就有:
官方幫助頁節(jié)點分類
對比上面兩張圖猜极,可以發(fā)現(xiàn)這不是一一對應(yīng)的關(guān)系中姜,即模塊分類 !=節(jié)點分類。但是乍看一眼跟伏,兩者貌似又有重合的地方丢胚,這也是第一個讓人比較迷惑的地方。而且我們還是不清楚SOP是干什么的酬姆。
第二個讓人迷惑的地方就是:官方幫助里的節(jié)點分類其實本身并不是完整的。不是說官方節(jié)點分類不完整奥溺,而是說幫助文檔里所顯示的節(jié)點分類不完整辞色。甚至因為歷史遺留原因?qū)е乱恍┕?jié)點類型的名稱與其底層代碼類上的名稱是沒有一一對應(yīng)的。Houdini真實的節(jié)點類型如下圖所示(這里使用Houdini18.5版本):
Houdini18.5節(jié)點分類
其實從節(jié)點類型上去學(xué)Houdini那將會是最輕松的方式,而且能隨著Houdini的功能拓展而進(jìn)行增量學(xué)習(xí)相满。尤其對于開發(fā)人員來說层亿,能更好的理解各個模塊之間的聯(lián)系。話雖如此立美,但本來模塊分類與官方幫助頁的分類已經(jīng)夠繞了匿又,現(xiàn)在又多了一些,會不會更復(fù)雜了建蹄?沒有碌更,很簡單。我們只需要從節(jié)點層級上就能識別出節(jié)點類型洞慎,Houdini自身就是這么來劃分的痛单,而且每種節(jié)點類型從其外觀上就有一定的特征。
認(rèn)清Houdini節(jié)點類型
在之前劲腿,我們先用一個小腳本來獲取我們所選擇的節(jié)點類型與節(jié)點類型名稱旭绒。
import hou
sn=hou.selectedNodes()
for n in sn:
print(n.type(),n.type().name())
各節(jié)點類型功能
1.Director
字面上意思是導(dǎo)演,其實就是唯一的root根節(jié)點hou.node("/"),在該節(jié)點下才會有ch,obj,img等功能模塊節(jié)點焦人。該節(jié)點是沒有實體節(jié)點形狀的挥吵,從程序角度理解就是每個工程的節(jié)點根路徑。
2.Manager
管理節(jié)點花椭,也就是各模塊節(jié)點忽匈,能包含其他節(jié)點的容器節(jié)點.跟Director一樣,它們也是沒有具體節(jié)點形狀的个从。但比Director要直觀一點的地方就是脉幢,你可以認(rèn)為節(jié)點面板里的每個分頁就是它們。Houdini中的Manager節(jié)點有:
hou.node("/ch")
hou.node("/img")
hou.node("/mat")
hou.node("/obj")
hou.node("/out")
hou.node("/shop")
hou.node("/stage")
hou.node("/tasks")
3.Chop
數(shù)據(jù)通道節(jié)點嗦锐,針對Houdini所有數(shù)據(jù)通道處理的節(jié)點嫌松,可以實現(xiàn)數(shù)據(jù)圖形化。所有chop network下的第一層節(jié)點都是Chop類型奕污。注意是萎羔,。下面圖2中碳默,即使里面有chopnet2,sopnet2這些網(wǎng)絡(luò)容器贾陷,但是它們都是Chop類型,打印這2個節(jié)點的類型與類型名稱,如下:
<hou.NodeType for Chop chopnet> chopnet #節(jié)點類型為Chop 節(jié)點類型名稱為chopnet
<hou.NodeType for Chop sopnet> sopnet
所謂"第一層"即當(dāng)前網(wǎng)絡(luò)層級嘱根,在圖2sopnet1里面的節(jié)點髓废,就不是Chop節(jié)點類型了。
<hou.NodeType for Chop chopnet> chopnet
<hou.NodeType for Chop sopnet> sopnet
<hou.NodeType for Chop vopnet> vopnet
<hou.NodeType for Chop chopnet> chopnet
<hou.NodeType for Chop image> image
4.ChopNet
所有帶Net結(jié)尾的節(jié)點類型都是該類節(jié)點的網(wǎng)絡(luò)容器節(jié)點。所謂網(wǎng)絡(luò)容器節(jié)點脊僚,就是可以包含很多其他節(jié)點的節(jié)點,且該容器里創(chuàng)建的所有節(jié)點都是同一類節(jié)點饿敲。這里的ChopNet就是在/ch下創(chuàng)建的Chop network網(wǎng)絡(luò)容器節(jié)點冈爹,有且僅有這么一個涌攻。
注意,在其他模塊節(jié)點下創(chuàng)建的Chop network就不是ChopNet類型频伤,參考Chop中的圖2
<hou.NodeType for ChopNet ch>
5.Cop2
合成類節(jié)點恳谎,Houdini針對圖像合成處理的節(jié)點,功能類似Nuke憋肖。凡是Img network網(wǎng)絡(luò)容器節(jié)點下創(chuàng)建的節(jié)點因痛,都是Cop2節(jié)點。合成節(jié)點很好辨識瞬哼,一般都帶縮略圖的婚肆。
<hou.NodeType for Cop2 file> file
<hou.NodeType for Cop2 color> color
6.CopNet
在/img下創(chuàng)建的Img network網(wǎng)絡(luò)容器節(jié)點,僅這么一個坐慰。<hou.NodeType for CopNet img> img
7.Object
物體節(jié)點较性,在/obj下創(chuàng)建的所有節(jié)點以及Object network網(wǎng)絡(luò)容器節(jié)點里創(chuàng)建的節(jié)點都是Object節(jié)點類型,下圖都是Object節(jié)點结胀。注意Object network網(wǎng)絡(luò)容器節(jié)點本身的類型則取決于它的父節(jié)點赞咙。
<hou.NodeType for Object dopnet> dopnet
<hou.NodeType for Object subnet> subnet
<hou.NodeType for Object chopnet> chopnet
<hou.NodeType for Object vopnet> vopnet
<hou.NodeType for Object cam> cam
<hou.NodeType for Object geo> geo
<hou.NodeType for Object hlight::2.0> hlight::2.0
<hou.NodeType for Object agentcam> agentcam
8.Sop
終于來了Sop。Object節(jié)點里除去所有是network網(wǎng)絡(luò)容器的第一層節(jié)點糟港,都是Sop節(jié)點攀操,因為network網(wǎng)絡(luò)容器節(jié)點里創(chuàng)建的都是它本身獨特類型而非Sop類型,所以要除去秸抚。這也是官方對Sop的定義速和,雖然幫助文檔上的描述也不全面,但這是唯一正確描述Sop的方式剥汤。因為Sop節(jié)點和功能太多颠放,尤其Houdini17.5過后,Sop的功能界限越來越模糊吭敢,比如一些Sop節(jié)點本身會帶有動力學(xué)解算碰凶,所以是無法從節(jié)點功能上去描述劃分它的,而所有模塊節(jié)點即Manager節(jié)點里創(chuàng)建的也不是Sop節(jié)點鹿驼,所以也不能從模塊上去描述它欲低,只能以節(jié)點類型去描述。
下圖是geo1里的節(jié)點畜晰,都是Sop節(jié)點砾莱。
<hou.NodeType for Sop chopnet> chopnet
<hou.SopNodeType for Sop attribvop> attribvop
<hou.SopNodeType for Sop dopnet> dopnet
<hou.NodeType for Sop matnet> matnet
9.Dop
動力學(xué)節(jié)點,Houdini專門處理動力學(xué)解算的節(jié)點凄鼻。所有Dop network網(wǎng)絡(luò)容器節(jié)點里的第一層節(jié)點都是Dop節(jié)點腊瑟。
<hou.NodeType for Dop popobject> popobject
<hou.NodeType for Dop popadvectbyfilaments> popadvectbyfilaments
<hou.NodeType for Dop popsolver::2.0> popsolver::2.0
<hou.NodeType for Dop output> output
10.Driver
渲染面哼、輸出節(jié)點。這個其實就是官方幫助頁上說的ROP節(jié)點,以前可能只是為了渲染Render所以叫ROP,其真實節(jié)點類型名稱叫Driver,可以理解為驅(qū)動程序扫步,就是帶復(fù)雜計算過程的節(jié)點。不難理解匈子,因為Houdini現(xiàn)在的運算與輸出已經(jīng)不僅僅是渲染的內(nèi)容了河胎,比如CSV還有其他USD格式的輸出,等等這些都超出了渲染范疇虎敦,所以用Driver更合理游岳。所有/out以及Rop network網(wǎng)絡(luò)容器節(jié)點下創(chuàng)建的第一層節(jié)點都是Driver節(jié)點。
<hou.NodeType for Driver agent> agent
<hou.NodeType for Driver usdrender> usdrender
<hou.NodeType for Driver ifd> ifd
<hou.NodeType for Driver sopnet> sopnet
11.Lop
為USD流程操作的節(jié)點其徙。所有/stage與LOP network網(wǎng)絡(luò)容器節(jié)點下創(chuàng)建的第一層節(jié)點都是Lop節(jié)點,/stage是manager節(jié)點胚迫。同樣,LOP network網(wǎng)絡(luò)節(jié)點類型取決于它的父節(jié)點唾那。
<hou.NodeType for Lop sceneimport> sceneimport
<hou.NodeType for Lop attribvop> attribvop
<hou.NodeType for Lop dopnet> dopnet
<hou.NodeType for Lop camera> camera
12.Shop
材質(zhì)shader節(jié)點访锻。也是歷史遺留下的節(jié)點,現(xiàn)在基本成為了外部渲染插件的材質(zhì)存放根據(jù)地闹获。所有/shop與Shop network網(wǎng)絡(luò)容器節(jié)點下創(chuàng)建的第一層節(jié)點都是Shop節(jié)點期犬。Shop network節(jié)點類型取決于它的父節(jié)點。
<hou.NodeType for Shop matnet> matnet
<hou.ShopNodeType for Shop vopcvex> vopcvex
<hou.ShopNodeType for Shop v_fluffy> v_fluffy
<hou.ShopNodeType for Shop v_ambient> v_ambient
13.Top
任務(wù)流節(jié)點避诽,Houdini17.5新增的強(qiáng)大功能龟虎,PDG就是其主要核心功能,能進(jìn)行多線程沙庐,多變量批量計算鲤妥,可以認(rèn)為是平行宇宙吧。所有/tasks與Top network下創(chuàng)建的第一層節(jié)點都是Top節(jié)點拱雏。Top network網(wǎng)絡(luò)容器節(jié)點類型取決于它的父節(jié)點棉安。
<hou.NodeType for Top localscheduler> localscheduler
<hou.NodeType for Top genericgenerator> genericgenerator
<hou.NodeType for Top geometryimport> geometryimport
<hou.NodeType for Top waitforall> waitforall
<hou.NodeType for Top csvoutput> csvoutput
14.TopNet
在/tasks里創(chuàng)建的Top network網(wǎng)絡(luò)容器節(jié)點,也是唯一一個古涧。
<hou.NodeType for TopNet topnet> topnet
15.VopNet類型
這也是Houdini歷史遺留下的網(wǎng)絡(luò)容器節(jié)點垂券,用來計算vex的地方,也是可視化編程的地方羡滑。注意菇爪,在Vop network里創(chuàng)建的所有節(jié)點都是VopNet節(jié)點,不是Vop節(jié)點柒昏。
16.Vop
vex程序運行節(jié)點凳宙,這里的V是vex的意思,vex是houdini自身軟件的語言职祷,是仿著C++的閹割版C氏涩,為提升軟件計算效率用的届囚。官方幫助頁里說它是Shader Nodes這也是讓人迷惑的地方。因為以前vex就是主要執(zhí)行shader的是尖,而現(xiàn)在vex的功能已經(jīng)被Houdini拓展到了全局意系。也有人會把V理解為view當(dāng)做可視化編程來理解,其實算是歪打正著吧饺汹,畢竟Houdini是為藝術(shù)家而不是程序員設(shè)計的一款軟件蛔添,其大部分程序功能確實是可以通過可視化編程節(jié)點進(jìn)行實現(xiàn)的,就現(xiàn)階段而言兜辞,要識別Vop節(jié)點通過判斷它是不是可視化編程節(jié)點確實是一種非常直觀又準(zhǔn)確的辦法迎瞧。
所有/mat以及Vop network,Mat network網(wǎng)絡(luò)容器節(jié)點里創(chuàng)建的第一層節(jié)點都是Vop節(jié)點。所以Attribute VOP與Mat network里的節(jié)點其實都是Vop節(jié)點逸吵。Vop節(jié)點有個很明顯的一個視圖特征就是橫向節(jié)點流凶硅,如下圖
<hou.NodeType for Vop geometryvopglobal::2.0> geometryvopglobal::2.0
<hou.NodeType for Vop normalize> normalize
<hou.NodeType for Vop geometryvopoutput> geometryvopoutput
<hou.NodeType for Vop snippet> snippet
到此,Houdini18.5的所有節(jié)點類型都講完了扫皱。所以“為什么ROP network與/out一樣足绅,/stage與LOP network一樣”,這類由于Houdini將節(jié)點功能與模塊功能混在一起的風(fēng)騷迷惑操作韩脑,大家應(yīng)該理解了吧编检。
獲取Houdini的各類節(jié)點
知道Houdini的節(jié)點類型,是玩Houdini的基本前提扰才。Houdini本身還是一款應(yīng)用工具軟件允懂,我們既不能無視它的功能也不能神化它的存在,它和其他DCC軟件其實跟電腦里的計算器還有手機(jī)里的小程序一樣衩匣,需要的時候就用蕾总,能解決一些問題就可以了,認(rèn)清你想要的琅捏,你才不會迷惑生百。
Houdini18.5里每種節(jié)點類型下有多少個節(jié)點,到底哪類節(jié)點重要一些呢柄延?我統(tǒng)計了一下蚀浆。
結(jié)果可以看出Vop最多,Sop其次搜吧,然后是Dop市俊,這三個占了絕大部分。怎么獲取所有節(jié)點呢滤奈?方式如下:
import hou
node_types=hou.nodeTypeCategories() #獲取節(jié)點各類型
all_nodes=[]
counts={}
for nc,nt in node_types.items():
all_types=nt.nodeTypes() #獲取各大類下的所有節(jié)點(字典)
all_node_names=list(all_types.keys()) #所有節(jié)點名稱
counts[nc]=len(all_node_names)
for name in all_node_names:
all_nodes.append(name)
print(counts)
print(len(all_nodes))
需要注意的是Director與Manager節(jié)點類型無法通過node.Types()來獲取,它返回的是空{(diào)}摆昧,很神奇。
Houdini節(jié)點參數(shù)翻譯
先上個效果圖
怎么實現(xiàn)的呢蜒程?
思路是:
1.先獲取所有節(jié)點類型
2.再獲取每個類型下的所有節(jié)點
3.然后獲取每個節(jié)點的參數(shù)名稱绅你,參數(shù)標(biāo)簽
4.將所有標(biāo)簽翻譯為中文
5.將數(shù)據(jù)存入工具架
6.通過工具架對選中節(jié)點進(jìn)行復(fù)制,替換新復(fù)制出的節(jié)點上的所有參數(shù)標(biāo)簽伺帘,得到翻譯后的節(jié)點.
主要腳本操作如下:
收集節(jié)點參數(shù)信息get_data.py
import numpy as np
import pandas as pd
node_types=hou.nodeTypeCategories() #返回的一個字典
'''
{'Chop': <hou.NodeTypeCategory for Chop>, 'ChopNet': <hou.NodeTypeCategory for ChopNet>, 'Cop2': <hou.NodeTypeCategory for Cop2>, 'CopNet': <hou.Nod
eTypeCategory for CopNet>, 'Director': <hou.NodeTypeCategory for Director>, 'Dop': <hou.NodeTypeCategory for Dop>, 'Driver': <hou.NodeTypeCategory f
or Driver>, 'Lop': <hou.NodeTypeCategory for Lop>, 'Manager': <hou.NodeTypeCategory for Manager>, 'Object': <hou.NodeTypeCategory for Object>, 'Shop
': <hou.NodeTypeCategory for Shop>, 'Sop': <hou.NodeTypeCategory for Sop>, 'Top': <hou.NodeTypeCategory for Top>, 'TopNet': <hou.NodeTypeCategory fo
r TopNet>, 'Vop': <hou.NodeTypeCategory for Vop>, 'VopNet': <hou.NodeTypeCategory for VopNet>}
'''
all_nodes=[] #所有節(jié)點名稱
parm_names =[]
data_list=[]
for nc,nt in node_types.items():
#nc為Categories各大類名稱,nt為各大類的腳本類型
node_types=nt.nodeTypes() #獲取各大類下的所有節(jié)點(字典)
node_names=list(node_types.keys()) #該節(jié)點類型下所有節(jié)點名稱
for name in node_names:
all_nodes.append(name) # 記錄所有節(jié)點
node=hou.nodeType(nt,name)
plg=node.parmTemplateGroup()
f_parms=[p for p in plg.entries()] #獲取每個最高層級參數(shù)
i_parms=[u for u in plg.entriesWithoutFolders()] #獲取非目錄參數(shù)
f_parms.extend(i_parms)
parms=list(set(f_parms))
for i in parms:
p_name =i.name() #參數(shù)名稱
p_label=i.label() if i.label() else p_name #當(dāng)不存在標(biāo)簽時,就用參數(shù)名稱
if p_name not in parm_names:
parm_names.append(p_name)
per_list=[p_name,p_label,name,nc]
data_list.append(per_list)
print('all_nodes:',len(all_nodes))
print('parm_names:',len(parm_names))
data=np.array(data_list)
df=pd.DataFrame(data,columns=['parm_name','parm_label','nodename','category'])
save_path=os.path.join(hou.getenv('HIP'),'node_info.csv')
df.to_csv(save_path)
輸出的節(jié)點數(shù)據(jù)node_info.csv 結(jié)構(gòu)如下
節(jié)點翻譯 translate_node.py
工具地址:
gitee:https://gitee.com/cgai/chinese-corpus-of-houdini.git
百度云:https://pan.baidu.com/s/1O4wVF4rOWfg5zRV6JpcifQ 提取碼:t1iu
這個功能其實就是將節(jié)點上的參數(shù)翻譯一遍忌锯,實現(xiàn)也不難伪嫁,對制作與學(xué)習(xí)基本上也什么用,我做這個的主要原因是因為我一直沒有找到CG專業(yè)術(shù)語的中文語料偶垮。Houdini是一個可控性很強(qiáng)的DCC軟件礼殊,如果只是針對專業(yè)人員來操作,那么所有DCC軟件用其本身的英語是最好的针史,但,假如不是呢碟狞?或者說如果我們要對DCC軟件進(jìn)行外部的交互式操作啄枕,比如手勢、聲控族沃、語音這些频祝,這個時候我們會發(fā)現(xiàn),還得需要一套標(biāo)準(zhǔn)的專業(yè)語料脆淹,否則根本就不好識別命令意圖常空。所以我把Houdini18.5里的所有節(jié)點的參數(shù)名稱以及參數(shù)標(biāo)簽都導(dǎo)成一個csv,然后用百度翻譯接口把所有標(biāo)簽機(jī)翻為中文盖溺,存為一個大Json也放在gitee里漓糙,機(jī)翻的肯定有很多不對,我稍微修改了幾個烘嘱,個人能力有限昆禽,還希望有興趣的朋友來一起完善。哈哈蝇庭,加油醉鳖。