Files
2025-09-29 00:52:08 +02:00

352 lines
10 KiB
Plaintext
Executable File

filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms")
rsta_loadCommonFunction #("FN_RSTA_userSettings")
if (RsPathDeform != undefined) do try(RsPathDeform.dispose())catch()
struct RsPathDeform
(
-----------------------------------------------------
-- LOCALS
-----------------------------------------------------
version = 2.01,
MainWindow,
Settings = rsta_userSettings app:"RsPathDeform",
vm,
theObject,
theSpline,
-----------------------------------------------------
-- FUNCTIONS
-----------------------------------------------------
fn ease_in_out t b c d =
(
t = t as float
b = b as float
c = c as float
d = d as float
if ((t /= d / 2) < 1) then v = (c - b) / 2 * t * t + b
else v = -(c - b) / 2 * ((t - 1) * ((t - 1) - 2) - 1) + b
return v
),
-----------------------------------------------------------
fn sTwist_sortByPercent v1 v2 =
(
if (v1.percent < v2.percent) do return -1
if (v1.percent > v2.percent) do return 1
return 0
),
-----------------------------------------------------------
fn twistCurve3D spline fraction =
(
local percent = fraction * 100
-- GET SPLINE TWISTS
local sTwists = for h in helpers where (classof h == RsSplineTwist) AND (h.spline == spline) collect h
if (sTwists.count != 0) then
(
qsort sTwists sTwist_sortByPercent
-- GET SPLINE TWISTS TO THE LEF AND RIGHT OF PERCENT POINT
local c = 1
while (c < sTwists.count + 1) AND (percent > sTwists[c].percent) do c += 1
local idx_left = if (c == 1) then c else c-1
local idx_right = if (c > sTwists.count) then idx_left else c
local left_sTwist = sTwists[idx_left]
local right_sTwist = sTwists[idx_right]
-- GET RELATIVE PERCENT BETWEEN SPLINE TWISTS
local relativePercent = (100.0/(right_sTwist.percent - left_sTwist.percent)) * (percent - left_sTwist.percent)
relativePercent = (if relativePercent > 100 then 100 else relativePercent)
-- GET TWIST AMOUNT WITH EASE IN/OUT
return (ease_in_out relativePercent left_sTwist.angle right_sTwist.angle 100)
)
else return 0
),
----------------------------------------------------
fn isSpline obj =
(
return (classof_array #(line,SplineShape) obj)
),
-----------------------------------------------------
fn Set_Object =
(
for i in (getCurrentSelection()) do
(
if (classof_array #(editable_poly, editable_mesh) i) do
(
theObject = i
vm.ObjectName = theObject.name
)
)
),
-----------------------------------------------------
fn getSplineLength s =
(
local l = getSegLengths s 1
return l[l.count]
),
-----------------------------------------------------
fn getTemplateLength t =
(
return (t.max - t.min).y
),
-----------------------------------------------------
fn deform_mesh theMesh startFraction endFraction =
(
scale (matrix3 1) theMesh.scale
theMesh.pos = [0,0,0]
theMesh.transform = (matrix3 1)
local numVerts = meshop.getNumVerts theMesh
local y_length = getTemplateLength theMesh
local y_min = theMesh.min.y
local vP
local lengthFraction
for vertNum = 1 to numVerts do
(
vP = meshop.getvert theMesh vertNum
lengthFraction = (vP.y - y_min)/y_length
--if lengthFraction < 0.001 do lengthFraction = 0
--if lengthFraction > 0.999 do lengthFraction = 1
adjustedLengthFraction = (lengthFraction * (endFraction - startFraction)) + startFraction
-- CURRENT SPLINE INFO
spPos = interpCurve3D theSpline 1 adjustedLengthFraction
spTangent = normalize (tangentCurve3D theSpline 1 adjustedLengthFraction)
spTwist = twistCurve3D theSpline adjustedLengthFraction
-- TRANS MATRIX
tm = transMatrix [vP.x,0,vP.z]
-- SPLINE DIRECTION
rotateX tm (atan2 spTangent.z 1)
rotateY tm spTwist
rotateZ tm -(atan2 spTangent.x spTangent.y)
-- MOVE VERT
meshop.setVert theMesh vertNum (spPos + tm.pos)
)
),
-----------------------------------------------------
fn getFractionArray c =
(
local b = (vm.StartPos/100)
local e = (vm.EndPos/100)
return (for i=0 to c-1 collect #(b + (((e - b)/c) * i), b + (((e - b)/c) * i) + ((e - b)/c)))
),
--------------------------------------------------------
fn do_deform =
(
undo "Path Deform" on
(
for s in (getCurrentSelection()) where (isSpline s) do
(
theSpline = s
if (vm.IsAutoFill) do
(
local sl = getSplineLength theSpline
sl *= ((vm.EndPos - vm.StartPos)/100)
local tl = getTemplateLength theObject
if (tl > sl) then vm.ObjCount = 1
else vm.ObjCount = floor ((sl/tl) + 0.5)
)
local objs = #()
local fArray = getFractionArray vm.ObjCount
for i=1 to vm.ObjCount do
(
local temp_obj = copy theObject
convertToMesh temp_obj
deform_mesh temp_obj fArray[i][1] fArray[i][2]
temp_obj.pivot = temp_obj.center
append objs temp_obj
)
if (vm.IsMerged) do
(
for i=2 to objs.count do meshop.attach objs[1] objs[i]
)
completeRedraw()
)
)
),
------------------------------------------------------------------------
-- SPLINE TOOLS
------------------------------------------------------------------------
fn makePoint pos dir:[0,0,1] =
(
local pnt = (point pos:pos dir:dir centermarker:false axistripod:true cross:false box:true size:10)
pnt.wirecolor = color 114 255 0
return pnt
),
------------------------------------------------------------------------
fn Do_CreateSplineBetweenHelpers =
(
local pntA = $[1]
local pntB = $[2]
local offsetA = (preTranslate pntA.transform [0,1,0]).translationpart
local offsetB = (preTranslate pntB.transform [0,-1,0]).translationpart
local vA = normalize (offsetA - pntA.pos)
local vB = normalize (offsetB - pntB.pos)
local dist = (distance pntA pntB)/2
local handA = pntA.pos + (vA * dist * vm.Spline_startVel)
local handB = pntB.pos + (vB * dist * vm.Spline_endVel)
ss = SplineShape pos:pntA.pos
addNewSpline ss
addKnot ss 1 #bezier #curve pntA.pos pntA.pos handA
addKnot ss 1 #bezier #curve pntB.pos handB pntB.pos
updateShape ss
ss
completeRedraw()
),
------------------------------------------------------------------------
fn Do_FlipSplineHelper =
(
for h in (getCurrentSelection()) where (superclassof h == helper) do
(
in coordsys local h.rotation.z_rotation += 180
)
),
------------------------------------------------------------------------
fn Do_addSplineHelper =
(
if (selection.count == 0) then makePoint [0,0,0]
else
(
local obj = selection[1]
case of
(
(classof obj == editable_poly) :
(
local edges = polyop.getEdgeSelection obj
if not (edges.isempty) then
(
verts = polyop.getVertsUsingEdge obj (edges as array)[1]
v1 = polyop.getVert obj (verts as array)[1]
v2 = polyop.getVert obj (verts as array)[2]
local pnt = makePoint v2 dir:(v2 - v1)
in coordsys local pnt.rotation.x_rotation -= 90
)
else makePoint obj.pos dir:obj.dir
)
(classof obj == editable_mesh) :
(
local edges = getEdgeSelection obj
if not (edges.isempty) then
(
verts = meshop.getVertsUsingEdge obj (edges as array)[1]
v1 = getVert obj (verts as array)[1]
v2 = getVert obj (verts as array)[2]
local pnt = makePoint v2 dir:(v2 - v1)
in coordsys local pnt.rotation.x_rotation -= 90
)
else makePoint obj.pos dir:obj.dir
)
(classof_array #(line, SplineShape) obj) :
(
selKnot = getKnotSelection obj 1
if (selKnot.count == 1) then
(
local pos = getKnotPoint obj 1 selKnot[1]
local vec = if (selKnot[1] == 1) then getOutVec obj 1 selKnot[1] else getInVec obj 1 selKnot[1]
local pnt = makePoint pos dir:(pos - vec)
in coordsys local pnt.rotation.x_rotation -= 90
)
else makePoint obj.pos dir:obj.dir
)
default:
(
makePoint obj.pos dir:obj.dir
)
)
)
),
------------------------------------------------------------------------
fn Do_AddTwistsToSpline =
(
for spline in (getCurrentSelection()) where (isSpline spline) do
(
local fraction_step = 100/(vm.TwistCountToAdd - 1)
for i=1 to (vm.TwistCountToAdd) do
(
local sTwist = RsSplineTwist()
sTwist.spline = spline
case i of
(
1 : sTwist.percent = 0
(vm.TwistCountToAdd) : sTwist.percent = 100
default : sTwist.percent = fraction_step * (i - 1)
)
)
)
),
-----------------------------------------------------
fn Do_ResizeTwists =
(
local twists = #()
if (vm.TwistResize_FilterIdx == 0) then twists = for h in (getCurrentSelection()) where (classof h == RsSplineTwist) collect h
else twists = for h in helpers where (classof h == RsSplineTwist) collect h
for i in twists do
(
i.size = vm.TwistResize_Size
i.distance = vm.TwistResize_Distance
)
),
------------------------------------------------------------------------
-- STRUCT FUNCTIONS
------------------------------------------------------------------------
fn dispose =
(
if (MainWindow != undefined) do
(
-- WINDOW POS
settings.wpf_windowPos mainWindow #set
-- CLOSE AND DISPOSE THE WINDOW
MainWindow.Close()
MainWindow = undefined
)
execute ("RsPathDeform = undefined")
),
-----------------------------------------------------
-- EVENTS
-----------------------------------------------------
on create do
(
-- LOAD ASSEMBLY
dotnet.loadAssembly (RsConfigGetToolsDir() + @"techart\dcc\3dsMax\RSG.TechArt.PathDeform.dll")
-- MAKE MAIN WINDOW INSTANCE
MainWindow = dotNetObject "RSG.TechArt.PathDeform.MainWindow"
MainWindow.Title = "Path Deform - " + version as string
dn_window.setup MainWindow
MainWindow.Tag = dotnetmxsvalue this
-- PARENTS THE WINDOW UNDER MAX, STOPS IT FROM DROPPING BEHIND
MainWindow.ChangeOwner (DotNetObject "System.IntPtr" (Windows.GetMAXHWND()))
-- WINDOW POS
settings.wpf_windowPos mainWindow #get
-- SHOW THE WINDOW
MainWindow.show()
vm = MainWindow.DataContext
)
)
RsPathDeform = RsPathDeform()