537 lines
15 KiB
Plaintext
Executable File
537 lines
15 KiB
Plaintext
Executable File
--createNormalSlidersFromMaps
|
|
--tool for taking user selection of normal maps
|
|
--then generating animated normal sliders & expressions
|
|
|
|
--Jan 2014
|
|
--Matt Rennie
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
filein "rockstar/export/settings.ms" -- This is fast
|
|
|
|
-- Figure out the project
|
|
theProjectRoot = RsConfigGetProjRootDir()
|
|
theProject = RSConfigGetProjectName()
|
|
theWildWest = RsConfigGetWildWestDir()
|
|
|
|
theProjectConfig = RsConfigGetProjBinConfigDir()
|
|
|
|
toolsRoot = RsConfigGetToolsRootDir()
|
|
|
|
-- filein (RsConfigGetWildWestDir() + "script\\max\\Rockstar_North\\character\\Includes\\FN_Rigging.ms")
|
|
filein (theWildWest + "script/3dsMax/_config_files/Wildwest_header.ms")
|
|
|
|
filein (theWildWest + "script/3dsMax/_common_functions/FN_RSTA_Perforce.ms")
|
|
|
|
-- filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms")
|
|
filein (theWildWest + "script/3dsMax/_common_functions/FN_RSTA_Rigging.ms" )
|
|
filein (theWildWest + "script/3dsMax/_common_functions/FN_RSTA_UI.ms" )
|
|
|
|
filein (theWildWest + "script/3dsMax/_config_files/Wildwest_header.ms")
|
|
|
|
|
|
filein (theWildWest + "script/3dsMax/Characters/Rigging/mrSkeleton_v2/mrSkeleton_2_functions.ms")
|
|
|
|
-- filein (theWildWest + "script/3dsMax/Characters/Rigging/mrSkeleton_v2/mrSkeleton_2_weaponRigging_functions.ms")
|
|
-- filein (theWildWest + "script/3dsMax/Characters/Rigging/mrSkeleton_v2/mrSkeleton_2_weaponRigging_functions.ms") --HORRIBLE HACK. HAVE TO FILEIN TWICE TO TRY AND HACK AROUND A SCOPE ISSUE WITH FUNCTION ORDERS.
|
|
|
|
-- filein (theWildWest + "script/3dsMax/Characters/Rigging/mrSkeleton_v2/mrSkeleton_2_propRigging_functions.ms")
|
|
|
|
-- filein (theWildWest + "script/3dsMax/Characters/Rigging/mrSkeleton_v2/mrSkeleton_2_propRigging_subRollouts.ms")
|
|
|
|
filein (theWildWest + "script/3dsMax/Characters/Rigging/mrSkeleton_v2/expressionExport/mrExpression_SpringHack.ms")
|
|
|
|
filein (theWildWest + "script/3dsMax/Characters/Rigging/mrSkeleton_v2/expressionExport/mrExpression_CutPasteController.ms")
|
|
|
|
filein (theWildWest + "script/3dsMax/Characters/Rigging/mrSkeleton_v2/expressionExport/mrExpression_Export.ms")
|
|
|
|
filein (theWildWest + "script/3dsMax/Characters/Rigging/mrSkeleton_v2/expressionExport/mrExpression_Import.ms")
|
|
|
|
boneTagMappingXmlFile = (toolsRoot + "/etc/content/animconfig/bone_tags.xml")
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
fn RSTA_configureAnimatedNormalShader normalMapArray =
|
|
(
|
|
slidersToBuild = #()
|
|
|
|
for i = 1 to normalMapArray[1].count do
|
|
(
|
|
--from the texture name we can derive which piece of geo this texture is for
|
|
nameFlt = filterString normalMapArray[7][i] "_"
|
|
|
|
nameString = (nameFlt[1]+"_"+nameFlt[2])
|
|
|
|
append slidersToBuild nameFlt[2]
|
|
format ("Looking for "+nameString+"\n")
|
|
obj = RSTA_getNodeByNameWildcard (nameString+"_U")
|
|
|
|
objName = undefined
|
|
if obj != undefined then
|
|
(
|
|
objName = (nameString+"_U")
|
|
)
|
|
else
|
|
(
|
|
obj = RSTA_getNodeByNameWildcard (nameString+"_R")
|
|
objName = (nameString+"_R")
|
|
)
|
|
|
|
objNameLength = objName.count
|
|
format ("objNameLength: "+(objNameLength as string)+"\n")
|
|
format ("objName: "+(objName)+"\n")
|
|
matchingObjs = #()
|
|
|
|
--gonna do somethign a bit hacky here to try and find the real version - gonna grab all objects with nameStr in and find the highest poly version!
|
|
for ob in objects do
|
|
(
|
|
if toLower((substring ob.name 1 objNameLength)) == toLower(objName) do
|
|
(
|
|
append matchingObjs ob
|
|
)
|
|
)
|
|
|
|
vertCount = 0
|
|
for ob in matchingObjs do
|
|
(
|
|
--format ("Testing "+ob.name+"\n")
|
|
if ob.numverts > vertCount do
|
|
(
|
|
vertCount = ob.numverts
|
|
obj = ob
|
|
)
|
|
)
|
|
|
|
mapList = #()
|
|
|
|
for ml = 1 to obj.material.count do
|
|
(
|
|
append mapList ml
|
|
)
|
|
|
|
format ("obj:"+(obj as string)+"\n")
|
|
idList = RsMatGetMapIdsUsedOnObject obj mapList
|
|
|
|
--now what we need to is find which of the material id's has the most faces assigned
|
|
--this should then allow us to know which is the appropriate material
|
|
|
|
faceid = undefined
|
|
if classof obj == Editable_mesh then
|
|
(
|
|
faceCount = 0
|
|
faceId = 0
|
|
for id in idList do
|
|
(
|
|
newFaceSel = #()
|
|
for f = 1 to obj.numfaces do
|
|
(
|
|
if getFaceMatID obj f == id do
|
|
(
|
|
append newFaceSel f
|
|
)--end if
|
|
|
|
)--end f loop
|
|
|
|
if newFaceSel.count > faceCount do
|
|
(
|
|
faceCount = newFaceSel.count
|
|
faceId = id
|
|
)
|
|
)
|
|
|
|
)
|
|
else
|
|
(
|
|
if classof obj == PolyMeshObject do
|
|
(
|
|
faceCount = 0
|
|
faceid = 0
|
|
|
|
for id in idList do
|
|
(
|
|
newFaceSel = #()
|
|
numFaces = polyOp.getNumFaces obj
|
|
for f = 1 to numFaces do
|
|
(
|
|
if (polyOp.getFaceMatID obj f) == id do
|
|
(
|
|
append newFaceSel f
|
|
)
|
|
)
|
|
|
|
if newFaceSel.count > faceCount do
|
|
(
|
|
faceCount = newFaceSel.count
|
|
faceId = id
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
objMat = obj.material
|
|
|
|
--now we have the id we can find the shader IDin objMat
|
|
if classof objMat == MultiMaterial then
|
|
(
|
|
format ("faceId: "+(faceId as string)+"\n")
|
|
objMatToUse = objMat[faceId]
|
|
|
|
format ("Relevant material: "+(objMatToUse as string)+"\n")
|
|
|
|
--now we need to use the rage commands to query the shader tpe and only change and configure the norals if its ped.sps or a nomral shader already
|
|
|
|
currShader = RstGetShaderName objMatToUse
|
|
|
|
format ("currShader :"+(currShader as string)+"\n" )
|
|
|
|
continueShader = false
|
|
if currShader == "ped.sps" then
|
|
(
|
|
shadertoset = "ped_wrinkle.sps"
|
|
|
|
RstSetShaderName objMatToUse shadertoset
|
|
|
|
continueShader = true
|
|
)
|
|
else
|
|
(
|
|
if currShader == "ped_wrinkle.sps" do
|
|
(
|
|
continueShader = true
|
|
)
|
|
)
|
|
|
|
if continueShader == true then
|
|
(
|
|
--now we need to add the wrinkles etc
|
|
|
|
shdrParams = RstGetVariableCount objMatToUse
|
|
wrinkleMasks = #(
|
|
#(
|
|
normalMapArray[2][i],
|
|
normalMapArray[3][i],
|
|
normalMapArray[4][i],
|
|
normalMapArray[5][i],
|
|
normalMapArray[1][i],
|
|
normalMapArray[8][i]
|
|
),
|
|
#(
|
|
"Wrinkle Mask 0",
|
|
"Wrinkle Mask 1",
|
|
"Wrinkle Mask 2",
|
|
"Wrinkle Mask 3",
|
|
"Wrinkle A",
|
|
"Wrinkle B"
|
|
)
|
|
)
|
|
if shdrParams != undefined do
|
|
(
|
|
for sParam = 1 to shdrParams do
|
|
(
|
|
thisParam = RstGetVariableName objMatToUse sParam
|
|
for wm = 1 to wrinkleMasks[2].count do
|
|
(
|
|
if thisParam == wrinkleMasks[2][wm] do
|
|
(
|
|
print ("wrinkleMasks[1]["+(wm as string)+"]: "+(wrinkleMasks[1][wm] as string))
|
|
|
|
--now we need to set this parameter to be wrinkleMasks[1][wm]
|
|
RstSetVariable objMatToUse sParam wrinkleMasks[1][wm]
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
else
|
|
(
|
|
format ("Skipping shader creation for "+normalMapArray[7][i]+" as the shader is not ped.sps or ped_wrinkle.sps\n")
|
|
)
|
|
)
|
|
else
|
|
(
|
|
format ("Multimaterial not found\n")
|
|
)
|
|
)
|
|
return slidersToBuild
|
|
)
|
|
|
|
fn RSTA_ConfigureWrinkleSliderExpression normalMapArray =
|
|
(
|
|
firstPic = selection as array
|
|
--first off we'll store all objects in the scene
|
|
max select all
|
|
origArray = selection as array
|
|
|
|
--now we need to hook up the expression
|
|
--WE'LL USE THE FUNCTIONS FROM MREXPRESSION HERE
|
|
|
|
exprXml = "X:/gta5/art/peds/Skeletons/pedBodyWrinkleUpper/pedBodyWrinkleUpper.xml" --set of wrinkle slider expressions saved from Michael
|
|
preserveExistingExpressionsVal = false
|
|
forceDeleteSprings = false
|
|
|
|
startObjects = objects as array
|
|
|
|
RSTA_LoadExpressions exprXml forceDeleteSprings preserveExistingExpressionsVal true
|
|
|
|
postExpressionObjects = objects as array
|
|
|
|
newObjs = #()
|
|
for post in postExpressionObjects do
|
|
(
|
|
-- newObj = false
|
|
-- for pre in startObjects do
|
|
-- (
|
|
-- if post == pre do
|
|
-- (
|
|
-- newObj = true
|
|
-- )
|
|
-- )
|
|
--
|
|
-- if newObj == true do
|
|
-- (
|
|
-- append newObjs post
|
|
-- )
|
|
newObj = finditem startObjects post
|
|
|
|
if newObj == 0 do
|
|
(
|
|
append NewObjs post
|
|
format (post.name+" is a new object\n")
|
|
)
|
|
)
|
|
|
|
--now we need to setup the shader.
|
|
slidersToBuild = RSTA_configureAnimatedNormalShader normalMapArray
|
|
|
|
--now we need to only leave the wrinkle shaders for the maps we have.
|
|
|
|
for i = 1 to slidersToBuild.count do
|
|
(
|
|
sliderNumber = slidersToBuild[i]
|
|
|
|
for ind = newObjs.count to 1 by -1 do
|
|
(
|
|
obj = newObjs[ind]
|
|
if obj.name == ("RECT_"+"WM_Upper_"+sliderNumber) do
|
|
(
|
|
--format ("KEEPING "+obj.name+"\n")
|
|
deleteItem newObjs ind
|
|
)
|
|
|
|
if obj.name == ("TEXT_"+"WM_Upper_"+sliderNumber) do
|
|
(
|
|
--format ("KEEPING "+obj.name+"\n")
|
|
deleteItem newObjs ind
|
|
)
|
|
if obj.name == ("WM_Upper_"+sliderNumber) do
|
|
(
|
|
--format ("KEEPING "+obj.name+"\n")
|
|
deleteItem newObjs ind
|
|
)
|
|
if obj.name == "UPPER_WRINKLES_TEXT" do
|
|
(
|
|
deleteItem newObjs ind
|
|
)
|
|
if obj.name == "WRINKLES_TEXT" do
|
|
(
|
|
deleteItem newObjs ind
|
|
)
|
|
)
|
|
)
|
|
|
|
for i = newObjs.count to 1 by -1 do
|
|
(
|
|
--format ("Removing "+newObjs[i].name+"\n")
|
|
delete newObjs[i]
|
|
)
|
|
)
|
|
|
|
fn RSTA_pickNormalMaps =
|
|
(
|
|
normalArray = #(
|
|
#(), --WrinkleA Map
|
|
#(), -- A1 Mask
|
|
#(), -- A2 Mask
|
|
#(), --B1 Mask
|
|
#(), -- B2 Mask
|
|
#(), --component
|
|
#(), --name
|
|
#() --WrinkleB Map
|
|
)
|
|
|
|
--wrinkle maps will always be in /textures/HighRes/wrinkleMaps/
|
|
fileFilter = "TGA Files (*_WA.tga)|*_WA.tga|All Files (*.*)|*.*"
|
|
titleBar = "Select One Or More WrinkleMAP files"
|
|
initialDir = (maxfilepath+"textures")
|
|
|
|
dirExists = doesFileExist initialDir
|
|
if dirExists == false do
|
|
(
|
|
initialDir = maxfilePath
|
|
)
|
|
|
|
format ("Using texturePath: "+initialDir+"\n")
|
|
|
|
-- local wrinkleMaps = RSgetOpenFilenames caption:titleBar filename:"" types:fileFilter
|
|
wrinkleMaps = RSTA_multiFileSelector fileFilter titleBar initialDir
|
|
|
|
|
|
--wrinkle masks will always be in /textures/HighRes/wrinkleMasks/
|
|
|
|
fileNotFound = undefined
|
|
|
|
if wrinkleMaps != undefined do
|
|
(
|
|
for wMap in wrinkleMaps do
|
|
(
|
|
append normalArray[1] wMap
|
|
|
|
bMap = ((substring wMap 1 ((wMap.count)- 5)+"B.tga"))
|
|
|
|
format ("bMap: "+(bMap as string)+"\n")
|
|
|
|
append normalArray[8] bMap
|
|
--now we need to find the A and B masks
|
|
--so we get the filePath of wMap
|
|
--then look for the corrseponding wrinkleMasks folder
|
|
--format ("wMap: "+(wMap as string)+"\n")
|
|
|
|
wMapFileName = filenameFromPath wMap
|
|
--format ("wMapFileName: "+(wMapFileName as string)+"\n")
|
|
wMapPath = getFilenamePath wMap
|
|
--format ("wMapPath: "+(wMapPath as string)+"\n")
|
|
|
|
--ok now we need to strip back wMapPath to substitue wrinkleMasks
|
|
|
|
s2 = "wrinkleMaps"
|
|
s3 = "wrinkleMasks"
|
|
maskPath = substituteString wMapPath s2 s3
|
|
--format ("maskPath: "+(maskPath as string)+"\n")
|
|
|
|
--now we need to do some file name switching
|
|
--wrinkleMap will be of the form Uppr_000_WA.tga
|
|
--wrinkle Masks will be of the form Uppr_Normal_000_MA1
|
|
|
|
mapFilt = filterString wMapFileName "."
|
|
mapName = mapFilt[1]
|
|
mapNameFilt = filterString mapName "_"
|
|
|
|
maskAName = (mapNameFilt[1]+"_"+"Normal_")
|
|
|
|
append normalArray[6] mapNameFilt[1]
|
|
|
|
for i = 2 to (mapNameFilt.count - 1) do
|
|
(
|
|
maskAname = (maskAName+mapNameFilt[i]+"_")
|
|
)
|
|
|
|
tmpArr = #()
|
|
|
|
append normalArray[7] mapName
|
|
|
|
maskAName1 = (maskPath+maskAName+"M"+"A"+"1.tga")
|
|
--format ("maskAName1: "+(maskAName1 as string)+"\n")
|
|
append tmpArr maskAName1
|
|
maskAName2 = (maskPath+maskAName+"M"+"A"+"2.tga")
|
|
--format ("maskAName2: "+(maskAName2 as string)+"\n")
|
|
append tmpArr maskAName2
|
|
maskBName1 = (maskPath+maskAName+"M"+"B"+"1.tga")
|
|
--format ("maskBName1: "+(maskBName1 as string)+"\n")
|
|
append tmpArr maskBName1
|
|
maskBName2 = (maskPath+maskAName+"M"+"B"+"2.tga")
|
|
--format ("maskBName2: "+(maskBName2 as string)+"\n")
|
|
append tmpArr maskBName2
|
|
|
|
--now we need to check if these files actually exist
|
|
for i = 1 to tmpArr.count do
|
|
(
|
|
exists = doesFileExist tmpArr[i]
|
|
|
|
if exists == true then
|
|
(
|
|
append normalArray[i+1] tmpArr[i]
|
|
--format ("appending "+tmpArr[i]+"\n")
|
|
)
|
|
else
|
|
(
|
|
format ("WARNING! "+tmpArr[i]+" not found\n")
|
|
fileNotFound = false
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
returnData = undefined
|
|
|
|
if fileNotFound == undefined then
|
|
(
|
|
returnData = normalArray
|
|
)
|
|
return returnData
|
|
)
|
|
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
if ((createNormalSliderGUI != undefined) and (createNormalSliderGUI.isDisplayed)) do
|
|
(destroyDialog createNormalSliderGUI)
|
|
|
|
rollout createNormalSliderGUI "Normal Sliders"
|
|
(
|
|
dotNetControl rsBannerPanel "Panel" pos:[0,0] height:32 width:140
|
|
local banner = makeRsBanner dn_Panel:rsBannerPanel wiki:"PedAnimatedNormalMap" filename:(getThisScriptFilename())
|
|
|
|
button btnSelectNormals "Select Wrinkle Maps" width:135 height:40 tooltip:"Select your A maps and generate sliders"
|
|
checkBox chkDebugPrnt "DebugPrint" checked:false tooltip:"Check to enable debug --print output."
|
|
|
|
on createNormalSliderGUI open do
|
|
(
|
|
banner.setup()
|
|
chkDebugPrnt.state = false
|
|
debugPrintVal = false
|
|
)
|
|
|
|
on chkDebugPrnt changed theState do
|
|
(
|
|
if chkDebugPrnt.state == false then
|
|
(
|
|
debugPrintVal = false
|
|
)
|
|
else
|
|
(
|
|
debugPrintVal = true
|
|
)
|
|
)
|
|
|
|
on btnSelectNormals pressed do
|
|
(
|
|
normalMaps = RSTA_pickNormalMaps()
|
|
|
|
-- if normalMaps != undefined then
|
|
if normalMaps[1].count > 0 then
|
|
(
|
|
--ok we can carry on
|
|
for i = 1 to normalMaps[1].count do
|
|
(
|
|
format ("Wrinkle:"+normalMaps[1][i]+"\n"+"Mask A1:"+normalMaps[2][i]+"\n"+"Mask A2:"+normalMaps[3][i]+"\n"+"Mask B1:"+normalMaps[4][i]+"\n"+"Mask B2:"+normalMaps[5][i]+"\n\n")
|
|
format ("6:" +normalMaps[6][1]+"\n")
|
|
format ("7:" +normalMaps[7][1]+"\n")
|
|
)
|
|
|
|
-- RSTA_generateNormalSliders normalMaps
|
|
|
|
RSTA_ConfigureWrinkleSliderExpression normalMaps
|
|
|
|
format "DONE!\n"
|
|
)
|
|
else
|
|
(
|
|
format ("Cannot continue as maps not found. Please see the listener.")
|
|
messagebox ("Cannot continue as maps not found. Please see the listener.") beep:true
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
CreateDialog createNormalSliderGUI width:140 pos:[150, 150] |