3天学会MaxScript教程之(第二三天:编写一个高级Max顶点动画back到Texture的插件)

本文主要是介绍3天学会MaxScript教程之(第二三天:编写一个高级Max顶点动画back到Texture的插件),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

3天学会MaxScrip的第一天在这里: 点击打开链接

有了第一天的知识和初步认识,我们就来制作一个高级点的脚本插件吧。max脚本其实非常简单,主要知道语法就可以了,逻辑难度几乎为零。首先来看这个插件的效果

做动画其实有很多种方式,除了骨骼,目标变形,物理解算外,还有BackToTextureAnimation。其实这个和GPUSkin原理类似。
这个插件的原理是将所有顶点的位置数据拍成一列,然后再把每帧的这个数组再排到帧数组中,这样就能再Shader中读取顶点的位置,然后让顶点动画在引擎里还原了。

最后存出来是一张这种样子的图,它记录了模型位置的变化。

现在知道了原理,那么它是如何在max中生成然后导入引擎里,然后引擎的shader去读取识别然后还原的呢。下面就来一步一步制作。

首先建个文本文件,命名为VertexAnimationTool.ms

然后用VSCode打开。我们先创建一个max的工作窗口。

macroScript TextureAnimation category:"Texture_Vertex_Animaton" buttontext:"Vertex Animation Tools" tooltip:"Vertex Animation Tools"
(rollout TexMorphRollout "Vertex texture Animation Tool" ()global Morph_Floater = newRolloutFloater "" 200 230 addRollout TexMorphRollout Morph_Floater
)
macros.run "Texture_Vertex_Animaton" "TextureAnimation" 

把脚本拖进去就能看到如下的效果了。

如果一切正常,下面我们来继续编写我们的工具。我们的工具需要指明我们需要Bake的动画帧范围,比如0到30帧的动画范围我们需要把它bake到我们的贴图里。所以我们需要一个指认动画范围的UI。同时我们的工具还需要动画的采样密度,0~30帧这个范围我们是把每帧都记录下来还是每隔一帧记录一次。然后我们还需要一个按钮,当我们设置好后,点击这个按钮后就开始bake工作流程并把烘焙的顶点动画贴图导出。

所以我们的代码变成了这样:

macroScript TextureAnimation category: "Texture_Vertex_Animaton" buttontext: "Vertex Animation Tools" tooltip: "Vertex Animation Tools"
(
    rollout TexMorphRollout "Vertex texture Animation Tool"
    (
        group "Morpher Meshes"
        (
            spinner spinnerAnimationRangeStart "Anim Start" type: #integer range: [ 0 , 1000000 , animationRange.start ]
            spinner spinnerAnimationRangeEnd "Anim End" type: #integer range: [ 0 , 1000000 , animationRange.end ]
            spinner spinnerAnimationRate "Frame step Skip" type: #integer range: [ 0 , 1000000 , 0 ]
            button CreateVertexAnimation "Create Vertex Animation"
        )
    )
    global Morph_Floater = newRolloutFloater "" 200 230
    addRollout TexMorphRollout Morph_Floater
)
macros.run "Texture_Vertex_Animaton" "TextureAnimation"

把脚本拖进max你将会看到:

现在还没完,我们的模型UV是用来给模型纹理映射用的,那我们的这张顶点动画贴图应该怎样将保存进贴图里的值取出来然后给对应的顶点呢。答案是分第二套UV,把顶点按照顺序排列起来,然后在sample的时候直接就把值取出来给到顶点了,这是在为在引擎里还原顶点动画作考虑了。

所以我们的工具还需要给模型指认一套UV,然后把模型的UV按照一定顺序排列成一排。

再给工具加上Help按钮,我们的工具UI声明代码如下
macroScript TextureAnimation category: "Texture_Vertex_Animaton" buttontext: "Vertex Animation Tools" tooltip: "Vertex Animation Tools"
(
    rollout TexMorphRollout "Vertex texture Animation Tool"
    (
        group "Morpher Meshes"
        (
            spinner spinnerAnimationRangeStart "Anim Start" type: #integer range: [ 0 , 1000000 , animationRange.start ]
            spinner spinnerAnimationRangeEnd "Anim End" type: #integer range: [ 0 , 1000000 , animationRange.end ]
            spinner spinnerAnimationRate "Frame step Skip" type: #integer range: [ 0 , 1000000 , 0 ]
            dropdownlist ddlTextureCoordinate "Texture Coordinate:" items: #( "2" , "3" , "4" , "5" , "6" , "7" , "8" ) tooltip: "用第二套UV来放顶点动画的顶点位置"
            button CreateVertexAnimation "Create Vertex Animation"
        )
        button help "help"
    )
    global Morph_Floater = newRolloutFloater "" 200 230
    addRollout TexMorphRollout Morph_Floater
)
macros.run "Texture_Vertex_Animaton" "TextureAnimation"
我们要完成我们的操作,首先需要有一个储存原始模型的变量,一个储存顶点数的变量来决定顶点数组的长度,当然还要一个储存模型顶点的数组。我们还需要一个二维数组用来储存每帧模型所有顶点的位置。我们还需要一个数组用来储存所有顶点对应的UV的位置。所以我们的代码变成了如下的样子:
macroScript TextureAnimation category: "Texture_Vertex_Animaton" buttontext: "Vertex Animation Tools" tooltip: "Vertex Animation Tools"
(
    rollout TexMorphRollout "Vertex texture Animation Tool"
    (
        global originalMesh
        global copyBaseMesh
        global numberofVerts                                   --原始模型的顶点树木
        global originalMeshVertPositions = #()
        global MorphTargetArray
        global Morph_Floater
        global internalArrayOfStaticBaseMeshes = #()              --选中的模型们的一维数组
        global vertexUVPosition = #()                             --储存顶点模型的UV的位置
        global MorphNormalArray = #()
        global MorphVertOffsetArray = #()
        global MorphTargetProgressPercentage = 0.0
        global masterMorphArray = #()                              --二维数组,第一层为选中的模型,第二层为那个模型对应时间范围内的所有snapshot
        global noMeshesArray = #( " No meshes processed" as string )
        group "Morpher Meshes"
        (
            spinner spinnerAnimationRangeStart "Anim Start" type: #integer range: [ 0 , 1000000 , animationRange.start ]
            spinner spinnerAnimationRangeEnd "Anim End" type: #integer range: [ 0 , 1000000 , animationRange.end ]
            spinner spinnerAnimationRate "Frame step Skip" type: #integer range: [ 0 , 1000000 , 0 ]
            dropdownlist ddlTextureCoordinate "Texture Coordinate:" items: #( "2" , "3" , "4" , "5" , "6" , "7" , "8" ) tooltip: "用第二套UV来放顶点动画的顶点位置"
            button CreateVertexAnimation "Create Vertex Animation"
        )
        button help "help"
    )
    global Morph_Floater = newRolloutFloater "" 200 230
    addRollout TexMorphRollout Morph_Floater
)
macros.run "Texture_Vertex_Animaton" "TextureAnimation"

我们的工具代码主要分为两部分,一部分为逻辑代码,一部分为UI交互代码。我们需要声明两个函数,来处理:

macroScript TextureAnimation category: "Texture_Vertex_Animaton" buttontext: "Vertex Animation Tools" tooltip: "Vertex Animation Tools"
(
    rollout TexMorphRollout "Vertex texture Animation Tool"
    (
        global originalMesh
        global copyBaseMesh
        global numberofVerts                                   --原始模型的顶点树木
        global originalMeshVertPositions = #()
        global MorphTargetArray
        global Morph_Floater
        global internalArrayOfStaticBaseMeshes = #()              --选中的模型们的一维数组
        global vertexUVPosition = #()                             --储存顶点模型的UV的位置
        global MorphNormalArray = #()
        global MorphVertOffsetArray = #()
        global MorphTargetProgressPercentage = 0.0
        global masterMorphArray = #()                              --二维数组,第一层为选中的模型,第二层为那个模型对应时间范围内的所有snapshot
        global noMeshesArray = #( " No meshes processed" as string )
        group "Morpher Meshes"
        (
            spinner spinnerAnimationRangeStart "Anim Start" type: #integer range: [ 0 , 1000000 , animationRange.start ]
            spinner spinnerAnimationRangeEnd "Anim End" type: #integer range: [ 0 , 1000000 , animationRange.end ]
            spinner spinnerAnimationRate "Frame step Skip" type: #integer range: [ 0 , 1000000 , 0 ]
            dropdownlist ddlTextureCoordinate "Texture Coordinate:" items: #( "2" , "3" , "4" , "5" , "6" , "7" , "8" ) tooltip: "用第二套UV来放顶点动画的顶点位置"
            button CreateVertexAnimation "Create Vertex Animation"
        )
        button help "help"

        on CreateVertexAnimation pressed do
        (

        )
   
        on help pressed do
        (
              
        )

    )
    global Morph_Floater = newRolloutFloater "" 200 230
    addRollout TexMorphRollout Morph_Floater
)
macros.run "Texture_Vertex_Animaton" "TextureAnimation"

首先我们来补全Help函数:

on help pressed do
        (
            S = #()
            HelpString = ""
            append S "第一步:输入顶点动画开始的位置。"
            append S "第二步:输入顶点动画结束的位置。"
            append S "第三步:输入顶点动画需要跳过的位置。"
            append S "第四步:选择一个供顶点动画贴图sample的UV空间,默认使用第二套UV"
            append S "第五步:点击生成顶点动画按钮,选择导出路径。"
            for i in S do HelpString += i + " \r\r "
            messageBox HelpString
        )

你将会看到如下效果:

下面我们来补全最为重要的CreateVertexAnimation函数。首先我们这个函数需要做以下几件事情

(1)先要判断模型资源,单位长度设置是否正确。不能有单独的点,没有用的点,或者说是破面啥的。

(2)把每一帧的模型SnapShot出来,然后把这一帧的顶点数组压入数组。
(3)创建一个原模型的克隆,然后给它分好UV和平滑组。
(4)清空每一帧创建的模型。
(5)把顶点数组烘焙到纹理上然后导出。

这个函数大概的结构是这样的,下面我们一步一步完善它

       on CreateVertexAnimation pressed do
        (
            /*判断一下系统单位是否和引擎保持一致*/
            if (CheckUnits() == true ) do
            (
                try
                with redraw off
                (
                    ReInitVarriables()
                    /*把选中的模型压入数组*/
                    for i in selection do if CheckMesh i do append internalArrayOfStaticBaseMeshes i
                   
                    geoConversionModelFailNamelist = #()
                    --遍历所有选中的需要处理的模型,把有问题的模型找出来
                    for i in internalArrayOfStaticBaseMeshes do
                    (
                        CopyMesh = convertTo ( snapshot i) Editable_Poly
                        if (( getNumVerts i) != ( getNumVerts CopyMesh)) then
                        (
                            append geoConversionModelFailNamelist i.name
                        )
                        delete CopyMesh
                    )
                    --如果找到了模型,则不会进行顶点动画的烘焙
                    if geoConversionModelFailNamelist.count > 0 then
                    (
                        string S = "模型有问题"
                        for i in geoConversionModelFailNamelist do append S ( " \r " + i)
                        messageBox S
                    )
                    else
                    (
                        if internalArrayOfStaticBaseMeshes.count > 0 then
                        (
                            --把选中的模型在指定范时间围的状态全部snapshot出来,并且把这些数据保存在二维数组masterMorphArray中
                            MakeAndMergeSnapShots internalArrayOfStaticBaseMeshes
                            SmoothCopyMesh masterMorphArray[ 1 ]
                            PackVertexUVs originalMesh
                            populateMorphTargetArrays()
                            ClearMeshes()
                            RenderTexture()
                        )
                    )

                )
                catch
                (
                    messageBox "Catched Error !!!"
                    ResumeEditing()
                )
            )
            ResumeEditing()
        )
首先我们有个try with catch结构,为了不让我们的程序出问题了直接就崩了,所以这里需要有个这个。

        function ReInitVarriables =
        (
            masterMorphArray = #()
            MorphVertOffsetArray = #()
            originalMesh = undefined
            numberofVerts = 0
            internalArrayOfStaticBaseMeshes = #()
            MorphTargetProgressPercentage = 0.0
            originalMeshVertPositions = #()
            MorphNormalArray = #()
            tempMorphArray = #()
        )
ReInitVarribles重新初始化我们的那个globle变量。
        function CheckMesh selectmesh =
        (
            isvalidnode selectmesh and superclassof selectmesh == GeometryClass
        )

CheckMesh是为了检查一次模型是不是集合体。
        function MakeAndMergeSnapShots ArrayOfMeshes =
        (
            if ArrayOfMeshes.count > 0 do
            (
                for i in ArrayOfMeshes do
                (
                    --把每一帧的模型全部snapshot出来,并且保存在全局变量masterMorphArray二维数组中的第二维。
                    if CheckMesh i do append masterMorphArray (MakeSnapShotsReturnArray i)
                )
                --如果有多个有关键帧的原始模型,则会把每帧的两个模型的关键帧克隆attach到一起,如果没有,下面的逻辑没跑
                masterMorphArray1Count = masterMorphArray[ 1 ]. count
                if masterMorphArray.count > 1 do
                (
                    for i = 2 to masterMorphArray.count do
                    (
                        for framecount = 1 to masterMorphArray1Count do
                        (
                            currentMasterObject = masterMorphArray[ 1 ][framecount]
                            attachMeshes currentMasterObject masterMorphArray[i][framecount]
                        )
                    )
                )
                masterMorphArray = masterMorphArray[ 1 ]
            )
        )

这里是给每一帧都创建一个snapshot。

然后把snapshot的顶点压入数组。
        function SmoothCopyMesh Meshes =
        (
            OrgName = Meshes.name
            originalMesh = at time 0 snapshot Meshes
            originalMesh.name = OrgName + "_MorphUV" + (targetMorphUV as string ) + "_MorphExport"
            s = smooth ()
            s.smoothingBits = 1
            addModifier originalMesh s

            numberofVerts = getNumVerts originalMesh
            originalMeshVertPositions = #()   --清空位置数组,它是定义在全局的
            if ClassOf originalMesh.baseobject == Editable_Poly then
            (
                for i = 1 numberofVerts do
                (
                    append originalMeshVertPositions ( in coordsys world polyop.getVert originalMesh i)
                )
            )
            else
            (
                for i = 1 to numberofVerts do
                (
                    append originalMeshVertPositions ( in coordsys world getVert originalMesh i)
                )
            )
        )

了解这些核心函数后,我将我整个脚本的代码奉上:

macroScript TextureAnimation category: "Texture_Vertex_Animaton" buttontext: "Vertex Animation Tools" tooltip: "Vertex Animation Tools"
(
    ResumeEditing()
    escapeEnable = true
   
    global targetMorphUV = 2

    rollout TexMorphRollout "Vertex texture Animation Tool"
    (
        global originalMesh
        global copyBaseMesh
        global numberofVerts                                   --原始模型的顶点树木
        global originalMeshVertPositions = #()
        global MorphTargetArray
        global Morph_Floater
        global internalArrayOfStaticBaseMeshes = #()              --选中的模型们的一维数组
        global vertexUVPosition = #()                             --储存顶点模型的UV的位置
        global MorphNormalArray = #()
        global MorphVertOffsetArray = #()
        global MorphTargetProgressPercentage = 0.0
        global masterMorphArray = #()                              --二维数组,第一层为选中的模型,第二层为那个模型对应时间范围内的所有snapshot
        global noMeshesArray = #( " No meshes processed" as string )
        group "Morpher Meshes"
        (
            spinner spinnerAnimationRangeStart "Anim Start" type: #integer range: [ 0 , 1000000 , animationRange.start ]
            spinner spinnerAnimationRangeEnd "Anim End" type: #integer range: [ 0 , 1000000 , animationRange.end ]
            spinner spinnerAnimationRate "Frame step Skip" type: #integer range: [ 0 , 1000000 , 0 ]
            dropdownlist ddlTextureCoordinate "Texture Coordinate:" items: #( "2" , "3" , "4" , "5" , "6" , "7" , "8" ) tooltip: "用第二套UV来放顶点动画的顶点位置"
            button CreateVertexAnimation "Create Vertex Animation"
        )
        button help "help"
       

        /*******************************************************************************功能函数**************************************************************************************/

        function CheckUnits =
        (
            if ( units.SystemType != #Centimeters )
            then
            (
                messageBox "请校准好Max的系统单位,保持与Unity中的一致"
                return false
            )
            else
            (
                return true
            )
        )

        function CheckMesh selectmesh =
        (
            isvalidnode selectmesh and superclassof selectmesh == GeometryClass
        )

        function ClearMeshes =
        (
            if isValidNode masterMorphArray[ 1 ] and masterMorphArray.count > 0 do
            (
                delete masterMorphArray
                masterMorphArray = #()
            )
        )

        function updateProgAmount i myArrayCount =
        (
            MorphTargetProgressPercentage = ((i as float / myArrayCount as float ) * 100.0 )
            progressUpdate MorphTargetProgressPercentage  
            if MorphTargetProgressPercentage == 100.0 do progressEnd()
            if getProgressCancel() == true do
            (
                progressEnd()
            ) -- returns true if cancelled
        )

        function ReInitVarriables =
        (
            masterMorphArray = #()
            MorphVertOffsetArray = #()
            originalMesh = undefined
            numberofVerts = 0
            internalArrayOfStaticBaseMeshes = #()
            MorphTargetProgressPercentage = 0.0
            originalMeshVertPositions = #()
            MorphNormalArray = #()
            tempMorphArray = #()
        )

        function MakeSnapShotsReturnArray MeshToSnapShot =
        (
            progressStart "Create morph targets"
            FrameArray = #()
            NumOfFrames = floor ( spinnerAnimationRangeEnd.value - spinnerAnimationRangeStart.value )
            for i = 0 to NumOfFrames by ( spinnerAnimationRate.value + 1 ) do
            (
                newtime = spinnerAnimationRangeStart.value + i
                newCopy = at time newtime snapshot MeshToSnapShot
                --deleteKeys newCopy #allKeys
                meshop.unifyNormals newCopy #{ 1. . newCopy . numfaces }
                append FrameArray newCopy
            updateProgAmount i NumOfFrames
            )
            progressEnd()
            return FrameArray
        )

        function attachMeshes mesh1 mesh2 =
        (
            if classof mesh1 == editable_poly then mesh1.attach mesh2 mesh1
            else attach mesh1 mesh2
        )

        function fixUVNames polyToFix =
        (
            for i = 1 to ( polyop.getNumMaps polyToFix) do ( ChannelInfo.NameChannel polyToFix 3 i ( "UVChannel_" + i as string ))
        )

        function MakeAndMergeSnapShots ArrayOfMeshes =
        (
            if ArrayOfMeshes.count > 0 do
            (
                for i in ArrayOfMeshes do
                (
                    --把每一帧的模型全部snapshot出来,并且保存在全局变量masterMorphArray二维数组中的第二维。
                    if CheckMesh i do append masterMorphArray (MakeSnapShotsReturnArray i)
                )
                --如果有多个有关键帧的原始模型,则会把每帧的两个模型的关键帧克隆attach到一起,如果没有,下面的逻辑没跑
                masterMorphArray1Count = masterMorphArray[ 1 ]. count
                if masterMorphArray.count > 1 do
                (
                    for i = 2 to masterMorphArray.count do
                    (
                        for framecount = 1 to masterMorphArray1Count do
                        (
                            currentMasterObject = masterMorphArray[ 1 ][framecount]
                            attachMeshes currentMasterObject masterMorphArray[i][framecount]
                        )
                    )
                )
                masterMorphArray = masterMorphArray[ 1 ]
            )
        )

        function SmoothCopyMesh Meshes =
        (
            OrgName = Meshes.name
            originalMesh = at time 0 snapshot Meshes
            originalMesh.name = OrgName + "_MorphUV" + (targetMorphUV as string ) + "_MorphExport"
            s = smooth ()
            s.smoothingBits = 1
            addModifier originalMesh s

            numberofVerts = getNumVerts originalMesh
            originalMeshVertPositions = #()   --清空位置数组,它是定义在全局的
            if ClassOf originalMesh.baseobject == Editable_Poly then
            (
                for i = 1 numberofVerts do
                (
                    append originalMeshVertPositions ( in coordsys world polyop.getVert originalMesh i)
                )
            )
            else
            (
                for i = 1 to numberofVerts do
                (
                    append originalMeshVertPositions ( in coordsys world getVert originalMesh i)
                )
            )
        )

        function PackVertexUVs myMesh =
        (
            progressStart "Packing the game mesh UVs"
            convertTo myMesh Editable_Poly
            for i = 1 to numberofVerts do
            (
                offset = 1.0 / (numberofVerts * 2 )
                currentPosition = (((i as float ) - 0.5 ) / numberofVerts)
                polyop.setVertColor myMesh targetMorphUV i [currentPosition * 255.0 , 128.0 , 0 ]
                append vertexUVPosition currentPosition
                updateProgAmount i numberofVerts
            )
            fixUVNames myMesh
            progressEnd()
        )

        function getVertPos model index =
        (
            pos = [ 0 , 0 , 0 ]
            if classof model.baseobject == editable_poly then (
                pos =in coordsys world polyop.getVert model index
            ) else (
                pos =in coordsys world getVert model index
            )
            return pos
        )

        function populateMorphTargetArrays =
        (
            progressStart "Creating the Morph Targets"
            masterCount = masterMorphArray.count
             for i = 1 to masterCount do
            (
                CurrentMorphTargetNormalArray = #()
                currentMorphTarget = masterMorphArray[i]
                 global currentMorphVertexOffsetArray = #()
                MorphTargetProgressPercentage = updateProgAmount i masterCount
                 for j = 1 to numberofVerts do
                (
                    originalVertPos = originalMeshVertPositions[j]
                    currentModelVertPos = getVertPos currentMorphTarget j
                    currentOffset = (currentModelVertPos - originalVertPos)
                    currentOffset = [currentOffset[ 1 ], - 1.0 * currentOffset[ 2 ],currentOffset[ 3 ]]
                    currentOffset *= 255.0
                     append currentMorphVertexOffsetArray currentOffset
                )
                 append MorphVertOffsetArray currentMorphVertexOffsetArray
                 append MorphNormalArray CurrentMorphTargetNormalArray
            )
        )

        function Rendertexture =
        (
            fopenexr.SetCompression 0
            fopenexr.setLayerOutputType 0 1 -- set layer 0  main layer to RGBA, RGB = 1
            fopenexr.setLayerOutputFormat 0 1 --0 32 sets main layer to float 16 via 1. other options are 0 float 32, 2 int 32
            global TextureName = getSaveFileName types: "EXR (*.EXR)|*.EXR"
            if TextureName == undefined then
            (
                messagebox "please select a file location"
            )
            else
            (
                uvString = "_UV" + ((targetMorphUV - 1 ) as string )
                TextureNameOffset = replace TextureName ( findString TextureName ".EXR" ) 4 (uvString + ".EXR" )
                global FinalTexture = bitmap numberofVerts ( MorphVertOffsetArray.count ) filename: TextureNameOffset hdr: true ;
                for i = 0 to ( MorphVertOffsetArray.count - 1 ) do
                (
                    setPixels FinalTexture [ 0 , i] MorphVertOffsetArray[(i + 1 )]
                )
                save FinalTexture gamma:1.0
                close FinalTexture
            )
        )

        /*******************************************************************************UI交互函数**************************************************************************************/
        on CreateVertexAnimation pressed do
        (
            /*判断一下系统单位是否和引擎保持一致*/
            if (CheckUnits() == true ) do
            (
                try
                with redraw off
                (
                    ReInitVarriables()
                    /*把选中的模型压入数组*/
                    for i in selection do if CheckMesh i do append internalArrayOfStaticBaseMeshes i
                   
                    geoConversionModelFailNamelist = #()
                    --遍历所有选中的需要处理的模型,把有问题的模型找出来
                    for i in internalArrayOfStaticBaseMeshes do
                    (
                        CopyMesh = convertTo ( snapshot i) Editable_Poly
                        if (( getNumVerts i) != ( getNumVerts CopyMesh)) then
                        (
                            append geoConversionModelFailNamelist i.name
                        )
                        delete CopyMesh
                    )
                    --如果找到了模型,则不会进行顶点动画的烘焙
                    if geoConversionModelFailNamelist.count > 0 then
                    (
                        string S = "模型有问题"
                        for i in geoConversionModelFailNamelist do append S ( " \r " + i)
                        messageBox S
                    )
                    else
                    (
                        if internalArrayOfStaticBaseMeshes.count > 0 then
                        (
                            --把选中的模型在指定范时间围的状态全部snapshot出来,并且把这些数据保存在二维数组masterMorphArray中
                            MakeAndMergeSnapShots internalArrayOfStaticBaseMeshes
                            SmoothCopyMesh masterMorphArray[ 1 ]
                            PackVertexUVs originalMesh
                            populateMorphTargetArrays()
                            ClearMeshes()
                            RenderTexture()
                        )
                    )

                )
                catch
                (
                    messageBox "Catched Error !!!"
                    ResumeEditing()
                )
            )
            ResumeEditing()
        )

        on help pressed do
        (
            S = #()
            HelpString = ""
            append S "第一步:输入顶点动画开始的位置。"
            append S "第二步:输入顶点动画结束的位置。"
            append S "第三步:输入顶点动画需要跳过的位置。"
            append S "第四步:选择一个供顶点动画贴图sample的UV空间,默认使用第二套UV"
            append S "第五步:点击生成顶点动画按钮,选择导出路径。"
            for i in S do HelpString += i + " \r\r "
            messageBox HelpString
        )


        /******************************************************************************************************************************************************************************/
    )
     if Morph_Floater != undefined then CloseRolloutFloater Morph_Floater
     global Morph_Floater = newRolloutFloater "" 200 230
    addRollout TexMorphRollout Morph_Floater
)

macros.run "Texture_Vertex_Animaton" "TextureAnimation"

这篇关于3天学会MaxScript教程之(第二三天:编写一个高级Max顶点动画back到Texture的插件)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/315582

相关文章

IDEA自动生成注释模板的配置教程

《IDEA自动生成注释模板的配置教程》本文介绍了如何在IntelliJIDEA中配置类和方法的注释模板,包括自动生成项目名称、包名、日期和时间等内容,以及如何定制参数和返回值的注释格式,需要的朋友可以... 目录项目场景配置方法类注释模板定义类开头的注释步骤类注释效果方法注释模板定义方法开头的注释步骤方法注

Python虚拟环境终极(含PyCharm的使用教程)

《Python虚拟环境终极(含PyCharm的使用教程)》:本文主要介绍Python虚拟环境终极(含PyCharm的使用教程),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录一、为什么需要虚拟环境?二、虚拟环境创建方式对比三、命令行创建虚拟环境(venv)3.1 基础命令3

使用Node.js制作图片上传服务的详细教程

《使用Node.js制作图片上传服务的详细教程》在现代Web应用开发中,图片上传是一项常见且重要的功能,借助Node.js强大的生态系统,我们可以轻松搭建高效的图片上传服务,本文将深入探讨如何使用No... 目录准备工作搭建 Express 服务器配置 multer 进行图片上传处理图片上传请求完整代码示例

MySQL高级查询之JOIN、子查询、窗口函数实际案例

《MySQL高级查询之JOIN、子查询、窗口函数实际案例》:本文主要介绍MySQL高级查询之JOIN、子查询、窗口函数实际案例的相关资料,JOIN用于多表关联查询,子查询用于数据筛选和过滤,窗口函... 目录前言1. JOIN(连接查询)1.1 内连接(INNER JOIN)1.2 左连接(LEFT JOI

python连接本地SQL server详细图文教程

《python连接本地SQLserver详细图文教程》在数据分析领域,经常需要从数据库中获取数据进行分析和处理,下面:本文主要介绍python连接本地SQLserver的相关资料,文中通过代码... 目录一.设置本地账号1.新建用户2.开启双重验证3,开启TCP/IP本地服务二js.python连接实例1.

Python 安装和配置flask, flask_cors的图文教程

《Python安装和配置flask,flask_cors的图文教程》:本文主要介绍Python安装和配置flask,flask_cors的图文教程,本文通过图文并茂的形式给大家介绍的非常详细,... 目录一.python安装:二,配置环境变量,三:检查Python安装和环境变量,四:安装flask和flas

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.

前端高级CSS用法示例详解

《前端高级CSS用法示例详解》在前端开发中,CSS(层叠样式表)不仅是用来控制网页的外观和布局,更是实现复杂交互和动态效果的关键技术之一,随着前端技术的不断发展,CSS的用法也日益丰富和高级,本文将深... 前端高级css用法在前端开发中,CSS(层叠样式表)不仅是用来控制网页的外观和布局,更是实现复杂交

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J