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

相关文章

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

2025版mysql8.0.41 winx64 手动安装详细教程

《2025版mysql8.0.41winx64手动安装详细教程》本文指导Windows系统下MySQL安装配置,包含解压、设置环境变量、my.ini配置、初始化密码获取、服务安装与手动启动等步骤,... 目录一、下载安装包二、配置环境变量三、安装配置四、启动 mysql 服务,修改密码一、下载安装包安装地

电脑提示d3dx11_43.dll缺失怎么办? DLL文件丢失的多种修复教程

《电脑提示d3dx11_43.dll缺失怎么办?DLL文件丢失的多种修复教程》在使用电脑玩游戏或运行某些图形处理软件时,有时会遇到系统提示“d3dx11_43.dll缺失”的错误,下面我们就来分享超... 在计算机使用过程中,我们可能会遇到一些错误提示,其中之一就是缺失某个dll文件。其中,d3dx11_4

Linux下在线安装启动VNC教程

《Linux下在线安装启动VNC教程》本文指导在CentOS7上在线安装VNC,包含安装、配置密码、启动/停止、清理重启步骤及注意事项,强调需安装VNC桌面以避免黑屏,并解决端口冲突和目录权限问题... 目录描述安装VNC安装 VNC 桌面可能遇到的问题总结描js述linux中的VNC就类似于Window

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

Spring Boot Maven 插件如何构建可执行 JAR 的核心配置

《SpringBootMaven插件如何构建可执行JAR的核心配置》SpringBoot核心Maven插件,用于生成可执行JAR/WAR,内置服务器简化部署,支持热部署、多环境配置及依赖管理... 目录前言一、插件的核心功能与目标1.1 插件的定位1.2 插件的 Goals(目标)1.3 插件定位1.4 核

Windows环境下解决Matplotlib中文字体显示问题的详细教程

《Windows环境下解决Matplotlib中文字体显示问题的详细教程》本文详细介绍了在Windows下解决Matplotlib中文显示问题的方法,包括安装字体、更新缓存、配置文件设置及编码調整,并... 目录引言问题分析解决方案详解1. 检查系统已安装字体2. 手动添加中文字体(以SimHei为例)步骤

Java JDK1.8 安装和环境配置教程详解

《JavaJDK1.8安装和环境配置教程详解》文章简要介绍了JDK1.8的安装流程,包括官网下载对应系统版本、安装时选择非系统盘路径、配置JAVA_HOME、CLASSPATH和Path环境变量,... 目录1.下载JDK2.安装JDK3.配置环境变量4.检验JDK官网下载地址:Java Downloads