[Closed] MaxText to multiple strings
Hello
I’m relatively new to MaxScripting and I was wondering if someone could help me.
Is there a way to convert MaxText to multiple strings in editor? In my case, I would like to connect every row from MaxText to “keyframe name” and name should be printed in editbox below slider (just to check if is correct). In script I created a complicated way of this solution by adding single string for each name. I connected variable slider to sliderTime and all I want script to do is to select by hit MaxText node from maxscene (or select by name), print it in edittext box under the button, collect it and to convert every row to a specific string (that will be printed in editbox below slider) with removed first three symbols (“03” and “space” in, for example, “03 three-pose” to “three-pose”) –I want to remove those first three because that name will be in automated render save file image later in script.
I would be very grateful if someone could help me handle this.
Thanks in advance, the script is below.
try destroydialog ::TT catch()
Rollout TT "TimeText" width:120
(
spinner spTT "TimeSlider" type:#integer range:[0,100,currentTime] align:#left width:100 height:20
edittext nmTT readOnly:true align:#left offset:[0,-5] width:100 height:18
button bnSelText "Select MaxText" align:#left height:30 width:97
listbox list_text "" align:#left height:5 width:97 across:2 readOnly:true enabled:true
on spTT changed ttime do
(
pose00 = "00 zero-pose"
pose01 = "01 one-pose"
pose02 = "02 two-pose"
pose03 = "03 three-pose"
pose04 = "04 four-pose"
pose05 = "05 five-pose"
pose06 = "06 six-pose"
pose07 = "07 seven-pose"
pose08 = "08 eight-pose"
pose09 = "09 nine-pose"
pose10 = "10 ten-pose"
local p1 =
(
if ttime == 0f then pose00 else
(if ttime == 1f then pose01 else
(if ttime == 2f then pose02 else
(if ttime == 3f then pose03 else
(if ttime == 4f then pose04 else
(if ttime == 5f then pose05 else
(if ttime == 6f then pose06 else
(if ttime == 7f then pose07 else
(if ttime == 8f then pose08 else
(if ttime == 9f then pose09 else
(if ttime == 10f then pose10 else
(if ttime > 10f then "10+undefined-pose"
)
)
)
)
)
)
)
)
)
)
)
)
nmTT.text = p1
sliderTime = ttime --<<< when slider "TimeSlider" is changed value it changes "sliderTime" inside Max
)
on TT open do
(
nmTT.text = "undefined" --<<< instead of undifined this should be current name for that frame
)
fn FilterShapes obj = isKindOf obj shape
on bnSelText pressed do
(
sel = selectByName title:"Pick Text" filter:FilterShapes showHidden:true
if sel != undefined then
(
theObjects = sel
list_text.items = for j in theObjects collect j.name --<<< instead of collecting and printing name of that MaxText, script should collect content text inside this MaxText
)
)
/* 00 zero-pose
01 one-pose
02 two-pose
03 three-pose
04 four-pose
05 five-pose
06 six-pose
07 seven-pose
08 eight-pose
09 nine-pose
10 ten-pose
*/ --this should be inside MaxText in the scene
)
createDialog TT
Oh my… You’re doing some things in a very contrived way. : )
Like declaring a separate variable for every string. What you should really look into is arrays; they’re for storing a list of stuff and getting it using indexes. Would solve the problem of having a new variable for every frame.
Also, it’s probably better you declare your array of poses in the rollout, and not in the “slider changed” block. What happens currently is you redeclare the variables again every time the slider is moved. And those variables are local to the “slider changed” block, so the “load” block doesn’t see them.
Unless I misunderstood your intentions, this part…
list_text.items = for j in theObjects collect j.name
-- instead of collecting and printing name of that MaxText, script should collect content text inside this MaxText
…would simply be:
list_text.items = for j in theObjects collect j.text
As for the actual problem you are having… both your code and your explanation is a bit hard to follow.
There’s probably a better way of doing this. What is this for? What is the higher-level problem you are trying to solve? If you could simply and clearly describe what you need done, and how you want it to work, we can probably come up with a fitting simpler solution for it.
Thank you for response, Julius. Here I will post whole script and describe problem as close as I can.
I’m doing still poses (with biped) for a character with switchable face expressions and render them as separate: Head and body – on the same pose i can switch and render facial expressions defined by a diffuse map in separate material (number of facial expressions = standard materials in scene). This is for a game and those rendered images (body and few different expressions) are merged to a complete character. Later on, this will be animated with switchable faces with dialog text above and so on…
Scene is made from biped (and mesh skinned to it) MaxText with predefined poses for character formatted as (“pose number”, “(space)”, “pose name”) for example “04 welcoming” – pose number is also timeslider number in Max just to found specified poses more easily (it can be to 200 poses). Materials are node-based – standard, selfillumination:100, diffuse map (face expression). It can be more than 30 different expressions to switch on a face mesh so I want that to be automated with spinner somehow too. Temporarily I have setup for expressions using state sets (each set is different material) and it can be easily changed in between.
I’ve written a script with big help from Jorge Rodríguez here on this forum in thread: “MaxScript MATTE Global Override” Everything works perfectly, just as I wanted. Only thing that I want to do to finish the script is to add a function to those spinners on top of the script – pose and expressions. I want to collect text by hit or by list to a listbox, print them like you suggested, Julius, only difference is that has to separate it by rows with “
” or with “filterString” or with some other way to print poses one under another (just for 10 rows or less). And that kind of text to be connected to a “Pose” spinner as a string, I suppose, with first three symbols removed for example in “04 welcoming” to “welcoming” – and that string should be printed in edittext next to Pose spinner. When pose is named, text in this edittext is named in rendered .png under that name for example “welcoming.png” (which is already settled). The same thing is with expressions spinner – It should be a switchable materials in array with named materials in edittext – the same thing with rendering – only this time, in name of .png of expressions, it is named “pose name”, “-” “expression(material) name” for example “welcoming-happy.png” (this is also already settled) Also, the diffuse map name is the same name as it is material for example: happy.jpg as a diffuse map to a happy.material.
All that I want is to connect pose spinner to a variable strings by changing time/poses and expression spinner to expressions/materials. I hope that this makes more sense than previous post sry for bad English. The screenshots from scene are attached and the code for whole script is below. Thank you in advance and I hope that there must be some kind of solution for that situation.
try destroydialog ::CRM catch()
Rollout CRM "CRM" width:225
(
group "Character Def"
(
spinner sp_Pose "Pose" type:#integer range:[0,200,currentTime] align:#left across:2 width:100 height:20
spinner sp_Expression "Expression" type:#integer range:[0,20,1] align:#right width:100 height:20
edittext tx_Pose readOnly:true align:#left across:2 offset:[0,-5] width:100 height:18
edittext tx_Expression readOnly:true align:#right offset:[0,-5] width:100 height:18
)
group "Select and Location"
(
button bt_selectFolder "..." tooltip:"Pick path for render" align:#left width:30 offset: [0,0] across:2 height:18
edittext tx_folder "" readonly:true align:#right height:18 width:165
button bt_SelectGeometry "Select Geometry" align:#right height:30 width:97 across:2
button bt_SelectCamera "Select Camera" align:#left height:30 width:97
listbox list_geometry "" align:#left height:5 width:97 across:2 readOnly:true enabled:true
listbox list_cameras "" align:#right height:5 width:97
button bnSelText "Select MaxText" align:#left height:30 width:97
listbox list_text "" align:#left height:5 width:97 readOnly:true enabled:true
label rend_option "Render:" align:#left across:2
radiobuttons rad_options "" labels:#("Pose","Expression") align:#left offsets:#([-50,0],[-40,0])
)
group "Update - Render"
(
button bt_update "Update" align:#left across:2 width: 97 height:30
button bt_render "Render" align:#right width:97 height:30
)
local matteMaterial
local theObjects = #()
local theCameras = #()
local outputFolder = undefined
local p1 = "pose" + sliderTime as string --<<<this should be a variable string for each pose or something that will cycle poses in MaxText that is selected and convert them to strings
local e1 = "expression1" --<<<this should me material cycle that will print material name
on CRM open do
(
matteMaterial = Matte_Shadow_Reflection__mi catch_shadows:false ao_on:false catch_reflections:false
tx_Pose.text = p1
tx_Expression.text = "exp0"
)
fn FilterGeometry obj = isKindOf obj geometryClass and not isKindOf obj Targetobject --<<<it should list only geometry objects but it also lists bones in selectByName window for some reason
fn FilterCameras obj = isKindOf obj camera
fn FilterShapes obj = isKindOf obj shape
on sp_Pose changed ttime do
(
p1 = if ttime >0 then "poza" + sliderTime as string
tx_Pose.text = p1 as string
sliderTime = ttime
)
on sp_Expression changed ttime do
(
tx_Expression.text = e1
)
on bt_SelectGeometry pressed do
(
sel = selectByName title:"Pick" filter:FilterGeometry showHidden:true
if sel != undefined then
(
theObjects = sel
list_geometry.items = for j in theObjects collect j.name
)else(
list_geometry.items = #()
theObjects = #()
)
)
on bt_SelectCamera pressed do
(
sel = selectByName title:"Pick" filter:FilterCameras showHidden:true
if sel != undefined then
(
theCameras = sel
list_cameras.items = for j in theCameras collect j.name
)else(
list_cameras.items = #()
theCameras = #()
)
)
on bnSelText pressed do
(
sel = selectByName title:"Pick Text" filter:FilterShapes showHidden:true
if sel != undefined then
(
theObjects = sel
list_text.items = for j in theObjects collect j.text --<<< instead of printing text in one row it should be separated in each line below
)
)
on bt_selectFolder pressed do
(
outputFolder = getSavePath()
if outputFolder != undefined then tx_folder.text = outputFolder else tx_folder.text = "undefined"
)
on bt_render pressed do
(
if outputFolder == undefined do return messagebox "No Output Folder Selected"
if theObjects.count == 0 do return messagebox "No Geometry Selected"
if theCameras.count == 0 do return messagebox "No Camera Selected"
setwaitcursor()
cam = theCameras[list_cameras.selection]
case rad_options.state of
(
1:
(
matteObjects = theObjects
filename = outputFolder + "\\" + p1 + ".png"
)
2:
(
matteObjects = for j in geometry where finditem theObjects j == 0 collect j
filename = outputFolder + "\\" + p1 + "-" + e1 + ".png"
)
)
oldMaterials = for j in matteObjects collect #(j, j.material)
matteObjects.material = matteMaterial
render camera:cam vfb:false outputwidth:128 outputheight:256 outputfile:filename
for j in oldMaterials do j[1].material = j[2]
messagebox ("Image Rendered to:
" + filename)
setarrowcursor()
)
)
createdialog CRM
script_problem_02
wonder why don’t you just parse some text file for those pose names?
on bnSelText pressed do
(
sel = selectByName title:"Pick Text" filter:FilterShapes showHidden:true
if sel != undefined then
(
theObjects = sel
local arr = #()
for s in theObjects do (
for w in filterstring s.text "
" do append arr (substring w 4 (w.count - 2))
)
list_text.items = arr
)
)
Thank you for reply, Panteleev. And thank you for the code solution, it parsed text and removed first three symbols just like I wanted. Now I need to convert that parsed text in list_text.items into multiple strings or as a variable string if it is possible so they can be showed in tx_Expression edittext when changing spinner for poses. I’m still searching a way to do this and watching many tutorials on MaxScript but can’t find any similar problem or a solution to that. I attached 2 more images to simplify as close as I can.
004
on sp_Pose changed ttime do
(
p1 = if ttime > 0 then "poza" + sliderTime as string
tx_Pose.text = p1 as string
sliderTime = ttime
if ttime > 0 then (
tx_Expression.text = if list_text.items[ ttime ] != undefined then list_text.items[ttime] else ""
) else (
tx_Expression.text = ""
)
)
on sp_Expression changed ttime do
(
if ttime > 0 then (
tx_Expression.text = if list_text.items[ ttime ] != undefined then list_text.items[ttime] else ""
) else (
tx_Expression.text = ""
)
)
It worked like a charm, thank you, Panteleev …and for the links, I’ll study those arrays more through and test them in various ways as soon as possible. Like I said, I’m still a newbie in scripting but little by little I’ll figure it out.
I have one more problem to solve, looks very simple but still can’t figure it out. When rendering to a image it appears to be a “space” between pose name and extension “.png” I’ve tried trimRight, replace, and token commands on it but none of that is working… here is the screenshot:
space_problem
And here is the full script below. Now it is 90% finished, all I need to do is to connect material spinner to cycle through materials somehow and it’s done. I’ll figure it out somehow, there’s weekend ahead
try destroydialog ::CRM catch()
Rollout CRM "CRM" width:225
(
group "Character Def"
(
spinner sp_Pose "Pose" type:#integer range:[0,200,currentTime] align:#left across:2 width:100 height:20
spinner sp_Material "Material" type:#integer range:[0,20,1] align:#right width:100 height:20
edittext tx_Pose readOnly:true align:#left across:2 offset:[0,-5] width:100 height:18
edittext tx_Material readOnly:true align:#right offset:[0,-5] width:100 height:18
)
group "Select and Location"
(
button bt_selectFolder "..." tooltip:"Pick path for render" align:#left width:30 offset: [0,0] across:2 height:18
edittext tx_folder "" readonly:true align:#right height:18 width:165
button bt_SelectGeometry "Select Geometry" align:#right height:30 width:97 across:2
button bt_SelectCamera "Select Camera" align:#left height:30 width:97
listbox list_geometry "" align:#left height:5 width:97 across:2 readOnly:true enabled:true
listbox list_cameras "" align:#right height:5 width:97
button bt_SelectText "Select MaxText" align:#left height:30 width:97
listbox list_text "" align:#left height:5 width:97 readOnly:true enabled:true
label rend_option "Render:" align:#left across:2
radiobuttons rad_options "" labels:#("Pose","FaceExpression") align:#left offsets:#([-50,0],[-40,0])
)
group "Update - Render"
(
button bt_update "Update" align:#left across:2 width: 97 height:30
button bt_render "Render" align:#right width:97 height:30
)
local matteMaterial
local theObjects = #()
local theCameras = #()
local outputFolder = undefined
on CRM open do
(
matteMaterial = Matte_Shadow_Reflection__mi catch_shadows:false ao_on:false catch_reflections:false
tx_Pose.text = "undefined"
tx_Material.text = "undefined"
)
fn FilterGeometry obj = isKindOf obj geometryClass and not isKindOf obj Targetobject --<<<it should list only geometry objects but it also lists bones in selectByName window for some reason
fn FilterCameras obj = isKindOf obj camera
fn FilterShapes obj = isKindOf obj shape
on sp_Pose changed ttime do
(
sliderTime = ttime
if ttime > 0 then (
tx_Pose.text = if list_text.items[ ttime ] != undefined then list_text.items[ttime] else ""
) else (
tx_Pose.text = ""
)
)
on bt_SelectGeometry pressed do
(
sel = selectByName title:"Pick" filter:FilterGeometry showHidden:true
if sel != undefined then
(
theObjects = sel
list_geometry.items = for j in theObjects collect j.name
)else(
list_geometry.items = #()
theObjects = #()
)
)
on bt_SelectCamera pressed do
(
sel = selectByName title:"Pick" filter:FilterCameras showHidden:true
if sel != undefined then
(
theCameras = sel
list_cameras.items = for j in theCameras collect j.name
)else(
list_cameras.items = #()
theCameras = #()
)
)
on bt_SelectText pressed do
(
sel = selectByName title:"Pick Text" filter:FilterShapes showHidden:true
if sel != undefined then
(
theObjects = sel
local arr = #()
for s in theObjects do (
for w in filterstring s.text "
" do append arr (substring w 4 (w.count - 2))
)
list_text.items = arr
)
)
on bt_selectFolder pressed do
(
outputFolder = getSavePath()
if outputFolder != undefined then tx_folder.text = outputFolder else tx_folder.text = "undefined"
)
on bt_render pressed do
(
if outputFolder == undefined do return messagebox "No Output Folder Selected"
if theObjects.count == 0 do return messagebox "No Geometry Selected"
if theCameras.count == 0 do return messagebox "No Camera Selected"
setwaitcursor()
cam = theCameras[list_cameras.selection]
rendName = tx_Pose.text
case rad_options.state of
(
1:
(
matteObjects = theObjects
filename = outputFolder + "\\" + rendName + ".png"
)
2:
(
matteObjects = for j in geometry where finditem theObjects j == 0 collect j
filename = outputFolder + "\\" + rendName + "-" + "material_name" + ".png"
)
)
oldMaterials = for j in matteObjects collect #(j, j.material)
matteObjects.material = matteMaterial
render camera:cam vfb:false outputwidth:128 outputheight:256 outputfile:filename
for j in oldMaterials do j[1].material = j[2]
--messagebox ("Image Rendered to:
" + filename)
setarrowcursor()
)
)
createdialog CRM
Thanks everyone! I have figured out almost everything thanks to cgsociety and scriptspot forums and now I have 99% of script settled. I have one more issue to solve and still can’t figure it out… I want my sp_Material spinner to instantly change and assign those materials (which are collected from scene and in array and listed) to selected mesh or, if it is possible, let Max to found mesh in which has a name in it (“Head” in “MESH_Head_01” – that would be fantastic) and make that as a selection (just to avoid manually selecting in scene) I tried to access the material index via spinner.value but i got “–No ““get”” function for undefined” error. Here is the code and screenshot is in the attachment.
try destroydialog ::CRM catch()
Rollout CRM "CRM" width:225
(
group "Character Def"
(
spinner sp_Pose "Pose" type:#integer range:[0,200,currentTime] align:#left across:2 width:100 height:20
spinner sp_Material "Material" type:#integer range:[0,20,1] align:#right width:100 height:20
edittext tx_Pose readOnly:true align:#left across:2 offset:[0,-5] width:100 height:18
edittext tx_Material readOnly:true align:#right offset:[0,-5] width:100 height:18
)
group "Select and Location"
(
button bt_selectFolder "..." tooltip:"Pick path for render" align:#left width:30 offset: [0,0] across:2 height:18
edittext tx_folder "" readonly:true align:#right height:18 width:165
button bt_SelectGeometry "Select Geometry" align:#right height:30 width:97 across:2
button bt_SelectCamera "Select Camera" align:#left height:30 width:97
listbox list_geometry "" align:#left height:5 width:97 across:2 readOnly:true enabled:true
listbox list_cameras "" align:#right height:5 width:97
button bt_SelectText "Select MaxText" align:#left height:30 width:97 across:2
button bt_SelectMaterials "Collect Materials" align:#right height:30 width:97
listbox list_text "" align:#left height:5 width:97 readOnly:true across:2 enabled:true
listbox list_materials "" align:#right height:5 width:97 readonly:true enabled:true
label rend_option "Render:" align:#left across:2
radiobuttons rad_options "" labels:#("Pose","FaceExpression") align:#left offsets:#([-50,0],[-40,0])
)
group "Update - Render"
(
--button bt_update "Update" align:#left across:2 width: 97 height:30
button bt_render "Render" border:false align:#center width:206 height:256
)
local matteMaterial
local theObjects = #()
local theCameras = #()
local outputFolder = undefined
local tpose = "t-pose"
on CRM open do
(
matteMaterial = Matte_Shadow_Reflection__mi catch_shadows:false ao_on:false catch_reflections:false
tx_Pose.text = tpose
tx_Material.text = "undefined"
)
fn FilterGeometry obj = isKindOf obj geometryClass and not isKindOf obj Targetobject --<<<it should list only geometry objects but it also lists bones in selectByName window for some reason
fn FilterCameras obj = isKindOf obj camera
fn FilterShapes obj = isKindOf obj shape
on sp_Pose changed ttime do
(
sliderTime = ttime
if ttime > 0 then
(
tx_Pose.text = if list_text.items[ ttime+1 ] != undefined then list_text.items[ttime+1] else ""
)
else if ttime == 0 then
(
tx_Pose.text = "t-pose"
)
)
on sp_Material changed FEx do
(
if sp_Material.value > 0 then (
tx_Material.text = if list_materials.items[sp_Material.value] != undefined then list_materials.items[sp_Material.value] else ""
) else (
tx_Material.text = ""
)
FEx = theMaterials[sp_Material.value]
face = $
face.material = FEx showInViewport:true
)
on bt_SelectGeometry pressed do
(
sel = selectByName title:"Pick" filter:FilterGeometry showHidden:true
if sel != undefined then
(
theObjects = sel
list_geometry.items = for j in theObjects collect j.name
)else(
list_geometry.items = #()
theObjects = #()
)
)
on bt_SelectCamera pressed do
(
sel = selectByName title:"Pick" filter:FilterCameras showHidden:true
if sel != undefined then
(
theCameras = sel
list_cameras.items = for c in theCameras collect c.name
)else(
list_cameras.items = #()
theCameras = #()
)
)
on bt_SelectText pressed do
(
sel = selectByName title:"Pick Text" filter:FilterShapes showHidden:true
if sel != undefined then
(
theObjects = sel
local arr = #()
for s in theObjects do (
for w in filterstring s.text "
" do append arr (substring w 4 (w.count - 2))
)
list_text.items = arr
)
)
on bt_selectFolder pressed do
(
outputFolder = getSavePath()
if outputFolder != undefined then tx_folder.text = outputFolder else tx_folder.text = "undefined"
)
local theMaterials = #()
on bt_SelectMaterials pressed do
(
viewNode = sme.GetView (sme.activeView)
smeViewMats = #()
for n = 1 to trackViewNodes[#sme][(sme.activeView)].numSubs do
(
m = trackViewNodes[#sme][(sme.activeView)][n].reference
if superclassof m == material do append smeViewMats m
)
local selMats = smeViewMats
if selMats != undefined then
(
theMaterials = selMats
list_materials.items = for m in theMaterials collect m.name
)
else
(
list_materials.items = #()
theMaterials = #()
)
)
on bt_render pressed do
(
if outputFolder == undefined do return messagebox "No Output Folder Selected"
if theObjects.count == 0 do return messagebox "No Geometry Selected"
if theCameras.count == 0 do return messagebox "No Camera Selected"
setwaitcursor()
cam = theCameras[list_cameras.selection]
rendName = tx_Pose.text as string
local poseName = rendName = substring rendName 1 (rendName.count - 1)
case rad_options.state of
(
1:
(
matteObjects = theObjects
filename = outputFolder + "\\" + poseName + ".png"
)
2:
(
matteObjects = for j in geometry where finditem theObjects j == 0 collect j
filename = outputFolder + "\\" + poseName + "-" + "material_name" + ".png"
)
)
oldMaterials = for j in matteObjects collect #(j, j.material)
matteObjects.material = matteMaterial
fnRender = render camera:cam vfb:false outputwidth:128 outputheight:256 outputfile:filename
bt_Render.images = #(fnRender, undefined, 1,1,1,1,1 )
fnRender
for j in oldMaterials do j[1].material = j[2]
--messagebox ("Image Rendered to:
" + filename)
setarrowcursor()
)
)
createdialog CRM
material
Thank you for reply! I’ve finished script and it’s finally working.
Cheers