3D MAX Script是我迄今為止見過編程語言最自由的一種腳本開源環境,他的自由程度遠遠超過了Sun 的JAVA,她沒有大小寫的區分,以及固定的公式和程序工作流程樹,MAX Script一旦被編寫,人們就可以從任何一行進行代碼的編譯,不需要符合格式的束縛。而且MAX Script的功能相當強大。
詳細的說明一下MAX Script功能到底有多強大:MAX Script是完全基於OpenGL開源以及VC核心制作出來的,而當今世界上任何一款CG制作軟件也主要依賴這兩點編寫,也就是說如果MAX Script使用的好,我們完全有那個能力在3D MAX里面集成Maya的所有功能!這不光光是二次開發的樂趣,我想她更是一次CGer思維的革命,很多使用傳統制作方法難以完成的任務,在使用了MAX Script后就會變的非常簡便、快捷!
我認為想要學好MAX Script不在於你前面有多少編程的基礎和學習經驗,關鍵在於是否能很好的理解MAX Script里面每一個字串符的使用方法和他的作用。舉個很簡單的例子:“()小誇號”和“[]中誇號”有什么區別呢?他們可以在什么地方使用?兩個符號可以結合在一起使用嗎?怎么結合在一起使用更加科學合理?其實就是這樣的幾個問題解決好了,你甚至可以模仿出一些美國大片級別的視頻特效!(以上的幾點我會在接下來的雜志中進行詳細講解)
第一講:MAX Script基礎片
認識MAX Script界面:

按下鍵盤上的F11,或者按照圖示單雞按鈕,即可彈出MAX Script窗口

第一講,第二節:基礎應用片:
用實例講解MAX Script的基礎符號.
很多人感覺MAX Script很難,其實我覺得他們覺得很難的原因是因為基礎沒有學好,而我認為的MAX Script基礎就是符號,倘若能把幾個基本符號理解的很好的話,相信很多問題就可以迎刃而解. MAX Script真的不難,關鍵是在於你對他的理解.
現在我開始講解MAX Script中最基礎的符號,希望大家認真學習,因為在這一節學好了,接下來的學習就會顯的很輕松
MAX Scrip中:使用―― $、””、()、[]、和. 的理解。
接下來我向大家演示兩個例子,並且在此例中向大家講解以上幾個符號的使用方法,和如何理解.
首先,來看一張效果圖:比較抽象些,只是表達個意思
一張大數量,宏觀城市景觀,共15376個BOX,怎樣制作速度最快?
最簡單的方法就是――制作許許多多個BOX,然后一個一個的對他們進行高度、大小設置(― | | |)―凸―)~_~)――_―)。。。不過這個。。這個這個。。呵呵,冷不?好冷。。。
而我使用了MAX Script后,只要一句就可以高定!


1:隨便拉一個BOX
2:陣列一下(我的是30*30一共900個BOX)
3:選中所有物體!寫入腳本
4:渲染,完成局部的制作。
我使用的語句是:for a in selection do a.height=(random 0 10)
有人說:“老師,你寫的那句話是什么意思?”好,我現在說明一下。
首先是:for a in selection。什么意思?for a in selection是一個固定搭配,表示“被選擇的物體”而被選擇的物體就是用――a來表示。
然后是――do,這個不用多解釋了,“做,做一件事情” 被選中的物體去做一件事情;那是去做什么事情?這就是代碼運算的結果――a.height=(random 0 10)
a. height=(random 0 10):
表示被選擇的物體――a的 高度等於(0到10之間的一個隨機數)
random是隨機的意思; 0 10表示范圍;height表示物體的高。他應該=…………
有了上面的這些解釋,下面我們返回這一講的主題:
仔細觀察上面所給的代碼,首先我們發現一個有趣的表達式a.height,很有意思,a表示已選擇的物體,而height表示物體的高度,而者怎么聯系到一起去的呢?原來是中間的一個 . 號。這個符號是關鍵,如何理解?你可以把他理解成――“什么什么的屬性”這個后面再跟具體屬性,比如這個a.height,他的意思是說a的高的屬性。然后再繼續接表達式。a.height=什么什么(一個可選的數)
再仔細觀察,有沒有發現什么?呵呵――小誇號!小誇號()怎么理解?不能說理解了,應該說怎么使用,在這里小誇號的使用方法為――“(加可選的客觀數值,或者運算表達式)”向在這里,小誇號()里面就是一個表達式,他的取值范圍在0到10之間。連接上前面的a.height,意思就是“被選擇的物體高度在0到10之間隨機變化。”講到這里,你已經豁然開朗了吧
其實原理是很簡單的,關鍵在於你能不能想的到。
第一講第三部分:實例2:
完成了上一個例子.好,有人又說了:“丁,怎么樣把那些房子都做成不一樣的顏色?”最簡單的方法就是一個一個的點擊物體,然后一個一個的對他們的線筐顏色進行調整。(― | | |)―凸―)~_~)――_―)。這個這個。呵呵。。倘若想使用MAX Script,仔細想一下,其實這也是很簡單的,學會一個屬性命令――wirecolor就可以做到了,這個屬性命令我是在――亓鑫輝老師的公開講課中學到的。在此非常感謝火星培訓部的亓鑫輝老師!也希望大家支持亓鑫輝老師!

1:這里有100個BOX,選中他們。
2:然后腳本
3:然后完成,我這里有100BOX他們的顏色都是不一樣的。
來看一下代碼:for a in selection do a.wirecolor=color(random 0 255) (random 0 255) (random 0 255)
有人說:“老師,什么意思?”在這里for a in selection不說了,do 后面跟的是a 及wircolor兩個關鍵詞。Wirecolor是線筐顏色的意思,中間 . 號連接表示a的線筐顏色,后面是一個新的表達式:color
現在我來說一下color的使用方法。
Color+RGB是理論表達式,RGB都用0到255之間的數字表示,好了這樣就有人寫出了這樣的表達式:Color 50 250 150。回車執行代碼后,發現是錯誤的。而我就覺得這些人在我前面說的內容還是沒有理解。Color后面既然想表達3個數字分別對應RGB,能這樣表達嗎?是3個數字,不是一個數字。50 250 150,這是什么值?雖然可以表達RGB,但是格式不對。前面的內容我已經詳細的講解過了一點了:小誇號()的使用方法,小誇號()里面用來表示一個具體的數值。所以在這里,寫成Color (50)(250)(150),就顯的更加合理
跟上前面的表達式連起來看一下。for a in selection do a.wirecolor=color(random 0 255) (random 0 255) (random 0 255)顯然,我把已選擇的物體的RGB都在0到255上面進行隨機取值,這樣就可以做到顏色都不一樣了。

以上是MAX Script經常出現的幾中情況錯誤,仔細觀察。紅色的文字告訴你是什么地方出了問題。
1:-- Error occurred in a loop
-- Frame:
-- a: $Box101
-- Argument count error: Color wanted 4, got 1
這個提示應該還是比較好理解的,他告訴你BOX101沒有辦法按照代碼被賦予正確的線筐顏色。而且也告訴了你是在“Color”這一指令后出的問題,很明顯這個就說明Color的表達有問題。
仔細觀察,發現錯誤語句中的Color表達是:Color(0 255 255)。而實際上3DMAX Scrip中的――()小誇號,里面只能存一個固定的數值,0 255 255雖然是“RGB”色彩代碼的表示方法,但是不符合語法,小誇號內必須存一個固定的數值,在MAX Scrip中“Color”指令后確實是要跟三個數字來表達R、G、B的,此時我們使用3個小誇號:()就比較合理了。
2:-- Syntax error: at keyword parameter, expected name
-- In line: for a in selection do a.wirecolor:color
出錯了沒有關系,MAX Scrip中的錯誤是最好排除的,仔細觀察紅色的提示代碼,要認認真真的找下在什么地方出錯。他告訴你咯,這個“for a in selection do a.wirecolor:后出現了錯誤,”意思是這個“等於”號不能這么打,而輸入“=”就比較合理了。(我上是用“冒號”代替“等於號”的)
3:我胡亂打的蝦米…...看看他告訴我什么:undefined。意思是有定義。
解決辦法比較傳統,入下:“沒有定義的變量或者名稱”=*即可(*可以是任何數值或者表達式,總之必須是一個已經被定義過的語句。)
4:這是在MAX Script中一個比較典型的錯誤,如何判斷一個有效的表達式。MAX Script中運行代碼的時候,是從上向下依次逐行運算,仔細觀察,發現錯誤代碼為:
a+b/c
+d
MAX Script在進行運算的時候,在第一行,會把他當成a+b/c進行運算然后直接輸出結果,執行第二行的時候,就會提示“+號”使用錯誤,這是一段斷開的代碼,沒有從頭到尾的連續性。VC 和JAVA在這方面都使用了――{}大誇號來表示一段完整的程序代碼。然后一段代碼中還能繼續使用{}大誇號繼續定義子程序樹。在MAX Script,加上反斜杠\就顯得比較合理了
a+b/c\
+d
這樣效果就等同於a+b/c+d.。如果想要把幾條表達式合並成一行,也可以使用分號隔離.比如如圖.

第二講:第一節:學會使用語句 : showProperties()
顧名思義,Showproperties意思就是顯示物體的信息,為什么要先學會使用這個表達語句呢?譬如,在3D MAX里面有個自帶AEC插件,做樹木用的,(盡管效果很假)。當我在場景中間創建了一個樹木。想用腳本來控制他的一些參數,但是我也不知道他有那些參數。怎么辦?這個時候Showproperties命令就派上用場了~

當我把創建的這個樹選中,輸入showproperties$回車,立刻白色代碼執行區顯示出了這個物體的所有屬性。(其中符號 “$” 表示別選中的物體,意思是in selection,但是二者不等同,$更傾向與一個表達試,而in selection更傾向與一個命令)譬如height表示他的高度,seed表示他的隨機種子數等。仔細觀察,會發現前面都有一個 “.”(點)這個點前面也都省略了一個”$”.倘若把$加上,相信大家一定一目了然了~
接下來我們就可以自由的使用這些命令了,利用第一講的知識,我們可以很快的做出許多完全不一樣的樹~(如圖:利用random命令,讓他們的高度和種子隨機變化,很簡單的例子,第一期有詳細的介紹.)
小結: 利用Showproperties命令,查看物體有那些可編輯屬性參數,然后就可以使用命令對需要修改的參數進行控制了~
第二節:2.1.打開 宏記錄:
你在3D MAX 里面創建了一些物體,或者對一些物體屬性進行了修改,做的這些事情都會被3D MAX用腳本語言的形式給記錄下來,所以,打開了宏記錄我們就可以在腳本代碼里面看見自己都是怎么對MAX進行操作的.但是宏記錄也有不足的地方,那就是不是所有的操作行為都能被3DMAX的宏記錄,記錄下來.眼下靈活的使用宏記錄,是學好3D MAX腳本的關鍵所在~

如圖,這就是打開3D MAX宏記錄的方法,在書寫腳本的窗口上端的MacroRecorder下拉菜單中勾選Enable起用勾選,這樣就打開了3DMAX腳本的宏記錄.圖中是我在世界坐標系中央創建了一個BOX時候被記錄下來的命令.
Box lengthsegs:1 widthsegs:1 heightsegs:1 length:29.8779 width:33.3667 height:48.5474 mapcoords:on pos:[-13.0051,-19.3169,0] isSelected:on
前面三句lengthsegs:1 widthsegs:1 heightsegs:1分別表示長寬高上面的片段數.接着就是長寬高的具體數值,然后pos后面中括號里面是XYZ軸的坐標值.接着是一個狀態顯示參數: isSelected:on表示這個物體正被選中的狀態~
2.2.:執行一段代碼的正規操作
現在我們要開始接觸更多的MAX Script語言代碼了,這意味着我們今后要執行什么命令不會象第一期中單句單句執行的那么簡單了,我們將要執行大段大段的代碼,而要執行大段大段的代碼就不要想按下回車了事~

看看這張圖吧,由於直接用回車進行代碼執行,導致了只執行了一行代碼,白色的代碼執行區顯示出了紅色的出錯提示語句,而正確的代碼執行規則是如圖所示:首先保存成MAX Script 腳本的*.ms文件,然后再使用Run Script按鈕執行。
2.3:小括號又一理解思路:
在前面第一期我解釋過,小括號里面是來表示一個數值的,在這個,我講一下小括號的又一理解思路,意思是:在小括號內寫的是一段完整的可執行的MAX Script代碼,有人用過JAVA的一定知道,在JAVA里面是大括號 { } ,大括號內括的是一段完整的可執行代碼 “{”表示程序開始,“}”表示程序結束,在MAX Script里,小括號也是這么一個用法。
Mental Ray大家都用過的吧。
2.4添加控制菜單
通過這樣的幾句話,就完成了控制面板的添加,老規矩還是來解釋一下是什么意思。
代碼是這樣寫的喲
utility Publicname "標題名稱"
(
button Publicname "enjoy 3D MAX" pos:[12,20] width:140 height:30
)
什么意思?第一句有一個“utility”語句,他的意思是指在上面圖中MAX Script面板里面那條下拉菜單里面添加一個選項。這個語句怎么用?我來說一下:首先他的固定語法是:utility + name +“標題名稱”, 中間name指的是程序內部的名稱,計算機運行代碼的時候,他要知道你新添加的東西叫什么名字,才能執行這個東西下面的子代碼,所以這個name只能是英文,他表示:你新添加的面板的名稱,而后面“標題名稱”就是標題名稱了,觀察下上面的圖就明白了,我也不多說咯~
我們繼續往下看:
button Publicname "enjoy 3D MAX" pos:[12,20] width:140 height:30
這句,首先button(按鈕)也是一個他的固定語法也是和utility一模一樣的:button + name + “標題名稱”,這里我給的標題名稱是:"enjoy 3D MAX" 。
最后這段代碼在第一段小括號內還少一句話才顯的完整——on Publicname pressed do意思是:當Publicname按鈕被按下的時候do一件事情。(有關於do的語法第一期有講)至於做什么事情,我們可以緊接着前面的代碼繼續一個小括號,在這個小括號內書寫一段完整的可執行代碼,作為“do“的具體內容
utility Publicname "標題名稱"
(
button Publicname "enjoy 3D MAX" pos:[12,20] width:140 height:30
on Publicname pressed do
)
)
--這里一對小括號內書寫一段完整的可執行代碼,用語承接上文中“do“的內容
(
關於button按鈕語句,用客觀一點的公式來表達應該是這樣:
button <name> [ <caption> ] [ images:<image_spec_array> ] \
[ toolTip:<string> ]
我不能把什么東西都解釋完了,要不然大家的思想會變的很局限,所以關於按鈕。我做了一個比較有意思的東西,也希望大家自己能夠思考一下
這個東西比較有意思,一個渲染按鈕,制作起來也比較方便,單擊他后,原來按鈕的位置就會被渲染出來場景中的物體。
大家仔細考慮一下我這個按紐是怎么制作的,其實方法很簡單關鍵看你能不能想的到。
代碼我也公布給大家,想不出來的時候自己可以對着這代碼看一看思路。
rollout image_button_test "Image Button"
(
button theButton "Press To Render!" width:200 height:200
on theButton pressed do
(
theBmp = render outputsize:[200,200] vfb:off
theButton.images = #(theBmp, undefined, 1,1,1,1,1 )
)
)
createDialog image_button_test 210 210
思路:創建大氣物體,使用環境火焰特效,進行制作,並打開宏錄,記錄制作流程,最后結合前面所學的命令進行制作優化。

創建大氣物體——圓柱,3D MAX的宏記錄記錄了下他的創建過程:
CylGizmo radius:15.6403 pos:[0.166849,0.496013,0] isSelected:on height:44.8379
當然我們知道很多都是沒有用的廢話,經過修改后得到
CylGizmo radius:10 height:33
把過長的浮點修改整,去掉一些類似於isSelected:on的廢話 ,pos[]語句也被刪除了,pos[]是表示物理坐標位置的語句,如果被刪除了,那么物體會自動的被創建在[0,0,0]世界坐標軸中間。

宏記錄的時候記錄的不是很完全了,如圖粉色的部分有用的只有這兩句其中addAtmospheric (Fire_Effect ())表示給物體添加Fire_Effect這個大氣特效的意思
CylGizmo radius:10 height:33
addAtmospheric (Fire_Effect ())
這就是宏記錄后被我選擇的語句,其中addAtmospheric (Fire_Effect ())表示添加Fire Effect這個大氣特效的意思,但是添加歸添加,要把Fire Effect這個大氣特效添加給哪個物體?通常我們會在環境特效編輯器里面拾取,但是這樣的拾取在3DMAX里面是不能被宏記錄的,如果想要讓Fire Effect這個特效指定給特定的大氣Gizmo的話,就要用到下面這句話
appendGizmo (Fire_Effect ()) CyLGizmo 01
意識是:把Fire Effect這個特效指定給 CylGizmo 01。語言是這個意思了,但這樣表達不好,因為他只能使用一次,在這里CylGizmo 01是一個物體,他不是變量,所以以后的代碼再出現CylGizmo 01就不能被循環使用了。
為了避免這個現象,我們得給這個大氣Gizmo設置一個變量
這個變量這樣寫:
wy=Fire_Effect ()
GZM=CylGizmo radius:10 height:33
使得一個 Fire Effect 特效等於變量wy ,由變量wy替代,大氣Gizmo由變量GZM替代。加上3DMAX的宏記錄就有了以下代碼
utility Cosmicbrid "飛船尾焰"
(
button Cosmic "飛船尾焰" pos:[12,20] width:140 height:30
on Cosmic pressed do --當按鈕按下時候做 ↓↓↓
(
GZM=CylGizmo radius:10 height:33 ---創建園柱形大氣線框
wy=Fire_Effect ()
addAtmospheric wy ---增加火焰特效
appendGizmo wy GZM——將火焰特效賦予給相應的大氣Gizmo

基本上這樣就創建了一個尾焰,下面的事情就需要我們來對他進行參數設置,首先看看上面的圖。先來將第一個color面板:
這里有3個顏色選擇Inner Color:內部顏色 , Out Color: 外部顏色,Smoke Color: 煙霧顏色。Inner Color:內部顏色是火焰內部的顏色,飛船尾焰內部應該是很亮的,到了外部應該是藍色的(氫氣燃燒顯淡藍色的火焰)
Shape: flame Type:Fireball : 火球 。
Stretch 拉伸 ,Regularity 規則性
Stretch 拉伸:這里數值越大拉伸的越厲害,飛船應該是比較長的火焰,所以可以設置的高一些。
Regularity 規則性:當他小於 1.0,將壓縮火焰,使火焰更短更粗。 當他大於 1.0,將拉伸火焰,使火焰更長更細。
Characteristics: 特性 Flame Size : 火焰大小,單位和系統默認單位一樣。
Density:密度,火焰的密度大小。 Flame Detail 火焰細節,飛船尾焰的尾處有很多類似“須須“形狀的火焰,很細,這個值調的越高,那么這種效果就會越明顯。
Samples:采樣數,數值越大采樣越大,效果越好,渲染時間越長
進行了一下顏色的調節,完整的記錄下了宏記錄,這是調節到圖中所給顏色所記錄下的宏記錄
(getAtmospheric 1).Inner_Color = color 153 199 255
(getAtmospheric 1).Outer_Color = color 29 56 255
(getAtmospheric 1).Smoke_Color = color 206 240 248
你可以把他插入到你的代碼第二節中(按鈕按下后發生的事件),並且可以通過使用一個Random命令(第一期有非常詳細的介紹)進行色彩上微弱的變化調節,這樣就可以做到每次生成的Gizmo的顏色都不一樣了。
3.2使用Showproperties和Showclass命令參看 Fire Effect具有的屬性。

可以發現,這些數值都是和面板上面相對應的。
插入卷簾:
rollout property "Shape" width:160 height:150
(
)
on Cosmicbrid open do
(
addRollout property rolledup:true
)
這一段完整的卷簾代碼,用到了一個新的命令——rollout卷簾命令。固定語法不說了,后面是他的寬和高,接下來的一對小括號里面書寫一段完整的可執行代碼。這樣雖然沒有問題了但是執行代碼這樣的卷簾他不會被顯示出來。還要添加一段:
on Cosmicbrid open do
(
addRollout property rolledup:true
)
他的意思是“Cosmicbrid ”這個面板必須打開,添加“property”這個卷簾。后面rolledup:true表示允許添加到Cosmicbrid 這個面板當中。(我在這個程序中的主面板的名字是Cosmicbrid ,大家在最早定義自己添加的面板的時候起的什么名字,在這里就用什么名字,或者你想把這個卷簾添加到別的面板當中去,那個面板叫什么名字。)

把這段代碼接到后面,發現並不能運行。仔細觀察一下,發現代碼分上下兩段,上面一段代碼在結束的時候,有一個小括號作為結束命令,(紅色加重顯示的地方)這樣導致了下面一段沒被包涵到上面的一整段代碼中,所以就沒有能被執行下來了。
這樣把那個小括號移到下面來,作為整段程序的最終結束語句就可以了。
添加控制滑竿:
這里我演示只一個哦,其他的留給大家自己做,呵呵,我把所有的都做了就不太好玩了
在剛才
rollout property "Shape" width:160 height:150
(
)
的小括號中,輸入以下語句:,
spinner spn1 "Stertch拉伸" range:[0,40,1] type:#float scale:0.1
on spn1 changed val do
wy.Stretch =spn1.value
我們主要想對火焰的拉伸值進行控制,前面也已經使用了Classof命令查看了Fire_Effect的屬性項目表,里面的拉伸選項是.Stretch: float。這里正好可以用上了。
來說一下這句話是什么意思,spinner spn1 "Stertch拉伸"。這里有是一個新的語句,spinner,他是一個滑竿的控制命令,語法同上(基本上3D MAX腳本都是這個語法:一個物體指令+ name +“標題名稱”)后面緊接着了一個range:[0,40,1]命令,這個命令的意思是取值范圍,我需要把火焰的拉伸在1—40之間隨便選擇,所以這里定義了range:[0,40,1],你也可以定義自己想要的值域。
接着on spn1 changed val do。這里和前面的button按鈕語句差不多
(
button Cosmic "飛船尾焰" pos:[12,20] width:140 height:30
on Cosmic pressed do --當按鈕按下時候做 ↓↓↓
(
on Cosmic pressed do,
on spn1 changed val do
上面的是按鈕的,下面的是滑塊的比較一下你就了解了,不多說了。兩者的原理一模一樣。
最后:wy.Stretch =spn1.value 前面我們定義過了一句話,不知道大家還記得不?wy=Fire_Effect ()這句話是給了Fire_Effect這個東東一個變量,讓Fire_Effect等於變量wy,wy. Stretch意思就是Fire_Effect特效中的Stretch(拉伸)數值了,這個數值又跟了一個表達式子-- spn1.value。spn1是前面我們制作的滑塊名字,他加上一個“點“后面跟value一詞,意思就是說spn1的數值大小了。
連起來的意思就是:火焰特效中火焰拉伸的數值等於滑塊spn1的數值大小。

執行后出現了問題
仔細觀察,發現是Fire_Effect語句出了問題,他說Stretch這個語句沒有定義?分析一下,首先Stretch的拼寫是沒有錯誤的,那就說明系統沒有找到Stretch對應的具體變量,或者說,是什么東西的Stretch?而出錯的地方表達式是wy.Stretch =spn1.value 說的是wy的Stretch。而上文有定義了wy= Fire_Effect。那是什么情況呢?
原來上文定義的wy= Fire_Effect只能給上文使用,當那一段代碼結束的時候wy= Fire_Effect就不在成立了,那怎么樣可以讓wy= Fire_Effect這句話在全文都成立呢?其實,這個很簡單只要在上文的wy= Fire_Effect前面加一個Global語句就OK了~意思是全局適用
旋轉和縮放
在3DMAX中可以有3中方式來對對象進行旋轉:Euler Angles(歐拉角) ,Angleaxis(角軸),Quaternions(四元素)
這里我只介紹Euler Angles歐拉角。其語法是:
rot_obj=eulerangles x y z
其中rot_obj是旋轉變量,x ,y, z分代表各個軸向上旋轉的角度。
1:addmodifier()語句
addmodifier()語句的作用是給場景中的某一個物體添加指定的修改器。譬如我們如果想給一個BOX添加一個UVW Map的修改器,就可以通過使用這個addmodifier()語句來實現。在3D MAX腳本字典中給出了它的標准使用方式為
2: distance() 用來計算2物體間的距離
標准使用方法為: distance <point3> <point3>
讀高中的時候碰到一道超級爆難幾何題,要用空間向量求2個點之間的距離,想了一個下午還沒有頭緒。呵呵,后來晚上急了,我就拿3DMAX的distance()語句把這道題目給搞定了。

觀察圖例:第一個窗口中給出了一條為:
-- Unable to convert: Taper to type: Modifier
的報錯返回值,現在我們來分析一下這句話的意思:他說不知道 Taper修改器的子類別參數,也就是說在taper導邊修改器下面有那一個參數起作用?導邊的片段數?還是圓滑程度?在現階段的3DMAX中,使用addmodifier()語句這個參數是不能省的。如果我們只想添加一個修改器,不想去設置這個修改器,那么我們就可以添加一個:() 圓括號來解決這個問題。
如圖第二次,我們添加了一個() 園括號,里面不寫任何表達試和參數,他表示:不修改任何修改器中的指令。

如圖,在第二段代碼進行了編譯后,就得到了這張圖中的BOX了
在這里我要特別的說一下UVWMap修改器的添加,這個比較特別。

觀察如圖的內容,第一個窗口返回了一段報錯提示:
-- Error occurred in anonymous codeblock
-- Frame:
-- uvwmapping: undefined
-- Type error: Call needs function or class, got: undefined
他的意思是說uvwmapping這個語句沒有定義,這是為什么?為什么uvwmapping會沒有定義,仔細觀察我們3DMAX的修改器下拉菜單如下圖。

如果我們直接用鼠標來添加這個UVWMap修改器,那么在添加之前,他的名稱是——UVWMap,但在添加個一個物體后,他的名稱就變成了UVW Mapping。也就是說我們書寫表達式的時候要使用UVWMap被添加給物體前的名稱——“UVWMap”,添加后如果想對這個修改器進行什么參數設置的話,我們就要使用他被添加給一個物體后的名字“UVW Mapping”。

distance()語句的使用方法很簡單只要在distance這個單詞后根上2個<Point 3>坐標點就OK了。來舉一個比較簡單的例子:有兩個坐標點:a = [10,20,30], b = [100,30.5,41.3],現在a和b已經代表的是2個坐標點的數值了,我們只要直接輸入distance a b然后回車,系統就會返回點a和點b之間的距離了。


縮放scale
縮放場景中的一個物體可以通過scale語句來實現,例如,mybox.scale=[1,2,3] ,執行這個語句后,mybox在X軸向上不被縮放,在Y軸向上縮放2倍,在Z軸方向上縮放3倍。


addmodifier()語句的作用是給場景中的某一個物體添加指定的修改器。譬如我們如果想給一個BOX添加一個UVW Map的修改器,就可以通過使用這個addmodifier()語句來實現。在3D MAX腳本字典中給出了它的標准使用方式為
addModifier <node> <modifier> [before:index]

觀察圖例:第一個窗口中給出了一條為:
-- Unable to convert: Taper to type: Modifier
的報錯返回值,現在我們來分析一下這句話的意思:他說不知道 Taper修改器的子類別參數,也就是說在taper導邊修改器下面有那一個參數起作用?導邊的片段數?還是圓滑程度?在現階段的3DMAX中,使用addmodifier()語句這個參數是不能省的。如果我們只想添加一個修改器,不想去設置這個修改器,那么我們就可以添加一個:() 圓括號來解決這個問題。
如圖第二次,我們添加了一個() 園括號,里面不寫任何表達試和參數,他表示:不修改任何修改器中的指令。

如圖,在第二段代碼進行了編譯后,就得到了這張圖中的BOX了
在這里我要特別的說一下UVWMap修改器的添加,這個比較特別。

觀察如圖的內容,第一個窗口返回了一段報錯提示:
-- Error occurred in anonymous codeblock
-- Frame:
-- uvwmapping: undefined
-- Type error: Call needs function or class, got: undefined
他的意思是說uvwmapping這個語句沒有定義,這是為什么?為什么uvwmapping會沒有定義,仔細觀察我們3DMAX的修改器下拉菜單如下圖。

如果我們直接用鼠標來添加這個UVWMap修改器,那么在添加之前,他的名稱是——UVWMap,但在添加個一個物體后,他的名稱就變成了UVW Mapping。也就是說我們書寫表達式的時候要使用UVWMap被添加給物體前的名稱——“UVWMap”,添加后如果想對這個修改器進行什么參數設置的話,我們就要使用他被添加給一個物體后的名字“UVW Mapping”。
2: distance() 用來計算2物體間的距離
標准使用方法為: distance <point3> <point3>
讀高中的時候碰到一道超級爆難幾何題,要用空間向量求2個點之間的距離,想了一個下午還沒有頭緒。呵呵,后來晚上急了,我就拿3DMAX的distance()語句把這道題目給搞定了。

distance()語句的使用方法很簡單只要在distance這個單詞后根上2個<Point 3>坐標點就OK了。來舉一個比較簡單的例子:有兩個坐標點:a = [10,20,30], b = [100,30.5,41.3],現在a和b已經代表的是2個坐標點的數值了,我們只要直接輸入distance a b然后回車,系統就會返回點a和點b之間的距離了。

if 表達式用於有條件地執行一個表達式,這個表達式以布爾測試表達為結果為基礎
if語句的使用方法為:
if <expr> then <expr> [else <expr> ]
if <expr> do <expr>
第一個<expr>是測試表達式,他的值一定要是true或者false,如果在這第一個<expr>測試表達式這里返回的值是true的話,那么就程序就回繼續執行then或者do語句,然后結束。而如果第一個<expr>返回了一個false,則后面的else語句將會被執行。
注意:如果表達式中沒有else語句,或者你編寫的是第二中 if , do的格式,那么在第一個<expr>表達試返回false后,系統會自動中斷程序編譯,並返回一個undefined值。
例如:
mybox=box()
if mybox.height==25
then mybox.width=40
else mybox.width=100
他的意思是創建一個名稱為mybox的BOX幾何體,如果mybox的高為25那么,他的寬就為40,否則寬等於100。
在這里要特別理解我前面說的那句話:第一個<expr>是測試表達式,他的值一定要是true或者false。怎么理解?來看看下面這短代碼為什么出錯了:

第一個窗口中返回了一句為:
-- Type error: if-test requires BooleanClass, got: 25
的報錯,他的意思是說第一個<expr>測試表達式需要布爾函數類(真或假)。自己的體會一下這句話的意思,然后我們再來看看第一個<expr>測試表達式的代碼:
if mybox.height=25
你能看出什么問題嗎?系統說缺少布爾函數類這句話為什么會缺少布爾函數類呢?其實問題出在這個“=”等於號上面,在這里,等於號沒有判斷性,不能判斷這個BOX的高度是否等於25。如果我們想讓一句代碼有布爾性質,那么我們就要使用“==”雙等號,他表判斷。這樣程序就可以判斷第一個<expr>測試表達式的真或者假,然后,把真或假的值傳遞給下一句代碼。
如圖,第2個窗口中使用了“==”雙等號,使得程序按我們的表意進行正確的返回。
接下來我們就剛才的“==”雙等號的問題來談談if語句中比較表達式,他可以是以下形式中的任何一種:
== 等於判斷
!=不等於判斷
>大於判斷
>=大於或者等於判斷
<小於判斷
<=小於或者等於判斷
其實我們可以發現,只要牽扯到了有關大於小於號的表達式,他們就已經具有了判斷性了。
此外If語句還可以作為表達式的一部分,例如:x if a>b then else d
3.2:case of 表達試
case of表達式你可以把他看做是if語句的一個高級形式,你可以給出一組條件,這一組條件中可以有多個測試表達試,還可以為這多個測試表達式分別去定義他們的返回值,相比較if語句而言,他的選擇不會局限於then 或者else的概念,case語句的選擇可以是多個的。
個人觀點:3DMAX的if語句設計的沒有C++的更科學,不管從格式上說,還是執行方式來說,或許C++中if語句的設計,是為了更適合大型的復雜程序使用,但總的來說3DMAX的if語句並不是一個很好的編程風格,尤其是讓別人閱讀你程序的時候,程序思路就顯的不如C++那么整潔和清晰。
他的標准語法是:
case [ <expr> ] of ( <cases> )
在這里<expr>是測試表達式,<cases>是表達失序列,譬如:
<factor>:<expr>
default:<expr>
default是一個標記,在case語句中是可以進行選擇的,如果你給出一個組的條件都沒有一條能和測試表達式匹配,default可以選擇繼續case 表達式。如果沒有default標記,而且前面的一組條件中也都沒有一條和測試表達式匹配,case表達式將返回一個undefined值。
以下是一個小例子

if 表達式用於有條件地執行一個表達式,這個表達式以布爾測試表達為結果為基礎
if語句的使用方法為:
if <expr> then <expr> [else <expr> ]
if <expr> do <expr>
第一個<expr>是測試表達式,他的值一定要是true或者false,如果在這第一個<expr>測試表達式這里返回的值是true的話,那么就程序就回繼續執行then或者do語句,然后結束。而如果第一個<expr>返回了一個false,則后面的else語句將會被執行。
注意:如果表達式中沒有else語句,或者你編寫的是第二中 if , do的格式,那么在第一個<expr>表達試返回false后,系統會自動中斷程序編譯,並返回一個undefined值。
例如:
mybox=box()
if mybox.height==25
then mybox.width=40
else mybox.width=100
他的意思是創建一個名稱為mybox的BOX幾何體,如果mybox的高為25那么,他的寬就為40,否則寬等於100。
在這里要特別理解我前面說的那句話:第一個<expr>是測試表達式,他的值一定要是true或者false。怎么理解?來看看下面這短代碼為什么出錯了:

第一個窗口中返回了一句為:
-- Type error: if-test requires BooleanClass, got: 25
的報錯,他的意思是說第一個<expr>測試表達式需要布爾函數類(真或假)。自己的體會一下這句話的意思,然后我們再來看看第一個<expr>測試表達式的代碼:
if mybox.height=25
你能看出什么問題嗎?系統說缺少布爾函數類這句話為什么會缺少布爾函數類呢?其實問題出在這個“=”等於號上面,在這里,等於號沒有判斷性,不能判斷這個BOX的高度是否等於25。如果我們想讓一句代碼有布爾性質,那么我們就要使用“==”雙等號,他表判斷。這樣程序就可以判斷第一個<expr>測試表達式的真或者假,然后,把真或假的值傳遞給下一句代碼。
如圖,第2個窗口中使用了“==”雙等號,使得程序按我們的表意進行正確的返回。
接下來我們就剛才的“==”雙等號的問題來談談if語句中比較表達式,他可以是以下形式中的任何一種:
== 等於判斷
!=不等於判斷
>大於判斷
>=大於或者等於判斷
<小於判斷
<=小於或者等於判斷
其實我們可以發現,只要牽扯到了有關大於小於號的表達式,他們就已經具有了判斷性了。
此外If語句還可以作為表達式的一部分,例如:x if a>b then else d
3.2:case of 表達試
case of表達式你可以把他看做是if語句的一個高級形式,你可以給出一組條件,這一組條件中可以有多個測試表達試,還可以為這多個測試表達式分別去定義他們的返回值,相比較if語句而言,他的選擇不會局限於then 或者else的概念,case語句的選擇可以是多個的。
個人觀點:3DMAX的if語句設計的沒有C++的更科學,不管從格式上說,還是執行方式來說,或許C++中if語句的設計,是為了更適合大型的復雜程序使用,但總的來說3DMAX的if語句並不是一個很好的編程風格,尤其是讓別人閱讀你程序的時候,程序思路就顯的不如C++那么整潔和清晰。
他的標准語法是:
case [ <expr> ] of ( <cases> )
在這里<expr>是測試表達式,<cases>是表達失序列,譬如:
<factor>:<expr>
default:<expr>
default是一個標記,在case語句中是可以進行選擇的,如果你給出一個組的條件都沒有一條能和測試表達式匹配,default可以選擇繼續case 表達式。如果沒有default標記,而且前面的一組條件中也都沒有一條和測試表達式匹配,case表達式將返回一個undefined值。
以下是一個小例子


想做一個漫游動畫,在一個很大的空間里面漫游,周圍全是一個有一個的細胞模型。類似於這樣的在生物體內漫游的動畫應該怎么去做?很多很多的細胞(也就是標准幾何體—sphere)被放置在這個空間里面,這么多的細胞如何放?還是那個最簡單的方法——一個一個的創建,然后調整位置 —_+++。呵呵,要是需要100萬個細胞那就做死你去吧—凸—。
顯然我們又需要使用到腳本工具了,正好有那么一條語句是我們需要的,在腳本字典上定義為:
Random <point3><ponit3>
他的功能是可以通過2個已經確定了的點的對角線確定一個空間,然后在這個空間里面隨機尋找坐標點!有這樣功能的語句,我們實現用小球去填充一個空間的目的就不難了,不管是100個小球、1萬個小球還是1000萬個小球,都能讓他們很快的填充在一個空間里面,以下是我做的范例,大家也可以式一式。
a = [-10,-20,-30] -- 定義一個坐標為 a的值
b = [20,30,50] -- 定義一個坐標為 b的值
p1 = Point pos:a
p2 = Point pos:b
for i = 1 to 2000 do
sphere pos:(random a b) radius:2 wirecolor:red
這短代碼的意思是:先定義一個坐標為a的值,和一個坐標為b的值,然后在空間中創建2個實點:p1和p2,他們的坐標分別為a和b。
接着定義一個循環函數,從1到2000,也就是創建2000個小球,他們的坐標在p1點和p2點之間隨即選擇,這樣,我們就完成了這個用標准幾何體來填充一個空間的制作

內存分配:運行一段腳本內存不夠時怎么辦?
MaxScript工作的時候是需要占用一定的內存空間的,系統默認的占用量是5.5MB,同所有的3DMAX內存一樣,MaxScript工作時候的內存也是虛擬的,並且按頁管理。通常情況下默認的5.5MB內存就已經夠用了,如果要運行一些大的腳本,需要更多的內存,可以通過系統全局變量的heapSize來增加內存:
HeapSize+=1000000 (另增1MB,一共6.5MB)
需要額外掉用內存的時候,把這句話添加到腳本當中即可,因為這樣的內存調用方式會使系統所有的內存資源下降,所以一般情況下輸入這句話3DMAX是不會執行的,只有在MaxScript返回了“Out of memory”的錯誤信息后,才能使用heapSize語句調用系統內存供MaxScript使用。當重新啟動3DMAX后,MaxScript內存占用
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!希望你也加入到我們人工智能的隊伍中來!https://www.cnblogs.com/captainbed