您好，歡迎使用藝術家腳本。我叫Sybren。
在這一集中，我將向您展示如何創建自己的運算符。
到目前為止，我們僅創建了代碼片段，您可以使用它們，但是它們不是最用戶友好的。
許多人問過創建菜單和按鈕以及自描繪面板和內容的方法。
在本集中，我們將不再關注。
但是，我們將考慮一個必要的第一步，即創建您的第一個運算符。
我們將看看運算符的確切含義，
然後，我們將了解如何創建自己的運算符以及如何使它成為現實。
通過向其傳遞參數來提高靈活性。
然後，我們通過將運算符限制為特定的上下文來得出結論。
運算子(operator)應在菜單，按鈕和熱鍵以及應由其執行的代碼之間粘合。
在第一集中
我們已經通過將運算子從菜單和按鈕複製粘貼到我們自己的腳本中來與他們進行合作。
運營商可以實施
在Blender中使用C編程語言編寫。
或者，它們當然可以用Python編寫。
無論如何製造，它們都具有相同的成分。
首先是一個標識符。因此，
這就是您要放在“bpy.ops”之後的內容，例如，在此運算符中，它遠非完整，
但是我們正在建立它。所以在這個例子中
“bpy.ops.sfa.example”。
這些總是形式“某些類別 句號 一個名稱”。
最好選擇一個已經存在的類別，例如對像或網格或雕刻
或任何適合您的運算子的東西。
但是正如您所看到的，您也可以創建自己的。然後，我們有一個標籤。
這就是菜單項和按鈕上顯示的內容，並以工具提示顯示說明。
然後，一切都合併了
類別(Class)這是我們待會兒要討論的問題。
現在，僅將其視為收集運算子所有成分的鍋具。
你可以看到
該類以運算符命名。
因此，我們用大寫字母表示類別，然後將OT作為運算符類型，
然後其餘的標識符。
到目前為止，我們已經看到了描述，但是還沒有看到實際的代碼。
可以用不同的方式添加用於不同的目的。
因此，這裡有從簡單到複雜的可能性。
您具有“執行”，這是您放置的位置代碼的主要功能。
如果要創建600隻猴子，則可以在這裡進行。
執行功能也是直接從Python調用什麼。
因此，如果您呼出運算子，例如“bpy.something.something”
那就是被調用的函數。
然後我們有“Invoke”，當調用菜單的運算子時調用此函數
或一個按鈕。
如果您想做一些額外的事情，在這種情況下，您想要有一些稍微不同的行為，
那麼您可以在Invoke中執行此操作，然後從那裡調用Execute函數。
現在，我們進入最複雜的模態模型。
模態功能適用於需要較長時間運行的特殊運算子。
這會收到各種事件在Blender中， 當您移動鼠標時，單擊按鈕，然後使用鍵盤，就可以了。
諸如Blender Cloud，紋理瀏覽器或CG美洲獅之類的東西，
Retopo，Float，已實施，就像這樣。
如果所有這些之後，如果您不確定要使用哪個功能，請保持簡單，
只需使用執行功能。
如果結果證明您無法做自己想做的事，那麼您就有具體的理由
看一些更複雜的東西。但在此之前，只需保持簡單即可。
現在，讓我們將其轉換為可以使用的實際運算符。
讓我們再製造一些猴子。
讓我們從刪除不需要的內容開始。
讓我們保持簡單，只是一個Execute函數。如果您看一下網格運算符，
您會看到，它們以“bpy.ops網格原始猴子添加”或
“bpy.ops網格原始ico球形添加”開頭
因此，所有創建新網格對象的運算符都以“網格”開頭。
因此，讓我們繼續這樣做。
因此，ID名稱變為“mesh”，我們將創建一個猴子網格。
猴子網格，標籤為“猴子網格”，工具提示將為
“讓我們散播一些喜悅”
然後我們必須更改類名稱，即成為類別
“mesh_ot_monkey_grid”。
Execute函數必須執行某些操作，但還必須告訴Blender一切是否成功。
這樣一切都很好，您返回“完成”
這告訴Blender代碼實際上執行得很好，
但是也許您的運算子無法工作，也許是為了拉伸網格
且網格沒有任何頂點。
因此，在這種情況下，您將返回“已取消”。
還有其他一些選項，它們都在菜單中進行了描述。
去那裡您可以轉到“幫助”，然後轉到“Python API參考”，
然後轉到有關“bpy.ops”的部分。
所以我們假設 一切都會正常進行，
我們將返回“完成”。
現在，我們要做的就是將代碼放入此處以創建我們的猴子網格。
因此，讓我們複製“腳本藝術家”第3章中的代碼，並將其放在此處。
因此，這會在25行中創建600隻猴子，
它們之間有一個Blender單元。
運算子幾乎已經完成了。所以我們這裡有所有的成分。
現在我們唯一需要做的就是告訴Blender這個操作項存在，這叫做註冊。
幸運的是，這很簡單，我們只稱
“bpy.utils.register_class”，然後是類的名稱， 在本例中為“網眼OT猴子網格”。
為了對稱，
還應該有取消註冊功能。這樣看起來像這樣。
代替調用“註冊類”，它被稱為“取消註冊類”。
基本上，它撤消了寄存器功能的作用，然後，我們快要完成了。
如您所知，當您擁有
這樣的函數，運行腳本時不會自動調用它。
有一個小竅門。
如果您在此處添加這樣的魔術，它看起來會有些奇怪。
但是從根本上講，這意味著，如果運行此腳本，則應調用register函數。
Blender可以通過多種方式訪問​​腳本，執行腳本，也可以從其他方式導入腳本，
就像我們導入BPY一樣，其他代碼也可以導入此文件。
因此，從其他位置導入與運行之間是有區別的。而且只有在運行時，
它應該調用Register函數嗎，這就是這段代碼的作用。
現在，我們可以做的就是將其命名為“monkey_grid.py”
很好
然後點擊播放。
而且什麼也沒發生，這是一件好事。
我們沒有看到任何錯誤消息，我們的代碼也沒有顯示任何消息。
因此，這裡的沉默是件好事。
那麼，讓我們看看現在會發生什麼，
“bpy.ops.mesh.monkey_grid”
好了 我們可以創建一個猴子抓地力。
運算子在那裡。讓我們散佈一些喜悅。我們不要在這裡稱呼它。
讓我們看看是否可以在F3菜單中找到我們的新運算符
和猴子在一起，還有你的猴子網格。所以這真的很酷。
按“輸入”執行它。如您所見，
Blender現在凍結一隻正在製造600隻猴子。
這就是當您執行需要花一些時間在Execute函數中 並且沒關係的事情時發生的情況。
該代碼是
此Blend文件。因此，讓我們看看創建新的Blend文件時會發生什麼。
如您所見，運算子仍在那兒。
已加載到Blender的內存中。
它已註冊，並且一直在發送。
現在，讓我們看看會發生什麼如果重新啟動Blender。
現在，猴子網格運算符不再存在。
這是因為，Blender不僅執行了可以在Blend文件中找到的所有腳本， 還必須告訴它首先執行該腳本。
您必須確保文本文件的名稱以“.py”結尾，
然後在文本菜單中，
您可以選中已註冊複選框。
現在，保存，重新啟動Blender，
現在就在那裡。因此，讓我們玩得開心，並添加一些參數。
添加立方體時，在此處左側看到的內容稱為“重做”面板。
打開它時，您會看到不同的參數
您可以設置。所以發生的是
當您更改參數值時，
Blenderoa會自動地按下“撤消”按鈕和重新執行運算子。
這就是為什麼將其稱為“重做”面板的原因，因為它一直在重做。
因此，讓我們向運算子添加對“重做”面板的支持。
我們首先聲明我們想要的屬性。
這將是X方向上的猴子數，Y方向上的猴子數以及猴子的大小。
就像運算符位於“bpy.ops”中一樣，屬性也位於“bpy.props”中。
再說一遍，如果你想要獲取更多信息，
只需轉到“幫助”，“Python”，“API參考”，然後單擊“bpy.props”部分。
我給你看看起來像什麼。
我們稱其為“count x：bpy.props.IntProperty”。
IN代表整數，表示整數，因為我們不能有半隻猴子。
所以計數X必須是一或二或三，
但永遠不能像2.5一樣。
因此，它僅是整數，它聲明我們要擁有該屬性。
這裡的“：”和此處的“=”符號之間有很大的區別。
這將一個名稱設置為一個值，
這是為了只需設置。我們必須設置“BL ID名稱”以匹配
“猴子網格”使其工作。但是在這裡我們並沒有真正設置任何東西。
我們只是向Blender聲明，這是一個IN屬性，請相應執行操作。
您可以在此處添加一些參數以更改行為。
首先，我們應該設置一個名稱。
我們可以稱它為X。這可能有點神秘。
但就目前而言，會做到的。
我們可以添加一個描述，
“X方向上的猴子數”。
因此，我們將其複製到Y。
將此Y命名為“Y方向上的猴子數”，並命名為任意大小，
這就是另一個“bpy.props.FloatProperty”
float代表浮點數，是僅十進制數字的技術術語。
“名稱=大小”和“描述=每隻猴子的大小”，這為我們提供了屬性，但尚未使用。
讓我們來看看
在我們應該使用它們的Execute函數中。
這個註釋必須走，因為我們不再在25行中創建600隻猴子，但是它非常靈活。
因此，讓我們暫時將其刪除。
現在我們必須訪問屬性。
因此，我們已經聲明了它們，並且此“自我”使我們可以訪問實際值。
“自我”是很重要的事情，在這裡我不會詳細介紹它所代表的含義。
只要知道，如果您聲明
此處的屬性為count X， 那麼您可以在此處以“self.count X”訪問它。
所以猴子總數
是X和Y方向上的猴子數，
這裡的25是X方向上的猴子數。
然後，剩下的就是設置一個大小，
就是這樣。
試一試吧。
讓我們看看控制台中發生了什麼。
在這裡，您可以看到我們的屬性，X，Y，大小，
它們都等於0，因為我們尚未設置任何默認值。
那裡，我們有我們的三隻猴子。
在我們從視口實際調用它之前，讓我們設置一些明智的默認值。
默認值為3。
對於Y，默認值為2，我故意在其中選擇不同的值。
這是默認值。
因此，當有人單擊猴子網格按鈕或從F3列表中選擇它時，
這將是他們所追求的。
因為他們看到3x2的網格，所以他們立即知道需要進行哪些更改。
如果他們想將3更改為4，只需將3更改為4，而不必考慮是X方向還是Y方向。
因此，如果我們給他們相同的默認值，那麼他們將看不到它。
然後，他們將擁有
例如哪個方向是X，哪個方向是Y，我想更改哪個值。
這就是為什麼我給他們獨特的價值觀。
最後，默認大小，再次運行，
刪除所有內容。
在這裡，您可以看到默認值。
當我們執行時沒有任何值時，它將僅使用默認值。
與F3菜單相同。
還剩下一個步驟，那就是獲得“重做”面板。我們有屬性，
因此，Blender知道該去哪裡。
只是還不知道我們是否支持該Redo面板。
因此，讓我們告訴Blender我們這樣做。
這是通過“bl選項”完成的。默認值為“註冊”，
並且我們必須在其中添加“撤消”。這將為我們提供最終成分。
這就對了，
現在我們可以使它們變大和變小，甚至為它們提供無效的值。
因此，為了讓人們使用起來愉快，我們應該對滑塊進行真正的設置，
以便，您可以在此處選擇所有明智的值。
幸運的是，這很簡單。
我們可以設置最小值為1。
因為創建0個猴子沒有意義。甚至更少地製造負數猴子。
因此，讓我們嘗試1。現在將最大數量設置為10。
我們可以對Y計數做同樣的事情，
我們可以將大小0設置為最小值，將最大值設置為1。
現在，我們可以拖拉，並且一切仍然美好而理智。
您會看到，當這些數字增加時，它已經變得有點慢了。
而且我們仍然無法達到之前的600
即使我在此處鍵入100，它也會被最大程度地切斷。
因此，這就是Blender具有軟限制的原因。
硬限制是我們現在設置的，即屬性值的絕對限制。而軟限制是
拖動時滑塊將執行的操作。
因此，如果您想允許最大值大於10或大小大於1，但仍然需要這些限制
作為滑塊的極限，您可以將最大值更改為柔和的最大值。
我們現在擁有的最小值實際上是最小值，因為創建0個猴子沒有意義，
負數的猴子是不可能的。同樣，創建一個負大小的猴子也是不可能的。
因此，讓我們將最大值更改為soft。
現在，拖動仍然是相同的，
但是我們可以將其設置為創建比拖動更多的猴子。
現在，讓我們回到該類聲明。
我將進一步解釋有關類如何以初始方式工作的信息，
我希望不要過多地討論技術細節。
類使用稱為繼承的系統，
就像與人一樣，它就像一個父子結構。
因此，在這種情況下，“bpy.types.operator”是父級，
並且“網格OT猴子網格”是訪問到子級。
如果您問孩子一個您知道答案的問題，例如您想吃餅乾，
當然，孩子會立即不答應父母。
但是，如果您詢問稅收，那麼“媽媽，請幫助我，因為我什麼都不知道！”
然後孩子順從這個問題交給父母。
大致上，類與Python中的工作方式相同。
我們可以不用“bl”選項。
我們的孩子對此一無所知。於是Python問父母。
當我們想擁有不同的東西時，我們可以為孩子和班級添加“bl”選項。
然後，首先要問因此優先於父母的意願。
因此，我們總是有幸運的孩子們得到他們想要的所有cookie。
在結束本視頻之前，我還有兩件事我想告訴你。
再次，我們看一下Execute函數。
您會看到它獲得了一個上下文參數，這非常類似於我們之前所見的上下文。
它給我們“上下文對象”，“context.scene”，“context.selected對象”，
您之前在“ bpy.context”中看到的所有這些內容也都到達了這裡，
但是隨後專門針對此運算符進行了本地化。
因此，作為一般經驗法則，如果您有一個獲取上下文的函數，請使用該上下文。
請勿使用“ bpy.context。
因此，如果您想在此Execute函數中對所有選定的姿勢骨骼進行操作，
您將使用“context.selected姿勢骨骼”。
另一個功能是我想向您展示的第二件事，另一個獲得上下文的功能是Poll功能，
而且它的編寫方式有點怪異，但只要從我這裡獲取，它就可以那樣工作。
同樣，您在此函數中獲得一個上下文。
但是，除了做類似的事情，而不是執行動作，
此功能旨在檢查是否可以執行此操作。
因此，每次應該在菜單中顯示此運算子時，Blender都會調用此輪詢功能，
或作為面板上的按鈕。我可以告訴你這是如何工作的。
現在，返回“true”，這意味著它始終像以前一樣被允許。 和以前一樣，
它顯示在F3菜單中。
當我碰到“假(False)”的時候，
它永遠不會出現在任何地方，這是沒有用的。
讓我們對其進行調整，使其更加有用。
您可以在控制台中看到這裡
我們有自動完成功能，這在Python控制台中很有意義。
但是那個運算符不起作用
在3D視口中，因為上下文錯誤。這也是我們可以做的事情。
現在，當我再次將其更改為“真(true)”時，
Monkey網格運算符也會在Python出現的上下文中顯示。
它會顯示在Blender中的任何位置，這並不是正確的方法。
讓我們再看一看在該上下文中的變量處。
“Context.area”為您提供了Blender用戶界面中 當前處於活動狀態的區域。
因此，在這種情況下，它將是控制台。
但是如果鼠標在這裡，我們拉出3個菜單，
然後突然之間，它的3D視口處於活動狀態，這裡就是“大綱視圖”。
所以Blender中的每個區域都有自己的區域類型
我們可以在“投票”功能中使用該功能，以確保它僅在該地區有效
我不喜歡的一件事是猜測。
因此，我們現在知道控制台的“區域類型”是“控制台”，但是在3D視口中是嗎？
是“3D視圖”嗎？“3D_view”，是“3D視口”嗎？
我不知道。因此，讓我們讓腳本告訴我們。
我可以說“打印我的區域是context.area.type”
讓我們看看將所有這些打印稿發送到的終端上發生了什麼。
在這裡，您看到了控制台，然後立即看到它被稱為
“我的區域是3D視圖”。當我在大綱視圖中執行此操作時， “我的區域就是大綱視圖”。
如果我在“屬性”面板中執行此操作，
我的區域是屬性。
這樣，您就可以使用這些打印語句來知道必須放置在什麼位置。
現在，我們知道了要為3D視口使用哪個值。
因此，讓我們開始吧。
如果“context.area.type = view 3D”，則返回“true”。
否則，我們可以返回“false”。
讓我們看看它是如何工作的。
在這裡，它仍然顯示。
但是這裡不再存在，當然，這裡和那裡現在只顯示在我們希望它顯示的位置。
最後一件事，
這種結構，我也從經驗豐富的程序員那裡看到很多。
它比必要的更為複雜。
因為這個傢伙已經是對或錯的表達。
因此，基本上，代碼在說什麼，如果這個東西的價值，這個選定的表達式，
如果該事物的值為true，則返回true；
如果該事物的值為false，則返回false。
所以這基本上意味著
返回該事物的值，您當然可以這樣寫。
這就是“藝術家腳本”這一集的內容。
如果您有任何疑問或意見，請在下面發表評論，我們很快會再見。