529 lines
15 KiB
Plaintext
Executable File
529 lines
15 KiB
Plaintext
Executable File
try (destroyDialog RsPedDirtBakerRoll) catch ()
|
|
RSTA_LoadCommonFunction #("fn_RSTA_vertexColours.ms")
|
|
|
|
rollout RsPedDirtBakerRoll "Ped Dirt Baker [v1.01:FurtiveJar]" width:260
|
|
(
|
|
-- Version-phrase generated via: (filein (RsConfigGetWildWestDir() + "script/3dsmax/_config_files/wildwest_header.ms"); print (RsRandomPhrase count:100))
|
|
|
|
local dirtChan = 14
|
|
|
|
local rndSeed
|
|
local noiseContrast = 2.0
|
|
local noiseScale = 10
|
|
|
|
local dirtyRange = (dataPair min:4 max:32)
|
|
local dirtierRange = (dataPair min:15 max:110)
|
|
local dirtiestRange = (dataPair min:30 max:127)
|
|
|
|
local dirtierBonesString = "Calf"
|
|
local dirtiestBonesString = "Foot, Toe"
|
|
|
|
-- VertexPaint colour/size options:
|
|
local paintClrs = #((color 5 5 5 ), (color 127 127 127 ))
|
|
local brushSizes = #(0.02, 0.15)
|
|
|
|
-- CONTROLS --
|
|
dotNetControl RsBannerPanel "Panel" pos:[0,0] height:32 width:RsPedDirtBakerRoll.width
|
|
local bannerStruct = makeRsBanner dn_Panel:RsBannerPanel wiki:"PedDirtBaker" filename:(getThisScriptFilename())
|
|
|
|
button btnDoDirty "Apply Dirt to Selection" tooltip:"Apply Dirt data to vertex-colour channel 14" width:((RsPedDirtBakerRoll.width / 2) - 6) height:30 align:#left offset:[-8, 0] across:3
|
|
button btnShowDirty "Show Dirt" tooltip:"Show Dirt Channel (channel 14) on selection" width:((RsPedDirtBakerRoll.width / 4) - 4) height:30 align:#right offset:[25, 0]
|
|
button btnUnshowDirty "Unshow" tooltip:"Revert view to show materials" width:((RsPedDirtBakerRoll.width / 4) - 6) height:30 align:#right offset:[8, 0]
|
|
|
|
|
|
group "Dirt VertexPaint"
|
|
(
|
|
button btnAddVpaint "Add VertexPaint" tooltip:"Apply Dirt VertexPaint modifier to selection (set to channel 14)" height:30 align:#left
|
|
label lblPaintClr "Paint:" align:#left pos:(btnAddVpaint.pos + [110,1])
|
|
radiobuttons rdoPaintClr "" default:0 labels:#("Dark", "Light") align:#right offset:[0,-18]
|
|
label lblBrushSize "Size:" align:#left pos:(lblPaintClr.pos + [5,16])
|
|
radiobuttons rdoBrushSize "" default:0 labels:#("Fine", "Large") align:#right offset:[0,-18]
|
|
timer tmrVpaint interval:500 active:True
|
|
)
|
|
|
|
group "Dirtiness:"
|
|
(
|
|
spinner spnMinDirty "Default: Min:" range:[0, 127, 0] type:#integer fieldWidth:34 align:#right offset:[0,-3] across:2
|
|
spinner spnMaxDirty "Max:" range:[0, 127, 0] type:#integer fieldWidth:34 align:#right offset:[0,-3]
|
|
slider sldMinDirty "" range:[0, 127, 0] type:#integer ticks:0 align:#right offset:[10,-4] across:2
|
|
slider sldMaxDirty "" range:[0, 127, 0] type:#integer ticks:0 align:#left offset:[10,-4]
|
|
|
|
editText txtDirtier "Dirtier Bones:" fieldWidth:160 align:#right
|
|
spinner spnMinDirtier "Dirtier: Min:" range:[0, 127, 0] type:#integer fieldWidth:34 align:#right offset:[0,0] across:2
|
|
spinner spnMaxDirtier "Max:" range:[0, 127, 0] type:#integer fieldWidth:34 align:#right offset:[0,0]
|
|
slider sldMinDirtier "" range:[0, 127, 0] type:#integer ticks:0 align:#right offset:[10,-4] across:2
|
|
slider sldMaxDirtier "" range:[0, 127, 0] type:#integer ticks:0 align:#left offset:[10,-4]
|
|
|
|
editText txtDirtiest "Dirtiest Bones:" fieldWidth:160 align:#right
|
|
spinner spnMinDirtiest "Dirtiest: Min:" range:[0, 127, 0] type:#integer fieldWidth:34 align:#right offset:[0,0] across:2
|
|
spinner spnMaxDirtiest "Max:" range:[0, 127, 0] type:#integer fieldWidth:34 align:#right offset:[0,0]
|
|
slider sldMinDirtiest "" range:[0, 127, 0] type:#integer ticks:0 align:#right offset:[10,-4] across:2
|
|
slider sldMaxDirtiest "" range:[0, 127, 0] type:#integer ticks:0 align:#left offset:[10,-4]
|
|
)
|
|
group "Dirt Noise:"
|
|
(
|
|
spinner spnScale "Scale:" range:[0,100,0] scale:0.1 fieldWidth:50 align:#center offset:[0,-3] across:2
|
|
spinner spnContrast "Contrast:" range:[0,100,0] scale:0.1 fieldWidth:50 align:#center offset:[0,-3]
|
|
|
|
spinner spnSeed "Seed:" range:[0, 999999, 0] type:#integer fieldWidth:50 align:#center offset:[1,0] across:2
|
|
button btnRandom "RND" width:30 height:16 align:#right pos:(spnSeed.pos + [14,0])
|
|
)
|
|
|
|
-- FUNCTIONS --
|
|
fn updateCtrls =
|
|
(
|
|
txtDirtier.text = dirtierBonesString
|
|
txtDirtiest.text = dirtiestBonesString
|
|
|
|
spnMinDirty.value = dirtyRange.min
|
|
spnMaxDirty.value = dirtyRange.max
|
|
spnMinDirtier.value = dirtierRange.min
|
|
spnMaxDirtier.value = dirtierRange.max
|
|
spnMinDirtiest.value = dirtiestRange.min
|
|
spnMaxDirtiest.value = dirtiestRange.max
|
|
|
|
sldMinDirty.value = dirtyRange.min
|
|
sldMaxDirty.value = dirtyRange.max
|
|
sldMinDirtier.value = dirtierRange.min
|
|
sldMaxDirtier.value = dirtierRange.max
|
|
sldMinDirtiest.value = dirtiestRange.min
|
|
sldMaxDirtiest.value = dirtiestRange.max
|
|
|
|
spnScale.value = noiseScale
|
|
spnContrast.value = noiseContrast
|
|
spnSeed.value = rndSeed
|
|
)
|
|
|
|
fn showDirty unshow:False =
|
|
(
|
|
local objs = getCurrentSelection()
|
|
|
|
if unshow then
|
|
(
|
|
objs.showVertexColors = False
|
|
displayColor.shaded = #material
|
|
)
|
|
else
|
|
(
|
|
objs.showVertexColors = True
|
|
objs.vertexColorType = #map_channel
|
|
objs.vertexColorMapChannel = dirtChan
|
|
displayColor.shaded = #object
|
|
)
|
|
completeRedraw()
|
|
)
|
|
|
|
fn pedDirtBake objs:(getCurrentSelection()) =
|
|
(
|
|
-- Filter out invalid objs:
|
|
objs = for obj in objs where (isEditPolyMesh obj) collect obj
|
|
if (selection.count == 0) do return False
|
|
|
|
-- Generate noise-offset, based on random seed:
|
|
seed rndSeed
|
|
local noiseShift = random [-100,-100,-100] [100,100,100]
|
|
|
|
-- Get search-patterns for dirtier/dirtiest bone-names:
|
|
local dirtierBoneNames = for item in (filterString dirtierBonesString ", ") collect ("*" + item + "*")
|
|
local dirtiestBoneNames = for item in (filterString dirtiestBonesString ", ") collect ("*" + item + "*")
|
|
|
|
-- Process each object:
|
|
for obj in objs do
|
|
(
|
|
local skinMod = undefined
|
|
|
|
-- Get Skin modifier:
|
|
for thisMod in obj.modifiers while (skinMod == undefined) do
|
|
(
|
|
if (isKindOf thisMod skin) do
|
|
(
|
|
skinMod = thisMod
|
|
)
|
|
)
|
|
|
|
local vertDirts
|
|
|
|
if (skinMod == undefined) then
|
|
(
|
|
-- If object has no Skin modifier, use default dirt-ranges for all verts:
|
|
vertDirts = for n = 1 to obj.numVerts collect dirtyRange
|
|
)
|
|
else
|
|
(
|
|
-- Get verts used by specified bones:
|
|
|
|
if (getCommandPanelTaskMode() != #modify) do (setCommandPanelTaskMode #modify)
|
|
modPanel.setCurrentObject skinMod
|
|
|
|
local skinBoneCount = skinOps.getNumberBones skinMod
|
|
local dirtierBoneNums = #{}
|
|
local dirtiestBoneNums = #{}
|
|
|
|
-- Find Dirtier/Dirtiest boneNums:
|
|
for boneNum = 1 to skinBoneCount do
|
|
(
|
|
local skinBoneName = skinOps.getBoneName skinMod boneNum 1
|
|
|
|
local keepLooking = True
|
|
for item in dirtierBoneNames while keepLooking do
|
|
(
|
|
if (matchPattern skinBoneName pattern:item) do
|
|
(
|
|
dirtierBoneNums[boneNum] = True
|
|
keepLooking = True
|
|
)
|
|
)
|
|
for item in dirtiestBoneNames while keepLooking do
|
|
(
|
|
if (matchPattern skinBoneName pattern:item) do
|
|
(
|
|
dirtiestBoneNums[boneNum] = True
|
|
keepLooking = True
|
|
)
|
|
)
|
|
)
|
|
|
|
vertDirts = for skinVertNum = 1 to (skinOps.getNumberVertices skinMod) collect
|
|
(
|
|
local dirtierWeights = #()
|
|
local dirtiestWeights = #()
|
|
|
|
for vertBoneNum = 1 to (skinOps.getVertexWeightCount skinMod skinVertNum) do
|
|
(
|
|
getBoneID = skinOps.GetVertexWeightBoneID skinMod skinVertNum vertBoneNum
|
|
|
|
local weightList = case of
|
|
(
|
|
(dirtierBoneNums[getBoneID]):dirtierWeights
|
|
(dirtiestBoneNums[getBoneID]):dirtiestWeights
|
|
Default:undefined
|
|
)
|
|
|
|
if (weightList != undefined) do
|
|
(
|
|
append weightList (skinOps.GetVertexWeight skinMod skinVertNum vertBoneNum)
|
|
)
|
|
)
|
|
|
|
local hasDirtier = (dirtierWeights.count != 0)
|
|
local hasDirtiest = (dirtiestWeights.count != 0)
|
|
|
|
local dirtyVals = case of
|
|
(
|
|
-- Find mix between dirtier/dirtiest weightings:
|
|
(hasDirtier and hasDirtiest):
|
|
(
|
|
local dirtierSum = 0.0
|
|
local dirtiestSum = 0.0
|
|
|
|
for val in dirtierWeights do
|
|
(
|
|
dirtierSum += val
|
|
)
|
|
for val in dirtiestWeights do
|
|
(
|
|
dirtiestSum += val
|
|
)
|
|
|
|
local totalSum = (dirtierSum + dirtiestSum)
|
|
local dirtierMult = (dirtierSum / totalSum)
|
|
local dirtiestMult = (dirtiestSum / totalSum)
|
|
|
|
local minVal = ((dirtierMult * dirtierRange.min) + (dirtiestMult * dirtiestRange.min))
|
|
local maxVal = ((dirtierMult * dirtierRange.max) + (dirtiestMult * dirtiestRange.max))
|
|
|
|
dataPair min:minVal max:maxVal
|
|
)
|
|
(hasDirtiest):(dirtiestRange)
|
|
(hasDirtier):
|
|
(
|
|
local dirtierMult = 0.0
|
|
for val in dirtierWeights do
|
|
(
|
|
dirtierMult += val
|
|
)
|
|
|
|
local dirtyMult = (1.0 - dirtierMult)
|
|
|
|
local minVal = ((dirtierMult * dirtierRange.min) + (dirtyMult * dirtyRange.min))
|
|
local maxVal = ((dirtierMult * dirtierRange.max) + (dirtyMult * dirtyRange.max))
|
|
|
|
dataPair min:minVal max:maxVal
|
|
)
|
|
(Default):(dirtyRange)
|
|
)
|
|
|
|
--format "%, % : %\n" hasDirtiest hasDirtier (dirtyVals as string)
|
|
|
|
dirtyVals
|
|
)
|
|
)
|
|
|
|
local tempObj = RsVertClr_makeTempObj obj copyChan:dirtChan
|
|
local objOp = RsMeshPolyOp tempObj
|
|
|
|
for vertNum = 1 to vertDirts.count do
|
|
(
|
|
-- Get vert's dirtiness:
|
|
local dirtRange = vertDirts[vertNum]
|
|
|
|
-- Get vertex position:
|
|
local vertPos = objOp.getVert tempObj vertNum
|
|
|
|
-- Generate dirtiness-multiplier for this position based on 3d noise values:
|
|
local noiseVal = noise3 (noiseScale * (vertPos + noiseShift))
|
|
|
|
-- Scale and clamp value:
|
|
noiseVal *= noiseContrast
|
|
noiseVal += 1
|
|
noiseVal /= 2
|
|
case of
|
|
(
|
|
(noiseVal < 0):(noiseVal = 0)
|
|
(noiseVal > 1):(noiseVal = 1)
|
|
)
|
|
|
|
-- Use noise-value to pick grey from vert's dirt-range:
|
|
local greyVal = dirtRange.min + (noiseVal * (dirtRange.max - dirtRange.min))
|
|
|
|
objOp.SetVertColor tempObj dirtChan vertNum [greyVal,greyVal,greyVal]
|
|
)
|
|
|
|
RsVertClr_applyTempData tempObj obj dirtChan modName:"DirtColours"
|
|
)
|
|
|
|
select objs
|
|
|
|
return OK
|
|
)
|
|
|
|
|
|
-- VERTEXPAINT MODIFIER BITS --
|
|
|
|
-- Get currently-active VertexPaint modifier, if shown:
|
|
local vertMod
|
|
local vertModEdit = VertexPaintTool()
|
|
fn getVertMod =
|
|
(
|
|
local getMod = modPanel.getCurrentObject()
|
|
|
|
if (getMod != vertMod) do
|
|
(
|
|
if (isKindOf getMod vertexPaint) then
|
|
(
|
|
vertMod = getMod
|
|
)
|
|
else
|
|
(
|
|
vertMod = undefined
|
|
)
|
|
)
|
|
|
|
return vertMod
|
|
)
|
|
|
|
-- Update controls to match current VertexPaint settings:
|
|
fn updatePaintCtrls =
|
|
(
|
|
getVertMod()
|
|
|
|
if (vertMod == undefined) then
|
|
(
|
|
rdoPaintClr.enabled = False
|
|
rdoBrushSize.enabled = False
|
|
|
|
rdoPaintClr.state = 0
|
|
rdoBrushSize.state = 0
|
|
)
|
|
else
|
|
(
|
|
rdoPaintClr.enabled = True
|
|
rdoBrushSize.enabled = True
|
|
|
|
-- Push buttons if they match relevant value:
|
|
|
|
local setState = 0
|
|
local toolPaintClr = (vertModEdit.paintColor as point3)
|
|
for ctrlNum = 1 to paintClrs.count while (setState == 0) do
|
|
(
|
|
if (distance toolPaintClr (paintClrs[ctrlNum] as point3) < 0.001) do
|
|
(
|
|
setState = ctrlNum
|
|
)
|
|
)
|
|
if (rdoPaintClr.state != setState) do (rdoPaintClr.state = setState)
|
|
|
|
local setState = 0
|
|
local toolBrushSize = vertModEdit.brushSize
|
|
for ctrlNum = 1 to brushSizes.count while (setState == 0) do
|
|
(
|
|
if (abs (toolBrushSize - brushSizes[ctrlNum]) < 0.001) do
|
|
(
|
|
setState = ctrlNum
|
|
)
|
|
)
|
|
if (rdoBrushSize.state != setState) do (rdoBrushSize.state = setState)
|
|
)
|
|
)
|
|
|
|
-- Use timer to keep control-states up-to-date with Vertex Paint Toolkit:
|
|
on tmrVpaint tick do
|
|
(
|
|
updatePaintCtrls()
|
|
)
|
|
|
|
-- Change VertexPaint colour:
|
|
fn pressPaintClrBtn num =
|
|
(
|
|
vertModEdit.paintColor = paintClrs[num]
|
|
vertModEdit.keepToolboxOpen = vertModEdit.keepToolboxOpen
|
|
updatePaintCtrls()
|
|
)
|
|
on rdoPaintClr changed state do (pressPaintClrBtn state)
|
|
|
|
-- Change VertexPaint brush-size:
|
|
fn pressBrushSizeBtn num =
|
|
(
|
|
vertModEdit.brushSize = brushSizes[num]
|
|
vertModEdit.keepToolboxOpen = vertModEdit.keepToolboxOpen
|
|
updatePaintCtrls()
|
|
)
|
|
on rdoBrushSize changed state do (pressBrushSizeBtn state)
|
|
|
|
-- Add new VertexPaint modifier to selection:
|
|
on btnAddVpaint pressed do
|
|
(
|
|
local objs = for obj in getCurrentSelection() where (isEditPolyMesh obj) collect obj
|
|
|
|
if (objs.count == 0) do
|
|
(
|
|
return False
|
|
)
|
|
|
|
showDirty()
|
|
local paintMod = vertexPaint mapChannel:dirtChan name:"Dirt VertexPaint"
|
|
addModifier objs paintMod
|
|
showDirty()
|
|
select objs
|
|
)
|
|
|
|
-- /VERTEXPAINT MODIFIER BITS --
|
|
|
|
|
|
on txtDirtier entered newText do
|
|
(
|
|
dirtierBonesString = newText
|
|
)
|
|
on txtDirtiest entered newText do
|
|
(
|
|
dirtiestBonesString = newText
|
|
)
|
|
|
|
fn minDirtyChanged val =
|
|
(
|
|
dirtyRange.min = val
|
|
if (val > dirtyRange.max) do (dirtyRange.max = val)
|
|
updateCtrls()
|
|
)
|
|
on spnMinDirty changed val do (minDirtyChanged val)
|
|
on sldMinDirty changed val do (minDirtyChanged val)
|
|
|
|
fn maxDirtyChanged val =
|
|
(
|
|
dirtyRange.max = val
|
|
if (val < dirtyRange.min) do (dirtyRange.min = val)
|
|
updateCtrls()
|
|
)
|
|
on spnMaxDirty changed val do (maxDirtyChanged val)
|
|
on sldMaxDirty changed val do (maxDirtyChanged val)
|
|
|
|
fn minDirtierChanged val =
|
|
(
|
|
dirtierRange.min = val
|
|
if (val > dirtierRange.max) do (dirtierRange.max = val)
|
|
updateCtrls()
|
|
)
|
|
on spnMinDirtier changed val do (minDirtierChanged val)
|
|
on sldMinDirtier changed val do (minDirtierChanged val)
|
|
|
|
fn maxDirtierChanged val =
|
|
(
|
|
dirtierRange.max = val
|
|
if (val < dirtierRange.min) do (dirtierRange.min = val)
|
|
updateCtrls()
|
|
)
|
|
on spnMaxDirtier changed val do (maxDirtierChanged val)
|
|
on sldMaxDirtier changed val do (maxDirtierChanged val)
|
|
|
|
fn minDirtiestChanged val =
|
|
(
|
|
dirtiestRange.min = val
|
|
if (val > dirtiestRange.max) do (dirtiestRange.max = val)
|
|
updateCtrls()
|
|
)
|
|
on spnMinDirtiest changed val do (minDirtiestChanged val)
|
|
on sldMinDirtiest changed val do (minDirtiestChanged val)
|
|
|
|
fn maxDirtiestChanged val =
|
|
(
|
|
dirtiestRange.max = val
|
|
if (val < dirtiestRange.min) do (dirtiestRange.min = val)
|
|
updateCtrls()
|
|
)
|
|
on spnMaxDirtiest changed val do (maxDirtiestChanged val)
|
|
on sldMaxDirtiest changed val do (maxDirtiestChanged val)
|
|
|
|
on btnRandom pressed do
|
|
(
|
|
rndSeed = (random spnSeed.range[1] spnSeed.range[2])
|
|
|
|
updateCtrls()
|
|
)
|
|
on spnSeed changed val do
|
|
(
|
|
rndSeed = val
|
|
)
|
|
on spnScale changed val do
|
|
(
|
|
noiseScale = val
|
|
)
|
|
on spnContrast changed val do
|
|
(
|
|
noiseContrast = val
|
|
)
|
|
|
|
on btnDoDirty pressed do
|
|
(
|
|
local objs = for obj in getCurrentSelection() where (isEditPolyMesh obj) collect obj
|
|
|
|
if (objs.count == 0) do
|
|
(
|
|
messageBox "No geometry is selected" title:"Error: Invalid Selection"
|
|
return False
|
|
)
|
|
|
|
showDirty()
|
|
pedDirtBake objs:objs
|
|
showDirty()
|
|
)
|
|
on btnShowDirty pressed do
|
|
(
|
|
showDirty()
|
|
)
|
|
on btnUnshowDirty pressed do
|
|
(
|
|
showDirty unshow:True
|
|
)
|
|
|
|
on RsPedDirtBakerRoll open do
|
|
(
|
|
-- Initialise tech-art banner:
|
|
bannerStruct.setup()
|
|
|
|
rndSeed = (random spnSeed.range[1] spnSeed.range[2])
|
|
updateCtrls()
|
|
)
|
|
)
|
|
|
|
createDialog RsPedDirtBakerRoll
|