如何從選取的節點中,過濾出燈光來?

Jul 5 2008

Screenshot_Maya_retrieve_lights_from_selection

簡答如下:

from pymel import *
filter( lambda n: 'light' in n.classification(), ls(sl=True, dag=True, leaf=True))

這邊我使用 pymel 這個 python module 來簡化一些細節。

對照於文章後頭引用的原文(使用 mel 作法,建議先閱讀後,再回過頭來想上頭的這邊兩行程式碼),使用 pymel 不需檢查 getClassification() 的回傳值是不是空字串,透過 python 的 in 這個 operator 就會自動幫你處理掉一些「例外」了,同時,還可能因此少寫一些 if else。寫程式時,如果能少一些判斷式(if … else … elif …, switch case …),就「程式的易閱讀性」這一點來說,就像是少了一些特例的處理,是個比較好也比較推崇的寫法。像是說,日後在做維護時,不需要一個一個 if else 看下去,一個一個了解哪些情況下,要做什麼檢查之類的,因為對於正在維護或是新增功能的 programmer,他會希望花最少力氣就完成這類工作。同時,心理頭要能很有自信,確信不會因為他寫的程式而造成不必要的 bug 出來。少一些 if else,就少一些這層顧慮,因為你等於是替未來接手的 programmer(這個人常常是你自己)幫了個大忙。

同時,藉由 Functional Programming 裏好用的 list operator: filter ,原本要寫上四五行的 for loop + if else,現在只要一個 filter 就成了,當然,再加上隨寫即可用的 lambda function,寫起程式來,輕鬆得很。這裏的好處,不是只有把原來要寫四五行的程式碼縮短成一行而已,它同時暗指了,讓 programmer 去習慣把一個 for-loop 的想法,一個以流程為主的邏輯想法(flow-oriented logical thinking),轉化為以資料為主的想法(data-oriented thinking),而且是以比較高階的資料結構來思考(一次以一整個 array 或 list 來想)。

在 pymel 的 google groups 上頭,分別有兩位提供了不同的作法,列在內容供參考。

take out the ‘sl=True’ by using pymel’s “selected()” function by Ofer Koren

from pymel import *
filter( lambda n: 'light' in n.classification(), selected(dag=True, leaf=True)) 

Doing it through the API requires more code but is considerably faster by Dean Edmonds

import maya.OpenMaya as om
sel = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sel)
iter = om.MItSelectionList(sel, om.MFn.kLight)
lights = []

while not iter.isDone():
    light = om.MDagPath()
    iter.getDagPath(light)
    lights += [light]
    iter.next()

接下來的文章,是由 Bryan Ewert 所撰寫,原來可以在 http://www.ewertb.com/maya/mel 這個網址找到,但因為一些原因,這個網站已經關站一陣子了。很幸運的是,因為 Bryan 的 Mel Howto 寫得實在太好了,於是你可以透過這兩個網址,看到別人備份的版本:http://ewertb.soundlinker.com/ 或是 Wayback Machine。我把原文貼上來,方便看官你查閱。

Well, logically you would think this would do it:

string $selectedLights[] = `ls -sl -lights`;  

But – while this does indeed return the list of selected lights, unfortunately it is only reliable if the user selects the shape node of the light. Often they won’t, nor should they be required to. Fortunately, the “ls” command offers a convenient method for retrieving the shape nodes from the current selection:

string $selectedShapes[] = `ls -selection -dag -leaf`;  

By using this query, you need not concern yourself if the user has selected the transform or the shape for a particular node. From here, you can typically use the “nodeType” command to query if the shape is the type you’re looking for:

if ( "mesh" == `nodeType $shape` ) {

  // Do something with a mesh shape. }  
if ( "camera" == `nodeType $shape` ) {

  // Do something with a camera. }  

However, “light” is not a node type; rather, there are several types of lights: spotLight, directionalLight, etc. A more generalized query is convenient in this case - that provided by the “getClassification” command. This command returns a classification string for the node’s type. Be aware that this returns a string array and not just a string.

  getClassification spotLight;

 // Result: light //

  getClassification volumeLight;

 // Result: light //

The following procedure demonstrates its use for extracting all lights from the current selection.

proc string[] getSelectedLights()

{

  string $selectedLights[];


  string $select[] = `ls -sl -dag -leaf`;


  for ( $shape in $select )

  {

    // Determine if this is a light.

    //

    string $class[] = getClassification( `nodeType $shape` );


    if ( ( `size $class` ) > 0 && ( "light" == $class[0] ) )

    {

      $selectedLights[ `size $selectedLights` ] = $shape;

    }

  }


  // Result is an array of all lights included in

  // current selection list.

  return $selectedLights;

}
comments powered by Disqus