返回列表 回复 发帖

(3dsmax)'Developing a Scripted Utility'-开发一个脚本工具

'Developing a Scripted Utility'--开发一个脚本工具
'Developing a Scripted Utility'
by Sathish Shanmugasundaram (Email:
Sathish101@gmail.com
原文链接:
http://www.3dtotal.com/team/Tutorials_3/scripted_utility/scripted_utility01.asp


Hello everyone, this tutorial will guide you to develop a scripted utility in 3DS MAX 9. This tutorial is for users with basic knowledge in max script or any other object oriented language. Here I explained everything step by step. Actually this coding is a part in my plug-in. Due to coding complexity, I cut short some and added only a few things. If time permits I will explain the rest.
(大家好,这篇教程将引导你在3dsmax9中开发一个脚本工具。这个教程需要使用者具有基本的max脚本知识或是其他任何计算机语言基础。这里我将一步步的进行讲解。事实上,这段代码是我写的插件的一部分。因为代码很复杂,我删减了一些,只添加了很少的东西。如果时间允许我将解释剩下的部分。)It covers:
(它包括)

How to develop a tool (with rollouts, buttons, check boxes etc) in 3ds Max.
(如何在3dsmax中扩展一个工具(如卷展栏,按钮,点击框等等)。)

How to position an object over another objects vertex or polygon.

(如果在另一个物体的顶点或面上放置物体。)

Calculating local normals of vertex and polygons in an object and positioning another object according to it.
(获取一个物体的顶点和多边形面的自身法线,并据此放置其他物体。)

By using basic coding, making copies of an object according to user selection (may be Instance, Copy or references).


(使用基本的代码,创建使用者选中的物体的复制体(也可以是关联复制或是参考复制)。)
What is Scripted Utility?
(脚本工具集是什么?)

--------------------------------------------------------------------------------

Max Script allows us to create our own Tools for specific purpose and embed them into existing max interface. The Scripted Utilities are tools appear in Utility panel > Max Script Utility. Scripted utility is an easiest way of developing tools, since they are special kind of rollouts that saves the developer some UI management work.

(max的脚本允许我们为特定的目的创建自己的工具,并将其纳入已存在的max的交互界面中。脚本工具集显示在Utility panel > Max Script Utility下的一个工具。脚本功能集是一个很容易扩展的工具,因为它们有特殊类型的卷展栏,这将节省开发者的界面管理工作。)
Creating and running Scripted Utility:
(创建和运行脚本工具)

--------------------------------------------------------------------------------

To create new script go to MaxScript menu->New (or)

Open Utility panel -> MaxScript->New script.


(要创建一个新的脚本,你可以选择MaxScript menu->New 或是打开工具面板,Utility panel -> MaxScript->New script.)

To run a script, go to MaxScript menu->Run Script (or) Utility panel
MaxScript-> Run Script and choose script to be run.
(要运行一个脚本,你可以进入菜单 MaxScript menu->Run Script 或是通过工具面板Utility panel -> MaxScript-> Run Script ,然后选择你要运行的脚本即可。)

When we put the Script file into \Scripts\Startup folder then it will automatically executed when 3DMax starts.

(如果我们将脚本文件放到目录\Scripts\Startup 下,那么当我们打开max时,这些脚本将会自动加载。)

After execution our utility is available at Utilities panel -> maxScript -> Utility dropdown list (See Fig01). When we select Object Placer the rollout will appear below dropdown list as shown below.
(在加载之后,我们在工具面板Utilities panel -> maxScript -> Utility 下拉菜单下的工具 就变的可用了(如图1)。当我们选择了Object Placer 工具,下拉列表下面会出现一个卷展栏。)


Fig.01 - OpeningTheScript(图1——打开脚本)
Purpose of our utility – Object Placer:

(我们的目标脚本工具——Object Placer)

--------------------------------------------------------------------------------

Object placer allow us to place copies of source object into the destination object‘s vertices and/or polygon’s centre, Also aligned with local normal.  
(Object placer工具允许我们放置源物体的拷贝到目标物体的顶点或多边面的中心,当然还要跟它们自身的法线方向对齐。)

Fig.02 shows the final object placer utility. The contents are: +nU',E  
(图2显示了完全展开的object placer工具。其内容包括:) 4#TnXxL  
w(aUEWYL  
About rollout with Labels. Parameter rollout with following:

(带标签的about卷展栏。属性卷展栏内容如下)


- Two Pick buttons for Source and Destination object selection.


(两个分别用于拾取源物体和目标物体的按钮)

- Two Check boxes for selecting Vertex and /or Polygon.

(两个分别定义是否选择顶点或是多边面的勾选框。)
- A Group named Copy option with three Radio buttons for selecting copy type.
(一组命名为拷贝选项的用于确定复制类型的3个圆形按钮。)



Fig.02 - ObjectPlacerUtility(图2——物体放置工具)
Fig.03 shows, source object Cone copied and aligned to Geosphere‘s polygons and another object box copied and aligned with vertices of Geosphere.
(如图3所示,源物体圆锥被复制对齐到几何球体的多边面上,另一些方盒子则被复制对齐到几何球体的顶点上。)



Fig.03 - ObjectWithConeandBox(图3——被圆锥和立方体附着的几何球体)

Before using this utility:
(使用这个工具前的说明)

--------------------------------------------------------------------------------
Actually this tool is not the final one, as I said earlier I added only basic coding. But here I gave you technique of developing the utility and manipulating objects through script. You can extend this script at your own way (At your own risk).

(事实上,这个工具并没有最终完成,如我之前所言,我仅仅添加了基本的代码。但是在这其中我将教给你扩展工具以及通过脚本操纵物体的技术。你可以自行扩展这个脚本,当然风险自担。)

1. Object positioning is based on local normal of a polygon or vertex in destination object and world up axis. So u needs to adjust rotation manually in some places. <&6u]uKrW  
(物体的位置是基于目标物体表面的顶点和面的自身法线和世界空间向上的轴线确定的。所以在某些位置你需要手动调整旋转。)

2. Scale Source object in Sub-object selection mode (in polygon, edge or vertex).Better use vertex mode for similar result as normal scaling.

(在次物体选择模式下缩放源物体。最好使用顶点模式来进行缩放。)
3. Source must be geometry object. Before selecting destination object, collapse it into Editable Poly.

(源物体必须是几何体。在选择目标物体前需要将其转换成可编辑多边形。)

4. Modify Source objects pivot for different type of arrangement.

(修改源物体的轴点可以达到不同的效果。)

5. When you use Vertex positioning, command panels may blink because it jumps between create and modify panels.
(当你使用顶点位置时,命令面板可能会闪烁,她会不断的在创建面板和修改面板之间切换。)
Normal:
(法线)

--------------------------------------------------------------------------------

Surface normal or normal is a vector perpendicular to the surface (Fig04).
(表面法线或者说法线是垂直于表面的一个矢量。如图4)


Fig.04 - NormalExample1(图4——法线实例)
Script: )
(脚本代码)
--------------------------------------------------------------------------------
Utility ObjPlacer "Object Palcer"                     
(


      Local copyState=1,sourceObj,destinationObj





fn Align souCopy desNormal pos =      
(                                                                          
  worldUpVector = [0,0,1]                        
  rightVector = normalize (cross worldUpVector desNormal)

  upVector = normalize ( cross rightVector desNormal)        
  theMatrix = matrix3 rightVector upVector desNormal Pos

  souCopy.transform = theMatrix                                            
)      
fn CopySource numCopies=                                    
    (
        case copyState of                                      
          (
          1:                                                      
                        souCpy = for i = 1 to numCopies  collect(copy sourceObj)               
          2:                                                      
                      souCpy = for i = 1 to numCopies  collect(instance sourceObj)   
          default:                                       
                  souCpy = for i = 1 to numCopies  collect(reference sourceObj)            
          )


              return souCpy   
            )      
rollout Abt "About"            
  (

    Label lab1 "Object Placer"        
    Label lab2 "By Sathish"   
    Label lab3 "Mail:Sathish101@gmail.com"


  )      
rollout Param "Parameters"                                                   
  (

      pickButton sourcePikBtn "Source" width:75 autoDisplay:true  
      pickButton destnationPikBtn "Destination" width:75                  
      checkBox vertexChkBox "Vertex" checked:true                                             
    checkBox polygonChkBox "Polygon"                                             
      group "Copy option"                                                                     
      (


        radioButtons copyOption labels:#("Copy", "Instance", "Reference") align:#left default:1
              )

on sourcePikBtn picked sObj do   
    ( 
      if  sObj != undefined then  
                sourceObj=sObj                    
            )

on destnationPikBtn picked dObj do                                                                    
    (

        if(sourceObj != undefined) and (not isDeleted sourceObj) then      
        (

        if(vertexChkBox.state == true or polygonChkBox.state == true) then   
        (   
        if dObj!= undefined then   
      (

              destinationObj=dObj   
              If ((classOf destinationObj) == Editable_poly) then     
                    (

                      if (polygonChkBox.state == true) then                           
                        (

                        numPolygon = destinationObj.getnumfaces()              

                            Source =CopySource numPolygon                        


                            for i = 1 to numPolygon do                             
                              (

                              faceCentre= polyOp.getFaceCenter destinationObj i         
                              faceNormal = polyOp.getFaceNormal destinationObj i  

                              Align source
faceNormal faceCentre  bHH}
                              )   
                            )                    

                  if (vertexChkBox.state == true) then                     
                        (

                        numVertex = destinationObj.getNumVertices()   

                            source =CopySource numVertex
                  editNormalsModifier=edit_Normals()                  
                          addModifier destinationObj editNormalsModifier

                      setCommandPanelTaskMode #modify  
                            destinationVertex = #{}            
                            destinationNormalIds = #{}            

                            for i = 1 to numVertex do               
                              (

                                  select destinationObj         
                                  destinationVertex = #{i}      

                                  destinationObj.edit_Normals.convertVertexSelection &destinationVertex &destinationNormalIds   

                                normalArray = destinationNormalIds as array


                                  firstNormalValue = destinationObj.edit_Normals.getNormal normalArray[1]
                                  vertexPos= polyOp.getVert destinationObj i      

                                  Align source
  firstNormalValue vertexPos   
                      )
                            deleteModifier destinationObj(editNormalsModifier)        
                            )  
              )
                      else

                            messageBox "Select only Editable poly object" title:"Error"

              )      
        )               


                            messageBox "Select Vertex or/and Polygon" title:"Error"
          )
              
                            messageBox "Select Source Object" title:"Error"   

            )


on copyOption changed State do    B
  (
  copyState=State                           
  )

)   
on ObjPlacer open do   
(

addRollout Abt            
addRollout Param         

)
on ObjPlacer  close do     

(

  removeRollout Abt            
  removeRollout Param     
)
)


[ 本帖最后由 火柴盒 于 2008-4-21 14:27 编辑 ]
Script Explanation:
(脚本解释)
--------------------------------------------------------------------------------
utility ObjPlacer "Object Palcer"
A Utility is created using a constructor utility with name ObjPlacer and caption Object Placer.
(使用utility创建一个名为ObjPlacer的工具,其标题栏显示为“Object Palcer”。)
Local copyState=1,sourceObj,destinationObj
(定义局部变量copyState,sourceObj,destinationObj,其中copyState赋值为1。)
Local variables are alive untill we close the utility is closed.
(除非工具被关闭,否则这些局部变量都是有效的。)
NOTE: Align and CopyOption functions are explained below.
(提示:对齐和复制选项的功能将在稍后讲解。)
About rollout:
(“About”卷展栏)
--------------------------------------------------------------------------------
rollout Abt "About"
A rollout named Abt with caption “About” is defined.
(创建一个名为Abt的卷展栏,并定义其标题为“About”。)
Label lab1 "Object Placer"

(建立标签 lab1,内容为"Object Placer")
Label lab2 "By Sathish"        

(建立标签 lab2,内容为"By Sathish" )
Label lab3 "Mail:Sathish101@gmail.com"        

(建立标签 lab3 ,内容为 "Mail:Sathish101@gmail.com"  )
Labels are used to display information and it could not be altered. (If u need syntax details refer MaxScript reference).
(标签被用于显示信息,它不能被修改。如果你需要了解语法细节,请参考软件自带的MaxScript reference。)


[ 本帖最后由 火柴盒 于 2008-4-21 14:28 编辑 ]
Parameter rollout:
(属性卷展栏)
--------------------------------------------------------------------------------
pickButton sourcePikBtn "Source" width:75 autoDisplay:true
pickButton destnationPikBtn "Destination" width:75
Two pick buttons with caption Source and Destination is created with width =75. In Source pick button autoDisplay is enabled to display selected objects name as button caption. |  
(定义两个宽度为75个像素的按钮分别用于拾取源物体和目标物体。其中拾取源物体的按钮其自动显示属性被打开,这样拾取之后,源物体的名字会自动显示在按钮上。)
checkBox vertexChkBox "Vertex" checked:true
checkBox polygonChkBox "Polygon"
Two checkboxes for Vertex and Polygon is created. Initially Vertex check box is enabled.
(为目标物体的顶点和面定义两个勾选框。顶点的勾选框默认是选中的。)
group "Copy option"
(
radioButtons copyOption labels:#("Copy", "Instance", "Reference") align:#left default:1
)
A group with three radio buttons for selecting copy type such as Copy, References or Instance is created. Radio buttons are aligned left in group box and Copy is set as default.
(定义3个一组的圆形按钮,用于选择复制类型是克隆,关联,还是参考。这组圆形按钮对齐到组的左侧,默认选择的是克隆类型。)
on sourcePikBtn picked sObj
(
if sObj != undefined then
sourceObj=sObj
)
This function will be called when source pick button picked. It checks whether object selected or the operation cancelled, after clicking pick button.   
(当拾取源物体的按钮被激活时,调用这个方法。它检查是否有物体被选择,或者在激活拾取按钮之后,操作是否被取消。)
If selected then assign it to a global variable.
(如果有物体被选择,将这个物体指定给一个全局变量“sourceObj”。)
on destnationPikBtn picked dObj do
(  
if(sourceObj != undefined) and (not isDeleted sourceObj) then
(
if(vertexChkBox.state == true or polygonChkBox.state == true) then
(
if dObj!= undefined then
(
destinationObj=dObj
If ((classOf destinationObj) == Editable_poly) then   
(
…………………………  
…………………………  
…………………………
) messageBox "Select only Editable poly object" title:"Error"
)
)
messageBox "Select Vertex or/and Polygon" title:"Error"
)
else messageBox "Select Source Object" title:"Error"
Following operation will took place when destination pick button is picked.
(当目标拾取按钮被激活时,以下操作将被执行。)
Check whether Source object already selected and not deleted else display message “ Select Source Object”.
(检查源物体是否被选择,并且没有被删除,否则将显示消息框“ Select Source Object”,提示先选择源物体.)
Check whether vertex and/or polygon checkbox checked else display message "Select Vertex or/and Polygon"
(检查顶点和面的勾选框是否有被勾选,如果都没有,显示消息框 "Select Vertex or/and Polygon",提示先进行勾选。)
Check whether destination object is picked after clicking destination button or the operation is cancelled.
(检查在激活拾取按钮之后,是否拾取了目标物体,或者操作是否被取消。)
Check whether selected object is Editable poly, else displays message “Select only Editable Poly object”.
(检查选择的物体是否时可编辑多边形,如果不是将显示消息框“Select only Editable Poly object”,提示只能选择可编辑多边形物体。)
If polygon checkbox is checked then following operation will took place.
(如果面的勾选框被选中,将执行以下操作。)
numPolygon = destinationObj.getnumfaces
Source =CopySource numPolygon
Get number polygons in destination object.
(获取目标物体多边形面的数量。)
Get copies of source object according to number of polygons in destination object and store it into an array.
(根据目标物体的面的数量复制源物体,并将其存储到一个数组中。)
for i = 1 to numPolygon do
(
faceCentre= polyOp.getFaceCenter destinationObj i  
faceNormal = polyOp.getFaceNormal destinationObj i
Align source faceNormal faceCentre
)
Iterate from 1 to numPolygon.
Get face centre and face normal of i th polygon in destination object.
Call Align function by passing i th copy of source object, face center and face normal of i th polygon in destination object.
End of iteration. sow bg
The following operation will took place when vertex check box checked
numVertex = destinationObj.getNumVertices
source =CopySource numVertex
editNormalsModifier=edit_Normals
addModifier destinationObj editNormalsModifier setCommandPanelTaskMode
destinationVertex
destinationNormalIds
For getting normal of vertex, we need to do some more work
Get number of vertices in destination object.
Make copies of source object equal to number of vertices, by calling CopySource function.
Add Edit Normals modifier to Destination object.
Set modify panel to be the active panel in the view port. We can get normal value only when modify panel is active and destination object is selected.

Declare two bit array for representing destination vertex and its normals.
for i = 1 to numVertex do
select destinationObj
destinationVertex
destinationObj.edit_Normals.convertVertexSelection &destinationVertex &destinationNormalIds
normalArray = destinationNormalIds as array
firstNormalValue = destinationObj.edit_Normals.getNormal normalArray[1]
vertexPos= polyOp.getVert destinationObj i
Align source
firstNormalValue vertexPos
)
Iterate from 1 to number of vertex
Select destination object. As I said already we can get normal value only when modify panel is active and destination object is selected.

Make the vertex bit array to represent i th vertex.
Get normas(normal Id’s) available in vertex i. Single vertex may contain more than one normal See fig below (vertex 7 contains 3 normals with Id 8, 19, 24.)
Store array of destinationNormals to normalArray, because destinationNormals is bit array. In bit array the corresponding bit value is set to true and all other values are set to false, but in this case we need normal Id. For example consider figure below, for 7 th vertex the bit values 8 ,18, 24 are set to true. If we convert bit array to an array we can get Id value 8 at normalArray[1].
firstNorml retrieves actual vector value of the first normal in the vertex. In below fig firstNormal =[0,0,1] for normal 8.
Get Position of i th vertex.
Call function Align by passing i th copy of Source object, normal and position of destination objects i th vertex (Fig05).

Fig.05 - NormalExample2


[ 本帖最后由 火柴盒 于 2008-4-21 14:30 编辑 ]
Other functions in Utility:  
(脚本中的其他方法)

--------------------------------------------------------------------------------

on copyOption changed State do
copyState=State
)

This function will be called when copy option radio buttons are changed.

(当复制选项的圆形按钮被更改时,脚本调用这个方法。)

If changed then store current state to a variable copyState.
(如果有所更改,将当前的状态存储到变量“copyState”。)
on ObjPlacer open do
(

addRollout Abt 

addRollout Param
)


This function will be called when object placer utility opened. Add About and Parameter rollout to the utility panel.


(当object placer脚本被打开时,调用这个方法。它会在工具面板添加脚本的“About”和“parameter”卷展栏。)

on ObjPlacer close do
(
removeRollout Abt
removeRollout Param
)
This function called when object placer utility closed.

(当脚本关闭时,调用这个方法。)

Remove About and Parameter rollout in the utility panel.

(从工具面板移除上述两个卷展栏。)
Align function:
(对齐方法)

--------------------------------------------------------------------------------

Align function calculates the transformation value of source object from a polygon or vertex of destination object. This technique is also explained in MaxScript user reference “How do I align the UVMap modifier to the selected face?”  
(对齐方法根据目标物体面或顶点的属性计算源物体的变换值。这个技术在maxScript用户参考里关于如何对齐UVmap修改器到选定的面的例子里也有解释。如图6)



Fig.06 - NormalCalculation (图6 ——法线解算)
fn Align souCopy desNormal pos
(  
worldUpVector = [0,0,1]  
rightVector = normalize (cross worldUpVector desNormal)
upVector = normalize ( cross rightVector desNormal)
theMatrix = matrix3 rightVector upVector desNormal Pos
souCopy.transform = theMatrix
)

Align function with three arguments. A copy of source object, destination objects normal and position.
(对齐方法需要3个数据。一个源物体的拷贝,以及目标物体的法线和位置。)

The default value of world up vector is [0, 0, 1] 

(默认的世界空间向上的轴向是[0,0,1],即Z轴正方向。)

Calculate right vector from world up vector and normal value )

(根据世界空间向上的矢量和法线矢量计算局部空间向右的矢量。)


Calculate local up vector from right vector and normal value.
(根据局部空间向右的矢量和法线矢量计算局部空间向上的矢量。)
Store right vector, up vector normal and position to theMatrix as a matrix3 value
(存储向右的矢量,向上的法线矢量,和法线的位置到矩阵变量matrix3。)

Set Source object transformation to theMatrix )
(将矩阵matrix赋于源物体的变换属性。)
Copy Option Function:
(复制选项 方法)
--------------------------------------------------------------------------------
The copy option function make copies of source object according to user’s selection.
(复制选项方法控制我们以何种类型复制所选择的物体。)
fn CopySource numCopies=
(
case copyState of
(
1:
souCpy = for i = 1 to numCopies collect(copy sourceObj)
2:
souCpy = for i = 1 to numCopies collect(instance sourceObj)
default:
souCpy = for i = 1 to numCopies collect(reference sourceObj)
)
return souCpy
If copy option function called .
(一旦复制选项方法被程序调用) 

Check the state of copy option radio buttons.
(首先检察复制选项的圆形按钮)

According to copy type make copy of object and store it to an array souCpy .
(根据选择的复制类型复制物体,并将其存储到souCpy的数组中。)
Return souCopy.
(返回souCpy的值给程序)
Script Link: Objectplacer.ms   
(脚本链接:
ObjectPlacer.zip )
I hope this tutorial is helpful. If u have any questions or suggestions, just mail me
sathish101@gmail.com.

(我希望这篇教程对你有所启发。如果你有任何意见或建议,请email我)

来源:译文3D网

[ 本帖最后由 火柴盒 于 2008-4-21 14:30 编辑 ]
返回列表