您好，歡迎使用藝術家腳本。我叫Sybren。
在這一集中，我們將介紹“自描繪屬性”。
在上一個視頻中，我們創建了一個面板，並向其中添加了現有屬性。
這已經非常強大。
如果這足以滿足您的情況，請不要使其變得更加複雜。
越簡單越好。
但是，在某些情況下，您想將自己的數據附加到Blender中的事物上。
首先，讓我們看一下其中的屬性。
在整個系列中，您已經看到了諸如
object.location”或“ context.scene”之類的現有屬性。
然後，您可以在“自描繪屬性”面板。
也許您還看到了這些屬性，這些地方的“編輯”按鈕消失了，
並且顯示了“API Define”，這意味著它是從Python描繪的。
這也是我們將在本視頻中看到的內容。
為了給我們一個具體的目標，我們將創建一個Mass OBJ Importer。
每個場景都會獲得一個包含以下內容的屬性
包含其OBJ文件的文件夾的路徑。接著，
我們將創建一個運算符，從該文件夾加載所有OBJ文件。
最後，我們將研究創建一個從磁盤重新加載這些OBJ文件的運算符。
所以這樣
您可以一鍵重載所有OBJ文件。
這是很多工作。因此，讓我們開始吧。
對於本集，我們將創建一個新的Add-on，我已經開始了。
我添加了一個新的Python文件。
我已將其安裝為插件，並將其加載到我的編輯器中，
這是Visual Studio代碼。
我將快速解決這個問題，因為您在之前的視頻中已經看過所有這些內容。
如果您還沒有看到它，請觀看有關創建自己的插件和創建用戶界面的視頻。
因此，我們從BL信息字典開始。
我已將名稱設置為“腳本腳本添加程序的藝術家”“大量導入程序”。
其餘信息幾乎與您期望的一樣，
接下來是“導入bpy”。
然後，我想在那裡的面板中提供我們要做的所有事情。
我們可以顯示按鈕，我們可以顯示屬性，我們可以做我們想做的所有事情。
我通過複製代碼創建了一個新面板
我們對猴子網格的代碼，然後對其進行調整。
因此，除了具有標籤“mass import”(質量導入)外，
它幾乎相同，並且也反映在類名中。
現在稱為“查看3D PT批量導入”
我們將要畫些東西，但還不是。然後，我們當然具有註冊和註銷功能。
這些對於任何插件都是必需的。我們將向該文件添加更多的類。
因此，我們將有一個運算子進行批量導入。
然後我們還會有一個運算符
一次重新導入一個對象，然後再執行一個運算子
大量重新導入所有導入的對象。
因此，我們將擁有更多。而且我不想複製粘貼
“bpy.utils.unregister類”，然後確保
在未註冊的目錄中，還復製到unregister類，並管理所有這些。
因此，我創建了一個列表，而不是
稱為Blender Classes，其中只有我們現在擁有的面板。
然後，在註冊和註銷之前，
我們使用前循環對其進行循環。
因此，對於Blender類和Blender類，將超過此列表。 對於該列表中的每個項目，
它將調用“bpy.utils.register類”或“取消註冊類”
這使得以後添加新內容變得容易一些，因為可以將新類添加到此列表中。
現在，我們的代碼非常簡單。
讓我們看一下它實際上在Blender中有效，這樣我們就可以確定
當我們開始添加內容時，我們是在實際有效的基礎上添加的。
因此，在用戶首選項中，啟用插件。
然後在這裡的“猴子”選項卡中，我們可以看到“批量導入”面板。
當然，還沒有畫出來，但這就是我們所期望的。
因此，根據我們的代碼「在面板本身存在的情況下進行註冊和註銷」，
這都是正確的。
好的。因此，讓我們開始創建我們想要的屬性。
實際上，這很簡單。
您知道“bpy.types”中有很多東西，並且我們希望在場景中包含
我們想要的OBJ文件的導入路徑。
因此，我們從“bpy.types.Scene”開始， 使用大寫字母“Scenene”，
“.”然後是我們財產的名稱。
我們稱之為“大量導入路徑”。
現在，這與將自己的屬性添加到自己的運算符非常相似，
除了，與運算子一起分類別，我們可以使用
聲明屬性，現在該類已經存在。
因此，我們無法對其添加任何內容。所以有點不同。
因此，我們使用“=”符號代替使用“：”，然後再次分配屬性。
它們甚至是道具的路徑，文件路徑或目錄路徑只是一個字符串。
這樣就給我們一個String屬性。
現在為用戶界面，我們可能要給它起一個好名字。
因此，我們將其稱為“obj文件夾”，
並且它們總是以“，”結尾，因為那樣，我可以在下一行添加內容
而無需返回並再次添加“，”。
這是有效的Python，它使您的更改更加本地化。您現在可以添加
其他內容，而無需更改上面的行。
這在Register函數中，因此我們在其中添加了一個屬性。
當然，我們必須在“取消註冊”中再次將其刪除以清理所做的事情。
然後，基本上，您接受該內容，然後說“刪除”該屬性。
這就告訴Python，只需刪除它即可。這就足夠了。
讓我們看看它在Blender中的外觀。
在這裡，我們必須重新加載我們的代碼。在Blender 2.83及更高版本中，
可以在這裡使用重新加載腳本來做到這一點。
如果您使用的是Blender的舊版本，請按F3，
然後輸入“重新加載腳本”。他們倆都做同樣的事情。
除了通過菜單，您可以在按Q時將其添加到快捷菜單中。這是我將使用的方法
從現在開始。因此，我們重新加載了代碼。
讓我們來看看場景。
妳去 我們擁有自己的屬性“大量導入路徑”。
默認值是空的，因為我們沒有設置任何默認值，它就在這裡，每個場景都會有它。
我們還可以從Python更改屬性。
請注意此處的“場景”選項卡中的“自描繪屬性”面板。
看一看，當我實際分配一個值時會發生什麼。
您必須使用鼠標一點點才能使其重繪。
但是您可以看到，現在，我們已經為其分配了一個值。
它實際上存儲在“自描繪屬性”中。
它是API描繪的，這意味著您不能只刪除它。
這是像這樣使用“屬性”的主要優點之一，而不是僅單擊此處的“添加”按鈕
並創建一個新的。
通過Python創建它時，可以確保該屬性在那裡。
即使未設置，也將具有默認值。因此，不必擔心。
另一個優點是，我們可以設置子類型。
這將向Blender指示我們正在談論的字符串類型。
所以這將是一條路徑，
如果它有個小按鈕，您可以使用文件瀏覽器為您選擇路徑，那就太好了，
無需在Python控制台中鍵入它。
一旦正確設置了子類型，所有這些操作都將由Blender完成。
來做吧。
子類型已設置
按Subtype參數，然後傳遞一個表示Subtype的字符串。
為了找到特定屬性的子類型，
您可以返回Blender，"幫助"，
Python，API參考，並蒐索“bpy.props.string屬性”
然後它會告訴您有哪個子類型。
在我們的情況下，它是目錄路徑或“目錄路徑”。
現在，讓我們重新加載代碼，並在接口的這一角看到這裡發生的情況。
妳去 它具有瀏覽按鈕，您可以選擇目錄。
因為我將其設置為傻值，所以它僅從傻目錄開始，因為它不是有效路徑。
但是如果我將其更改為“//”，則表示
Blend文件的當前目錄，
它將在這裡打開它，我可以導航到OBJ文件目錄，
單擊“接受”，然後在此處設置路徑。
這正是我們想要的，當然，除了我們希望在自己的面板中執行此行為。
來做吧。在我們的面板代碼中
我們可以刪除通行證，因為我們實際上將要做一些事情，讓我們從獲取佈局開始。
我們以前沒有這樣做，但是確實知道每個“自我”(某物)
我們將做一個小小的舞蹈，看看是否在該類中描繪了， 如果沒有，請看一下父級，是否在該類中描繪了，
如果沒有的話，看看祖父母等等。所以我們說
“layout=self.layout”，我們只跳舞一次，然後只使用layout對象。
讓我們添加一列，
然後添加屬性。該屬性是在場景中描繪的，
即“context.scene”。 屬性名稱是
“大量導入路徑”。這就對了。
重新加載代碼，然後有“屬性”瀏覽按鈕。
現在，讓我們創建一個運算符，該運算符從該目錄導入所有OBJ文件。
我想命名相似名稱導入OBJ文件已經存在的運算子。
因此，讓我們來看一下。那就是“bpy.ops.import_scene.obj”
所以我們打電話給我們的接線員
“導入scene.obj質量”。所以在這裡，我們有一個空運算符。
您之前已經看過。我只是以不同的方式命名這些，
稱為“imports scene.obj mass”，它具有Execute函數。
我把這個小註釋作為參考，然後它稱為
“self.report”。
這採用的報告類型可以是信息，警告或錯誤，然後是未報告的字符串。
它返回“已取消”，因為尚未執行任何操作。
同樣，我正在採取一些小步驟。
我首先確保您的打印機在那裡，並且已正確註冊。然後，我們可以將其添加到面板中。
我們可以單擊該按鈕，可以看到它可以工作，然後再添加更多的複雜性。
所以運算子在這裡。
現在，我複製了此名稱，然後轉到Blender classes列表，
我將名稱添加到列表中，並負責註冊和註銷。
現在剩下的就是將其添加到面板中。
因此，我們需要的只是“BL ID名稱”。
粘貼它，保存在Blender中，重新加載腳本。我們有一個按鈕，我們單擊它。
它說“沒有代碼可從/ /加載”，這是我們期望的錯誤。
現在，下一步是找到obj文件，然後將其導入。之後，我們希望能夠
重新導入它們。所以我們必須跟踪
從哪個文件導入了哪個對象。
最好的方法是向對像類型添加另一個屬性。所以現在就開始做
在我們開始導入它們之前。
在這裡，在Register函數中，我們將執行與場景相同的操作，
但然後到一個對象。
然後，它也變成了String屬性，
但隨後使用OBJ文件而不是OBJ文件夾。
因此，文件夾和文件名的組合將為我們提供OBJ文件的最終路徑。
因為沒有僅文件名的子類型，所以僅用於完整的文件路徑或完整的目錄路徑。
僅將其保留為字符串，並且不描繪任何子類型。
因此，在查看導入之前，請將此屬性添加到面板中。
我們在這裡有面板代碼，讓我們為此創建一個新列。
那裡，我們擁有屬性。但是請記住“context.object”
可以是無，所以我們必須對此加一點警惕。
在Python中，沒有一個被認為是錯誤的，而在實際對像中則被認為是正確的。
因此，如果“context.object”的求值結果為“true”， 則它是真實對象，然後繪製該屬性。
它將評估為“假”
如果沒有活動對象，則它將繪製標籤。
試一試吧。
在這裡，我們有了我們的屬性，可以將其設置為“每個對象”，
如你看到的。
現在讓我們構建導入本身。
因此，在這裡，我們有大量進口商運營商。讓我們寫一些佈局
它應該做什麼。它必須找到目標文件，
對於每個文件，
導入它
並在“對象屬性”中記錄其文件名。讓我們看看第一步。
實際上，這將採取一些步驟。
因為要查找文件，我們必須使用Python功能。
而且Python無法理解相對於當前Blend文件的Blender特定的“//”含義。
因此，我們必須將其轉換為Python可以理解的內容，
然後使用它來查找OBJ文件，然後將其轉換回
Blender可以理解的東西，然後導入文件。
首先，我們必須將“//”轉換為絕對值，這是通過...
“bpy.path.abspath”中的functin完成的
“bpy.path.abspath(context.scene.mass_import_path”
將為我們提供我們要導入的文件的絕對路徑。
我們可以通過在錯誤消息中報告此內容來進行檢查。
只是暫停視頻，嘗試一下，然後再回到這裡。
現在，我們必須將其轉換為Python的Path，Lib庫中的path對象。
然後，我們可以使用此導入路徑變量來查找所有OBJ文件， 並像這樣一遍遍地遍歷它們。
這將找到與“* .obj”匹配的所有內容，因此文件或目錄以該“obj”結尾。
從現在開始，我將假設您不會創建任何子目錄
“(something).obj”，
並且所有內容都是我們導入的實際OBJ文件。
現在，我們要做的就是導入它。
在Blender中
轉到OBJ導入程序，然後按Ctrl C，然後按Ctrl V，代碼。
這會將我們擁有的該路徑對象轉換回字符串，以便Blender能夠理解它。
然後，這整行將導入OBJ文件。
現在，我們已經介紹了導入的每個文件，剩下的就是記錄其文件名。
此Import運算符的部分工作是
它取消選擇所有內容，然後選擇要導入的對象。
這意味著我們可以遍歷所有選定的對象，然後將其自描繪屬性分配給它們。
這就是為什麼我如此喜歡Path Lib對象的原因。
如果您只想擁有路徑的文件名部分，則使用起來非常簡單，
只需執行“path.name”即可。
如果要使用驅動器對象，請執行“.drive”
這是一種非常面向對象的Paths方法，我非常喜歡。
現在我們正在導入。我們記錄文件名的來源。
所以應該在.....嘗試一下。
我將扔掉現有的物體，
瀏覽到我的OBJ文件目錄，
然後批量導入所有內容，然後就可以了。文件已導入。
它們都是源文件，每個文件的OBJ文件名都設置為它們的來源。
現在，剩下要做的就是讓運算子重新加載OBJ文件。
為了簡單起見，我們不要大量地這樣做，只需重新加載活動對象即可。
這意味著從場景中刪除對象
然後再次從OBJ文件加載它。
當然，在我們從場景中刪除之前，我們必須確保
我們存儲了對象的變換，以便在重新加載它時可以將其還原。
這樣就可以以相同的方式定位
就像我們重新加載之前一樣
讓我們從一個新的運算符開始。
我們稱其為“obj reload”。在這裡，我選擇了一些文本，按Ctrl D，
將選擇該文本的下一個出現位置。
然後，我可以點擊“重新加載”。
以及類名和ID名，我們將更改為“obj reload”。
假設“重新加載大量導入的obj”，然後我們可以編寫Execute函數。
對於此代碼，我將假定每個OBJ
裡面有一個物體。您可以擴展代碼，以便它可以處理OBJ的多個對象。
但是現在讓我們保持簡單。
我們將多次引用活動對象，因此讓我們簡化生活。
只需將其稱為“ob”即可，讓我們再次為自己做一些概述。
首先，我們必須存儲
我們想要記住的。
從場景中刪除對象，
加載OBJ文件，
並恢復我們所記得的。
加載OBJ文件不會自動設置我們的自描繪屬性。
最後，這就是我們要還原的內容。而且我們也希望能夠還原轉換。
讓我們記住文件名。
讓我們複製矩陣。如果我不打算複製矩陣，那麼變量矩陣世界
將是對對象矩陣的引用。如果我們刪除該對象，則該引用將不再有效，
您可以獲得各種奇怪的結果。
現在，從場景中刪除對象實際上意味著從其所在的所有集合中刪除對象。
幸運的是，Blender為我們提供了所有這些收藏的清單。
這將取消所有集合中對象的鏈接。
問題是，當然，一旦我們從第一個集合中取消對象的鏈接，我們就會循環
會改變。在循環中進行更改永遠不是一個好主意。
我們可以做到“list(ob.user_collections)”
這將為我們創建一個新列表。
該新列表是一個副本，因此不會通過從那些集合中刪除對象來對其進行更改，
從而使此for循環安全。
如果需要，您現在也可以從“bpy.data”中刪除該對象，
但這只有在沒有其他引用的情況下才是安全的。
再次，Blender營救。
“ob.users”將為我們提供該用戶數。
在整個Blend文件中的不同位置使用“材質”和“網格”時， 也會看到一個很小的小方塊。
如果該數字為0，則表示該對像不再使用， 們實際上可以將其從Blender的內存中刪除。
從這一點開始，我們不再引用
“ob”，因為它已從Blender中刪除。
因此，為了防止再次使用它，
我只是說“del ob”。這將從Python的內存中刪除“ob”名稱。
這意味著，如果我在這裡說“ob.location”，
Python會對我們大喊大叫，因為在此行之後，它不再知道“
ob”的含義。 對我們自己來說只是一點點安全
這樣我們就不會使用不再有效的東西。
現在。我們需要再次加載OBJ文件
我們之前做過的 因此，讓我們看一下該代碼。
我們必須再次執行此技巧，然後僅對一個對象執行此行。
因此，我們將其放入一個函數中
我們可以從兩個地方呼叫。
在這裡，我創建了一個帶場景的新函數，
這意味著它將返回“pathLib.path”。
我非常喜歡這種表示法，因為這樣，您可以看到
返回什麼，而不必深入研究代碼，看看會發生什麼。
Python不會對此進行檢查，
因此，您有責任切實履行自己的諾言。
現在，此代碼與此幾乎相同，並返回了新的路徑對象。
這意味著我們可以刪除這一行
我們可以在這裡執行“mass_import_path(context.scene)”。
我專門通過了這個場景，而不是上下文。必須在這裡解決一個小錯誤。
我明確地通過了場景而不是整個上下文。
如果我們要傳遞上下文，效果會很好，但是您將看不到上下文的哪一部分
實際上是由該功能使用的。
這就是為什麼我要傳遞場景本身而不是上下文。
當然，我們也可以傳遞“
context.scene(大量導入路徑)”，但這會使調用時間更長一些，
我認為這是一個很好的中間立場。
但是，當然，您可以使用自己認為最好的方法來處理代碼。
現在，我們有了要獲取的代碼導入路徑，我們可以複製此行
進入我們的Reload運算符。
然後我們可以得到這條線，
放到這裡
現在，我們要做的就是從目錄的“導入路徑”到“導入文件路徑”，
這是一個文件名。導入文件路徑是
“import_ path / mass_import_fname”是我們在那裡複製的。
Python中的路徑對象支持此“/”表示法。
它會自動在任何平台上正常工作。
在Windows上，它使用反斜杠； 在Linux和Mac OS上，它使用“/”。
現在我們已經構建了文件名，可以將其傳遞給加載OBJ文件的運算子。
現在，剩下的就是還原我們想要還原的內容。
同樣，我們必須遍歷所選對象，並設置“批量導入”文件名。
現在，我們必須還原矩陣。
會告訴Blender運算子做了工作。
然後我們修復兩個錯字。
這裡的“：”和這裡必須使用“collection”，而不是“collections”。
最後，我們要做的是註冊和註銷運算子，並在面板上添加一個按鈕。
我們複製了類名，並將其添加到此列表中。
我們複製BL ID名稱並將其添加到面板中，
保存文件，
重新加載腳本，然後點擊按鈕。
如您所見，我們單擊它。
在導入OBJ文件中使用時，不再有活動對象，
僅選擇導入的對象，在這種情況下為Suzanne。
現在，讓我們看看它是否真正重新加載。
我在其中放置了一個新文件“cube.obj”，
現在應該用該多維數據集替換Suzanne。
而且確實如此，所以我們有了它。
我們的代碼正在運行，我們可以批量加載OBJ文件，
並且可以選擇要重新加載的單個對象。
我將其保留為練習為您提供一個批量重載運算符，
該運算符可對所有對像或僅對所有選定對象進行迭代。
我會留給你。這就是“藝術家腳本”這一集的內容。這不是最後一次
我們將討論自描繪屬性，但我認為該視頻已經播放了足夠長的時間。
如果你有任何問題或評論，將它們留在下面，我們很快會再見。